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  }