rpc: refactor tests

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2019-11-21 19:41:28 +03:00
parent d5fa31cecd
commit 3afcd784f0

View file

@ -7,175 +7,335 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"reflect"
"strings" "strings"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/rpc/wrappers"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
type executor struct {
chain *core.Blockchain
handler http.HandlerFunc
}
const (
defaultJSONRPC = "2.0"
defaultID = 1
)
type rpcTestCase struct {
name string
params string
fail bool
result func(e *executor) interface{}
check func(t *testing.T, e *executor, result interface{})
}
var rpcTestCases = map[string][]rpcTestCase{
"getaccountstate": {
{
name: "positive",
params: `["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]`,
result: func(e *executor) interface{} { return &GetAccountStateResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*GetAccountStateResponse)
require.True(t, ok)
assert.Equal(t, 1, len(res.Result.Balances))
assert.Equal(t, false, res.Result.Frozen)
},
},
{
name: "negative",
params: `["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"]`,
result: func(e *executor) interface{} { return "Invalid public account address" },
},
{
name: "no params",
params: `[]`,
fail: true,
},
{
name: "invalid address",
params: `["notabase58"]`,
fail: true,
},
},
"getassetstate": {
{
name: "positive",
params: `["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"]`,
result: func(e *executor) interface{} { return &GetAssetResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*GetAssetResponse)
require.True(t, ok)
assert.Equal(t, "00", res.Result.Owner)
assert.Equal(t, "AWKECj9RD8rS8RPcpCgYVjk1DeYyHwxZm3", res.Result.Admin)
},
},
{
name: "negative",
params: `["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de2"]`,
result: func(e *executor) interface{} { return "Invalid assetid" },
},
{
name: "no params",
params: `[]`,
fail: true,
},
{
name: "invalid hash",
params: `["notahex"]`,
fail: true,
},
},
"getbestblockhash": {
{
params: "[]",
result: func(e *executor) interface{} {
return "0x" + e.chain.CurrentBlockHash().ReverseString()
},
},
{
params: "1",
fail: true,
},
},
"getblock": {
{
name: "positive",
params: "[1]",
result: func(e *executor) interface{} { return &GetBlockResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*GetBlockResponse)
require.True(t, ok)
block, err := e.chain.GetBlock(e.chain.GetHeaderHash(1))
require.NoErrorf(t, err, "could not get block")
expectedHash := "0x" + block.Hash().ReverseString()
assert.Equal(t, expectedHash, res.Result.Hash)
},
},
{
name: "no params",
params: `[]`,
fail: true,
},
{
name: "invalid height",
params: `[-1]`,
fail: true,
},
{
name: "invalid hash",
params: `["notahex"]`,
fail: true,
},
{
name: "missing hash",
params: `["` + util.Uint256{}.String() + `"]`,
fail: true,
},
},
"getblockcount": {
{
params: "[]",
result: func(e *executor) interface{} { return int(e.chain.BlockHeight() + 1) },
},
},
"getblockhash": {
{
params: "[1]",
result: func(e *executor) interface{} { return "" },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*StringResultResponse)
require.True(t, ok)
block, err := e.chain.GetBlock(e.chain.GetHeaderHash(1))
require.NoErrorf(t, err, "could not get block")
expectedHash := "0x" + block.Hash().ReverseString()
assert.Equal(t, expectedHash, res.Result)
},
},
{
name: "string height",
params: `["first"]`,
fail: true,
},
{
name: "invalid number height",
params: `[-2]`,
fail: true,
},
},
"getconnectioncount": {
{
params: "[]",
result: func(*executor) interface{} { return 0 },
},
},
"getpeers": {
{
params: "[]",
result: func(*executor) interface{} {
return &GetPeersResponse{
Jsonrpc: defaultJSONRPC,
Result: struct {
Unconnected []int `json:"unconnected"`
Connected []int `json:"connected"`
Bad []int `json:"bad"`
}{
Unconnected: []int{},
Connected: []int{},
Bad: []int{},
},
ID: defaultID,
}
},
},
},
"getrawtransaction": {
{
name: "no params",
params: `[]`,
fail: true,
},
{
name: "invalid hash",
params: `["notahex"]`,
fail: true,
},
{
name: "missing hash",
params: `["` + util.Uint256{}.String() + `"]`,
fail: true,
},
},
"getunspents": {
{
name: "positive",
params: `["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]`,
result: func(e *executor) interface{} { return &GetUnspents{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*GetUnspents)
require.True(t, ok)
require.Equal(t, 1, len(res.Result.Balance))
assert.Equal(t, 1, len(res.Result.Balance[0].Unspents))
},
},
{
name: "negative",
params: `["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"]`,
result: func(e *executor) interface{} { return "Invalid public account address" },
},
},
"getversion": {
{
params: "[]",
result: func(*executor) interface{} { return &GetVersionResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
resp, ok := result.(*GetVersionResponse)
require.True(t, ok)
require.Equal(t, "/NEO-GO:/", resp.Result.UserAgent)
},
},
},
"sendrawtransaction": {
{
name: "positive",
params: `["d1001b00046e616d6567d3d8602814a429a91afdbaa3914884a1c90c733101201cc9c05cefffe6cdd7b182816a9152ec218d2ec000000141403387ef7940a5764259621e655b3c621a6aafd869a611ad64adcc364d8dd1edf84e00a7f8b11b630a377eaef02791d1c289d711c08b7ad04ff0d6c9caca22cfe6232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]`,
result: func(e *executor) interface{} { return &SendTXResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*SendTXResponse)
require.True(t, ok)
assert.True(t, res.Result)
},
},
{
name: "negative",
params: `["0274d792072617720636f6e7472616374207472616e73616374696f6e206465736372697074696f6e01949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500a3e11100000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5004f2418010000001cc9c05cefffe6cdd7b182816a9152ec218d2ec0014140dbd3cddac5cb2bd9bf6d93701f1a6f1c9dbe2d1b480c54628bbb2a4d536158c747a6af82698edf9f8af1cac3850bcb772bd9c8e4ac38f80704751cc4e0bd0e67232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]`,
fail: true,
},
{
name: "no params",
params: `[]`,
fail: true,
},
{
name: "invalid string",
params: `["notahex"]`,
fail: true,
},
{
name: "invalid tx",
params: `["0274d792072617720636f6e747261637"]`,
fail: true,
},
},
"validateaddress": {
{
name: "positive",
params: `["AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"]`,
result: func(*executor) interface{} { return &ValidateAddrResponse{} },
check: func(t *testing.T, e *executor, result interface{}) {
res, ok := result.(*ValidateAddrResponse)
require.True(t, ok)
assert.Equal(t, "AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i", res.Result.Address)
assert.True(t, res.Result.IsValid)
},
},
{
name: "negative",
params: "[1]",
result: func(*executor) interface{} {
return &ValidateAddrResponse{
Jsonrpc: defaultJSONRPC,
Result: wrappers.ValidateAddressResponse{
Address: float64(1),
IsValid: false,
},
ID: defaultID,
}
},
},
},
}
func TestRPC(t *testing.T) { func TestRPC(t *testing.T) {
chain, handler := initServerWithInMemoryChain(t) chain, handler := initServerWithInMemoryChain(t)
t.Run("getbestblockhash", func(t *testing.T) { e := &executor{chain: chain, handler: handler}
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getbestblockhash", "params": []}` for method, cases := range rpcTestCases {
body := doRPCCall(rpc, handler, t) t.Run(method, func(t *testing.T) {
checkErrResponse(t, body, false) rpc := `{"jsonrpc": "2.0", "id": 1, "method": "%s", "params": %s}`
var res StringResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "0x"+chain.CurrentBlockHash().ReverseString(), res.Result)
})
t.Run("getblock", func(t *testing.T) { for _, tc := range cases {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblock", "params": [1]}` t.Run(tc.name, func(t *testing.T) {
body := doRPCCall(rpc, handler, t) body := doRPCCall(fmt.Sprintf(rpc, method, tc.params), handler, t)
checkErrResponse(t, body, false) checkErrResponse(t, body, tc.fail)
var res GetBlockResponse if tc.fail {
err := json.Unmarshal(body, &res) return
assert.NoErrorf(t, err, "could not parse response: %s", body) }
block, err := chain.GetBlock(chain.GetHeaderHash(1))
assert.NoErrorf(t, err, "could not get block")
expectedHash := "0x" + block.Hash().ReverseString()
assert.Equal(t, expectedHash, res.Result.Hash)
})
t.Run("getblockcount", func(t *testing.T) { expected, res := tc.getResultPair(e)
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblockcount", "params": []}` err := json.Unmarshal(body, res)
body := doRPCCall(rpc, handler, t) require.NoErrorf(t, err, "could not parse response: %s", body)
checkErrResponse(t, body, false)
var res IntResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, chain.BlockHeight()+1, uint32(res.Result))
})
t.Run("getblockhash", func(t *testing.T) { if tc.check == nil {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [1]}` assert.Equal(t, expected, res)
body := doRPCCall(rpc, handler, t) } else {
checkErrResponse(t, body, false) tc.check(t, e, res)
var res StringResultResponse }
err := json.Unmarshal(body, &res) })
assert.NoErrorf(t, err, "could not parse response: %s", body) }
block, err := chain.GetBlock(chain.GetHeaderHash(1)) })
assert.NoErrorf(t, err, "could not get block") }
expectedHash := "0x" + block.Hash().ReverseString()
assert.Equal(t, expectedHash, res.Result)
})
t.Run("getconnectioncount", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getconnectioncount", "params": []}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res IntResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, 0, res.Result)
})
t.Run("getversion", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getversion", "params": []}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res GetVersionResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "/NEO-GO:/", res.Result.UserAgent)
})
t.Run("getpeers", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getpeers", "params": []}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res GetPeersResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, []int{}, res.Result.Bad)
assert.Equal(t, []int{}, res.Result.Unconnected)
assert.Equal(t, []int{}, res.Result.Connected)
})
t.Run("validateaddress_positive", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res ValidateAddrResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, true, res.Result.IsValid)
})
t.Run("validateaddress_negative", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [1]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res ValidateAddrResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, false, res.Result.IsValid)
})
t.Run("getassetstate_positive", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res GetAssetResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "00", res.Result.Owner)
assert.Equal(t, "AWKECj9RD8rS8RPcpCgYVjk1DeYyHwxZm3", res.Result.Admin)
})
t.Run("getassetstate_negative", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de2"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res StringResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "Invalid assetid", res.Result)
})
t.Run("getaccountstate_positive", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res GetAccountStateResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, 1, len(res.Result.Balances))
assert.Equal(t, false, res.Result.Frozen)
})
t.Run("getunspents_positive", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getunspents", "params": ["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res GetUnspents
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, 1, len(res.Result.Balance))
assert.Equal(t, 1, len(res.Result.Balance[0].Unspents))
})
t.Run("getaccountstate_negative", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res StringResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "Invalid public account address", res.Result)
})
t.Run("getunspents_negative", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getunspents", "params": ["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"]}`
body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false)
var res StringResultResponse
err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "Invalid public account address", res.Result)
})
t.Run("getrawtransaction", func(t *testing.T) { t.Run("getrawtransaction", func(t *testing.T) {
block, _ := chain.GetBlock(chain.GetHeaderHash(0)) block, _ := chain.GetBlock(chain.GetHeaderHash(0))
@ -185,31 +345,52 @@ func TestRPC(t *testing.T) {
checkErrResponse(t, body, false) checkErrResponse(t, body, false)
var res StringResultResponse var res StringResultResponse
err := json.Unmarshal(body, &res) err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body) require.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, "400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res.Result) assert.Equal(t, "400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res.Result)
}) })
t.Run("sendrawtransaction_positive", func(t *testing.T) { t.Run("getrawtransaction 2 arguments", func(t *testing.T) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["d1001b00046e616d6567d3d8602814a429a91afdbaa3914884a1c90c733101201cc9c05cefffe6cdd7b182816a9152ec218d2ec000000141403387ef7940a5764259621e655b3c621a6aafd869a611ad64adcc364d8dd1edf84e00a7f8b11b630a377eaef02791d1c289d711c08b7ad04ff0d6c9caca22cfe6232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]}` block, _ := chain.GetBlock(chain.GetHeaderHash(0))
TXHash := block.Transactions[1].Hash()
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s", 0]}"`, TXHash.ReverseString())
body := doRPCCall(rpc, handler, t) body := doRPCCall(rpc, handler, t)
checkErrResponse(t, body, false) checkErrResponse(t, body, false)
var res SendTXResponse var res StringResultResponse
err := json.Unmarshal(body, &res) err := json.Unmarshal(body, &res)
assert.NoErrorf(t, err, "could not parse response: %s", body) require.NoErrorf(t, err, "could not parse response: %s", body)
assert.Equal(t, true, res.Result) assert.Equal(t, "400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res.Result)
}) })
}
t.Run("sendrawtransaction_negative", func(t *testing.T) { func (tc rpcTestCase) getResultPair(e *executor) (expected interface{}, res interface{}) {
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["0274d792072617720636f6e7472616374207472616e73616374696f6e206465736372697074696f6e01949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500a3e11100000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5004f2418010000001cc9c05cefffe6cdd7b182816a9152ec218d2ec0014140dbd3cddac5cb2bd9bf6d93701f1a6f1c9dbe2d1b480c54628bbb2a4d536158c747a6af82698edf9f8af1cac3850bcb772bd9c8e4ac38f80704751cc4e0bd0e67232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]}` expected = tc.result(e)
body := doRPCCall(rpc, handler, t) switch exp := expected.(type) {
checkErrResponse(t, body, true) case string:
}) res = new(StringResultResponse)
expected = &StringResultResponse{
Jsonrpc: defaultJSONRPC,
Result: exp,
ID: defaultID,
}
case int:
res = new(IntResultResponse)
expected = &IntResultResponse{
Jsonrpc: defaultJSONRPC,
Result: exp,
ID: defaultID,
}
default:
resVal := reflect.New(reflect.TypeOf(expected).Elem())
res = resVal.Interface()
}
return
} }
func checkErrResponse(t *testing.T, body []byte, expectingFail bool) { func checkErrResponse(t *testing.T, body []byte, expectingFail bool) {
var errresp ErrorResponse var errresp ErrorResponse
err := json.Unmarshal(body, &errresp) err := json.Unmarshal(body, &errresp)
assert.Nil(t, err) require.Nil(t, err)
if expectingFail { if expectingFail {
assert.NotEqual(t, 0, errresp.Error.Code) assert.NotEqual(t, 0, errresp.Error.Code)
assert.NotEqual(t, "", errresp.Error.Message) assert.NotEqual(t, "", errresp.Error.Message)