Skip to content

Commit e1be616

Browse files
committed
test: improve tests for get trusted accounts handler
1 parent 63c045a commit e1be616

File tree

4 files changed

+307
-50
lines changed

4 files changed

+307
-50
lines changed

.mockery.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ packages:
6565
ResignUseCase:
6666
GetRevenueReportUseCase:
6767
GetSummariesReportUseCase:
68+
GetTrustedAccountsUseCase:
6869
ServerInfoUseCase:
6970
WithdrawCollateralUseCase:
7071
github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider:

internal/adapters/entrypoints/rest/handlers/get_trusted_accounts.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
package handlers
22

33
import (
4+
"context"
45
"net/http"
56

67
"github.com/rsksmart/liquidity-provider-server/internal/adapters/entrypoints/rest"
7-
"github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider"
8+
"github.com/rsksmart/liquidity-provider-server/internal/entities"
9+
"github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider"
810
"github.com/rsksmart/liquidity-provider-server/pkg"
911
)
1012

13+
type GetTrustedAccountsUseCase interface {
14+
Run(ctx context.Context) ([]entities.Signed[liquidity_provider.TrustedAccountDetails], error)
15+
}
16+
1117
// NewGetTrustedAccountsHandler
1218
// @Title Get Trusted Accounts
1319
// @Description Returns all trusted accounts
1420
// @Success 200 object
1521
// @Route /management/trusted-accounts [get]
16-
func NewGetTrustedAccountsHandler(useCase *liquidity_provider.GetTrustedAccountsUseCase) http.HandlerFunc {
22+
func NewGetTrustedAccountsHandler(useCase GetTrustedAccountsUseCase) http.HandlerFunc {
1723
return func(w http.ResponseWriter, req *http.Request) {
1824
accounts, err := useCase.Run(req.Context())
1925
if err != nil {
Lines changed: 200 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package handlers_test
22

33
import (
4-
"encoding/hex"
54
"encoding/json"
65
"errors"
76
"net/http"
87
"net/http/httptest"
98
"testing"
109

10+
"github.com/rsksmart/liquidity-provider-server/internal/adapters/entrypoints/rest"
1111
"github.com/rsksmart/liquidity-provider-server/internal/adapters/entrypoints/rest/handlers"
1212
"github.com/rsksmart/liquidity-provider-server/internal/entities"
1313
"github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider"
14-
lpuc "github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider"
1514
"github.com/rsksmart/liquidity-provider-server/pkg"
1615
"github.com/rsksmart/liquidity-provider-server/test/mocks"
1716
"github.com/stretchr/testify/assert"
@@ -20,71 +19,224 @@ import (
2019
)
2120

2221
// nolint:funlen
23-
func TestNewGetTrustedAccountsHandler(t *testing.T) {
24-
t.Run("should return 200 with accounts on success", func(t *testing.T) {
22+
func TestGetTrustedAccountsHandlerHappyPath(t *testing.T) {
23+
t.Run("should return 200 with multiple accounts", func(t *testing.T) {
24+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
2525
recorder := httptest.NewRecorder()
26-
request := httptest.NewRequest("GET", "/management/trusted-accounts", nil)
27-
mockHashBytes := []byte("mockhash12345678")
28-
mockHashHex := hex.EncodeToString(mockHashBytes)
26+
2927
account1 := liquidity_provider.TrustedAccountDetails{
30-
Address: "0x123",
28+
Address: "0x1234567890abcdef1234567890abcdef12345678",
3129
Name: "Test Account 1",
32-
BtcLockingCap: entities.NewWei(100),
33-
RbtcLockingCap: entities.NewWei(200),
30+
BtcLockingCap: entities.NewWei(1000000000000000000),
31+
RbtcLockingCap: entities.NewWei(2000000000000000000),
3432
}
3533
account2 := liquidity_provider.TrustedAccountDetails{
36-
Address: "0x456",
34+
Address: "0xabcdef1234567890abcdef1234567890abcdef12",
3735
Name: "Test Account 2",
38-
BtcLockingCap: entities.NewWei(300),
39-
RbtcLockingCap: entities.NewWei(400),
36+
BtcLockingCap: entities.NewWei(3000000000000000000),
37+
RbtcLockingCap: entities.NewWei(4000000000000000000),
4038
}
41-
mockSignedAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{
42-
{
43-
Value: account1,
44-
Hash: mockHashHex,
45-
Signature: "sig1",
46-
},
47-
{
48-
Value: account2,
49-
Hash: mockHashHex,
50-
Signature: "sig2",
51-
},
39+
mockAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{
40+
{Value: account1, Hash: "hash1", Signature: "sig1"},
41+
{Value: account2, Hash: "hash2", Signature: "sig2"},
5242
}
53-
repo := mocks.NewTrustedAccountRepositoryMock(t)
54-
repo.On("GetAllTrustedAccounts", mock.Anything).Return(mockSignedAccounts, nil)
55-
hashMock := &mocks.HashMock{}
56-
hashMock.On("Hash", mock.Anything).Return(mockHashBytes)
57-
signerMock := &mocks.SignerMock{}
58-
signerMock.On("Validate", mock.Anything, mock.Anything).Return(true)
59-
useCase := lpuc.NewGetTrustedAccountsUseCase(repo, hashMock.Hash, signerMock)
60-
handler := http.HandlerFunc(handlers.NewGetTrustedAccountsHandler(useCase))
43+
44+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
45+
mockUseCase.On("Run", mock.Anything).Return(mockAccounts, nil)
46+
47+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
48+
handler := http.HandlerFunc(handlerFunc)
49+
6150
handler.ServeHTTP(recorder, request)
51+
6252
assert.Equal(t, http.StatusOK, recorder.Code)
53+
assert.Equal(t, "application/json", recorder.Header().Get("Content-Type"))
54+
6355
var response pkg.TrustedAccountsResponse
6456
err := json.Unmarshal(recorder.Body.Bytes(), &response)
6557
require.NoError(t, err)
58+
59+
// Verify response structure
6660
require.Len(t, response.Accounts, 2)
67-
assert.Equal(t, "0x123", response.Accounts[0].Address)
61+
62+
// Verify first account
63+
assert.Equal(t, "0x1234567890abcdef1234567890abcdef12345678", response.Accounts[0].Address)
6864
assert.Equal(t, "Test Account 1", response.Accounts[0].Name)
69-
assert.Equal(t, "0x456", response.Accounts[1].Address)
65+
assert.Equal(t, "1000000000000000000", response.Accounts[0].BtcLockingCap.String())
66+
assert.Equal(t, "2000000000000000000", response.Accounts[0].RbtcLockingCap.String())
67+
68+
// Verify second account
69+
assert.Equal(t, "0xabcdef1234567890abcdef1234567890abcdef12", response.Accounts[1].Address)
7070
assert.Equal(t, "Test Account 2", response.Accounts[1].Name)
71-
repo.AssertExpectations(t)
72-
hashMock.AssertExpectations(t)
73-
signerMock.AssertExpectations(t)
71+
assert.Equal(t, "3000000000000000000", response.Accounts[1].BtcLockingCap.String())
72+
assert.Equal(t, "4000000000000000000", response.Accounts[1].RbtcLockingCap.String())
73+
74+
mockUseCase.AssertExpectations(t)
75+
})
76+
77+
t.Run("should return 200 with single account", func(t *testing.T) {
78+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
79+
recorder := httptest.NewRecorder()
80+
81+
account := liquidity_provider.TrustedAccountDetails{
82+
Address: "0x1234567890abcdef1234567890abcdef12345678",
83+
Name: "Single Account",
84+
BtcLockingCap: entities.NewWei(5000000000000000000),
85+
RbtcLockingCap: entities.NewWei(6000000000000000000),
86+
}
87+
mockAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{
88+
{Value: account, Hash: "hash1", Signature: "sig1"},
89+
}
90+
91+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
92+
mockUseCase.On("Run", mock.Anything).Return(mockAccounts, nil)
93+
94+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
95+
handler := http.HandlerFunc(handlerFunc)
96+
97+
handler.ServeHTTP(recorder, request)
98+
99+
assert.Equal(t, http.StatusOK, recorder.Code)
100+
101+
var response pkg.TrustedAccountsResponse
102+
err := json.Unmarshal(recorder.Body.Bytes(), &response)
103+
require.NoError(t, err)
104+
require.Len(t, response.Accounts, 1)
105+
assert.Equal(t, "Single Account", response.Accounts[0].Name)
106+
107+
mockUseCase.AssertExpectations(t)
108+
})
109+
}
110+
111+
func TestGetTrustedAccountsHandlerEdgeCases(t *testing.T) {
112+
t.Run("should return 200 with empty accounts list", func(t *testing.T) {
113+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
114+
recorder := httptest.NewRecorder()
115+
116+
mockAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{}
117+
118+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
119+
mockUseCase.On("Run", mock.Anything).Return(mockAccounts, nil)
120+
121+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
122+
handler := http.HandlerFunc(handlerFunc)
123+
124+
handler.ServeHTTP(recorder, request)
125+
126+
assert.Equal(t, http.StatusOK, recorder.Code)
127+
128+
var response pkg.TrustedAccountsResponse
129+
err := json.Unmarshal(recorder.Body.Bytes(), &response)
130+
require.NoError(t, err)
131+
assert.Empty(t, response.Accounts)
132+
assert.Empty(t, response.Accounts)
133+
134+
mockUseCase.AssertExpectations(t)
74135
})
75-
t.Run("should return 500 on error", func(t *testing.T) {
136+
137+
t.Run("should return 200 with nil accounts (converted to empty)", func(t *testing.T) {
138+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
76139
recorder := httptest.NewRecorder()
77-
request := httptest.NewRequest("GET", "/management/trusted-accounts", nil)
78-
repo := mocks.NewTrustedAccountRepositoryMock(t)
79-
repo.On("GetAllTrustedAccounts", mock.Anything).Return(nil, errors.New("database error"))
80-
hashMock := &mocks.HashMock{}
81-
signerMock := &mocks.SignerMock{}
82-
useCase := lpuc.NewGetTrustedAccountsUseCase(repo, hashMock.Hash, signerMock)
83-
handler := http.HandlerFunc(handlers.NewGetTrustedAccountsHandler(useCase))
140+
141+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
142+
mockUseCase.On("Run", mock.Anything).Return(nil, nil)
143+
144+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
145+
handler := http.HandlerFunc(handlerFunc)
146+
84147
handler.ServeHTTP(recorder, request)
148+
149+
assert.Equal(t, http.StatusOK, recorder.Code)
150+
151+
var response pkg.TrustedAccountsResponse
152+
err := json.Unmarshal(recorder.Body.Bytes(), &response)
153+
require.NoError(t, err)
154+
assert.Empty(t, response.Accounts)
155+
156+
mockUseCase.AssertExpectations(t)
157+
})
158+
}
159+
160+
func TestGetTrustedAccountsHandlerErrorCases(t *testing.T) {
161+
t.Run("should return 500 on use case error", func(t *testing.T) {
162+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
163+
recorder := httptest.NewRecorder()
164+
165+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
166+
mockUseCase.On("Run", mock.Anything).Return(nil, errors.New("database connection error"))
167+
168+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
169+
handler := http.HandlerFunc(handlerFunc)
170+
171+
handler.ServeHTTP(recorder, request)
172+
85173
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
86-
repo.AssertExpectations(t)
87-
hashMock.AssertNotCalled(t, "Hash")
88-
signerMock.AssertNotCalled(t, "Validate")
174+
175+
var errorResponse rest.ErrorResponse
176+
err := json.Unmarshal(recorder.Body.Bytes(), &errorResponse)
177+
require.NoError(t, err)
178+
assert.Equal(t, handlers.UnknownErrorMessage, errorResponse.Message)
179+
assert.False(t, errorResponse.Recoverable)
180+
assert.Contains(t, errorResponse.Details, "error")
181+
182+
mockUseCase.AssertExpectations(t)
183+
})
184+
}
185+
186+
func TestGetTrustedAccountsHandlerResponseFormat(t *testing.T) {
187+
t.Run("response should have correct Content-Type", func(t *testing.T) {
188+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
189+
recorder := httptest.NewRecorder()
190+
191+
mockAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{}
192+
193+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
194+
mockUseCase.On("Run", mock.Anything).Return(mockAccounts, nil)
195+
196+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
197+
handler := http.HandlerFunc(handlerFunc)
198+
199+
handler.ServeHTTP(recorder, request)
200+
201+
assert.Equal(t, "application/json", recorder.Header().Get("Content-Type"))
202+
})
203+
204+
t.Run("error response should have timestamp", func(t *testing.T) {
205+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
206+
recorder := httptest.NewRecorder()
207+
208+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
209+
mockUseCase.On("Run", mock.Anything).Return(nil, errors.New("error"))
210+
211+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
212+
handler := http.HandlerFunc(handlerFunc)
213+
214+
handler.ServeHTTP(recorder, request)
215+
216+
var errorResponse rest.ErrorResponse
217+
err := json.Unmarshal(recorder.Body.Bytes(), &errorResponse)
218+
require.NoError(t, err)
219+
assert.NotZero(t, errorResponse.Timestamp)
220+
})
221+
222+
t.Run("response should have accounts key even when empty", func(t *testing.T) {
223+
request := httptest.NewRequest(http.MethodGet, "/management/trusted-accounts", nil)
224+
recorder := httptest.NewRecorder()
225+
226+
mockAccounts := []entities.Signed[liquidity_provider.TrustedAccountDetails]{}
227+
228+
mockUseCase := new(mocks.GetTrustedAccountsUseCaseMock)
229+
mockUseCase.On("Run", mock.Anything).Return(mockAccounts, nil)
230+
231+
handlerFunc := handlers.NewGetTrustedAccountsHandler(mockUseCase)
232+
handler := http.HandlerFunc(handlerFunc)
233+
234+
handler.ServeHTTP(recorder, request)
235+
236+
// Verify JSON structure has "accounts" key
237+
var rawResponse map[string]interface{}
238+
err := json.Unmarshal(recorder.Body.Bytes(), &rawResponse)
239+
require.NoError(t, err)
240+
assert.Contains(t, rawResponse, "accounts")
89241
})
90242
}

0 commit comments

Comments
 (0)