github.com/ethersphere/bee/v2@v2.2.0/pkg/api/chequebook_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package api_test 6 7 import ( 8 "context" 9 "errors" 10 "math/big" 11 "net/http" 12 "reflect" 13 "testing" 14 15 "github.com/ethereum/go-ethereum/common" 16 "github.com/ethersphere/bee/v2/pkg/api" 17 "github.com/ethersphere/bee/v2/pkg/bigint" 18 "github.com/ethersphere/bee/v2/pkg/jsonhttp" 19 "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" 20 "github.com/ethersphere/bee/v2/pkg/sctx" 21 "github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook" 22 "github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook/mock" 23 swapmock "github.com/ethersphere/bee/v2/pkg/settlement/swap/mock" 24 25 "github.com/ethersphere/bee/v2/pkg/swarm" 26 ) 27 28 func TestChequebookBalance(t *testing.T) { 29 t.Parallel() 30 31 returnedBalance := big.NewInt(9000) 32 returnedAvailableBalance := big.NewInt(1000) 33 34 chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) { 35 return returnedBalance, nil 36 } 37 38 chequebookAvailableBalanceFunc := func(context.Context) (ret *big.Int, err error) { 39 return returnedAvailableBalance, nil 40 } 41 42 testServer, _, _, _ := newTestServer(t, testServerOptions{ 43 ChequebookOpts: []mock.Option{ 44 mock.WithChequebookBalanceFunc(chequebookBalanceFunc), 45 mock.WithChequebookAvailableBalanceFunc(chequebookAvailableBalanceFunc), 46 }, 47 }) 48 49 expected := &api.ChequebookBalanceResponse{ 50 TotalBalance: bigint.Wrap(returnedBalance), 51 AvailableBalance: bigint.Wrap(returnedAvailableBalance), 52 } 53 54 var got *api.ChequebookBalanceResponse 55 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusOK, 56 jsonhttptest.WithUnmarshalJSONResponse(&got), 57 ) 58 59 if !reflect.DeepEqual(got, expected) { 60 t.Errorf("got balance: %+v, expected: %+v", got, expected) 61 } 62 } 63 64 func TestChequebookBalanceError(t *testing.T) { 65 t.Parallel() 66 67 wantErr := errors.New("New errors") 68 chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) { 69 return big.NewInt(0), wantErr 70 } 71 72 testServer, _, _, _ := newTestServer(t, testServerOptions{ 73 ChequebookOpts: []mock.Option{mock.WithChequebookBalanceFunc(chequebookBalanceFunc)}, 74 }) 75 76 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusInternalServerError, 77 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 78 Message: api.ErrChequebookBalance, 79 Code: http.StatusInternalServerError, 80 }), 81 ) 82 } 83 84 func TestChequebookAvailableBalanceError(t *testing.T) { 85 t.Parallel() 86 87 chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) { 88 return big.NewInt(0), nil 89 } 90 91 chequebookAvailableBalanceFunc := func(context.Context) (ret *big.Int, err error) { 92 return nil, errors.New("New errors") 93 } 94 95 testServer, _, _, _ := newTestServer(t, testServerOptions{ 96 ChequebookOpts: []mock.Option{ 97 mock.WithChequebookBalanceFunc(chequebookBalanceFunc), 98 mock.WithChequebookAvailableBalanceFunc(chequebookAvailableBalanceFunc), 99 }, 100 }) 101 102 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/balance", http.StatusInternalServerError, 103 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 104 Message: api.ErrChequebookBalance, 105 Code: http.StatusInternalServerError, 106 }), 107 ) 108 } 109 110 func TestChequebookAddress(t *testing.T) { 111 t.Parallel() 112 113 chequebookAddressFunc := func() common.Address { 114 return common.HexToAddress("0xfffff") 115 } 116 117 testServer, _, _, _ := newTestServer(t, testServerOptions{ 118 ChequebookOpts: []mock.Option{mock.WithChequebookAddressFunc(chequebookAddressFunc)}, 119 }) 120 121 address := common.HexToAddress("0xfffff") 122 123 expected := &api.ChequebookAddressResponse{ 124 Address: address.String(), 125 } 126 127 var got *api.ChequebookAddressResponse 128 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/address", http.StatusOK, 129 jsonhttptest.WithUnmarshalJSONResponse(&got), 130 ) 131 132 if !reflect.DeepEqual(got, expected) { 133 t.Errorf("got address: %+v, expected: %+v", got, expected) 134 } 135 } 136 137 func TestChequebookWithdraw(t *testing.T) { 138 t.Parallel() 139 140 txHash := common.HexToHash("0xfffff") 141 142 t.Run("ok", func(t *testing.T) { 143 t.Parallel() 144 145 chequebookWithdrawFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) { 146 if amount.Cmp(big.NewInt(500)) == 0 { 147 return txHash, nil 148 } 149 return common.Hash{}, nil 150 } 151 152 testServer, _, _, _ := newTestServer(t, testServerOptions{ 153 ChequebookOpts: []mock.Option{mock.WithChequebookWithdrawFunc(chequebookWithdrawFunc)}, 154 }) 155 156 expected := &api.ChequebookTxResponse{TransactionHash: txHash} 157 158 var got *api.ChequebookTxResponse 159 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/withdraw?amount=500", http.StatusOK, 160 jsonhttptest.WithUnmarshalJSONResponse(&got), 161 ) 162 163 if !reflect.DeepEqual(got, expected) { 164 t.Errorf("got address: %+v, expected: %+v", got, expected) 165 } 166 }) 167 168 t.Run("custom gas", func(t *testing.T) { 169 t.Parallel() 170 171 chequebookWithdrawFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) { 172 if sctx.GetGasPrice(ctx).Cmp(big.NewInt(10)) != 0 { 173 return common.Hash{}, errors.New("wrong gas price") 174 } 175 if amount.Cmp(big.NewInt(500)) == 0 { 176 return txHash, nil 177 } 178 return common.Hash{}, nil 179 } 180 181 testServer, _, _, _ := newTestServer(t, testServerOptions{ 182 ChequebookOpts: []mock.Option{mock.WithChequebookWithdrawFunc(chequebookWithdrawFunc)}, 183 }) 184 185 expected := &api.ChequebookTxResponse{TransactionHash: txHash} 186 187 var got *api.ChequebookTxResponse 188 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/withdraw?amount=500", http.StatusOK, 189 jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10"), 190 jsonhttptest.WithUnmarshalJSONResponse(&got), 191 ) 192 193 if !reflect.DeepEqual(got, expected) { 194 t.Errorf("got address: %+v, expected: %+v", got, expected) 195 } 196 }) 197 } 198 199 func TestChequebookDeposit(t *testing.T) { 200 t.Parallel() 201 202 txHash := common.HexToHash("0xfffff") 203 204 t.Run("ok", func(t *testing.T) { 205 t.Parallel() 206 207 chequebookDepositFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) { 208 if amount.Cmp(big.NewInt(700)) == 0 { 209 return txHash, nil 210 } 211 return common.Hash{}, nil 212 } 213 214 testServer, _, _, _ := newTestServer(t, testServerOptions{ 215 ChequebookOpts: []mock.Option{mock.WithChequebookDepositFunc(chequebookDepositFunc)}, 216 }) 217 218 expected := &api.ChequebookTxResponse{TransactionHash: txHash} 219 220 var got *api.ChequebookTxResponse 221 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/deposit?amount=700", http.StatusOK, 222 jsonhttptest.WithUnmarshalJSONResponse(&got), 223 ) 224 225 if !reflect.DeepEqual(got, expected) { 226 t.Errorf("got address: %+v, expected: %+v", got, expected) 227 } 228 }) 229 230 t.Run("custom gas", func(t *testing.T) { 231 t.Parallel() 232 233 chequebookDepositFunc := func(ctx context.Context, amount *big.Int) (hash common.Hash, err error) { 234 if sctx.GetGasPrice(ctx).Cmp(big.NewInt(10)) != 0 { 235 return common.Hash{}, errors.New("wrong gas price") 236 } 237 238 if amount.Cmp(big.NewInt(700)) == 0 { 239 return txHash, nil 240 } 241 return common.Hash{}, nil 242 } 243 244 testServer, _, _, _ := newTestServer(t, testServerOptions{ 245 ChequebookOpts: []mock.Option{mock.WithChequebookDepositFunc(chequebookDepositFunc)}, 246 }) 247 248 expected := &api.ChequebookTxResponse{TransactionHash: txHash} 249 250 var got *api.ChequebookTxResponse 251 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/deposit?amount=700", http.StatusOK, 252 jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10"), 253 jsonhttptest.WithUnmarshalJSONResponse(&got), 254 ) 255 256 if !reflect.DeepEqual(got, expected) { 257 t.Errorf("got address: %+v, expected: %+v", got, expected) 258 } 259 }) 260 } 261 262 func TestChequebookLastCheques(t *testing.T) { 263 t.Parallel() 264 265 addr1 := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 266 addr2 := swarm.MustParseHexAddress("2000000000000000000000000000000000000000000000000000000000000000") 267 addr3 := swarm.MustParseHexAddress("3000000000000000000000000000000000000000000000000000000000000000") 268 addr4 := swarm.MustParseHexAddress("4000000000000000000000000000000000000000000000000000000000000000") 269 addr5 := swarm.MustParseHexAddress("5000000000000000000000000000000000000000000000000000000000000000") 270 beneficiary := common.HexToAddress("0xfff5") 271 beneficiary1 := common.HexToAddress("0xfff0") 272 beneficiary2 := common.HexToAddress("0xfff1") 273 beneficiary3 := common.HexToAddress("0xfff2") 274 cumulativePayout1 := big.NewInt(700) 275 cumulativePayout2 := big.NewInt(900) 276 cumulativePayout3 := big.NewInt(600) 277 cumulativePayout4 := big.NewInt(550) 278 cumulativePayout5 := big.NewInt(400) 279 cumulativePayout6 := big.NewInt(720) 280 chequebookAddress1 := common.HexToAddress("0xeee1") 281 chequebookAddress2 := common.HexToAddress("0xeee2") 282 chequebookAddress3 := common.HexToAddress("0xeee3") 283 chequebookAddress4 := common.HexToAddress("0xeee4") 284 chequebookAddress5 := common.HexToAddress("0xeee5") 285 286 lastSentChequesFunc := func() (map[string]*chequebook.SignedCheque, error) { 287 lastSentCheques := make(map[string]*chequebook.SignedCheque, 3) 288 sig := make([]byte, 65) 289 lastSentCheques[addr1.String()] = &chequebook.SignedCheque{ 290 Cheque: chequebook.Cheque{ 291 Beneficiary: beneficiary1, 292 CumulativePayout: cumulativePayout1, 293 Chequebook: chequebookAddress1, 294 }, 295 Signature: sig, 296 } 297 298 lastSentCheques[addr2.String()] = &chequebook.SignedCheque{ 299 Cheque: chequebook.Cheque{ 300 Beneficiary: beneficiary2, 301 CumulativePayout: cumulativePayout2, 302 Chequebook: chequebookAddress2, 303 }, 304 Signature: sig, 305 } 306 307 lastSentCheques[addr3.String()] = &chequebook.SignedCheque{ 308 Cheque: chequebook.Cheque{ 309 Beneficiary: beneficiary3, 310 CumulativePayout: cumulativePayout3, 311 Chequebook: chequebookAddress3, 312 }, 313 Signature: sig, 314 } 315 return lastSentCheques, nil 316 } 317 318 lastReceivedChequesFunc := func() (map[string]*chequebook.SignedCheque, error) { 319 lastReceivedCheques := make(map[string]*chequebook.SignedCheque, 3) 320 sig := make([]byte, 65) 321 322 lastReceivedCheques[addr1.String()] = &chequebook.SignedCheque{ 323 Cheque: chequebook.Cheque{ 324 Beneficiary: beneficiary, 325 CumulativePayout: cumulativePayout4, 326 Chequebook: chequebookAddress1, 327 }, 328 Signature: sig, 329 } 330 331 lastReceivedCheques[addr4.String()] = &chequebook.SignedCheque{ 332 Cheque: chequebook.Cheque{ 333 Beneficiary: beneficiary, 334 CumulativePayout: cumulativePayout5, 335 Chequebook: chequebookAddress4, 336 }, 337 Signature: sig, 338 } 339 340 lastReceivedCheques[addr5.String()] = &chequebook.SignedCheque{ 341 Cheque: chequebook.Cheque{ 342 Beneficiary: beneficiary, 343 CumulativePayout: cumulativePayout6, 344 Chequebook: chequebookAddress5, 345 }, 346 Signature: sig, 347 } 348 349 return lastReceivedCheques, nil 350 } 351 352 testServer, _, _, _ := newTestServer(t, testServerOptions{ 353 SwapOpts: []swapmock.Option{swapmock.WithLastReceivedChequesFunc(lastReceivedChequesFunc), swapmock.WithLastSentChequesFunc(lastSentChequesFunc)}, 354 }) 355 356 lastchequesexpected := []api.ChequebookLastChequesPeerResponse{ 357 { 358 Peer: addr1.String(), 359 LastReceived: &api.ChequebookLastChequePeerResponse{ 360 Beneficiary: beneficiary.String(), 361 Chequebook: chequebookAddress1.String(), 362 Payout: bigint.Wrap(cumulativePayout4), 363 }, 364 LastSent: &api.ChequebookLastChequePeerResponse{ 365 Beneficiary: beneficiary1.String(), 366 Chequebook: chequebookAddress1.String(), 367 Payout: bigint.Wrap(cumulativePayout1), 368 }, 369 }, 370 { 371 Peer: addr2.String(), 372 LastReceived: nil, 373 LastSent: &api.ChequebookLastChequePeerResponse{ 374 Beneficiary: beneficiary2.String(), 375 Chequebook: chequebookAddress2.String(), 376 Payout: bigint.Wrap(cumulativePayout2), 377 }, 378 }, 379 { 380 Peer: addr3.String(), 381 LastReceived: nil, 382 LastSent: &api.ChequebookLastChequePeerResponse{ 383 Beneficiary: beneficiary3.String(), 384 Chequebook: chequebookAddress3.String(), 385 Payout: bigint.Wrap(cumulativePayout3), 386 }, 387 }, 388 { 389 Peer: addr4.String(), 390 LastReceived: &api.ChequebookLastChequePeerResponse{ 391 Beneficiary: beneficiary.String(), 392 Chequebook: chequebookAddress4.String(), 393 Payout: bigint.Wrap(cumulativePayout5), 394 }, 395 LastSent: nil, 396 }, 397 { 398 Peer: addr5.String(), 399 LastReceived: &api.ChequebookLastChequePeerResponse{ 400 Beneficiary: beneficiary.String(), 401 Chequebook: chequebookAddress5.String(), 402 Payout: bigint.Wrap(cumulativePayout6), 403 }, 404 LastSent: nil, 405 }, 406 } 407 408 expected := &api.ChequebookLastChequesResponse{ 409 LastCheques: lastchequesexpected, 410 } 411 412 // We expect a list of items unordered by peer: 413 var got *api.ChequebookLastChequesResponse 414 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cheque", http.StatusOK, 415 jsonhttptest.WithUnmarshalJSONResponse(&got), 416 ) 417 418 if !LastChequesEqual(got, expected) { 419 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 420 } 421 422 } 423 424 func TestChequebookLastChequesPeer(t *testing.T) { 425 t.Parallel() 426 427 addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 428 beneficiary0 := common.HexToAddress("0xfff5") 429 beneficiary1 := common.HexToAddress("0xfff0") 430 cumulativePayout1 := big.NewInt(700) 431 cumulativePayout2 := big.NewInt(900) 432 chequebookAddress := common.HexToAddress("0xeee1") 433 sig := make([]byte, 65) 434 435 lastSentChequeFunc := func(swarm.Address) (*chequebook.SignedCheque, error) { 436 437 sig := make([]byte, 65) 438 439 lastSentCheque := &chequebook.SignedCheque{ 440 Cheque: chequebook.Cheque{ 441 Beneficiary: beneficiary1, 442 CumulativePayout: cumulativePayout1, 443 Chequebook: chequebookAddress, 444 }, 445 Signature: sig, 446 } 447 448 return lastSentCheque, nil 449 } 450 451 lastReceivedChequeFunc := func(swarm.Address) (*chequebook.SignedCheque, error) { 452 453 lastReceivedCheque := &chequebook.SignedCheque{ 454 Cheque: chequebook.Cheque{ 455 Beneficiary: beneficiary0, 456 CumulativePayout: cumulativePayout2, 457 Chequebook: chequebookAddress, 458 }, 459 Signature: sig, 460 } 461 462 return lastReceivedCheque, nil 463 } 464 465 testServer, _, _, _ := newTestServer(t, testServerOptions{ 466 SwapOpts: []swapmock.Option{swapmock.WithLastReceivedChequeFunc(lastReceivedChequeFunc), swapmock.WithLastSentChequeFunc(lastSentChequeFunc)}, 467 }) 468 469 expected := &api.ChequebookLastChequesPeerResponse{ 470 Peer: addr.String(), 471 LastReceived: &api.ChequebookLastChequePeerResponse{ 472 Beneficiary: beneficiary0.String(), 473 Chequebook: chequebookAddress.String(), 474 Payout: bigint.Wrap(cumulativePayout2), 475 }, 476 LastSent: &api.ChequebookLastChequePeerResponse{ 477 Beneficiary: beneficiary1.String(), 478 Chequebook: chequebookAddress.String(), 479 Payout: bigint.Wrap(cumulativePayout1), 480 }, 481 } 482 483 var got *api.ChequebookLastChequesPeerResponse 484 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cheque/"+addr.String(), http.StatusOK, 485 jsonhttptest.WithUnmarshalJSONResponse(&got), 486 ) 487 488 if !reflect.DeepEqual(got, expected) { 489 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 490 } 491 492 } 493 494 func TestChequebookCashout(t *testing.T) { 495 t.Parallel() 496 497 addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 498 deployCashingHash := common.HexToHash("0xffff") 499 500 cashChequeFunc := func(ctx context.Context, peer swarm.Address) (common.Hash, error) { 501 return deployCashingHash, nil 502 } 503 504 testServer, _, _, _ := newTestServer(t, testServerOptions{ 505 SwapOpts: []swapmock.Option{swapmock.WithCashChequeFunc(cashChequeFunc)}, 506 }) 507 508 expected := &api.SwapCashoutResponse{TransactionHash: deployCashingHash.String()} 509 510 var got *api.SwapCashoutResponse 511 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/cashout/"+addr.String(), http.StatusOK, 512 jsonhttptest.WithUnmarshalJSONResponse(&got), 513 ) 514 515 if !reflect.DeepEqual(got, expected) { 516 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 517 } 518 } 519 520 func TestChequebookCashout_CustomGas(t *testing.T) { 521 t.Parallel() 522 523 addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 524 deployCashingHash := common.HexToHash("0xffff") 525 526 var price *big.Int 527 var limit uint64 528 cashChequeFunc := func(ctx context.Context, peer swarm.Address) (common.Hash, error) { 529 price = sctx.GetGasPrice(ctx) 530 limit = sctx.GetGasLimit(ctx) 531 return deployCashingHash, nil 532 } 533 534 testServer, _, _, _ := newTestServer(t, testServerOptions{ 535 SwapOpts: []swapmock.Option{swapmock.WithCashChequeFunc(cashChequeFunc)}, 536 }) 537 538 expected := &api.SwapCashoutResponse{TransactionHash: deployCashingHash.String()} 539 540 var got *api.SwapCashoutResponse 541 jsonhttptest.Request(t, testServer, http.MethodPost, "/chequebook/cashout/"+addr.String(), http.StatusOK, 542 jsonhttptest.WithRequestHeader(api.GasPriceHeader, "10000"), 543 jsonhttptest.WithRequestHeader(api.GasLimitHeader, "12221"), 544 jsonhttptest.WithUnmarshalJSONResponse(&got), 545 ) 546 547 if !reflect.DeepEqual(got, expected) { 548 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 549 } 550 551 if price.Cmp(big.NewInt(10000)) != 0 { 552 t.Fatalf("expected gas price 10000 got %s", price) 553 } 554 555 if limit != 12221 { 556 t.Fatalf("expected gas limit 12221 got %d", limit) 557 } 558 } 559 560 func TestChequebookCashoutStatus(t *testing.T) { 561 t.Parallel() 562 563 actionTxHash := common.HexToHash("0xacfe") 564 addr := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 565 beneficiary := common.HexToAddress("0xfff0") 566 recipientAddress := common.HexToAddress("efff") 567 totalPayout := big.NewInt(100) 568 cumulativePayout := big.NewInt(700) 569 uncashedAmount := big.NewInt(200) 570 chequebookAddress := common.HexToAddress("0xcfec") 571 peer := swarm.MustParseHexAddress("1000000000000000000000000000000000000000000000000000000000000000") 572 573 sig := make([]byte, 65) 574 cheque := &chequebook.SignedCheque{ 575 Cheque: chequebook.Cheque{ 576 Beneficiary: beneficiary, 577 CumulativePayout: cumulativePayout, 578 Chequebook: chequebookAddress, 579 }, 580 Signature: sig, 581 } 582 583 result := &chequebook.CashChequeResult{ 584 Beneficiary: cheque.Beneficiary, 585 Recipient: recipientAddress, 586 Caller: cheque.Beneficiary, 587 TotalPayout: totalPayout, 588 CumulativePayout: cumulativePayout, 589 CallerPayout: big.NewInt(0), 590 Bounced: false, 591 } 592 593 t.Run("with result", func(t *testing.T) { 594 t.Parallel() 595 596 cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) { 597 status := &chequebook.CashoutStatus{ 598 Last: &chequebook.LastCashout{ 599 TxHash: actionTxHash, 600 Cheque: *cheque, 601 Result: result, 602 Reverted: false, 603 }, 604 UncashedAmount: uncashedAmount, 605 } 606 return status, nil 607 } 608 609 testServer, _, _, _ := newTestServer(t, testServerOptions{ 610 SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)}, 611 }) 612 613 expected := &api.SwapCashoutStatusResponse{ 614 Peer: peer, 615 TransactionHash: &actionTxHash, 616 Cheque: &api.ChequebookLastChequePeerResponse{ 617 Chequebook: chequebookAddress.String(), 618 Payout: bigint.Wrap(cumulativePayout), 619 Beneficiary: cheque.Beneficiary.String(), 620 }, 621 Result: &api.SwapCashoutStatusResult{ 622 Recipient: recipientAddress, 623 LastPayout: bigint.Wrap(totalPayout), 624 Bounced: false, 625 }, 626 UncashedAmount: bigint.Wrap(uncashedAmount), 627 } 628 629 var got *api.SwapCashoutStatusResponse 630 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK, 631 632 jsonhttptest.WithUnmarshalJSONResponse(&got), 633 ) 634 635 if !reflect.DeepEqual(got, expected) { 636 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 637 } 638 }) 639 640 t.Run("without result", func(t *testing.T) { 641 t.Parallel() 642 643 cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) { 644 status := &chequebook.CashoutStatus{ 645 Last: &chequebook.LastCashout{ 646 TxHash: actionTxHash, 647 Cheque: *cheque, 648 Result: nil, 649 Reverted: false, 650 }, 651 UncashedAmount: uncashedAmount, 652 } 653 return status, nil 654 } 655 656 testServer, _, _, _ := newTestServer(t, testServerOptions{ 657 SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)}, 658 }) 659 660 expected := &api.SwapCashoutStatusResponse{ 661 Peer: peer, 662 TransactionHash: &actionTxHash, 663 Cheque: &api.ChequebookLastChequePeerResponse{ 664 Chequebook: chequebookAddress.String(), 665 Payout: bigint.Wrap(cumulativePayout), 666 Beneficiary: cheque.Beneficiary.String(), 667 }, 668 Result: nil, 669 UncashedAmount: bigint.Wrap(uncashedAmount), 670 } 671 672 var got *api.SwapCashoutStatusResponse 673 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK, 674 675 jsonhttptest.WithUnmarshalJSONResponse(&got), 676 ) 677 678 if !reflect.DeepEqual(got, expected) { 679 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 680 } 681 }) 682 683 t.Run("without last", func(t *testing.T) { 684 t.Parallel() 685 686 cashoutStatusFunc := func(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) { 687 status := &chequebook.CashoutStatus{ 688 Last: nil, 689 UncashedAmount: uncashedAmount, 690 } 691 return status, nil 692 } 693 694 testServer, _, _, _ := newTestServer(t, testServerOptions{ 695 SwapOpts: []swapmock.Option{swapmock.WithCashoutStatusFunc(cashoutStatusFunc)}, 696 }) 697 698 expected := &api.SwapCashoutStatusResponse{ 699 Peer: peer, 700 TransactionHash: nil, 701 Cheque: nil, 702 Result: nil, 703 UncashedAmount: bigint.Wrap(uncashedAmount), 704 } 705 706 var got *api.SwapCashoutStatusResponse 707 jsonhttptest.Request(t, testServer, http.MethodGet, "/chequebook/cashout/"+addr.String(), http.StatusOK, 708 709 jsonhttptest.WithUnmarshalJSONResponse(&got), 710 ) 711 712 if !reflect.DeepEqual(got, expected) { 713 t.Fatalf("Got: \n %+v \n\n Expected: \n %+v \n\n", got, expected) 714 } 715 }) 716 } 717 718 func Test_chequebookLastPeerHandler_invalidInputs(t *testing.T) { 719 t.Parallel() 720 721 client, _, _, _ := newTestServer(t, testServerOptions{}) 722 723 tests := []struct { 724 name string 725 peer string 726 want jsonhttp.StatusResponse 727 }{{ 728 name: "peer - odd hex string", 729 peer: "123", 730 want: jsonhttp.StatusResponse{ 731 Code: http.StatusBadRequest, 732 Message: "invalid path params", 733 Reasons: []jsonhttp.Reason{ 734 { 735 Field: "peer", 736 Error: api.ErrHexLength.Error(), 737 }, 738 }, 739 }, 740 }, { 741 name: "peer - invalid hex character", 742 peer: "123G", 743 want: jsonhttp.StatusResponse{ 744 Code: http.StatusBadRequest, 745 Message: "invalid path params", 746 Reasons: []jsonhttp.Reason{ 747 { 748 Field: "peer", 749 Error: api.HexInvalidByteError('G').Error(), 750 }, 751 }, 752 }, 753 }} 754 755 for _, tc := range tests { 756 tc := tc 757 t.Run(tc.name, func(t *testing.T) { 758 t.Parallel() 759 760 jsonhttptest.Request(t, client, http.MethodGet, "/chequebook/cheque/"+tc.peer, tc.want.Code, 761 jsonhttptest.WithExpectedJSONResponse(tc.want), 762 ) 763 }) 764 } 765 } 766 767 func LastChequesEqual(a, b *api.ChequebookLastChequesResponse) bool { 768 769 var state bool 770 771 for akeys := range a.LastCheques { 772 state = false 773 for bkeys := range b.LastCheques { 774 if reflect.DeepEqual(a.LastCheques[akeys], b.LastCheques[bkeys]) { 775 state = true 776 break 777 } 778 } 779 if !state { 780 return false 781 } 782 } 783 784 for bkeys := range b.LastCheques { 785 state = false 786 for akeys := range a.LastCheques { 787 if reflect.DeepEqual(a.LastCheques[akeys], b.LastCheques[bkeys]) { 788 state = true 789 break 790 } 791 } 792 if !state { 793 return false 794 } 795 } 796 797 return true 798 }