github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/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, 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 }