github.com/koko1123/flow-go-1@v0.29.6/engine/access/rest/accounts_test.go (about) 1 package rest 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 "strings" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 mocktestify "github.com/stretchr/testify/mock" 12 "github.com/stretchr/testify/require" 13 14 "github.com/koko1123/flow-go-1/access/mock" 15 "github.com/koko1123/flow-go-1/engine/access/rest/middleware" 16 "github.com/koko1123/flow-go-1/model/flow" 17 "github.com/koko1123/flow-go-1/utils/unittest" 18 ) 19 20 const expandableFieldKeys = "keys" 21 const expandableFieldContracts = "contracts" 22 23 func accountURL(t *testing.T, address string, height string) string { 24 u, err := url.ParseRequestURI(fmt.Sprintf("/v1/accounts/%s", address)) 25 require.NoError(t, err) 26 q := u.Query() 27 28 if height != "" { 29 q.Add("block_height", height) 30 } 31 32 u.RawQuery = q.Encode() 33 return u.String() 34 } 35 36 func TestGetAccount(t *testing.T) { 37 backend := &mock.API{} 38 39 t.Run("get by address at latest sealed block", func(t *testing.T) { 40 account := accountFixture(t) 41 var height uint64 = 100 42 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) 43 44 req := getAccountRequest(t, account, sealedHeightQueryParam, expandableFieldKeys, expandableFieldContracts) 45 46 backend.Mock. 47 On("GetLatestBlockHeader", mocktestify.Anything, true). 48 Return(block, flow.BlockStatusSealed, nil) 49 50 backend.Mock. 51 On("GetAccountAtBlockHeight", mocktestify.Anything, account.Address, height). 52 Return(account, nil) 53 54 expected := expectedExpandedResponse(account) 55 56 assertOKResponse(t, req, expected, backend) 57 mocktestify.AssertExpectationsForObjects(t, backend) 58 }) 59 60 t.Run("get by address at latest finalized block", func(t *testing.T) { 61 62 var height uint64 = 100 63 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) 64 account := accountFixture(t) 65 66 req := getAccountRequest(t, account, finalHeightQueryParam, expandableFieldKeys, expandableFieldContracts) 67 backend.Mock. 68 On("GetLatestBlockHeader", mocktestify.Anything, false). 69 Return(block, flow.BlockStatusFinalized, nil) 70 backend.Mock. 71 On("GetAccountAtBlockHeight", mocktestify.Anything, account.Address, height). 72 Return(account, nil) 73 74 expected := expectedExpandedResponse(account) 75 76 assertOKResponse(t, req, expected, backend) 77 mocktestify.AssertExpectationsForObjects(t, backend) 78 }) 79 80 t.Run("get by address at height", func(t *testing.T) { 81 var height uint64 = 1337 82 account := accountFixture(t) 83 req := getAccountRequest(t, account, fmt.Sprintf("%d", height), expandableFieldKeys, expandableFieldContracts) 84 85 backend.Mock. 86 On("GetAccountAtBlockHeight", mocktestify.Anything, account.Address, height). 87 Return(account, nil) 88 89 expected := expectedExpandedResponse(account) 90 91 assertOKResponse(t, req, expected, backend) 92 mocktestify.AssertExpectationsForObjects(t, backend) 93 }) 94 95 t.Run("get by address at height condensed", func(t *testing.T) { 96 var height uint64 = 1337 97 account := accountFixture(t) 98 req := getAccountRequest(t, account, fmt.Sprintf("%d", height)) 99 100 backend.Mock. 101 On("GetAccountAtBlockHeight", mocktestify.Anything, account.Address, height). 102 Return(account, nil) 103 104 expected := expectedCondensedResponse(account) 105 106 assertOKResponse(t, req, expected, backend) 107 mocktestify.AssertExpectationsForObjects(t, backend) 108 }) 109 110 t.Run("get invalid", func(t *testing.T) { 111 tests := []struct { 112 url string 113 out string 114 }{ 115 {accountURL(t, "123", ""), `{"code":400, "message":"invalid address"}`}, 116 {accountURL(t, unittest.AddressFixture().String(), "foo"), `{"code":400, "message":"invalid height format"}`}, 117 } 118 119 for i, test := range tests { 120 req, _ := http.NewRequest("GET", test.url, nil) 121 rr, err := executeRequest(req, backend) 122 assert.NoError(t, err) 123 124 assert.Equal(t, http.StatusBadRequest, rr.Code) 125 assert.JSONEq(t, test.out, rr.Body.String(), fmt.Sprintf("test #%d failed: %v", i, test)) 126 } 127 }) 128 } 129 130 func expectedExpandedResponse(account *flow.Account) string { 131 return fmt.Sprintf(`{ 132 "address":"%s", 133 "balance":"100", 134 "keys":[ 135 { 136 "index":"0", 137 "public_key":"%s", 138 "signing_algorithm":"ECDSA_P256", 139 "hashing_algorithm":"SHA3_256", 140 "sequence_number":"0", 141 "weight":"1000", 142 "revoked":false 143 } 144 ], 145 "_links":{"_self":"/v1/accounts/%s" }, 146 "_expandable": {}, 147 "contracts": {"contract1":"Y29udHJhY3Qx", "contract2":"Y29udHJhY3Qy"} 148 }`, account.Address, account.Keys[0].PublicKey.String(), account.Address) 149 } 150 151 func expectedCondensedResponse(account *flow.Account) string { 152 return fmt.Sprintf(`{ 153 "address":"%s", 154 "balance":"100", 155 "_links":{"_self":"/v1/accounts/%s" }, 156 "_expandable":{"contracts":"contracts", "keys":"keys"} 157 }`, account.Address, account.Address) 158 } 159 160 func getAccountRequest(t *testing.T, account *flow.Account, height string, expandFields ...string) *http.Request { 161 req, err := http.NewRequest("GET", accountURL(t, account.Address.String(), height), nil) 162 if len(expandFields) > 0 { 163 fieldParam := strings.Join(expandFields, ",") 164 q := req.URL.Query() 165 q.Add(middleware.ExpandQueryParam, fieldParam) 166 req.URL.RawQuery = q.Encode() 167 } 168 require.NoError(t, err) 169 return req 170 } 171 172 func accountFixture(t *testing.T) *flow.Account { 173 account, err := unittest.AccountFixture() 174 require.NoError(t, err) 175 return account 176 }