github.com/crptec/blockbook@v0.3.2/tests/sync/sync.go (about)

     1  // +build integration
     2  
     3  package sync
     4  
     5  import (
     6  	"blockbook/bchain"
     7  	"blockbook/common"
     8  	"blockbook/db"
     9  	"encoding/json"
    10  	"errors"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  )
    16  
    17  var testMap = map[string]func(t *testing.T, th *TestHandler){
    18  	"ConnectBlocks":         testConnectBlocks,
    19  	"ConnectBlocksParallel": testConnectBlocksParallel,
    20  	"HandleFork":            testHandleFork,
    21  }
    22  
    23  type TestHandler struct {
    24  	Coin     string
    25  	Chain    bchain.BlockChain
    26  	TestData *TestData
    27  }
    28  
    29  type Range struct {
    30  	Lower uint32 `json:"lower"`
    31  	Upper uint32 `json:"upper"`
    32  }
    33  
    34  type TestData struct {
    35  	ConnectBlocks struct {
    36  		SyncRanges []Range              `json:"syncRanges"`
    37  		Blocks     map[uint32]BlockInfo `json:"blocks"`
    38  	} `json:"connectBlocks"`
    39  	HandleFork struct {
    40  		SyncRanges []Range            `json:"syncRanges"`
    41  		FakeBlocks map[uint32]BlockID `json:"fakeBlocks"`
    42  		RealBlocks map[uint32]BlockID `json:"realBlocks"`
    43  	} `json:"handleFork"`
    44  }
    45  
    46  type BlockID struct {
    47  	Height uint32 `json:"height"`
    48  	Hash   string `json:"hash"`
    49  }
    50  
    51  type BlockInfo struct {
    52  	BlockID
    53  	NoTxs     uint32       `json:"noTxs"`
    54  	TxDetails []*bchain.Tx `json:"txDetails"`
    55  }
    56  
    57  func IntegrationTest(t *testing.T, coin string, chain bchain.BlockChain, mempool bchain.Mempool, testConfig json.RawMessage) {
    58  	tests, err := getTests(testConfig)
    59  	if err != nil {
    60  		t.Fatalf("Failed loading of test list: %s", err)
    61  	}
    62  
    63  	parser := chain.GetChainParser()
    64  	td, err := loadTestData(coin, parser)
    65  	if err != nil {
    66  		t.Fatalf("Failed loading of test data: %s", err)
    67  	}
    68  
    69  	for _, test := range tests {
    70  		if f, found := testMap[test]; found {
    71  			h := TestHandler{Coin: coin, Chain: chain, TestData: td}
    72  			t.Run(test, func(t *testing.T) { f(t, &h) })
    73  		} else {
    74  			t.Errorf("%s: test not found", test)
    75  			continue
    76  		}
    77  	}
    78  }
    79  
    80  func getTests(cfg json.RawMessage) ([]string, error) {
    81  	var v []string
    82  	err := json.Unmarshal(cfg, &v)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	if len(v) == 0 {
    87  		return nil, errors.New("No tests declared")
    88  	}
    89  	return v, nil
    90  }
    91  
    92  func loadTestData(coin string, parser bchain.BlockChainParser) (*TestData, error) {
    93  	path := filepath.Join("sync/testdata", coin+".json")
    94  	b, err := ioutil.ReadFile(path)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	var v TestData
    99  	err = json.Unmarshal(b, &v)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	for _, b := range v.ConnectBlocks.Blocks {
   105  		for _, tx := range b.TxDetails {
   106  			// convert amounts in test json to bit.Int and clear the temporary JsonValue
   107  			for i := range tx.Vout {
   108  				vout := &tx.Vout[i]
   109  				vout.ValueSat, err = parser.AmountToBigInt(vout.JsonValue)
   110  				if err != nil {
   111  					return nil, err
   112  				}
   113  				vout.JsonValue = ""
   114  			}
   115  
   116  			// get addresses parsed
   117  			err := setTxAddresses(parser, tx)
   118  			if err != nil {
   119  				return nil, err
   120  			}
   121  		}
   122  	}
   123  
   124  	return &v, nil
   125  }
   126  
   127  func setTxAddresses(parser bchain.BlockChainParser, tx *bchain.Tx) error {
   128  	for i := range tx.Vout {
   129  		ad, err := parser.GetAddrDescFromVout(&tx.Vout[i])
   130  		if err != nil {
   131  			return err
   132  		}
   133  		a, s, err := parser.GetAddressesFromAddrDesc(ad)
   134  		if err == nil && s {
   135  			tx.Vout[i].ScriptPubKey.Addresses = a
   136  		}
   137  	}
   138  	return nil
   139  }
   140  
   141  func makeRocksDB(parser bchain.BlockChainParser, m *common.Metrics, is *common.InternalState) (*db.RocksDB, func(), error) {
   142  	p, err := ioutil.TempDir("", "sync_test")
   143  	if err != nil {
   144  		return nil, nil, err
   145  	}
   146  
   147  	d, err := db.NewRocksDB(p, 1<<17, 1<<14, parser, m)
   148  	if err != nil {
   149  		return nil, nil, err
   150  	}
   151  
   152  	d.SetInternalState(is)
   153  
   154  	closer := func() {
   155  		d.Close()
   156  		os.RemoveAll(p)
   157  	}
   158  
   159  	return d, closer, nil
   160  }
   161  
   162  var metricsRegistry = map[string]*common.Metrics{}
   163  
   164  func getMetrics(name string) (*common.Metrics, error) {
   165  	if m, found := metricsRegistry[name]; found {
   166  		return m, nil
   167  	} else {
   168  		m, err := common.GetMetrics(name)
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  		metricsRegistry[name] = m
   173  		return m, nil
   174  	}
   175  }
   176  
   177  func withRocksDBAndSyncWorker(t *testing.T, h *TestHandler, startHeight uint32, fn func(*db.RocksDB, *db.SyncWorker, chan os.Signal)) {
   178  	m, err := getMetrics(h.Coin)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	is := &common.InternalState{}
   183  
   184  	d, closer, err := makeRocksDB(h.Chain.GetChainParser(), m, is)
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	defer closer()
   189  
   190  	ch := make(chan os.Signal)
   191  
   192  	sw, err := db.NewSyncWorker(d, h.Chain, 8, 0, int(startHeight), false, ch, m, is)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  
   197  	fn(d, sw, ch)
   198  }