@mojaloop/sdk-scheme-adapter 18.0.0 → 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 (116) hide show
  1. package/.dockerignore +18 -0
  2. package/.eslintignore +2 -0
  3. package/CHANGELOG.md +8 -0
  4. package/audit-resolve.json +5 -0
  5. package/package.json +2 -2
  6. package/test/__mocks__/@mojaloop/sdk-standard-components.js +0 -151
  7. package/test/__mocks__/javascript-state-machine.js +0 -21
  8. package/test/__mocks__/redis.js +0 -78
  9. package/test/__mocks__/uuidv4.js +0 -16
  10. package/test/config/integration.env +0 -146
  11. package/test/integration/lib/Outbound/data/quotesPostRequest.json +0 -52
  12. package/test/integration/lib/Outbound/data/transfersPostRequest.json +0 -24
  13. package/test/integration/lib/Outbound/parties.test.js +0 -31
  14. package/test/integration/lib/Outbound/quotes.test.js +0 -62
  15. package/test/integration/lib/Outbound/simpleTransfers.test.js +0 -70
  16. package/test/integration/lib/cache.test.js +0 -79
  17. package/test/integration/testEnv.js +0 -4
  18. package/test/unit/ControlClient.test.js +0 -69
  19. package/test/unit/ControlServer/events.js +0 -41
  20. package/test/unit/ControlServer/index.js +0 -227
  21. package/test/unit/ControlServer.test.js +0 -66
  22. package/test/unit/InboundServer.test.js +0 -443
  23. package/test/unit/TestServer.test.js +0 -392
  24. package/test/unit/api/accounts/accounts.test.js +0 -128
  25. package/test/unit/api/accounts/data/postAccountsBody.json +0 -7
  26. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +0 -33
  27. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +0 -19
  28. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +0 -31
  29. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +0 -34
  30. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +0 -39
  31. package/test/unit/api/accounts/utils.js +0 -79
  32. package/test/unit/api/proxy/data/proxyConfig.yaml +0 -82
  33. package/test/unit/api/proxy/data/requestBody.json +0 -22
  34. package/test/unit/api/proxy/data/requestHeaders.json +0 -5
  35. package/test/unit/api/proxy/data/requestQuery.json +0 -6
  36. package/test/unit/api/proxy/data/responseBody.json +0 -21
  37. package/test/unit/api/proxy/data/responseHeaders.json +0 -5
  38. package/test/unit/api/proxy/proxy.test.js +0 -220
  39. package/test/unit/api/proxy/utils.js +0 -79
  40. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +0 -24
  41. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +0 -18
  42. package/test/unit/api/transfers/data/postQuotesBody.json +0 -52
  43. package/test/unit/api/transfers/data/postTransfersBadBody.json +0 -17
  44. package/test/unit/api/transfers/data/postTransfersBody.json +0 -24
  45. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +0 -62
  46. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +0 -48
  47. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +0 -26
  48. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +0 -128
  49. package/test/unit/api/transfers/data/putPartiesBody.json +0 -20
  50. package/test/unit/api/transfers/data/putQuotesBody.json +0 -37
  51. package/test/unit/api/transfers/data/putTransfersBody.json +0 -17
  52. package/test/unit/api/transfers/transfers.test.js +0 -191
  53. package/test/unit/api/transfers/utils.js +0 -264
  54. package/test/unit/api/utils.js +0 -86
  55. package/test/unit/config.test.js +0 -119
  56. package/test/unit/data/commonHttpHeaders.json +0 -7
  57. package/test/unit/data/defaultConfig.json +0 -70
  58. package/test/unit/data/postQuotesBody.json +0 -52
  59. package/test/unit/data/putParticipantsBody.json +0 -12
  60. package/test/unit/data/putPartiesBody.json +0 -20
  61. package/test/unit/data/testFile.json +0 -29
  62. package/test/unit/data/testFile.yaml +0 -14
  63. package/test/unit/inboundApi/data/mockArguments.json +0 -117
  64. package/test/unit/inboundApi/data/mockTransactionRequest.json +0 -42
  65. package/test/unit/inboundApi/handlers.test.js +0 -786
  66. package/test/unit/index.test.js +0 -88
  67. package/test/unit/lib/cache.test.js +0 -145
  68. package/test/unit/lib/model/AccountsModel.test.js +0 -124
  69. package/test/unit/lib/model/InboundTransfersModel.test.js +0 -889
  70. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +0 -253
  71. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +0 -247
  72. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +0 -166
  73. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +0 -245
  74. package/test/unit/lib/model/OutboundTransfersModel.test.js +0 -1579
  75. package/test/unit/lib/model/PartiesModel.test.js +0 -478
  76. package/test/unit/lib/model/QuotesModel.test.js +0 -477
  77. package/test/unit/lib/model/TransfersModel.test.js +0 -481
  78. package/test/unit/lib/model/common/PersistentStateMachine.test.js +0 -178
  79. package/test/unit/lib/model/data/authorizationsResponse.json +0 -13
  80. package/test/unit/lib/model/data/bulkQuoteRequest.json +0 -27
  81. package/test/unit/lib/model/data/bulkQuoteResponse.json +0 -35
  82. package/test/unit/lib/model/data/bulkTransferFulfil.json +0 -13
  83. package/test/unit/lib/model/data/bulkTransferRequest.json +0 -29
  84. package/test/unit/lib/model/data/defaultConfig.json +0 -59
  85. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +0 -42
  86. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +0 -22
  87. package/test/unit/lib/model/data/getTransfersBackendResponse.json +0 -34
  88. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +0 -17
  89. package/test/unit/lib/model/data/mockArguments.json +0 -188
  90. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +0 -63
  91. package/test/unit/lib/model/data/notificationAbortedToPayee.json +0 -10
  92. package/test/unit/lib/model/data/notificationReservedToPayee.json +0 -10
  93. package/test/unit/lib/model/data/notificationToPayee.json +0 -10
  94. package/test/unit/lib/model/data/payeeParty.json +0 -18
  95. package/test/unit/lib/model/data/putQuotesResponse.json +0 -33
  96. package/test/unit/lib/model/data/putTransfersResponse.json +0 -5
  97. package/test/unit/lib/model/data/quoteResponse.json +0 -42
  98. package/test/unit/lib/model/data/requestToPayRequest.json +0 -20
  99. package/test/unit/lib/model/data/requestToPayTransferRequest.json +0 -27
  100. package/test/unit/lib/model/data/transactionRequestResponse.json +0 -18
  101. package/test/unit/lib/model/data/transferFulfil.json +0 -10
  102. package/test/unit/lib/model/data/transferRequest.json +0 -26
  103. package/test/unit/lib/model/mockedLibRequests.js +0 -74
  104. package/test/unit/mockLogger.js +0 -39
  105. package/test/unit/outboundApi/data/bulkQuoteRequest.json +0 -28
  106. package/test/unit/outboundApi/data/bulkTransferRequest.json +0 -28
  107. package/test/unit/outboundApi/data/mockBulkQuoteError.json +0 -45
  108. package/test/unit/outboundApi/data/mockBulkTransferError.json +0 -48
  109. package/test/unit/outboundApi/data/mockError.json +0 -41
  110. package/test/unit/outboundApi/data/mockGetPartiesError.json +0 -4
  111. package/test/unit/outboundApi/data/mockRequestToPayError.json +0 -32
  112. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +0 -39
  113. package/test/unit/outboundApi/data/requestToPay.json +0 -21
  114. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +0 -20
  115. package/test/unit/outboundApi/data/transferRequest.json +0 -21
  116. package/test/unit/outboundApi/handlers.test.js +0 -887
@@ -1,481 +0,0 @@
1
- /**************************************************************************
2
- * (C) Copyright ModusBox Inc. 2021 - 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
- * Kevin Leyow - kevin.leyow@modusbox.com *
9
- **************************************************************************/
10
-
11
- 'use strict';
12
-
13
- // we use a mock standard components lib to intercept and mock certain funcs
14
- jest.mock('@mojaloop/sdk-standard-components');
15
-
16
- const { uuid } = require('uuidv4');
17
- const Model = require('~/lib/model').TransfersModel;
18
- const PSM = require('~/lib/model/common').PersistentStateMachine;
19
- const { SDKStateEnum } = require('~/lib/model/common');
20
- const { MojaloopRequests } = require('@mojaloop/sdk-standard-components');
21
- const defaultConfig = require('./data/defaultConfig');
22
- const mockLogger = require('../../mockLogger');
23
- const deferredJob = require('~/lib/model/lib').deferredJob;
24
- const pt = require('promise-timeout');
25
- const putTransfersResponse = require('./data/putTransfersResponse.json');
26
-
27
- describe('TransfersModel', () => {
28
- let cacheKey;
29
- let data;
30
- let modelConfig;
31
-
32
- const subId = uuid();
33
- let handler = null;
34
- beforeEach(async () => {
35
-
36
- modelConfig = {
37
- logger: mockLogger({app: 'TransfersModel-test'}),
38
-
39
- // there is no need to mock redis but only Cache
40
- cache: {
41
- get: jest.fn(() => Promise.resolve(data)),
42
- set: jest.fn(() => Promise.resolve),
43
-
44
- // mock subscription and store handler
45
- subscribe: jest.fn(async (channel, h) => {
46
- handler = jest.fn(h);
47
- return subId;
48
- }),
49
-
50
- // mock publish and call stored handler
51
- publish: jest.fn(async (channel, message) => await handler(channel, message, subId)),
52
-
53
- unsubscribe: jest.fn(() => Promise.resolve())
54
- },
55
- ...defaultConfig
56
- };
57
- data = {
58
- the: 'mocked data'
59
- };
60
-
61
- cacheKey = `key-transfers-${uuid()}`;
62
- });
63
-
64
- describe('create', () => {
65
- test('proper creation of model', async () => {
66
- const model = await Model.create(data, cacheKey, modelConfig);
67
-
68
- expect(model.state).toBe('start');
69
-
70
- // model's methods layout
71
- const methods = [
72
- 'run',
73
- 'getResponse',
74
- 'onRequestAction'
75
- ];
76
-
77
- methods.forEach((method) => expect(typeof model[method]).toEqual('function'));
78
- });
79
- });
80
-
81
- describe('getResponse', () => {
82
-
83
- it('should remap currentState', async () => {
84
- const model = await Model.create(data, cacheKey, modelConfig);
85
- const states = model.allStates();
86
- // should remap for all states except 'init' and 'none'
87
- states.filter((s) => s !== 'init' && s !== 'none').forEach((state) => {
88
- model.context.data.currentState = state;
89
- const result = model.getResponse();
90
- expect(result.currentState).toEqual(Model.mapCurrentState[state]);
91
- });
92
-
93
- });
94
-
95
- it('should handle unexpected state', async() => {
96
- const model = await Model.create(data, cacheKey, modelConfig);
97
-
98
- // simulate lack of state by undefined property
99
- delete model.context.data.currentState;
100
-
101
- const resp = model.getResponse();
102
- expect(resp.currentState).toEqual(Model.mapCurrentState.errored);
103
-
104
- // ensure that we log the problem properly
105
- expect(modelConfig.logger.error).toHaveBeenCalledWith(`TransfersModel model response being returned from an unexpected state: ${undefined}. Returning ERROR_OCCURRED state`);
106
- });
107
- });
108
-
109
- describe('channelName', () => {
110
- it('should validate input', () => {
111
- expect(Model.channelName({})).toEqual('transfers-undefined');
112
- });
113
-
114
- it('should generate proper channel name', () => {
115
- const transferId = uuid();
116
- expect(Model.channelName({ transferId })).toEqual(`transfers-${transferId}`);
117
- });
118
-
119
- });
120
-
121
- describe('generateKey', () => {
122
- it('should generate proper cache key', () => {
123
- const transferId = uuid();
124
- expect(Model.generateKey({ transferId })).toEqual(`key-${Model.channelName({ transferId })}`);
125
- });
126
-
127
- it('should handle lack of transferId param', () => {
128
- expect(() => Model.generateKey({ })).toThrowError(new Error('TransfersModel args requires \'transferId\' is nonempty string and mandatory property'));
129
- });
130
-
131
- });
132
-
133
- describe('onRequestAction', () => {
134
-
135
- it('should implement happy flow', async () => {
136
- const transferId = uuid();
137
- const fspId = uuid();
138
- // our code takes care only about 'transferId' property
139
- const transfer = { transferId };
140
- const channel = Model.channelName({ transferId });
141
- const model = await Model.create(data, cacheKey, modelConfig);
142
- const { cache } = model.context;
143
- // mock workflow execution which is tested in separate case
144
- model.run = jest.fn(() => Promise.resolve());
145
-
146
- const message = {
147
- body: { ...putTransfersResponse },
148
- headers: {}
149
- };
150
-
151
- const onRequestActionPromise = new Promise((resolve, reject) => {
152
- // manually invoke transition handler
153
- model.onRequestAction(model.fsm, { transferId, fspId, transfer })
154
- .then(() => {
155
- // subscribe should be called only once
156
- expect(cache.subscribe).toBeCalledTimes(1);
157
-
158
- // subscribe should be done to proper notificationChannel
159
- expect(cache.subscribe.mock.calls[0][0]).toEqual(channel);
160
-
161
- // check invocation of request.getParties
162
- expect(MojaloopRequests.__postTransfers).toBeCalledWith(transfer, fspId);
163
-
164
- // check that this.context.data is updated
165
- expect(model.context.data).toEqual({
166
- transfer: { ...message },
167
- // current state will be updated by onAfterTransition which isn't called
168
- // when manual invocation of transition handler happens
169
- currentState: 'start'
170
- });
171
- // handler should be called only once
172
- expect(handler).toBeCalledTimes(1);
173
-
174
- // handler should unsubscribe from notification channel
175
- expect(cache.unsubscribe).toBeCalledTimes(1);
176
- expect(cache.unsubscribe).toBeCalledWith(channel, subId);
177
- resolve();
178
- }).catch((err) => { reject(err); } );
179
- });
180
-
181
- // ensure handler wasn't called before publishing the message
182
- expect(handler).not.toBeCalled();
183
-
184
- // ensure that cache.unsubscribe does not happened before fire the message
185
- expect(cache.unsubscribe).not.toBeCalled();
186
-
187
- // fire publication with given message
188
- const df = deferredJob(cache, channel);
189
- setImmediate(() => df.trigger(message));
190
-
191
- // wait for onRequestAction
192
- await onRequestActionPromise;
193
- });
194
-
195
- it('should handle timeouts', async () => {
196
- const transferId = uuid();
197
- const fspId = uuid();
198
- // our code takes care only about 'transferId' property
199
- const transfer = { transferId };
200
- const channel = Model.channelName({ transferId });
201
-
202
- const model = await Model.create(data, cacheKey, modelConfig);
203
- const { cache } = model.context;
204
- // mock workflow execution which is tested in separate case
205
- model.run = jest.fn(() => Promise.resolve());
206
-
207
- const message = {
208
- body: { ...putTransfersResponse },
209
- headers: {}
210
- };
211
-
212
- const onRequestActionPromise = new Promise((resolve, reject) => {
213
- // manually invoke transition handler
214
- model.onRequestAction(model.fsm, { transferId, fspId, transfer })
215
- .then(() => reject())
216
- .catch((err) => {
217
- // subscribe should be called only once
218
- expect(err instanceof pt.TimeoutError).toBeTruthy();
219
-
220
- // subscribe should be done to proper notificationChannel
221
- expect(cache.subscribe.mock.calls[0][0]).toEqual(channel);
222
-
223
- // check invocation of request.getParties
224
- expect(MojaloopRequests.__postTransfers).toBeCalledWith(transfer, fspId);
225
-
226
- // handler should be called only once
227
- expect(handler).toBeCalledTimes(0);
228
-
229
- // handler should unsubscribe from notification channel
230
- expect(cache.unsubscribe).toBeCalledTimes(1);
231
- expect(cache.unsubscribe).toBeCalledWith(channel, subId);
232
- resolve();
233
- });
234
- });
235
-
236
- // ensure handler wasn't called before publishing the message
237
- expect(handler).not.toBeCalled();
238
-
239
- // ensure that cache.unsubscribe does not happened before fire the message
240
- expect(cache.unsubscribe).not.toBeCalled();
241
-
242
- // fire publication with given message
243
- const df = deferredJob(cache, channel);
244
-
245
- setTimeout(
246
- () => { df.trigger(message); },
247
- // ensure that publication will be far long after timeout should be auto triggered
248
- (modelConfig.requestProcessingTimeoutSeconds+1)*1000
249
- );
250
-
251
- // wait for onRequestAction
252
- await onRequestActionPromise;
253
- });
254
-
255
- it('should unsubscribe from cache in case when error happens in workflow run', async () => {
256
- const transferId = uuid();
257
- const fspId = uuid();
258
- // our code takes care only about 'transferId' property
259
- const transfer = { transferId };
260
- const channel = Model.channelName({ transferId });
261
- const model = await Model.create(data, cacheKey, modelConfig);
262
- const { cache } = model.context;
263
-
264
- const onRequestActionPromise = new Promise((resolve, reject) => {
265
- // invoke transition handler
266
- model.onRequestAction(model.fsm, { transferId, fspId, transfer })
267
- .then(() => reject())
268
- .catch((err) => {
269
- expect(err.message).toEqual('Unexpected token u in JSON at position 0');
270
- expect(cache.unsubscribe).toBeCalledTimes(1);
271
- expect(cache.unsubscribe).toBeCalledWith(channel, subId);
272
- resolve();
273
- });
274
- });
275
-
276
- // fire publication to channel with invalid message
277
- // should throw the exception from JSON.parse
278
- const df = deferredJob(cache, channel);
279
- setImmediate(() => df.trigger(undefined));
280
-
281
- // wait for onRequestAction
282
- await onRequestActionPromise;
283
- });
284
-
285
- it('should unsubscribe from cache in case when error happens Mojaloop requests', async () => {
286
- // simulate error
287
- MojaloopRequests.__postTransfers = jest.fn(() => Promise.reject('postTransfers failed'));
288
- const transferId = uuid();
289
- const fspId = uuid();
290
- // our code takes care only about 'transferId' property
291
- const transfer = { transferId };
292
- const channel = Model.channelName({ transferId });
293
- const model = await Model.create(data, cacheKey, modelConfig);
294
- const { cache } = model.context;
295
-
296
- let theError = null;
297
- // invoke transition handler
298
- try {
299
- await model.onRequestAction(model.fsm, { transferId, fspId, transfer });
300
- throw new Error('this point should not be reached');
301
- } catch (error) {
302
- theError = error;
303
- expect(theError).toEqual('postTransfers failed');
304
- // handler should unsubscribe from notification channel
305
- expect(cache.unsubscribe).toBeCalledTimes(1);
306
- expect(cache.unsubscribe).toBeCalledWith(channel, subId);
307
- }
308
- });
309
-
310
- });
311
-
312
- describe('run workflow', () => {
313
- it('start', async () => {
314
- const transferId = uuid();
315
- const fspId = uuid();
316
- // our code takes care only about 'transferId' property
317
- const transfer = { transferId };
318
-
319
- const model = await Model.create(data, cacheKey, modelConfig);
320
-
321
- model.requestAction = jest.fn();
322
- model.getResponse = jest.fn(() => Promise.resolve({the: 'response'}));
323
-
324
- model.context.data.currentState = 'start';
325
- const result = await model.run({ transferId, fspId, transfer });
326
- expect(result).toEqual({the: 'response'});
327
- expect(model.requestAction).toBeCalledTimes(1);
328
- expect(model.getResponse).toBeCalledTimes(1);
329
- expect(model.context.logger.log.mock.calls).toEqual([
330
- ['State machine transitioned \'init\': none -> start'],
331
- ['Action called successfully'],
332
- [`Persisted model in cache: ${cacheKey}`],
333
- ]);
334
- });
335
- it('succeeded', async () => {
336
- const transferId = uuid();
337
- const fspId = uuid();
338
- // our code takes care only about 'transferId' property
339
- const transfer = { transferId };
340
-
341
- const model = await Model.create(data, cacheKey, modelConfig);
342
-
343
- model.getResponse = jest.fn(() => Promise.resolve({the: 'response'}));
344
-
345
- model.context.data.currentState = 'succeeded';
346
- const result = await model.run({ transferId, fspId, transfer });
347
-
348
- expect(result).toEqual({the: 'response'});
349
- expect(model.getResponse).toBeCalledTimes(1);
350
- expect(model.context.logger.log).toBeCalledWith('Action called successfully');
351
- });
352
-
353
- it('errored', async () => {
354
- const transferId = uuid();
355
- const fspId = uuid();
356
- // our code takes care only about 'transferId' property
357
- const transfer = { transferId };
358
-
359
- const model = await Model.create(data, cacheKey, modelConfig);
360
-
361
- model.getResponse = jest.fn(() => Promise.resolve({the: 'response'}));
362
-
363
- model.context.data.currentState = 'errored';
364
- const result = await model.run({ transferId, fspId, transfer});
365
-
366
- expect(result).toBeFalsy();
367
- expect(model.getResponse).not.toBeCalled();
368
- expect(model.context.logger.log).toBeCalledWith('State machine in errored state');
369
- });
370
-
371
- it('handling errors', async () => {
372
- const transferId = uuid();
373
- const fspId = uuid();
374
- // our code takes care only about 'transferId' property
375
- const transfer = { transferId };
376
-
377
- const model = await Model.create(data, cacheKey, modelConfig);
378
-
379
- model.requestAction = jest.fn(() => { throw new Error('mocked error'); });
380
-
381
- model.context.data.currentState = 'start';
382
-
383
- try {
384
- await model.run({ transferId, fspId, transfer });
385
- throw new Error('this point should not be reached');
386
- } catch (err) {
387
- expect(model.context.data.currentState).toEqual('errored');
388
- expect(err.requestActionState).toEqual( {
389
- ...data,
390
- currentState: SDKStateEnum.ERROR_OCCURRED,
391
- });
392
- }
393
- });
394
- it('should handle errors', async () => {
395
- const transferId = uuid();
396
- const fspId = uuid();
397
- // our code takes care only about 'transferId' property
398
- const transfer = { transferId };
399
-
400
- const model = await Model.create(data, cacheKey, modelConfig);
401
-
402
- model.requestAction = jest.fn(() => {
403
- const err = new Error('requestAction failed');
404
- err.requestActionState = 'some';
405
- return Promise.reject(err);
406
- });
407
- model.error = jest.fn();
408
- model.context.data.currentState = 'start';
409
-
410
- let theError = null;
411
- try {
412
- await model.run({ transferId, fspId, transfer });
413
- throw new Error('this point should not be reached');
414
- } catch(error) {
415
- theError = error;
416
- }
417
- // check propagation of original error
418
- expect(theError.message).toEqual('requestAction failed');
419
-
420
- // ensure we start transition to errored state
421
- expect(model.error).toBeCalledTimes(1);
422
- });
423
-
424
- it('should handle input validation for lack of transferId param', async () => {
425
- const model = await Model.create(data, cacheKey, modelConfig);
426
-
427
- expect(() => model.run({}))
428
- .rejects.toEqual(
429
- new Error('TransfersModel args requires \'transferId\' is nonempty string and mandatory property')
430
- );
431
- });
432
-
433
- it('should handle input validation for not transferId & transfer.transferId be in sync', async () => {
434
- const transferId = uuid();
435
- const model = await Model.create(data, cacheKey, modelConfig);
436
-
437
- expect(() => model.run({transferId, transfer: { transferId: uuid()}}))
438
- .rejects.toEqual(
439
- new Error('TransfersModel args requires properties \'transfer.transferId\' and \'transferId\' to be the equal in value')
440
- );
441
- });
442
-
443
- it('should handle input validation for fspId param', async () => {
444
- const transferId = uuid();
445
- const model = await Model.create(data, cacheKey, modelConfig);
446
-
447
- expect(() => model.run({transferId, fspId:'' }))
448
- .rejects.toEqual(
449
- new Error('TransfersModel args requires \'fspId\' to be nonempty string')
450
- );
451
- });
452
-
453
- });
454
-
455
- describe('loadFromCache', () => {
456
- test('should use PSM.loadFromCache properly', async () => {
457
- const spyLoadFromCache = jest.spyOn(PSM, 'loadFromCache');
458
- const key = uuid();
459
-
460
- // act
461
- const model = await Model.loadFromCache(key, modelConfig);
462
-
463
- // assert
464
- // check does model is proper
465
- expect(typeof model.requestAction).toEqual('function');
466
-
467
- // check how cache.get has been called
468
- expect(modelConfig.cache.get).toBeCalledWith(key);
469
-
470
- // check how loadFromCache from parent PSM module was used
471
- expect(spyLoadFromCache).toBeCalledTimes(1);
472
- expect(spyLoadFromCache).toBeCalledWith(
473
- modelConfig.cache,
474
- key,
475
- modelConfig.logger,
476
- expect.anything(),
477
- expect.anything()
478
- );
479
- });
480
- });
481
- });
@@ -1,178 +0,0 @@
1
- /**************************************************************************
2
- * (C) Copyright ModusBox Inc. 2020 - 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
- * Paweł Marzec - pawel.marzec@modusbox.com *
9
- **************************************************************************/
10
-
11
- 'use strict';
12
-
13
- const Cache = jest.createMockFromModule('~/lib/cache');
14
-
15
- const PSM = require('~/lib/model').PersistentStateMachine;
16
- const mockLogger = require('../../../mockLogger');
17
- describe('PersistentStateMachine', () => {
18
- let cache;
19
- let data;
20
- let smSpec;
21
- const key = 'cache-key';
22
-
23
- const logger = mockLogger({app: 'persistent-state-machine-test'});
24
-
25
- function checkPSMLayout(psm, optData) {
26
- expect(psm).toBeTruthy();
27
-
28
- expect(psm.state).toEqual((optData && optData.currentState) || smSpec.init || 'none');
29
-
30
- expect(psm.context).toEqual({
31
- // allow passing optional data, elsewhere use default
32
- data: optData || data,
33
- cache,
34
- key,
35
- logger
36
- });
37
-
38
- expect(typeof psm.onAfterTransition).toEqual('function');
39
- expect(typeof psm.onPendingTransition).toEqual('function');
40
- expect(typeof psm.saveToCache).toEqual('function');
41
- expect(typeof psm.init).toEqual('function');
42
- expect(typeof psm.gogo).toEqual('function');
43
- expect(typeof psm.error).toEqual('function');
44
- }
45
-
46
- function shouldNotBeExecuted() {
47
- throw new Error('test failure enforced: this code should never be executed');
48
- }
49
-
50
- beforeEach(async () => {
51
- smSpec = {
52
- // init: 'start',
53
- transitions: [
54
- { name: 'init', from: 'none', to: 'start'},
55
- { name: 'gogo', from: 'start', to: 'end' },
56
- { name: 'error', from: '*', to: 'errored' }
57
- ],
58
- methods: {
59
- onGogo: async () => {
60
- return new Promise( (resolved) => {
61
- setTimeout((() => resolved(true)), 100);
62
- } );
63
- },
64
- onError: () => {
65
- // eslint-disable-next-line no-console
66
- console.error('onError');
67
- }
68
- }
69
- };
70
-
71
- // test data
72
- data = { the: 'data' };
73
-
74
- cache = new Cache({
75
- cacheUrl: 'redis://dummy:1234',
76
- logger,
77
- });
78
- // mock cache set & get
79
- cache.get = jest.fn(async () => data);
80
- cache.set = jest.fn(async () => 'cache set replies');
81
-
82
- await cache.connect();
83
- });
84
-
85
- afterEach(async () => {
86
- await cache.disconnect();
87
- });
88
-
89
- test('module layout', () => {
90
- expect(typeof PSM.create).toEqual('function');
91
- expect(typeof PSM.loadFromCache).toEqual('function');
92
- });
93
-
94
- test('create', async () => {
95
- const psm = await PSM.create(data, cache, key, logger, smSpec);
96
- checkPSMLayout(psm);
97
- expect(psm.state).toEqual('none');
98
- await psm.init();
99
- expect(psm.state).toEqual('start');
100
- });
101
-
102
- describe('onPendingTransition', () => {
103
- it('should throw error if not `error` transition', async () => {
104
- const psm = await PSM.create(data, cache, key, logger, smSpec);
105
- checkPSMLayout(psm);
106
-
107
- psm.init();
108
- expect(() => psm.gogo()).toThrowError('Transition \'gogo\' requested while another transition is in progress');
109
-
110
- });
111
-
112
- it('should not throw error if `error` transition called when `gogo` is pending', (done) => {
113
- PSM.create(data, cache, key, logger, smSpec).then((psm) => {
114
- checkPSMLayout(psm);
115
-
116
- psm.init()
117
- .then(() => {
118
- expect(psm.state).toEqual('start');
119
- psm.gogo();
120
- expect(psm.state).toEqual('end');
121
- return Promise.resolve();
122
- })
123
- .then(() => psm.error())
124
- .then(done)
125
- .catch(shouldNotBeExecuted);
126
- });
127
- });
128
- });
129
-
130
- describe('loadFromCache', () => {
131
- it('should properly call cache.get, get expected data in `context.data` and setup state of machine', async () => {
132
- const dataFromCache = { this_is: 'data from cache', currentState: 'end'};
133
- cache.get = jest.fn( async () => dataFromCache);
134
- const psm = await PSM.loadFromCache(cache, key, logger, smSpec);
135
- checkPSMLayout(psm, dataFromCache);
136
-
137
- // to get value from cache proper key should be used
138
- expect(cache.get).toHaveBeenCalledWith(key);
139
-
140
- // check what has been stored in `context.data`
141
- expect(psm.context.data).toEqual(dataFromCache);
142
-
143
- });
144
-
145
- it('should throw when received invalid data from `cache.get`', async () => {
146
- cache.get = jest.fn( async () => null);
147
- try {
148
- await PSM.loadFromCache(cache, key, logger, smSpec);
149
- shouldNotBeExecuted();
150
- } catch (error) {
151
- expect(error.message).toEqual(`No cached data found for: ${key}`);
152
- }
153
- });
154
-
155
- it('should propagate error received from `cache.get`', async () => {
156
- cache.get = jest.fn( async () => { throw new Error('error from cache.get'); });
157
- expect(() => PSM.loadFromCache(cache, key, logger, smSpec))
158
- .rejects.toEqual(new Error('error from cache.get'));
159
- });
160
- });
161
-
162
- describe('saveToCache', () => {
163
-
164
- it('should rethrow error from cache.set', async () => {
165
-
166
- // mock to simulate throwing error
167
- cache.set = jest.fn(() => { throw new Error('error from cache.set'); });
168
-
169
- const psm = await PSM.create(data, cache, key, logger, smSpec);
170
- checkPSMLayout(psm);
171
- await psm.init();
172
-
173
- expect(() => psm.saveToCache())
174
- .rejects.toEqual(new Error('error from cache.set'));
175
- });
176
- });
177
-
178
- });
@@ -1,13 +0,0 @@
1
- {
2
- "type": "otpResponse",
3
- "data": {
4
- "authenticationInfo": {
5
- "authentication": "OTP",
6
- "authenticationValue": "12334567"
7
- },
8
- "responseType": "ENTERED"
9
- },
10
- "headers": {
11
- "fspiop-source": "foo"
12
- }
13
- }