@mojaloop/sdk-scheme-adapter 17.0.2-snapshot.6 → 18.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.circleci/config.yml +0 -4
  2. package/.dockerignore +18 -0
  3. package/.eslintignore +2 -0
  4. package/CHANGELOG.md +20 -0
  5. package/Dockerfile +8 -5
  6. package/audit-resolve.json +10 -0
  7. package/docker-compose.yml +3 -2
  8. package/package.json +4 -3
  9. package/src/lib/model/InboundTransfersModel.js +2 -2
  10. package/test/__mocks__/@mojaloop/sdk-standard-components.js +0 -151
  11. package/test/__mocks__/javascript-state-machine.js +0 -21
  12. package/test/__mocks__/redis.js +0 -78
  13. package/test/__mocks__/uuidv4.js +0 -16
  14. package/test/config/integration.env +0 -146
  15. package/test/integration/lib/Outbound/data/quotesPostRequest.json +0 -52
  16. package/test/integration/lib/Outbound/data/transfersPostRequest.json +0 -24
  17. package/test/integration/lib/Outbound/parties.test.js +0 -31
  18. package/test/integration/lib/Outbound/quotes.test.js +0 -62
  19. package/test/integration/lib/Outbound/simpleTransfers.test.js +0 -70
  20. package/test/integration/lib/cache.test.js +0 -79
  21. package/test/integration/testEnv.js +0 -4
  22. package/test/unit/ControlClient.test.js +0 -69
  23. package/test/unit/ControlServer/events.js +0 -41
  24. package/test/unit/ControlServer/index.js +0 -227
  25. package/test/unit/ControlServer.test.js +0 -66
  26. package/test/unit/InboundServer.test.js +0 -443
  27. package/test/unit/TestServer.test.js +0 -392
  28. package/test/unit/api/accounts/accounts.test.js +0 -128
  29. package/test/unit/api/accounts/data/postAccountsBody.json +0 -7
  30. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +0 -33
  31. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +0 -19
  32. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +0 -31
  33. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +0 -34
  34. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +0 -39
  35. package/test/unit/api/accounts/utils.js +0 -79
  36. package/test/unit/api/proxy/data/proxyConfig.yaml +0 -82
  37. package/test/unit/api/proxy/data/requestBody.json +0 -22
  38. package/test/unit/api/proxy/data/requestHeaders.json +0 -5
  39. package/test/unit/api/proxy/data/requestQuery.json +0 -6
  40. package/test/unit/api/proxy/data/responseBody.json +0 -21
  41. package/test/unit/api/proxy/data/responseHeaders.json +0 -5
  42. package/test/unit/api/proxy/proxy.test.js +0 -220
  43. package/test/unit/api/proxy/utils.js +0 -79
  44. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +0 -24
  45. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +0 -18
  46. package/test/unit/api/transfers/data/postQuotesBody.json +0 -52
  47. package/test/unit/api/transfers/data/postTransfersBadBody.json +0 -17
  48. package/test/unit/api/transfers/data/postTransfersBody.json +0 -24
  49. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +0 -62
  50. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +0 -48
  51. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +0 -26
  52. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +0 -128
  53. package/test/unit/api/transfers/data/putPartiesBody.json +0 -20
  54. package/test/unit/api/transfers/data/putQuotesBody.json +0 -37
  55. package/test/unit/api/transfers/data/putTransfersBody.json +0 -17
  56. package/test/unit/api/transfers/transfers.test.js +0 -191
  57. package/test/unit/api/transfers/utils.js +0 -264
  58. package/test/unit/api/utils.js +0 -86
  59. package/test/unit/config.test.js +0 -119
  60. package/test/unit/data/commonHttpHeaders.json +0 -7
  61. package/test/unit/data/defaultConfig.json +0 -70
  62. package/test/unit/data/postQuotesBody.json +0 -52
  63. package/test/unit/data/putParticipantsBody.json +0 -12
  64. package/test/unit/data/putPartiesBody.json +0 -20
  65. package/test/unit/data/testFile.json +0 -29
  66. package/test/unit/data/testFile.yaml +0 -14
  67. package/test/unit/inboundApi/data/mockArguments.json +0 -117
  68. package/test/unit/inboundApi/data/mockTransactionRequest.json +0 -42
  69. package/test/unit/inboundApi/handlers.test.js +0 -786
  70. package/test/unit/index.test.js +0 -88
  71. package/test/unit/lib/cache.test.js +0 -145
  72. package/test/unit/lib/model/AccountsModel.test.js +0 -124
  73. package/test/unit/lib/model/InboundTransfersModel.test.js +0 -889
  74. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +0 -253
  75. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +0 -247
  76. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +0 -166
  77. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +0 -245
  78. package/test/unit/lib/model/OutboundTransfersModel.test.js +0 -1579
  79. package/test/unit/lib/model/PartiesModel.test.js +0 -478
  80. package/test/unit/lib/model/QuotesModel.test.js +0 -477
  81. package/test/unit/lib/model/TransfersModel.test.js +0 -481
  82. package/test/unit/lib/model/common/PersistentStateMachine.test.js +0 -178
  83. package/test/unit/lib/model/data/authorizationsResponse.json +0 -13
  84. package/test/unit/lib/model/data/bulkQuoteRequest.json +0 -27
  85. package/test/unit/lib/model/data/bulkQuoteResponse.json +0 -35
  86. package/test/unit/lib/model/data/bulkTransferFulfil.json +0 -13
  87. package/test/unit/lib/model/data/bulkTransferRequest.json +0 -29
  88. package/test/unit/lib/model/data/defaultConfig.json +0 -59
  89. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +0 -42
  90. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +0 -22
  91. package/test/unit/lib/model/data/getTransfersBackendResponse.json +0 -34
  92. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +0 -17
  93. package/test/unit/lib/model/data/mockArguments.json +0 -188
  94. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +0 -63
  95. package/test/unit/lib/model/data/notificationAbortedToPayee.json +0 -10
  96. package/test/unit/lib/model/data/notificationReservedToPayee.json +0 -10
  97. package/test/unit/lib/model/data/notificationToPayee.json +0 -10
  98. package/test/unit/lib/model/data/payeeParty.json +0 -18
  99. package/test/unit/lib/model/data/putQuotesResponse.json +0 -33
  100. package/test/unit/lib/model/data/putTransfersResponse.json +0 -5
  101. package/test/unit/lib/model/data/quoteResponse.json +0 -42
  102. package/test/unit/lib/model/data/requestToPayRequest.json +0 -20
  103. package/test/unit/lib/model/data/requestToPayTransferRequest.json +0 -27
  104. package/test/unit/lib/model/data/transactionRequestResponse.json +0 -18
  105. package/test/unit/lib/model/data/transferFulfil.json +0 -10
  106. package/test/unit/lib/model/data/transferRequest.json +0 -26
  107. package/test/unit/lib/model/mockedLibRequests.js +0 -74
  108. package/test/unit/mockLogger.js +0 -39
  109. package/test/unit/outboundApi/data/bulkQuoteRequest.json +0 -28
  110. package/test/unit/outboundApi/data/bulkTransferRequest.json +0 -28
  111. package/test/unit/outboundApi/data/mockBulkQuoteError.json +0 -45
  112. package/test/unit/outboundApi/data/mockBulkTransferError.json +0 -48
  113. package/test/unit/outboundApi/data/mockError.json +0 -41
  114. package/test/unit/outboundApi/data/mockGetPartiesError.json +0 -4
  115. package/test/unit/outboundApi/data/mockRequestToPayError.json +0 -32
  116. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +0 -39
  117. package/test/unit/outboundApi/data/requestToPay.json +0 -21
  118. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +0 -20
  119. package/test/unit/outboundApi/data/transferRequest.json +0 -21
  120. package/test/unit/outboundApi/handlers.test.js +0 -887
@@ -1,889 +0,0 @@
1
- /**************************************************************************
2
- * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
- * *
4
- * This file is made available under the terms of the license agreement *
5
- * specified in the corresponding source code repository. *
6
- * *
7
- * ORIGINAL AUTHOR: *
8
- * Vassilis Barzokas - vassilis.barzokas@modusbox.com *
9
- **************************************************************************/
10
- 'use strict';
11
-
12
- // we use a mock standard components lib to intercept and mock certain funcs
13
- jest.mock('@mojaloop/sdk-standard-components');
14
- jest.mock('redis');
15
- jest.mock('~/lib/model/lib/requests',() => require('./mockedLibRequests'));
16
-
17
- const defaultConfig = require('./data/defaultConfig');
18
- const Model = require('~/lib/model').InboundTransfersModel;
19
- const mockArguments = require('./data/mockArguments');
20
- const mockTxnReqquestsArguments = require('./data/mockTxnRequestsArguments');
21
- const { MojaloopRequests, Ilp, Logger } = require('@mojaloop/sdk-standard-components');
22
- const { BackendRequests, HTTPResponseError } = require('~/lib/model/lib/requests');
23
- const Cache = require('~/lib/cache');
24
- const shared = require('~/lib/model/lib/shared');
25
-
26
- const getTransfersBackendResponse = require('./data/getTransfersBackendResponse');
27
- const getTransfersMojaloopResponse = require('./data/getTransfersMojaloopResponse');
28
- const getBulkTransfersBackendResponse = require('./data/getBulkTransfersBackendResponse');
29
- const getBulkTransfersMojaloopResponse = require('./data/getBulkTransfersMojaloopResponse');
30
- const notificationToPayee = require('./data/notificationToPayee');
31
- const notificationAbortedToPayee = require('./data/notificationAbortedToPayee');
32
- const notificationReservedToPayee = require('./data/notificationReservedToPayee');
33
-
34
- const { SDKStateEnum } = require('../../../../src/lib/model/common');
35
- const FSPIOPTransferStateEnum = require('@mojaloop/central-services-shared').Enum.Transfers.TransferState;
36
- const FSPIOPBulkTransferStateEnum = require('@mojaloop/central-services-shared').Enum.Transfers.BulkTransferState;
37
-
38
- describe('inboundModel', () => {
39
- let config;
40
- let mockArgs;
41
- let mockTxnReqArgs;
42
- let logger;
43
-
44
- beforeAll(async () => {
45
- logger = new Logger.Logger({ context: { app: 'inbound-model-unit-tests' }, stringify: () => '' });
46
- });
47
-
48
- beforeEach(async () => {
49
- config = JSON.parse(JSON.stringify(defaultConfig));
50
-
51
- mockArgs = JSON.parse(JSON.stringify(mockArguments));
52
- mockArgs.internalQuoteResponse.expiration = new Date(Date.now());
53
- mockTxnReqArgs = JSON.parse(JSON.stringify(mockTxnReqquestsArguments));
54
- });
55
-
56
- describe('quoteRequest', () => {
57
- let expectedQuoteResponseILP;
58
- let model;
59
- let cache;
60
-
61
- beforeEach(async () => {
62
- expectedQuoteResponseILP = Ilp.__response;
63
- BackendRequests.__postQuoteRequests = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalQuoteResponse));
64
- MojaloopRequests.__putQuotes = jest.fn().mockReturnValue(Promise.resolve({
65
- originalRequest: {
66
- headers: {},
67
- body: {},
68
- }
69
- }));
70
-
71
- cache = new Cache({
72
- cacheUrl: 'redis://dummy:1234',
73
- logger,
74
- });
75
- await cache.connect();
76
-
77
- model = new Model({
78
- ...config,
79
- cache,
80
- logger,
81
- });
82
- });
83
-
84
- afterEach(async () => {
85
- MojaloopRequests.__putQuotes.mockClear();
86
- await cache.disconnect();
87
- });
88
-
89
- test('calls `mojaloopRequests.putQuotes` with the expected arguments.', async () => {
90
- await model.quoteRequest(mockArgs.quoteRequest, mockArgs.fspId);
91
-
92
- expect(BackendRequests.__postQuoteRequests).toHaveBeenCalledTimes(1);
93
- expect(BackendRequests.__postQuoteRequests.mock.calls[0][0]).toEqual(mockArgs.internalQuoteRequest);
94
-
95
- expect(MojaloopRequests.__putQuotes).toHaveBeenCalledTimes(1);
96
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].expiration).toBe(mockArgs.internalQuoteResponse.expiration);
97
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
98
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].condition).toBe(expectedQuoteResponseILP.condition);
99
- expect(MojaloopRequests.__putQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
100
-
101
- // check the extension list gets translated correctly to the mojaloop form
102
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].extensionList)
103
- .toStrictEqual(mockArgs.internalQuoteResponse.extensionList);
104
- });
105
-
106
- test('adds a custom `expiration` property in case it is not defined.', async() => {
107
- // set a custom mock time in the global Date object in order to avoid race conditions.
108
- // Make sure to clear it at the end of the test case.
109
- const currentTime = new Date().getTime();
110
- const dateSpy = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => currentTime);
111
- const expectedExpirationDate = new Date(currentTime + (config.expirySeconds * 1000)).toISOString();
112
-
113
- delete mockArgs.internalQuoteResponse.expiration;
114
-
115
- await model.quoteRequest(mockArgs.quoteRequest, mockArgs.fspId);
116
-
117
- expect(MojaloopRequests.__putQuotes).toHaveBeenCalledTimes(1);
118
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].expiration).toBe(expectedExpirationDate);
119
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
120
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].condition).toBe(expectedQuoteResponseILP.condition);
121
- expect(MojaloopRequests.__putQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
122
-
123
- dateSpy.mockClear();
124
- });
125
-
126
-
127
- });
128
-
129
- describe('bulkQuoteRequest', () => {
130
- let expectedQuoteResponseILP;
131
- let model;
132
- let cache;
133
-
134
- beforeEach(async () => {
135
- // eslint-disable-next-line no-unused-vars
136
- expectedQuoteResponseILP = Ilp.__response;
137
- BackendRequests.__postBulkQuotes = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalBulkQuoteResponse));
138
-
139
- cache = new Cache({
140
- cacheUrl: 'redis://dummy:1234',
141
- logger,
142
- });
143
- await cache.connect();
144
- // eslint-disable-next-line no-unused-vars
145
- model = new Model({
146
- ...config,
147
- cache,
148
- logger,
149
- });
150
- });
151
-
152
- afterEach(async () => {
153
- MojaloopRequests.__putBulkQuotes.mockClear();
154
- await cache.disconnect();
155
- });
156
-
157
- test('calls mojaloopRequests.putBulkQuotes with the expected arguments.', async () => {
158
- await model.bulkQuoteRequest(mockArgs.bulkQuoteRequest, mockArgs.fspId);
159
-
160
- expect(MojaloopRequests.__putBulkQuotes).toHaveBeenCalledTimes(1);
161
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].expiration).toBe(mockArgs.internalBulkQuoteResponse.expiration);
162
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
163
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].condition).toBe(expectedQuoteResponseILP.condition);
164
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
165
- });
166
- test('adds a custom expiration property in case it is not defined.', async() => {
167
- // set a custom mock time in the global Date object in order to avoid race conditions.
168
- // Make sure to clear it at the end of the test case.
169
- const currentTime = new Date().getTime();
170
- const dateSpy = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => currentTime);
171
- const expectedExpirationDate = new Date(currentTime + (config.expirySeconds * 1000)).toISOString();
172
-
173
- delete mockArgs.internalBulkQuoteResponse.expiration;
174
-
175
- await model.bulkQuoteRequest(mockArgs.bulkQuoteRequest, mockArgs.fspId);
176
-
177
- expect(MojaloopRequests.__putBulkQuotes).toHaveBeenCalledTimes(1);
178
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].expiration).toBe(expectedExpirationDate);
179
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
180
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].condition).toBe(expectedQuoteResponseILP.condition);
181
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
182
-
183
- dateSpy.mockClear();
184
- });
185
-
186
- });
187
-
188
- describe('transactionRequest', () => {
189
- let model;
190
- let cache;
191
-
192
- beforeEach(async () => {
193
- BackendRequests.__postTransactionRequests = jest.fn().mockReturnValue(Promise.resolve(mockTxnReqArgs.internalTransactionRequestResponse));
194
-
195
- cache = new Cache({
196
- cacheUrl: 'redis://dummy:1234',
197
- logger,
198
- });
199
- await cache.connect();
200
-
201
- model = new Model({
202
- ...config,
203
- cache,
204
- logger,
205
- });
206
- });
207
-
208
- afterEach(async () => {
209
- MojaloopRequests.__putTransactionRequests.mockClear();
210
- await cache.disconnect();
211
- });
212
-
213
- test('calls `mojaloopRequests.putTransactionRequests` with the expected arguments.', async () => {
214
- await model.transactionRequest(mockTxnReqArgs.transactionRequest, mockTxnReqArgs.fspId);
215
-
216
- expect(MojaloopRequests.__putTransactionRequests).toHaveBeenCalledTimes(1);
217
- expect(MojaloopRequests.__putTransactionRequests.mock.calls[0][1].transactionRequestState).toBe(mockTxnReqArgs.internalTransactionRequestResponse.transactionRequestState);
218
-
219
- });
220
-
221
-
222
- });
223
-
224
- describe('authorizations', () => {
225
- let model;
226
- let cache;
227
-
228
- beforeEach(async () => {
229
- BackendRequests.__getOTP = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalGetOTPResponse));
230
-
231
- cache = new Cache({
232
- cacheUrl: 'redis://dummy:1234',
233
- logger,
234
- });
235
- await cache.connect();
236
-
237
- model = new Model({
238
- ...config,
239
- cache,
240
- logger,
241
- });
242
- });
243
-
244
- afterEach(async () => {
245
- MojaloopRequests.__putAuthorizations.mockClear();
246
- await cache.disconnect();
247
- });
248
-
249
- test('calls `mojaloopRequests.putAuthorizations` with the expected arguments.', async () => {
250
- await model.getAuthorizations('123456', mockTxnReqArgs.fspId);
251
-
252
- expect(MojaloopRequests.__putAuthorizations).toHaveBeenCalledTimes(1);
253
-
254
- });
255
-
256
-
257
- });
258
-
259
- describe('transferPrepare:', () => {
260
- let cache;
261
-
262
- beforeEach(async () => {
263
- MojaloopRequests.__putTransfersError.mockClear();
264
- BackendRequests.__postTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
265
- MojaloopRequests.__putTransfers = jest.fn().mockReturnValue(Promise.resolve({
266
- originalRequest: {
267
- headers: {},
268
- body: {},
269
- }
270
- }));
271
-
272
- cache = new Cache({
273
- cacheUrl: 'redis://dummy:1234',
274
- logger,
275
- });
276
- await cache.connect();
277
- });
278
-
279
- afterEach(async () => {
280
- await cache.disconnect();
281
- });
282
-
283
- test('fail on quote `expiration` deadline.', async () => {
284
- const TRANSFER_ID = 'fake-transfer-id';
285
- const model = new Model({
286
- ...config,
287
- cache,
288
- logger,
289
- rejectTransfersOnExpiredQuotes: true,
290
- });
291
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
292
- quote: {
293
- mojaloopResponse: {
294
- expiration: new Date(new Date().getTime() - 1000).toISOString(),
295
- }
296
- }
297
- });
298
- const args = {
299
- body: {
300
- transferId: TRANSFER_ID,
301
- }
302
- };
303
-
304
- await model.prepareTransfer(args, mockArgs.fspId);
305
-
306
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
307
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
308
- expect(call[0]).toEqual(TRANSFER_ID);
309
- expect(call[1].errorInformation.errorCode).toEqual('3302');
310
- });
311
-
312
- test('getTransfer should return COMMITTED transfer', async () => {
313
- const TRANSFER_ID = 'fake-transfer-id';
314
-
315
- const backendResponse = JSON.parse(JSON.stringify(getTransfersBackendResponse));
316
- backendResponse.to.fspId = config.dfspId;
317
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
318
-
319
- const model = new Model({
320
- ...config,
321
- cache,
322
- logger,
323
- });
324
-
325
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
326
-
327
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
328
- const call = MojaloopRequests.__putTransfers.mock.calls[0];
329
- expect(call[0]).toEqual(TRANSFER_ID);
330
- expect(call[1]).toEqual(getTransfersMojaloopResponse);
331
- expect(call[1].transferState).toEqual(FSPIOPTransferStateEnum.COMMITTED);
332
- });
333
-
334
- test('getTransfer should not return fulfillment from payer', async () => {
335
- const TRANSFER_ID = 'fake-transfer-id';
336
-
337
- const backendResponse = JSON.parse(JSON.stringify(getTransfersBackendResponse));
338
- backendResponse.to.fspId = 'payer-dfsp';
339
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
340
-
341
- const model = new Model({
342
- ...config,
343
- cache,
344
- logger,
345
- });
346
-
347
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
348
-
349
- const call = MojaloopRequests.__putTransfers.mock.calls[0];
350
- expect(call[0]).toEqual(TRANSFER_ID);
351
- expect(call[1]).toEqual({...getTransfersMojaloopResponse, fulfilment: undefined});
352
- expect(call[1].transferState).toEqual(FSPIOPTransferStateEnum.COMMITTED);
353
- });
354
-
355
- test('getTransfer should return not found error', async () => {
356
- const TRANSFER_ID = 'fake-transfer-id';
357
-
358
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(
359
- Promise.reject(new HTTPResponseError({
360
- res: {
361
- data: {
362
- statusCode: '3208'
363
- },
364
- }
365
- })));
366
-
367
- const model = new Model({
368
- ...config,
369
- cache,
370
- logger,
371
- });
372
-
373
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
374
-
375
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
376
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
377
- expect(call[0]).toEqual(`${TRANSFER_ID}`);
378
- expect(call[1].errorInformation.errorCode).toEqual('3208');
379
- });
380
-
381
- test('fail on transfer without quote.', async () => {
382
- const TRANSFER_ID = 'without_quote-transfer-id';
383
- const args = {
384
- body: {
385
- transferId: TRANSFER_ID,
386
- amount: {
387
- currency: 'USD',
388
- amount: 20.13
389
- },
390
- ilpPacket: 'mockBase64encodedIlpPacket',
391
- condition: 'mockGeneratedCondition'
392
- }
393
- };
394
-
395
- const model = new Model({
396
- ...config,
397
- cache,
398
- logger,
399
- allowTransferWithoutQuote: false,
400
- });
401
-
402
- await model.prepareTransfer(args, mockArgs.fspId);
403
-
404
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
405
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
406
- expect(call[0]).toEqual(TRANSFER_ID);
407
- expect(call[1].errorInformation.errorCode).toEqual('2001');
408
- });
409
-
410
- test('stores homeTransactionId in cache when received by dfsp acting as payee', async () => {
411
- const TRANSFER_ID = 'transfer-id';
412
- const HOME_TRANSACTION_ID = 'mockHomeTransactionId';
413
- shared.mojaloopPrepareToInternalTransfer = jest.fn().mockReturnValueOnce({});
414
-
415
- // mock response from dfsp acting as payee
416
- BackendRequests.__postTransfers = jest.fn().mockReturnValueOnce(Promise.resolve({
417
- homeTransactionId: HOME_TRANSACTION_ID,
418
- transferId: TRANSFER_ID
419
- }));
420
-
421
- const args = {
422
- body: {
423
- transferId: TRANSFER_ID,
424
- amount: {
425
- currency: 'USD',
426
- amount: 20.13
427
- },
428
- ilpPacket: 'mockBase64encodedIlpPacket',
429
- condition: 'mockGeneratedCondition'
430
- }
431
- };
432
-
433
- const model = new Model({
434
- ...config,
435
- cache,
436
- logger,
437
- checkIlp: false,
438
- rejectTransfersOnExpiredQuotes: false
439
- });
440
-
441
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
442
- transferId: TRANSFER_ID,
443
- quote: {
444
- fulfilment: 'mockFulfilment',
445
- mojaloopResponse: {
446
- condition: 'mockCondition',
447
- }
448
- }
449
- });
450
-
451
- await model.prepareTransfer(args, mockArgs.fspId);
452
-
453
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
454
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
455
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
456
- expect((await cache.get(`transferModel_in_${TRANSFER_ID}`)).homeTransactionId)
457
- .toEqual(HOME_TRANSACTION_ID);
458
- });
459
-
460
- test('pass on transfer without quote.', async () => {
461
- const TRANSFER_ID = 'without_quote-transfer-id';
462
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
463
- fulfilment: '',
464
- mojaloopResponse: {
465
- response: ''
466
- },
467
- quote: null
468
- });
469
-
470
- const args = {
471
- body: {
472
- transferId: TRANSFER_ID,
473
- amount: {
474
- currency: 'USD',
475
- amount: 20.13
476
- },
477
- ilpPacket: 'mockBase64encodedIlpPacket',
478
- condition: 'mockGeneratedCondition'
479
- }
480
- };
481
-
482
- const model = new Model({
483
- ...config,
484
- cache,
485
- logger,
486
- allowTransferWithoutQuote: true,
487
- });
488
-
489
- await model.prepareTransfer(args, mockArgs.fspId);
490
-
491
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
492
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
493
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
494
- });
495
-
496
- test('allow different transfer and transaction id', async () => {
497
- const transactionId = 'mockTransactionId';
498
- const TRANSFER_ID = 'transfer-id';
499
- shared.mojaloopPrepareToInternalTransfer = jest.fn().mockReturnValueOnce({});
500
-
501
- cache.set(`transferModel_in_${transactionId}`, {
502
- fulfilment: '',
503
- mojaloopResponse: {
504
- response: ''
505
- },
506
- quote: {
507
- fulfilment: 'mockFulfilment',
508
- mojaloopResponse: {
509
- condition: 'mockCondition',
510
- }
511
- }
512
- });
513
-
514
- const args = {
515
- body: {
516
- transferId: TRANSFER_ID,
517
- amount: {
518
- currency: 'USD',
519
- amount: 20.13
520
- },
521
- ilpPacket: 'mockIlpPacket',
522
- condition: 'mockGeneratedCondition'
523
- }
524
- };
525
-
526
- const model = new Model({
527
- ...config,
528
- cache,
529
- logger,
530
- allowDifferentTransferTransactionId: true,
531
- checkIlp: false,
532
- });
533
-
534
- await model.prepareTransfer(args, mockArgs.fspId);
535
-
536
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
537
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
538
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
539
- });
540
- });
541
-
542
- describe('prepareBulkTransfer:', () => {
543
- let cache;
544
-
545
- beforeEach(async () => {
546
- MojaloopRequests.__putBulkTransfersError.mockClear();
547
- MojaloopRequests.__putBulkTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
548
- BackendRequests.__postBulkTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
549
-
550
- cache = new Cache({
551
- cacheUrl: 'redis://dummy:1234',
552
- logger,
553
- });
554
- await cache.connect();
555
- });
556
-
557
- afterEach(async () => {
558
- await cache.disconnect();
559
- });
560
-
561
- test('fail on bulk quote `expiration` deadline.', async () => {
562
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
563
- const BULK_QUOTE_ID = 'fake-bulk-quote-id';
564
- const model = new Model({
565
- ...config,
566
- cache,
567
- logger,
568
- rejectTransfersOnExpiredQuotes: true,
569
- });
570
- cache.set(`bulkQuotes_${BULK_QUOTE_ID}`, {
571
- mojaloopResponse: {
572
- expiration: new Date(new Date().getTime() - 1000).toISOString(),
573
- individualQuoteResults: [],
574
- }
575
- });
576
- const args = {
577
- bulkTransferId: BULK_TRANSFER_ID,
578
- bulkQuoteId: BULK_QUOTE_ID,
579
- individualTransfers: [],
580
- };
581
-
582
- await model.prepareBulkTransfer(args, mockArgs.fspId);
583
-
584
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
585
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
586
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
587
- expect(call[1].errorInformation.errorCode).toEqual('3302');
588
- });
589
-
590
- test('getBulkTransfer should return COMMITTED bulk transfer', async () => {
591
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
592
-
593
- const backendResponse = JSON.parse(JSON.stringify(getBulkTransfersBackendResponse));
594
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
595
-
596
- const model = new Model({
597
- ...config,
598
- cache,
599
- logger,
600
- });
601
-
602
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
603
-
604
- expect(MojaloopRequests.__putBulkTransfers).toHaveBeenCalledTimes(1);
605
- const call = MojaloopRequests.__putBulkTransfers.mock.calls[0];
606
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
607
- expect(call[1]).toEqual(getBulkTransfersMojaloopResponse);
608
- expect(call[1].bulkTransferState).toEqual(FSPIOPBulkTransferStateEnum.COMPLETED);
609
- });
610
-
611
- test('getBulkTransfer should not return fulfillment from payer', async () => {
612
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
613
-
614
- const backendResponse = JSON.parse(JSON.stringify(getBulkTransfersBackendResponse));
615
- backendResponse.internalRequest.individualTransfers[0].to.fspId = 'payer-dfsp';
616
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
617
-
618
- const model = new Model({
619
- ...config,
620
- cache,
621
- logger,
622
- });
623
-
624
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
625
-
626
- const call = MojaloopRequests.__putBulkTransfers.mock.calls[0];
627
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
628
- expect(call[1].bulkTransferState).toEqual(FSPIOPBulkTransferStateEnum.COMPLETED);
629
- const expectedResponse = {...getBulkTransfersMojaloopResponse};
630
- expectedResponse.individualTransferResults[0].fulfilment = undefined;
631
- expect(call[1]).toMatchObject(expectedResponse);
632
- });
633
-
634
- test('getBulkTransfer should return not found error', async () => {
635
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
636
-
637
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(
638
- Promise.reject(new HTTPResponseError({
639
- res: {
640
- data: {
641
- statusCode: '3208'
642
- },
643
- }
644
- })));
645
-
646
- const model = new Model({
647
- ...config,
648
- cache,
649
- logger,
650
- });
651
-
652
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
653
-
654
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
655
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
656
- expect(call[0]).toEqual(`${BULK_TRANSFER_ID}`);
657
- expect(call[1].errorInformation.errorCode).toEqual('3208');
658
- });
659
-
660
- test('fail on bulk transfer without bulk quote.', async () => {
661
- const BULK_TRANSFER_ID = 'without_bulk-quote-bulk-transfer-id';
662
- const args = {
663
- bulkTransferId: BULK_TRANSFER_ID,
664
- ilpPacket: 'mockBase64encodedIlpPacket',
665
- condition: 'mockGeneratedCondition',
666
- individualTransfers: [
667
- {
668
- amount: {
669
- currency: 'USD',
670
- amount: 20.13
671
- },
672
- }
673
- ]
674
- };
675
-
676
- const model = new Model({
677
- ...config,
678
- cache,
679
- logger,
680
- allowTransferWithoutQuote: false,
681
- });
682
-
683
- await model.prepareBulkTransfer(args, mockArgs.fspId);
684
-
685
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
686
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
687
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
688
- expect(call[1].errorInformation.errorCode).toEqual('2001');
689
- });
690
-
691
- test('pass on bulk transfer without bulk quote.', async () => {
692
- const BULK_TRANSFER_ID = 'without_bulk-quote-bulk-transfer-id';
693
- const args = {
694
- bulkTransferId: BULK_TRANSFER_ID,
695
- individualTransfers: [
696
- {
697
- transferId: 'fake-transfer-id',
698
- transferAmount: {
699
- currency: 'USD',
700
- amount: 20.13
701
- },
702
- ilpPacket: 'mockBase64encodedIlpPacket',
703
- condition: 'mockGeneratedCondition',
704
- }
705
- ]
706
- };
707
-
708
- const model = new Model({
709
- ...config,
710
- cache,
711
- logger,
712
- allowTransferWithoutQuote: true,
713
- rejectTransfersOnExpiredQuotes: false,
714
- });
715
-
716
- await model.prepareBulkTransfer(args, mockArgs.fspId);
717
-
718
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(0);
719
- expect(BackendRequests.__postBulkTransfers).toHaveBeenCalledTimes(1);
720
- expect(MojaloopRequests.__putBulkTransfers).toHaveBeenCalledTimes(1);
721
- });
722
- });
723
-
724
- describe('sendNotificationToPayee:', () => {
725
- const transferId = '1234';
726
- let cache;
727
-
728
- beforeEach(async () => {
729
- cache = new Cache({
730
- cacheUrl: 'redis://dummy:1234',
731
- logger,
732
- });
733
- await cache.connect();
734
- });
735
-
736
- afterEach(async () => {
737
- await cache.disconnect();
738
- });
739
-
740
- test('sends notification to fsp backend', async () => {
741
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
742
- const notif = JSON.parse(JSON.stringify(notificationToPayee));
743
-
744
- const expectedRequest = {
745
- currentState: SDKStateEnum.COMPLETED,
746
- finalNotification: notif.data,
747
- };
748
-
749
- const model = new Model({
750
- ...config,
751
- cache,
752
- logger,
753
- });
754
-
755
- await model.sendNotificationToPayee(notif.data, transferId);
756
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
757
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
758
- expect(call[0]).toEqual(expectedRequest);
759
- expect(call[1]).toEqual(transferId);
760
- });
761
-
762
- test('sends ABORTED notification to fsp backend', async () => {
763
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
764
- const notif = JSON.parse(JSON.stringify(notificationAbortedToPayee));
765
-
766
- const expectedRequest = {
767
- currentState: SDKStateEnum.ABORTED,
768
- finalNotification: notif.data,
769
- };
770
-
771
- const model = new Model({
772
- ...config,
773
- cache,
774
- logger,
775
- });
776
-
777
- await model.sendNotificationToPayee(notif.data, transferId);
778
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
779
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
780
- expect(call[0]).toEqual(expectedRequest);
781
- expect(call[1]).toEqual(transferId);
782
- });
783
-
784
- test('sends RESERVED notification to fsp backend', async () => {
785
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
786
- const notif = JSON.parse(JSON.stringify(notificationReservedToPayee));
787
-
788
- const expectedRequest = {
789
- finalNotification: notif.data,
790
- lastError: 'Final notification state not COMMITTED',
791
- };
792
-
793
- const model = new Model({
794
- ...config,
795
- cache,
796
- logger,
797
- });
798
-
799
- await model.sendNotificationToPayee(notif.data, transferId);
800
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
801
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
802
- expect(call[0]).toEqual(expectedRequest);
803
- expect(call[1]).toEqual(transferId);
804
- });
805
-
806
- });
807
-
808
- describe('error handling:', () => {
809
- let cache;
810
- beforeEach(async () => {
811
- cache = new Cache({
812
- cacheUrl: 'redis://dummy:1234',
813
- logger,
814
- });
815
- await cache.connect();
816
- });
817
- afterEach(async () => {
818
- await cache.disconnect();
819
- });
820
- test('creates mojaloop spec error body when backend returns standard error code', async () => {
821
- const model = new Model({
822
- ...config,
823
- cache,
824
- logger,
825
- });
826
- const testErr = new HTTPResponseError({
827
- msg: 'Request returned non-success status code 500',
828
- res: {
829
- data: {
830
- statusCode: '3200',
831
- },
832
- }
833
- });
834
- const err = await model._handleError(testErr);
835
- expect(err).toBeDefined();
836
- expect(err.errorInformation).toBeDefined();
837
- expect(err.errorInformation.errorCode).toEqual('3200');
838
- // error message should be the default one, not custom.
839
- // it is debatibale whether this is truly correct, to overwrite
840
- // and custom error message; but it is the case for now.
841
- expect(err.errorInformation.errorDescription).toEqual('Generic ID not found');
842
- });
843
- test('creates custom error body when backend returns custom error code', async () => {
844
- const model = new Model({
845
- ...config,
846
- cache,
847
- logger,
848
- });
849
- const customMessage = 'some custom message';
850
- const testErr = new HTTPResponseError({
851
- msg: 'Request returned non-success status code 500',
852
- res: {
853
- data: {
854
- statusCode: '3299',
855
- message: customMessage,
856
- },
857
- }
858
- });
859
- const err = await model._handleError(testErr);
860
- expect(err).toBeDefined();
861
- expect(err.errorInformation).toBeDefined();
862
- expect(err.errorInformation.errorCode).toEqual('3299');
863
- expect(err.errorInformation.errorDescription).toEqual(customMessage);
864
- });
865
- test('creates custom error message when backend returns standard error code and message', async () => {
866
- const model = new Model({
867
- ...config,
868
- cache,
869
- logger,
870
- });
871
- const customMessage = 'some custom message';
872
- const testErr = new HTTPResponseError({
873
- msg: 'Request returned non-success status code 500',
874
- res: {
875
- data: {
876
- statusCode: '3200',
877
- message: customMessage,
878
- },
879
- }
880
- });
881
- const err = await model._handleError(testErr);
882
- expect(err).toBeDefined();
883
- expect(err.errorInformation).toBeDefined();
884
- expect(err.errorInformation.errorCode).toEqual('3200');
885
- // error message should be custom
886
- expect(err.errorInformation.errorDescription).toEqual(customMessage);
887
- });
888
- });
889
- });