Add unit test for explorerTx, explorerBlock, explorerIndex
This commit is contained in:
parent
cc11ae1e57
commit
a6dce9f770
@ -8,10 +8,12 @@ import (
|
|||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
"blockbook/tests/dbtestdata"
|
"blockbook/tests/dbtestdata"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -52,32 +54,15 @@ func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *c
|
|||||||
return d, is, tmp
|
return d, is, tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFreePort asks the kernel for a free open port that is ready to use
|
func setupPublicHTTPServer(t *testing.T) (*PublicServer, string) {
|
||||||
func getFreePort() (int, error) {
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l, err := net.ListenTCP("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer l.Close()
|
|
||||||
return l.Addr().(*net.TCPAddr).Port, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupPublicHTTPServer(t *testing.T) (*PublicServer, string, string) {
|
|
||||||
parser := btc.NewBitcoinParser(
|
parser := btc.NewBitcoinParser(
|
||||||
btc.GetChainParams("test"),
|
btc.GetChainParams("test"),
|
||||||
&btc.Configuration{BlockAddressesToKeep: 1})
|
&btc.Configuration{BlockAddressesToKeep: 1})
|
||||||
|
|
||||||
db, is, path := setupRocksDB(t, parser)
|
d, is, path := setupRocksDB(t, parser)
|
||||||
|
is.Coin = "Testnet"
|
||||||
port, err := getFreePort()
|
is.CoinLabel = "Bitcoin Testnet"
|
||||||
if err != nil {
|
is.CoinShortcut = "TEST"
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics, err := common.GetMetrics("Testnet")
|
metrics, err := common.GetMetrics("Testnet")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -86,20 +71,23 @@ func setupPublicHTTPServer(t *testing.T) (*PublicServer, string, string) {
|
|||||||
|
|
||||||
chain, err := dbtestdata.NewFakeBlockChain(parser)
|
chain, err := dbtestdata.NewFakeBlockChain(parser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatal("metrics: ", err)
|
glog.Fatal("fakechain: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding := "localhost:" + strconv.Itoa(port)
|
txCache, err := db.NewTxCache(d, chain, metrics, is, true)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal("txCache: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
s, err := NewPublicServer(binding, "", db, chain, nil, "", metrics, is, false)
|
// s.Run is never called, binding can be to any port
|
||||||
|
s, err := NewPublicServer("localhost:12345", "", d, chain, txCache, "", metrics, is, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return s, binding, path
|
return s, path
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeAndDestroyPublicServer(t *testing.T, s *PublicServer, dbpath string) {
|
func closeAndDestroyPublicServer(t *testing.T, s *PublicServer, dbpath string) {
|
||||||
|
|
||||||
// destroy db
|
// destroy db
|
||||||
if err := s.db.Close(); err != nil {
|
if err := s.db.Close(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -107,7 +95,104 @@ func closeAndDestroyPublicServer(t *testing.T, s *PublicServer, dbpath string) {
|
|||||||
os.RemoveAll(dbpath)
|
os.RemoveAll(dbpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_PublicServer_UTXO(t *testing.T) {
|
func newGetRequest(url string, body io.Reader) *http.Request {
|
||||||
s, _, dbpath := setupPublicHTTPServer(t)
|
r, err := http.NewRequest("GET", url, body)
|
||||||
defer closeAndDestroyPublicServer(t, s, dbpath)
|
if err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_PublicServer_UTXO(t *testing.T) {
|
||||||
|
s, dbpath := setupPublicHTTPServer(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()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
r *http.Request
|
||||||
|
status int
|
||||||
|
contentType string
|
||||||
|
body []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "explorerTx",
|
||||||
|
r: newGetRequest(ts.URL+"/tx/fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db", nil),
|
||||||
|
status: http.StatusOK,
|
||||||
|
contentType: "text/html; charset=utf-8",
|
||||||
|
body: []string{
|
||||||
|
`<a href="/" class="nav-link">Bitcoin Testnet Explorer</a>`,
|
||||||
|
`<h1>Transaction</h1>`,
|
||||||
|
`<span class="data">fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db</span>`,
|
||||||
|
`td class="data">0 TEST</td>`,
|
||||||
|
`<a href="/address/mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj">mzVznVsCHkVHX9UN8WPFASWUUHtxnNn4Jj</a>`,
|
||||||
|
`13.60030331 TEST`,
|
||||||
|
`<td><span class="float-left">No Inputs (Newly Generated Coins)</span></td>`,
|
||||||
|
`</html>`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// explorerSpendingTx
|
||||||
|
// explorerBlocks
|
||||||
|
{
|
||||||
|
name: "explorerBlock",
|
||||||
|
r: newGetRequest(ts.URL+"/block/225494", nil),
|
||||||
|
status: http.StatusOK,
|
||||||
|
contentType: "text/html; charset=utf-8",
|
||||||
|
body: []string{
|
||||||
|
`<a href="/" class="nav-link">Bitcoin Testnet Explorer</a>`,
|
||||||
|
`<h1>Block 225494</h1>`,
|
||||||
|
`<span class="data">00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6</span>`,
|
||||||
|
`<td class="data">4</td>`, // number of transactions
|
||||||
|
`<a href="/address/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL">mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL</a>`,
|
||||||
|
`9172.83951061 TEST`,
|
||||||
|
`<a href="/tx/fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db">fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db</a>`,
|
||||||
|
`</html>`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "explorerIndex",
|
||||||
|
r: newGetRequest(ts.URL+"/", nil),
|
||||||
|
status: http.StatusOK,
|
||||||
|
contentType: "text/html; charset=utf-8",
|
||||||
|
body: []string{
|
||||||
|
`<a href="/" class="nav-link">Bitcoin Testnet Explorer</a>`,
|
||||||
|
`<h1>Application status</h1>`,
|
||||||
|
`<h3 class="bg-warning text-white" style="padding: 20px;">Synchronization with backend is disabled, the state of index is not up to date.</h3>`,
|
||||||
|
`<a href="/block/225494">225494</a>`,
|
||||||
|
`<td class="data">/Satoshi:0.16.3/</td>`,
|
||||||
|
`</html>`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// explorerSearch
|
||||||
|
}
|
||||||
|
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("Page body does not contain %v, body %v", c, b)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package dbtestdata
|
|||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
@ -67,7 +68,7 @@ func (c *fakeBlockChain) GetBlockHash(height uint32) (v string, err error) {
|
|||||||
if height == b2.BlockHeader.Height {
|
if height == b2.BlockHeader.Height {
|
||||||
return b2.BlockHeader.Hash, nil
|
return b2.BlockHeader.Hash, nil
|
||||||
}
|
}
|
||||||
return "", errors.New("Block not found")
|
return "", bchain.ErrBlockNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) {
|
func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) {
|
||||||
@ -79,7 +80,7 @@ func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err
|
|||||||
if hash == b2.BlockHeader.Hash {
|
if hash == b2.BlockHeader.Hash {
|
||||||
return &b2.BlockHeader, nil
|
return &b2.BlockHeader, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("Block not found")
|
return nil, bchain.ErrBlockNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetBlock(hash string, height uint32) (v *bchain.Block, err error) {
|
func (c *fakeBlockChain) GetBlock(hash string, height uint32) (v *bchain.Block, err error) {
|
||||||
@ -91,11 +92,29 @@ func (c *fakeBlockChain) GetBlock(hash string, height uint32) (v *bchain.Block,
|
|||||||
if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height {
|
if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height {
|
||||||
return b2, nil
|
return b2, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("Block not found")
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlockInfo(b *bchain.Block) *bchain.BlockInfo {
|
||||||
|
bi := &bchain.BlockInfo{
|
||||||
|
BlockHeader: b.BlockHeader,
|
||||||
|
}
|
||||||
|
for _, tx := range b.Txs {
|
||||||
|
bi.Txids = append(bi.Txids, tx.Txid)
|
||||||
|
}
|
||||||
|
return bi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) {
|
func (c *fakeBlockChain) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) {
|
||||||
return nil, errors.New("Not implemented")
|
b1 := GetTestUTXOBlock1(c.parser)
|
||||||
|
if hash == b1.BlockHeader.Hash {
|
||||||
|
return getBlockInfo(b1), nil
|
||||||
|
}
|
||||||
|
b2 := GetTestUTXOBlock2(c.parser)
|
||||||
|
if hash == b2.BlockHeader.Hash {
|
||||||
|
return getBlockInfo(b2), nil
|
||||||
|
}
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetMempool() (v []string, err error) {
|
func (c *fakeBlockChain) GetMempool() (v []string, err error) {
|
||||||
@ -122,6 +141,18 @@ func (c *fakeBlockChain) GetTransaction(txid string) (v *bchain.Tx, err error) {
|
|||||||
return nil, errors.New("Not implemented")
|
return nil, errors.New("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *fakeBlockChain) GetTransactionSpecific(txid string) (v json.RawMessage, err error) {
|
||||||
|
tx, err := c.GetTransaction(txid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rm, err := json.Marshal(tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.RawMessage(rm), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
func (c *fakeBlockChain) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
|
||||||
return nil, errors.New("Not implemented")
|
return nil, errors.New("Not implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user