github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/rpc/provider/etherscan_test.go (about) 1 package provider 2 3 import ( 4 "context" 5 "encoding/json" 6 "net/http" 7 "net/http/httptest" 8 "strings" 9 "testing" 10 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 14 "golang.org/x/time/rate" 15 ) 16 17 func TestEtherscanProvider_url(t *testing.T) { 18 paginator := NewPageNumberPaginator(1, 1, 10) 19 provider := &EtherscanProvider{ 20 baseUrl: etherscanBaseUrl, 21 } 22 var err error 23 var result string 24 var expected string 25 26 result, err = provider.url( 27 "0xf503017d7baf7fbc0fff7492b751025c6a78179b", 28 paginator, 29 "int", 30 ) 31 if err != nil { 32 t.Fatal(err) 33 } 34 35 expected = "https://api.etherscan.io/api?module=account&sort=asc&action=txlistinternal&address=0xf503017d7baf7fbc0fff7492b751025c6a78179b&page=1&offset=10&apikey=" 36 if result != expected { 37 t.Fatal("wrong value", result) 38 } 39 40 // Change page 41 42 if err = paginator.NextPage(); err != nil { 43 t.Fatal(err) 44 } 45 46 result, err = provider.url( 47 "0xf503017d7baf7fbc0fff7492b751025c6a78179b", 48 paginator, 49 "int", 50 ) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 expected = "https://api.etherscan.io/api?module=account&sort=asc&action=txlistinternal&address=0xf503017d7baf7fbc0fff7492b751025c6a78179b&page=2&offset=10&apikey=" 56 if result != expected { 57 t.Fatal("wrong value", result) 58 } 59 } 60 61 func mockEtherscanServer(t *testing.T) (ts *httptest.Server) { 62 t.Helper() 63 64 pages := []etherscanResponseBody{ 65 { 66 Result: []types.Slurp{ 67 { 68 BlockNumber: 1, 69 TransactionIndex: 1, 70 }, 71 { 72 BlockNumber: 1, 73 TransactionIndex: 2, 74 }, 75 { 76 BlockNumber: 1, 77 TransactionIndex: 3, 78 }, 79 }, 80 }, 81 { 82 Result: []types.Slurp{ 83 { 84 BlockNumber: 2, 85 TransactionIndex: 1, 86 }, 87 }, 88 }, 89 } 90 ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 91 query := r.URL.Query() 92 var result etherscanResponseBody 93 switch query.Get("page") { 94 case "1": 95 result = pages[0] 96 case "2": 97 result = pages[1] 98 default: 99 result = etherscanResponseBody{} 100 } 101 102 b, err := json.Marshal(result) 103 if err != nil { 104 t.Fatal(err) 105 } 106 w.Write(b) 107 })) 108 109 return ts 110 } 111 112 // TODO: BOGUS - clean raw 113 func mockConvertSlurpType(t *testing.T) func(address string, requestType string, trans *types.Slurp) (types.Slurp, error) { 114 t.Helper() 115 return func(address string, requestType string, trans *types.Slurp) (types.Slurp, error) { 116 return types.Slurp{ 117 BlockNumber: trans.BlockNumber, 118 TransactionIndex: trans.TransactionIndex, 119 }, nil 120 } 121 } 122 123 func TestEtherscanProvider_fetchData(t *testing.T) { 124 perPage := 3 125 ts := mockEtherscanServer(t) 126 defer ts.Close() 127 128 provider := EtherscanProvider{ 129 perPage: perPage, 130 baseUrl: ts.URL, 131 } 132 provider.limiter = rate.NewLimiter(5, 5) 133 provider.convertSlurpType = mockConvertSlurpType(t) 134 paginator := NewPageNumberPaginator(1, 1, perPage) 135 136 var data []SlurpedPageItem 137 var count int 138 var err error 139 data, count, err = provider.fetchData(context.TODO(), base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), paginator, "int") 140 if err != nil { 141 t.Fatal(err) 142 } 143 144 if l := len(data); l != perPage { 145 t.Fatal("wrong len of page 1:", l) 146 } 147 if count != perPage { 148 t.Fatal("wrong count", count) 149 } 150 if paginator.Done() { 151 t.Fatal("paginator done but it should not be") 152 } 153 154 if err = paginator.NextPage(); err != nil { 155 t.Fatal(err) 156 } 157 158 data, _, err = provider.fetchData(context.TODO(), base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), paginator, "int") 159 if err != nil { 160 t.Fatal(err) 161 } 162 if l := len(data); l != 1 { 163 t.Fatal("wrong len of page 2:", l) 164 } 165 if !paginator.Done() { 166 t.Fatal("paginator should be done") 167 } 168 } 169 170 func TestEtherscanProvider_TransactionsByAddress(t *testing.T) { 171 perPage := 3 172 ts := mockEtherscanServer(t) 173 defer ts.Close() 174 175 provider := EtherscanProvider{ 176 baseUrl: ts.URL, 177 } 178 provider.limiter = rate.NewLimiter(5, 5) 179 provider.convertSlurpType = mockConvertSlurpType(t) 180 181 query := &Query{ 182 Addresses: []base.Address{ 183 base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), 184 }, 185 Resources: []string{"int"}, 186 PerPage: uint(perPage), 187 } 188 ctx, cancel := context.WithCancel(context.Background()) 189 defer cancel() 190 errors := make(chan error) 191 results := provider.TransactionsByAddress(ctx, query, errors) 192 193 count := 0 194 LOOP: 195 for { 196 select { 197 case err, ok := <-errors: 198 if ok { 199 cancel() 200 t.Fatal(err) 201 } 202 case data, ok := <-results: 203 if !ok { 204 break LOOP 205 } 206 t.Log("got data", data) 207 count++ 208 } 209 } 210 211 if count != 4 { 212 t.Fatal("wrong count:", count) 213 } 214 215 // Filter: all txs filtered out 216 217 query.BlockRange = []identifiers.Identifier{ 218 { 219 Orig: "14000000", 220 }, 221 } 222 provider.TransactionsByAddress(ctx, query, errors) 223 err := <-errors 224 if err == nil { 225 t.Fatal("expected error") 226 } 227 if !strings.Contains(err.Error(), "zero transactions reported") { 228 t.Fatal("expected zero transactions reported error") 229 } 230 } 231 232 func TestEtherscanProvider_Appearances(t *testing.T) { 233 perPage := 3 234 ts := mockEtherscanServer(t) 235 defer ts.Close() 236 237 provider := EtherscanProvider{ 238 baseUrl: ts.URL, 239 } 240 provider.limiter = rate.NewLimiter(5, 5) 241 provider.convertSlurpType = mockConvertSlurpType(t) 242 243 query := &Query{ 244 Addresses: []base.Address{ 245 base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), 246 }, 247 Resources: []string{"int"}, 248 PerPage: uint(perPage), 249 } 250 ctx, cancel := context.WithCancel(context.Background()) 251 defer cancel() 252 errors := make(chan error) 253 results := provider.Appearances(ctx, query, errors) 254 255 count := 0 256 LOOP: 257 for { 258 select { 259 case err, ok := <-errors: 260 if ok { 261 cancel() 262 t.Fatal(err) 263 } 264 case data, ok := <-results: 265 if !ok { 266 break LOOP 267 } 268 t.Log("got data", data) 269 count++ 270 } 271 } 272 273 if count != 4 { 274 t.Fatal("wrong count:", count) 275 } 276 } 277 278 func TestEtherscanProvider_Count(t *testing.T) { 279 perPage := 3 280 ts := mockEtherscanServer(t) 281 defer ts.Close() 282 283 provider := EtherscanProvider{ 284 baseUrl: ts.URL, 285 } 286 provider.limiter = rate.NewLimiter(5, 5) 287 provider.convertSlurpType = mockConvertSlurpType(t) 288 289 query := &Query{ 290 Addresses: []base.Address{ 291 base.HexToAddress("0xf503017d7baf7fbc0fff7492b751025c6a78179b"), 292 }, 293 Resources: []string{"int"}, 294 PerPage: uint(perPage), 295 } 296 ctx, cancel := context.WithCancel(context.Background()) 297 defer cancel() 298 errors := make(chan error) 299 300 results := provider.Count(ctx, query, errors) 301 302 count := make([]types.Monitor, 0, 1) 303 LOOP: 304 for { 305 select { 306 case err, ok := <-errors: 307 if ok { 308 cancel() 309 t.Fatal(err) 310 } 311 case data, ok := <-results: 312 if !ok { 313 break LOOP 314 } 315 count = append(count, data) 316 317 } 318 } 319 320 if l := len(count); l != 1 { 321 t.Fatal("wrong len:", l) 322 } 323 if n := count[0].NRecords; n != 4 { 324 t.Fatal("wrong NRecords", n) 325 } 326 }