Add public server unit tests for ethereum type coins

This commit is contained in:
Martin Boehm 2021-12-21 00:07:13 +01:00 committed by Martin
parent e3bb706ea2
commit 89b1e75641
3 changed files with 267 additions and 57 deletions

View File

@ -0,0 +1,60 @@
//go:build unittest
// +build unittest
package server
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/golang/glog"
"github.com/trezor/blockbook/bchain/coins/eth"
"github.com/trezor/blockbook/tests/dbtestdata"
)
func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
tests := []httpTests{
{
name: "apiIndex",
r: newGetRequest(ts.URL + "/api"),
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"blockbook":{"coin":"Fakecoin"`,
`"bestHeight":4321001`,
`"decimals":18`,
`"backend":{"chain":"fakecoin","blocks":2,"headers":2,"bestBlockHash":"0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee"`,
`"version":"001001","subversion":"/Fakecoin:0.0.1/"`,
},
},
{
name: "apiAddress EthAddr4b",
r: newGetRequest(ts.URL + "/api/v2/address/" + dbtestdata.EthAddr4b),
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","balance":"123450075","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":1,"nonTokenTxs":1,"txids":["0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2"],"nonce":"75","tokens":[{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":2,"symbol":"S13","decimals":18},{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":2,"symbol":"S74","decimals":18}],"erc20Contract":{"contract":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","name":"Contract 75","symbol":"S75","decimals":18}}`,
},
},
}
performHttpTests(tests, t, ts)
}
func Test_PublicServer_EthereumType(t *testing.T) {
parser := eth.NewEthereumParser(1)
chain, err := dbtestdata.NewFakeBlockChainEthereumType(parser)
if err != nil {
glog.Fatal("fakechain: ", err)
}
s, dbpath := setupPublicHTTPServer(parser, chain, t)
defer closeAndDestroyPublicServer(t, s, dbpath)
s.ConnectFullPublicInterface()
// take the handler of the public server and pass it to the test server
ts := httptest.NewServer(s.https.Handler)
defer ts.Close()
httpTestsEthereumType(t, ts)
}

View File

@ -36,7 +36,7 @@ func TestMain(m *testing.M) {
os.Exit(c)
}
func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *common.InternalState, string) {
func setupRocksDB(parser bchain.BlockChainParser, chain bchain.BlockChain, t *testing.T) (*db.RocksDB, *common.InternalState, string) {
tmp, err := ioutil.TempDir("", "testdb")
if err != nil {
t.Fatal(err)
@ -50,7 +50,15 @@ func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *c
t.Fatal(err)
}
d.SetInternalState(is)
block1 := dbtestdata.GetTestBitcoinTypeBlock1(parser)
// there are 2 simulated block, of height bestBlockHeight-1 and bestBlockHeight
bestHeight, err := chain.GetBestBlockHeight()
if err != nil {
t.Fatal(err)
}
block1, err := chain.GetBlock("", bestHeight-1)
if err != nil {
t.Fatal(err)
}
// setup internal state BlockTimes
for i := uint32(0); i < block1.Height; i++ {
is.BlockTimes = append(is.BlockTimes, 0)
@ -59,7 +67,10 @@ func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *c
if err := d.ConnectBlock(block1); err != nil {
t.Fatal(err)
}
block2 := dbtestdata.GetTestBitcoinTypeBlock2(parser)
block2, err := chain.GetBlock("", bestHeight)
if err != nil {
t.Fatal(err)
}
if err := d.ConnectBlock(block2); err != nil {
t.Fatal(err)
}
@ -70,31 +81,22 @@ func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *c
return d, is, tmp
}
func setupPublicHTTPServer(t *testing.T) (*PublicServer, string) {
parser := btc.NewBitcoinParser(
btc.GetChainParams("test"),
&btc.Configuration{
BlockAddressesToKeep: 1,
XPubMagic: 70617039,
XPubMagicSegwitP2sh: 71979618,
XPubMagicSegwitNative: 73342198,
Slip44: 1,
})
var metrics *common.Metrics
d, is, path := setupRocksDB(t, parser)
func setupPublicHTTPServer(parser bchain.BlockChainParser, chain bchain.BlockChain, t *testing.T) (*PublicServer, string) {
d, is, path := setupRocksDB(parser, chain, t)
// setup internal state and match BestHeight to test data
is.Coin = "Fakecoin"
is.CoinLabel = "Fake Coin"
is.CoinShortcut = "FAKE"
metrics, err := common.GetMetrics("Fakecoin")
if err != nil {
glog.Fatal("metrics: ", err)
}
chain, err := dbtestdata.NewFakeBlockChain(parser)
if err != nil {
glog.Fatal("fakechain: ", err)
var err error
// metrics can be setup only once
if metrics == nil {
metrics, err = common.GetMetrics("Fakecoin")
if err != nil {
glog.Fatal("metrics: ", err)
}
}
mempool, err := chain.CreateMempool(chain)
@ -204,14 +206,45 @@ func InitTestFiatRates(d *db.RocksDB) error {
}, d)
}
type httpTests struct {
name string
r *http.Request
status int
contentType string
body []string
}
func performHttpTests(tests []httpTests, t *testing.T, ts *httptest.Server) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resp, err := http.DefaultClient.Do(tt.r)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != tt.status {
t.Errorf("StatusCode = %v, want %v", resp.StatusCode, tt.status)
}
if resp.Header["Content-Type"][0] != tt.contentType {
t.Errorf("Content-Type = %v, want %v", resp.Header["Content-Type"][0], tt.contentType)
}
bb, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
b := string(bb)
for _, c := range tt.body {
if !strings.Contains(b, c) {
t.Errorf("got %v, want to contain %v", b, c)
break
}
}
})
}
}
func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
tests := []struct {
name string
r *http.Request
status int
contentType string
body []string
}{
tests := []httpTests{
{
name: "explorerTx",
r: newGetRequest(ts.URL + "/tx/fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db"),
@ -947,33 +980,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resp, err := http.DefaultClient.Do(tt.r)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != tt.status {
t.Errorf("StatusCode = %v, want %v", resp.StatusCode, tt.status)
}
if resp.Header["Content-Type"][0] != tt.contentType {
t.Errorf("Content-Type = %v, want %v", resp.Header["Content-Type"][0], tt.contentType)
}
bb, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
b := string(bb)
for _, c := range tt.body {
if !strings.Contains(b, c) {
t.Errorf("got %v, want to contain %v", b, c)
break
}
}
})
}
performHttpTests(tests, t, ts)
}
func socketioTestsBitcoinType(t *testing.T, ts *httptest.Server) {
@ -1558,7 +1565,22 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
}
func Test_PublicServer_BitcoinType(t *testing.T) {
s, dbpath := setupPublicHTTPServer(t)
parser := btc.NewBitcoinParser(
btc.GetChainParams("test"),
&btc.Configuration{
BlockAddressesToKeep: 1,
XPubMagic: 70617039,
XPubMagicSegwitP2sh: 71979618,
XPubMagicSegwitNative: 73342198,
Slip44: 1,
})
chain, err := dbtestdata.NewFakeBlockChain(parser)
if err != nil {
glog.Fatal("fakechain: ", err)
}
s, dbpath := setupPublicHTTPServer(parser, chain, t)
defer closeAndDestroyPublicServer(t, s, dbpath)
s.ConnectFullPublicInterface()
// take the handler of the public server and pass it to the test server

View File

@ -0,0 +1,128 @@
package dbtestdata
import (
"encoding/json"
"math/big"
"strconv"
"github.com/trezor/blockbook/bchain"
)
type fakeBlockChainEthereumType struct {
*fakeBlockChain
}
// NewFakeBlockChainEthereumType returns mocked blockchain RPC interface used for tests
func NewFakeBlockChainEthereumType(parser bchain.BlockChainParser) (bchain.BlockChain, error) {
return &fakeBlockChainEthereumType{&fakeBlockChain{&bchain.BaseChain{Parser: parser}}}, nil
}
func (c *fakeBlockChainEthereumType) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
return bchain.NewMempoolEthereumType(chain, 1, false), nil
}
func (c *fakeBlockChainEthereumType) GetChainInfo() (v *bchain.ChainInfo, err error) {
return &bchain.ChainInfo{
Chain: c.GetNetworkName(),
Blocks: 2,
Headers: 2,
Bestblockhash: GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Hash,
Version: "001001",
Subversion: c.GetSubversion(),
}, nil
}
func (c *fakeBlockChainEthereumType) GetBestBlockHash() (v string, err error) {
return GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Hash, nil
}
func (c *fakeBlockChainEthereumType) GetBestBlockHeight() (v uint32, err error) {
return GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Height, nil
}
func (c *fakeBlockChainEthereumType) GetBlockHash(height uint32) (v string, err error) {
b1 := GetTestEthereumTypeBlock1(c.Parser)
if height == b1.BlockHeader.Height {
return b1.BlockHeader.Hash, nil
}
b2 := GetTestEthereumTypeBlock2(c.Parser)
if height == b2.BlockHeader.Height {
return b2.BlockHeader.Hash, nil
}
return "", bchain.ErrBlockNotFound
}
func (c *fakeBlockChainEthereumType) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) {
b1 := GetTestEthereumTypeBlock1(c.Parser)
if hash == b1.BlockHeader.Hash {
return &b1.BlockHeader, nil
}
b2 := GetTestEthereumTypeBlock2(c.Parser)
if hash == b2.BlockHeader.Hash {
return &b2.BlockHeader, nil
}
return nil, bchain.ErrBlockNotFound
}
func (c *fakeBlockChainEthereumType) GetBlock(hash string, height uint32) (v *bchain.Block, err error) {
b1 := GetTestEthereumTypeBlock1(c.Parser)
if hash == b1.BlockHeader.Hash || height == b1.BlockHeader.Height {
return b1, nil
}
b2 := GetTestEthereumTypeBlock2(c.Parser)
if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height {
return b2, nil
}
return nil, bchain.ErrBlockNotFound
}
func (c *fakeBlockChainEthereumType) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) {
b1 := GetTestEthereumTypeBlock1(c.Parser)
if hash == b1.BlockHeader.Hash {
return getBlockInfo(b1), nil
}
b2 := GetTestEthereumTypeBlock2(c.Parser)
if hash == b2.BlockHeader.Hash {
return getBlockInfo(b2), nil
}
return nil, bchain.ErrBlockNotFound
}
func (c *fakeBlockChainEthereumType) GetTransaction(txid string) (v *bchain.Tx, err error) {
v = getTxInBlock(GetTestEthereumTypeBlock1(c.Parser), txid)
if v == nil {
v = getTxInBlock(GetTestEthereumTypeBlock2(c.Parser), txid)
}
if v != nil {
return v, nil
}
return nil, bchain.ErrTxNotFound
}
func (c *fakeBlockChainEthereumType) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) {
txS, _ := tx.CoinSpecificData.(bchain.EthereumSpecificData)
rm, err := json.Marshal(txS)
if err != nil {
return nil, err
}
return json.RawMessage(rm), nil
}
func (c *fakeBlockChainEthereumType) EthereumTypeGetBalance(addrDesc bchain.AddressDescriptor) (*big.Int, error) {
return big.NewInt(123450000 + int64(addrDesc[0])), nil
}
func (c *fakeBlockChainEthereumType) EthereumTypeGetNonce(addrDesc bchain.AddressDescriptor) (uint64, error) {
return uint64(addrDesc[0]), nil
}
func (c *fakeBlockChainEthereumType) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) {
addresses, _, _ := c.Parser.GetAddressesFromAddrDesc(contractDesc)
return &bchain.Erc20Contract{
Contract: addresses[0],
Name: "Contract " + strconv.Itoa(int(contractDesc[0])),
Symbol: "S" + strconv.Itoa(int(contractDesc[0])),
Decimals: 18,
}, nil
}