mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Add GET histroy-transactions endpoint
This commit is contained in:
621
api/api_test.go
Normal file
621
api/api_test.go
Normal file
@@ -0,0 +1,621 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
swagger "github.com/getkin/kin-openapi/openapi3filter"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/hermeznetwork/hermez-node/db/l2db"
|
||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/hermeznetwork/hermez-node/test"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const apiPort = ":4010"
|
||||
const apiURL = "http://localhost" + apiPort + "/"
|
||||
|
||||
type testCommon struct {
|
||||
blocks []common.Block
|
||||
tokens []common.Token
|
||||
batches []common.Batch
|
||||
usrAddr string
|
||||
usrBjj string
|
||||
accs []common.Account
|
||||
usrTxs historyTxAPIs
|
||||
othrTxs historyTxAPIs
|
||||
allTxs historyTxAPIs
|
||||
router *swagger.Router
|
||||
}
|
||||
|
||||
type historyTxAPIs []historyTxAPI
|
||||
|
||||
func (h historyTxAPIs) Len() int { return len(h) }
|
||||
func (h historyTxAPIs) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||
func (h historyTxAPIs) Less(i, j int) bool {
|
||||
// i not forged yet
|
||||
if h[i].BatchNum == nil {
|
||||
if h[j].BatchNum != nil { // j is already forged
|
||||
return false
|
||||
}
|
||||
// Both aren't forged, is i in a smaller position?
|
||||
return h[i].Position < h[j].Position
|
||||
}
|
||||
// i is forged
|
||||
if h[j].BatchNum == nil {
|
||||
return true // j is not forged
|
||||
}
|
||||
// Both are forged
|
||||
if *h[i].BatchNum == *h[j].BatchNum {
|
||||
// At the same batch, is i in a smaller position?
|
||||
return h[i].Position < h[j].Position
|
||||
}
|
||||
// At different batches, is i in a smaller batch?
|
||||
return *h[i].BatchNum < *h[j].BatchNum
|
||||
}
|
||||
|
||||
var tc testCommon
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// Init swagger
|
||||
router := swagger.NewRouter().WithSwaggerFromFile("./swagger.yml")
|
||||
// Init DBs
|
||||
pass := os.Getenv("POSTGRES_PASS")
|
||||
hdb, err := historydb.NewHistoryDB(5432, "localhost", "hermez", pass, "history")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "tmpdb")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sdb, err := statedb.NewStateDB(dir, false, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
l2db, err := l2db.NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 512, 24*time.Hour)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Init API
|
||||
api := gin.Default()
|
||||
if err := SetAPIEndpoints(
|
||||
true,
|
||||
true,
|
||||
api,
|
||||
hdb,
|
||||
sdb,
|
||||
l2db,
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Start server
|
||||
server := &http.Server{Addr: apiPort, Handler: api}
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); err != nil &&
|
||||
err != http.ErrServerClosed {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
// Populate DBs
|
||||
// Clean DB
|
||||
err = h.Reorg(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen blocks and add them to DB
|
||||
const nBlocks = 5
|
||||
blocks := test.GenBlocks(1, nBlocks+1)
|
||||
err = h.AddBlocks(blocks)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen tokens and add them to DB
|
||||
const nTokens = 10
|
||||
tokens := test.GenTokens(nTokens, blocks)
|
||||
err = h.AddTokens(tokens)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen batches and add them to DB
|
||||
const nBatches = 10
|
||||
batches := test.GenBatches(nBatches, blocks)
|
||||
err = h.AddBatches(batches)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen accounts and add them to DB
|
||||
const totalAccounts = 40
|
||||
const userAccounts = 4
|
||||
usrAddr := ethCommon.BigToAddress(big.NewInt(4896847))
|
||||
privK := babyjub.NewRandPrivKey()
|
||||
usrBjj := privK.Public()
|
||||
accs := test.GenAccounts(totalAccounts, userAccounts, tokens, &usrAddr, usrBjj, batches)
|
||||
err = h.AddAccounts(accs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen L1Txs and add them to DB
|
||||
const totalL1Txs = 40
|
||||
const userL1Txs = 4
|
||||
usrL1Txs, othrL1Txs := test.GenL1Txs(0, totalL1Txs, userL1Txs, &usrAddr, accs, tokens, blocks, batches)
|
||||
var l1Txs []common.L1Tx
|
||||
l1Txs = append(l1Txs, usrL1Txs...)
|
||||
l1Txs = append(l1Txs, othrL1Txs...)
|
||||
err = h.AddL1Txs(l1Txs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen L2Txs and add them to DB
|
||||
const totalL2Txs = 20
|
||||
const userL2Txs = 4
|
||||
usrL2Txs, othrL2Txs := test.GenL2Txs(totalL1Txs, totalL2Txs, userL2Txs, &usrAddr, accs, tokens, blocks, batches)
|
||||
var l2Txs []common.L2Tx
|
||||
l2Txs = append(l2Txs, usrL2Txs...)
|
||||
l2Txs = append(l2Txs, othrL2Txs...)
|
||||
err = h.AddL2Txs(l2Txs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Set test commons
|
||||
txsToAPITxs := func(l1Txs []common.L1Tx, l2Txs []common.L2Tx, blocks []common.Block, tokens []common.Token) historyTxAPIs {
|
||||
// Transform L1Txs and L2Txs to generic Txs
|
||||
genericTxs := []*common.Tx{}
|
||||
for _, l1tx := range l1Txs {
|
||||
genericTxs = append(genericTxs, l1tx.Tx())
|
||||
}
|
||||
for _, l2tx := range l2Txs {
|
||||
genericTxs = append(genericTxs, l2tx.Tx())
|
||||
}
|
||||
// Transform generic Txs to HistoryTx
|
||||
historyTxs := []*historydb.HistoryTx{}
|
||||
for _, genericTx := range genericTxs {
|
||||
// find timestamp
|
||||
var timestamp time.Time
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
if blocks[i].EthBlockNum == genericTx.EthBlockNum {
|
||||
timestamp = blocks[i].Timestamp
|
||||
break
|
||||
}
|
||||
}
|
||||
// find token
|
||||
token := common.Token{}
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
if tokens[i].TokenID == genericTx.TokenID {
|
||||
token = tokens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
historyTxs = append(historyTxs, &historydb.HistoryTx{
|
||||
IsL1: genericTx.IsL1,
|
||||
TxID: genericTx.TxID,
|
||||
Type: genericTx.Type,
|
||||
Position: genericTx.Position,
|
||||
FromIdx: genericTx.FromIdx,
|
||||
ToIdx: genericTx.ToIdx,
|
||||
Amount: genericTx.Amount,
|
||||
AmountFloat: genericTx.AmountFloat,
|
||||
TokenID: genericTx.TokenID,
|
||||
USD: token.USD * genericTx.AmountFloat,
|
||||
BatchNum: genericTx.BatchNum,
|
||||
EthBlockNum: genericTx.EthBlockNum,
|
||||
ToForgeL1TxsNum: genericTx.ToForgeL1TxsNum,
|
||||
UserOrigin: genericTx.UserOrigin,
|
||||
FromEthAddr: genericTx.FromEthAddr,
|
||||
FromBJJ: genericTx.FromBJJ,
|
||||
LoadAmount: genericTx.LoadAmount,
|
||||
LoadAmountFloat: genericTx.LoadAmountFloat,
|
||||
LoadAmountUSD: token.USD * genericTx.LoadAmountFloat,
|
||||
Fee: genericTx.Fee,
|
||||
FeeUSD: genericTx.Fee.Percentage() * token.USD * genericTx.AmountFloat,
|
||||
Nonce: genericTx.Nonce,
|
||||
Timestamp: timestamp,
|
||||
TokenSymbol: token.Symbol,
|
||||
CurrentUSD: token.USD * genericTx.AmountFloat,
|
||||
USDUpdate: token.USDUpdate,
|
||||
})
|
||||
}
|
||||
return historyTxAPIs(historyTxsToAPI(historyTxs))
|
||||
}
|
||||
usrTxs := txsToAPITxs(usrL1Txs, usrL2Txs, blocks, tokens)
|
||||
sort.Sort(usrTxs)
|
||||
othrTxs := txsToAPITxs(othrL1Txs, othrL2Txs, blocks, tokens)
|
||||
sort.Sort(othrTxs)
|
||||
allTxs := append(usrTxs, othrTxs...)
|
||||
sort.Sort(allTxs)
|
||||
tc = testCommon{
|
||||
blocks: blocks,
|
||||
tokens: tokens,
|
||||
batches: batches,
|
||||
usrAddr: "hez:" + usrAddr.String(),
|
||||
usrBjj: bjjToString(usrBjj),
|
||||
accs: accs,
|
||||
usrTxs: usrTxs,
|
||||
othrTxs: othrTxs,
|
||||
allTxs: allTxs,
|
||||
router: router,
|
||||
}
|
||||
// Run tests
|
||||
result := m.Run()
|
||||
// Stop server
|
||||
if err := server.Shutdown(context.Background()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := h.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := l2.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(result)
|
||||
}
|
||||
|
||||
func TestGetHistoryTxs(t *testing.T) {
|
||||
endpoint := apiURL + "transactions-history"
|
||||
fetchedTxs := historyTxAPIs{}
|
||||
appendIter := func(intr interface{}) {
|
||||
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
||||
tmp := &historyTxAPI{}
|
||||
if err := copier.Copy(tmp, &intr.(*historyTxsAPI).Txs[i]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fetchedTxs = append(fetchedTxs, *tmp)
|
||||
}
|
||||
}
|
||||
// Get all (no filters)
|
||||
limit := 8
|
||||
path := fmt.Sprintf("%s?limit=%d&offset=", endpoint, limit)
|
||||
err := doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
assertHistoryTxAPIs(t, tc.allTxs, fetchedTxs)
|
||||
// Get by ethAddr
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 7
|
||||
path = fmt.Sprintf(
|
||||
"%s?hermezEthereumAddress=%s&limit=%d&offset=",
|
||||
endpoint, tc.usrAddr, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
assertHistoryTxAPIs(t, tc.usrTxs, fetchedTxs)
|
||||
// Get by bjj
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 6
|
||||
path = fmt.Sprintf(
|
||||
"%s?BJJ=%s&limit=%d&offset=",
|
||||
endpoint, tc.usrBjj, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
assertHistoryTxAPIs(t, tc.usrTxs, fetchedTxs)
|
||||
// Get by tokenID
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 5
|
||||
tokenID := tc.allTxs[0].TokenID
|
||||
path = fmt.Sprintf(
|
||||
"%s?tokenId=%d&limit=%d&offset=",
|
||||
endpoint, tokenID, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
tokenIDTxs := historyTxAPIs{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].TokenID == tokenID {
|
||||
tokenIDTxs = append(tokenIDTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, tokenIDTxs, fetchedTxs)
|
||||
// idx
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 4
|
||||
idx := tc.allTxs[0].FromIdx
|
||||
path = fmt.Sprintf(
|
||||
"%s?accountIndex=%s&limit=%d&offset=",
|
||||
endpoint, idx, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
idxTxs := historyTxAPIs{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].FromIdx == idx {
|
||||
idxTxs = append(idxTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, idxTxs, fetchedTxs)
|
||||
// batchNum
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 3
|
||||
batchNum := tc.allTxs[0].BatchNum
|
||||
path = fmt.Sprintf(
|
||||
"%s?batchNum=%d&limit=%d&offset=",
|
||||
endpoint, *batchNum, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
batchNumTxs := historyTxAPIs{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].BatchNum != nil &&
|
||||
*tc.allTxs[i].BatchNum == *batchNum {
|
||||
batchNumTxs = append(batchNumTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, batchNumTxs, fetchedTxs)
|
||||
// type
|
||||
txTypes := []common.TxType{
|
||||
common.TxTypeExit,
|
||||
common.TxTypeWithdrawn,
|
||||
common.TxTypeTransfer,
|
||||
common.TxTypeDeposit,
|
||||
common.TxTypeCreateAccountDeposit,
|
||||
common.TxTypeCreateAccountDepositTransfer,
|
||||
common.TxTypeDepositTransfer,
|
||||
common.TxTypeForceTransfer,
|
||||
common.TxTypeForceExit,
|
||||
common.TxTypeTransferToEthAddr,
|
||||
common.TxTypeTransferToBJJ,
|
||||
}
|
||||
for _, txType := range txTypes {
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 2
|
||||
path = fmt.Sprintf(
|
||||
"%s?type=%s&limit=%d&offset=",
|
||||
endpoint, txType, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
txTypeTxs := historyTxAPIs{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].Type == txType {
|
||||
txTypeTxs = append(txTypeTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, txTypeTxs, fetchedTxs)
|
||||
}
|
||||
// Multiple filters
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 1
|
||||
path = fmt.Sprintf(
|
||||
"%s?batchNum=%d&tokeId=%d&limit=%d&offset=",
|
||||
endpoint, *batchNum, tokenID, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
mixedTxs := historyTxAPIs{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].BatchNum != nil {
|
||||
if *tc.allTxs[i].BatchNum == *batchNum && tc.allTxs[i].TokenID == tokenID {
|
||||
mixedTxs = append(mixedTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, mixedTxs, fetchedTxs)
|
||||
// All, in reverse order
|
||||
fetchedTxs = historyTxAPIs{}
|
||||
limit = 5
|
||||
path = fmt.Sprintf("%s?", endpoint)
|
||||
appendIterRev := func(intr interface{}) {
|
||||
tmpAll := historyTxAPIs{}
|
||||
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
||||
tmpItem := &historyTxAPI{}
|
||||
if err := copier.Copy(tmpItem, &intr.(*historyTxsAPI).Txs[i]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tmpAll = append(tmpAll, *tmpItem)
|
||||
}
|
||||
fetchedTxs = append(tmpAll, fetchedTxs...)
|
||||
}
|
||||
err = doGoodReqPaginatedReverse(path, &historyTxsAPI{}, appendIterRev, limit)
|
||||
assert.NoError(t, err)
|
||||
assertHistoryTxAPIs(t, tc.allTxs, fetchedTxs)
|
||||
// 400
|
||||
path = fmt.Sprintf(
|
||||
"%s?accountIndex=%s&hermezEthereumAddress=%s",
|
||||
endpoint, idx, tc.usrAddr,
|
||||
)
|
||||
err = doBadReq("GET", path, nil, 400)
|
||||
assert.NoError(t, err)
|
||||
path = fmt.Sprintf("%s?tokenId=X", endpoint)
|
||||
err = doBadReq("GET", path, nil, 400)
|
||||
assert.NoError(t, err)
|
||||
// 404
|
||||
path = fmt.Sprintf("%s?batchNum=999999", endpoint)
|
||||
err = doBadReq("GET", path, nil, 404)
|
||||
assert.NoError(t, err)
|
||||
path = fmt.Sprintf("%s?limit=1000&offset=1000", endpoint)
|
||||
err = doBadReq("GET", path, nil, 404)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func assertHistoryTxAPIs(t *testing.T, expected, actual historyTxAPIs) {
|
||||
assert.Equal(t, len(expected), len(actual))
|
||||
for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
|
||||
assert.Equal(t, expected[i].Timestamp.Unix(), actual[i].Timestamp.Unix())
|
||||
expected[i].Timestamp = actual[i].Timestamp
|
||||
assert.Equal(t, expected[i].USDUpdate.Unix(), actual[i].USDUpdate.Unix())
|
||||
expected[i].USDUpdate = actual[i].USDUpdate
|
||||
if expected[i].L2Info != nil {
|
||||
if expected[i].L2Info.FeeUSD > actual[i].L2Info.FeeUSD {
|
||||
assert.Less(t, 0.999, actual[i].L2Info.FeeUSD/expected[i].L2Info.FeeUSD)
|
||||
} else if expected[i].L2Info.FeeUSD < actual[i].L2Info.FeeUSD {
|
||||
assert.Less(t, 0.999, expected[i].L2Info.FeeUSD/actual[i].L2Info.FeeUSD)
|
||||
}
|
||||
expected[i].L2Info.FeeUSD = actual[i].L2Info.FeeUSD
|
||||
}
|
||||
assert.Equal(t, expected[i], actual[i])
|
||||
}
|
||||
}
|
||||
|
||||
func doGoodReqPaginated(
|
||||
path string,
|
||||
iterStruct paginationer,
|
||||
appendIter func(res interface{}),
|
||||
) error {
|
||||
next := 0
|
||||
for {
|
||||
// Call API to get this iteration items
|
||||
if err := doGoodReq("GET", path+strconv.Itoa(next), nil, iterStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
appendIter(iterStruct)
|
||||
// Keep iterating?
|
||||
pag := iterStruct.GetPagination()
|
||||
if pag.LastReturnedItem == pag.TotalItems-1 { // No
|
||||
break
|
||||
} else { // Yes
|
||||
next = int(pag.LastReturnedItem + 1)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doGoodReqPaginatedReverse(
|
||||
path string,
|
||||
iterStruct paginationer,
|
||||
appendIter func(res interface{}),
|
||||
limit int,
|
||||
) error {
|
||||
next := 0
|
||||
first := true
|
||||
for {
|
||||
// Call API to get this iteration items
|
||||
if first {
|
||||
first = false
|
||||
pagQuery := fmt.Sprintf("last=true&limit=%d", limit)
|
||||
if err := doGoodReq("GET", path+pagQuery, nil, iterStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
pagQuery := fmt.Sprintf("offset=%d&limit=%d", next, limit)
|
||||
if err := doGoodReq("GET", path+pagQuery, nil, iterStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
appendIter(iterStruct)
|
||||
// Keep iterating?
|
||||
pag := iterStruct.GetPagination()
|
||||
if iterStruct.Len() == pag.TotalItems || pag.LastReturnedItem-iterStruct.Len() == -1 { // No
|
||||
break
|
||||
} else { // Yes
|
||||
prevOffset := next
|
||||
next = pag.LastReturnedItem - iterStruct.Len() - limit + 1
|
||||
if next < 0 {
|
||||
next = 0
|
||||
limit = prevOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doGoodReq(method, path string, reqBody io.Reader, returnStruct interface{}) error {
|
||||
ctx := context.Background()
|
||||
client := &http.Client{}
|
||||
httpReq, _ := http.NewRequest(method, path, reqBody)
|
||||
route, pathParams, err := tc.router.FindRoute(httpReq.Method, httpReq.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Validate request against swagger spec
|
||||
requestValidationInput := &swagger.RequestValidationInput{
|
||||
Request: httpReq,
|
||||
PathParams: pathParams,
|
||||
Route: route,
|
||||
}
|
||||
if err := swagger.ValidateRequest(ctx, requestValidationInput); err != nil {
|
||||
return err
|
||||
}
|
||||
// Do API call
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body == nil {
|
||||
return errors.New("Nil body")
|
||||
}
|
||||
//nolint
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("%d response: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
// Unmarshal body into return struct
|
||||
if err := json.Unmarshal(body, returnStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
// Validate response against swagger spec
|
||||
responseValidationInput := &swagger.ResponseValidationInput{
|
||||
RequestValidationInput: requestValidationInput,
|
||||
Status: resp.StatusCode,
|
||||
Header: resp.Header,
|
||||
}
|
||||
responseValidationInput = responseValidationInput.SetBodyBytes(body)
|
||||
return swagger.ValidateResponse(ctx, responseValidationInput)
|
||||
}
|
||||
|
||||
func doBadReq(method, path string, reqBody io.Reader, expectedResponseCode int) error {
|
||||
ctx := context.Background()
|
||||
client := &http.Client{}
|
||||
httpReq, _ := http.NewRequest(method, path, reqBody)
|
||||
route, pathParams, err := tc.router.FindRoute(httpReq.Method, httpReq.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Validate request against swagger spec
|
||||
requestValidationInput := &swagger.RequestValidationInput{
|
||||
Request: httpReq,
|
||||
PathParams: pathParams,
|
||||
Route: route,
|
||||
}
|
||||
if err := swagger.ValidateRequest(ctx, requestValidationInput); err != nil {
|
||||
if expectedResponseCode != 400 {
|
||||
return err
|
||||
}
|
||||
log.Warn("The request does not match the API spec")
|
||||
}
|
||||
// Do API call
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body == nil {
|
||||
return errors.New("Nil body")
|
||||
}
|
||||
//nolint
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != expectedResponseCode {
|
||||
return fmt.Errorf("Unexpected response code: %d", resp.StatusCode)
|
||||
}
|
||||
// Validate response against swagger spec
|
||||
responseValidationInput := &swagger.ResponseValidationInput{
|
||||
RequestValidationInput: requestValidationInput,
|
||||
Status: resp.StatusCode,
|
||||
Header: resp.Header,
|
||||
}
|
||||
responseValidationInput = responseValidationInput.SetBodyBytes(body)
|
||||
return swagger.ValidateResponse(ctx, responseValidationInput)
|
||||
}
|
||||
Reference in New Issue
Block a user