github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/tests/integration.go (about) 1 // +build integration 2 3 package tests 4 5 import ( 6 "blockbook/bchain" 7 "blockbook/bchain/coins" 8 "blockbook/build/tools" 9 "blockbook/tests/rpc" 10 "blockbook/tests/sync" 11 "encoding/json" 12 "errors" 13 "fmt" 14 "io/ioutil" 15 "net" 16 "os" 17 "path/filepath" 18 "reflect" 19 "sort" 20 "strings" 21 "testing" 22 23 "github.com/jakm/btcutil/chaincfg" 24 ) 25 26 type TestFunc func(t *testing.T, coin string, chain bchain.BlockChain, testConfig json.RawMessage) 27 28 var integrationTests = map[string]TestFunc{ 29 "rpc": rpc.IntegrationTest, 30 "sync": sync.IntegrationTest, 31 } 32 33 var notConnectedError = errors.New("Not connected to backend server") 34 35 func runIntegrationTests(t *testing.T) { 36 tests, err := loadTests("tests.json") 37 if err != nil { 38 t.Fatal(err) 39 } 40 41 keys := make([]string, 0, len(tests)) 42 for k := range tests { 43 keys = append(keys, k) 44 } 45 sort.Strings(keys) 46 47 for _, coin := range keys { 48 cfg := tests[coin] 49 name := getMatchableName(coin) 50 t.Run(name, func(t *testing.T) { runTests(t, coin, cfg) }) 51 52 } 53 } 54 55 func loadTests(path string) (map[string]map[string]json.RawMessage, error) { 56 b, err := ioutil.ReadFile(path) 57 if err != nil { 58 return nil, err 59 } 60 v := make(map[string]map[string]json.RawMessage) 61 err = json.Unmarshal(b, &v) 62 return v, err 63 } 64 65 func getMatchableName(coin string) string { 66 if idx := strings.Index(coin, "_testnet"); idx != -1 { 67 return coin[:idx] + "=test" 68 } else { 69 return coin + "=main" 70 } 71 } 72 73 func runTests(t *testing.T, coin string, cfg map[string]json.RawMessage) { 74 if cfg == nil || len(cfg) == 0 { 75 t.Skip("No tests to run") 76 } 77 defer chaincfg.ResetParams() 78 79 bc, err := makeBlockChain(coin) 80 if err != nil { 81 if err == notConnectedError { 82 t.Fatal(err) 83 } 84 t.Fatalf("Cannot make blockchain config: %s", err) 85 } 86 87 for test, c := range cfg { 88 if fn, found := integrationTests[test]; found { 89 t.Run(test, func(t *testing.T) { fn(t, coin, bc, c) }) 90 } else { 91 t.Errorf("Test not found: %s", test) 92 } 93 } 94 } 95 96 func makeBlockChain(coin string) (bchain.BlockChain, error) { 97 c, err := build.LoadConfig("../configs", coin) 98 if err != nil { 99 return nil, err 100 } 101 102 outputDir, err := ioutil.TempDir("", "integration_test") 103 if err != nil { 104 return nil, err 105 } 106 defer os.RemoveAll(outputDir) 107 108 err = build.GeneratePackageDefinitions(c, "../build/templates", outputDir) 109 if err != nil { 110 return nil, err 111 } 112 113 b, err := ioutil.ReadFile(filepath.Join(outputDir, "blockbook", "blockchaincfg.json")) 114 if err != nil { 115 return nil, err 116 } 117 118 var cfg json.RawMessage 119 err = json.Unmarshal(b, &cfg) 120 if err != nil { 121 return nil, err 122 } 123 124 coinName, err := getName(cfg) 125 if err != nil { 126 return nil, err 127 } 128 129 return initBlockChain(coinName, cfg) 130 } 131 132 func getName(raw json.RawMessage) (string, error) { 133 var cfg map[string]interface{} 134 err := json.Unmarshal(raw, &cfg) 135 if err != nil { 136 return "", err 137 } 138 if n, found := cfg["coin_name"]; found { 139 switch n := n.(type) { 140 case string: 141 return n, nil 142 default: 143 return "", fmt.Errorf("Unexpected type of field `name`: %s", reflect.TypeOf(n)) 144 } 145 } else { 146 return "", errors.New("Missing field `name`") 147 } 148 } 149 150 func initBlockChain(coinName string, cfg json.RawMessage) (bchain.BlockChain, error) { 151 factory, found := coins.BlockChainFactories[coinName] 152 if !found { 153 return nil, fmt.Errorf("Factory function not found") 154 } 155 156 cli, err := factory(cfg, func(_ bchain.NotificationType) {}) 157 if err != nil { 158 if isNetError(err) { 159 return nil, notConnectedError 160 } 161 return nil, fmt.Errorf("Factory function failed: %s", err) 162 } 163 164 err = cli.Initialize() 165 if err != nil { 166 if isNetError(err) { 167 return nil, notConnectedError 168 } 169 return nil, fmt.Errorf("BlockChain initialization failed: %s", err) 170 } 171 172 return cli, nil 173 } 174 175 func isNetError(err error) bool { 176 if _, ok := err.(net.Error); ok { 177 return true 178 } 179 return false 180 }