@mojaloop/sdk-scheme-adapter 12.2.1 → 12.3.0

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 (37) hide show
  1. package/.env.example +1 -1
  2. package/CHANGELOG.md +22 -0
  3. package/audit-resolve.json +71 -1
  4. package/package.json +4 -1
  5. package/src/ControlAgent/index.js +2 -3
  6. package/src/ControlServer/index.js +2 -2
  7. package/src/InboundServer/index.js +7 -7
  8. package/src/InboundServer/middlewares.js +2 -2
  9. package/src/OutboundServer/handlers.js +3 -0
  10. package/src/OutboundServer/index.js +10 -11
  11. package/src/config.js +31 -14
  12. package/src/index.js +198 -10
  13. package/src/lib/cache.js +110 -52
  14. package/src/lib/metrics.js +148 -0
  15. package/src/lib/model/AccountsModel.js +4 -1
  16. package/src/lib/model/Async2SyncModel.js +4 -1
  17. package/src/lib/model/InboundTransfersModel.js +4 -1
  18. package/src/lib/model/OutboundBulkQuotesModel.js +4 -1
  19. package/src/lib/model/OutboundBulkTransfersModel.js +4 -1
  20. package/src/lib/model/OutboundRequestToPayModel.js +4 -1
  21. package/src/lib/model/OutboundRequestToPayTransferModel.js +4 -1
  22. package/src/lib/model/OutboundTransfersModel.js +61 -1
  23. package/src/lib/model/ProxyModel/index.js +4 -2
  24. package/src/lib/validate.js +2 -2
  25. package/test/__mocks__/redis.js +4 -0
  26. package/test/config/integration.env +5 -0
  27. package/test/unit/ControlServer/index.js +3 -3
  28. package/test/unit/InboundServer.test.js +1 -1
  29. package/test/unit/api/utils.js +4 -1
  30. package/test/unit/config.test.js +3 -3
  31. package/test/unit/data/defaultConfig.json +23 -7
  32. package/test/unit/index.test.js +95 -4
  33. package/test/unit/lib/model/OutboundTransfersModel.test.js +37 -1
  34. package/test/unit/lib/model/data/defaultConfig.json +24 -9
  35. package/src/lib/api/index.js +0 -12
  36. package/src/lib/randomphrase/index.js +0 -21
  37. package/src/lib/randomphrase/words.json +0 -3397
@@ -10,13 +10,18 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- const { Logger } = require('@mojaloop/sdk-standard-components');
14
- const defaultConfig = require('./data/defaultConfig');
15
-
16
13
  jest.mock('dotenv', () => ({
17
14
  config: jest.fn()
18
15
  }));
19
16
 
17
+ const promClient = require('prom-client');
18
+ const defaultConfig = require('./data/defaultConfig.json');
19
+ const { Logger } = require('@mojaloop/sdk-standard-components');
20
+ const { MetricsClient } = require('~/lib/metrics');
21
+
22
+ const TestControlServer = require('./ControlServer');
23
+
24
+
20
25
  process.env.PEER_ENDPOINT = '172.17.0.3:4000';
21
26
  process.env.BACKEND_ENDPOINT = '172.17.0.5:4000';
22
27
  process.env.CACHE_HOST = '172.17.0.2';
@@ -26,6 +31,10 @@ process.env.MGMT_API_WS_URL = '0.0.0.0';
26
31
  const index = require('~/index.js');
27
32
 
28
33
  describe('index.js', () => {
34
+ beforeEach(() => {
35
+ promClient.register.clear();
36
+ });
37
+
29
38
  test('WSO2 error events in OutboundServer propagate to top-level server', () => {
30
39
  const logger = new Logger.Logger({ stringify: () => '' });
31
40
  const svr = new index.Server(defaultConfig, logger);
@@ -50,7 +59,89 @@ describe('index.js', () => {
50
59
  expect(typeof(index.OutboundServerMiddleware)).toBe('object');
51
60
  expect(typeof(index.Router)).toBe('function');
52
61
  expect(typeof(index.Validate)).toBe('function');
53
- expect(typeof(index.RandomPhrase)).toBe('function');
54
62
  expect(typeof(index.Cache)).toBe('function');
55
63
  });
56
64
  });
65
+
66
+ describe('Server', () => {
67
+ let server, controlServer, conf, logger;
68
+
69
+ beforeEach(async () => {
70
+ promClient.register.clear();
71
+ logger = new Logger.Logger({ stringify: () => '' });
72
+ conf = JSON.parse(JSON.stringify(defaultConfig));
73
+ conf.enableTestFeatures = true;
74
+ conf.pm4mlEnabled = true;
75
+ conf.control.mgmtAPIWsUrl = 'localhost';
76
+ conf.control.mgmtAPIWsPort = 4005;
77
+ conf.control.port = conf.control.mgmtAPIWsPort;
78
+ controlServer = new TestControlServer.Server({ logger, appConfig: conf });
79
+ server = new index.Server(conf, logger);
80
+ await server.start();
81
+ });
82
+
83
+ afterEach(async () => {
84
+ await controlServer.stop();
85
+ await server.stop();
86
+ });
87
+
88
+ describe('is reconfigured correctly by the control client', () => {
89
+ let newConf;
90
+ beforeEach(async () => {
91
+ // not every server restarts on every config change, we'll make sure they all restart
92
+ newConf = { ...conf, logIndent: conf.logIndent + 1, control: { ...conf.control, rubbish: 'data' }, test: { trash: 'data' } };
93
+ // Just in case, we'll assert the new configuration is different to the old one
94
+ expect(newConf).not.toEqual(conf);
95
+ });
96
+
97
+ it('reconfigures and restarts constituent servers when triggered by control client', async () => {
98
+ const [restartInbound, restartOutbound, restartControl, restartOAuthTest, restartTest] =
99
+ Array.from({ length: 5 }).map(() => jest.fn());
100
+ server.inboundServer.reconfigure = jest.fn(() => restartInbound);
101
+ server.outboundServer.reconfigure = jest.fn(() => restartOutbound);
102
+ server.testServer.reconfigure = jest.fn(() => restartTest);
103
+ server.oauthTestServer.reconfigure = jest.fn(() => restartOAuthTest);
104
+ server.controlClient.reconfigure = jest.fn(() => restartControl);
105
+
106
+ await controlServer.broadcastConfigChange(newConf);
107
+
108
+ // We wait for the servers to get restarted
109
+ await new Promise((wait) => setTimeout(wait, 1000));
110
+
111
+ expect(server.inboundServer.reconfigure).toHaveBeenCalledTimes(1);
112
+ expect(server.inboundServer.reconfigure).toHaveBeenCalledWith(
113
+ newConf, expect.any(Logger.Logger), expect.any(index.Cache)
114
+ );
115
+ expect(server.outboundServer.reconfigure).toHaveBeenCalledTimes(1);
116
+ const metricsClient = new MetricsClient();
117
+ expect(server.outboundServer.reconfigure).toHaveBeenCalledWith(
118
+ newConf, expect.any(Logger.Logger), expect.any(index.Cache), metricsClient
119
+ );
120
+ expect(server.controlClient.reconfigure).toHaveBeenCalledTimes(1);
121
+ expect(server.controlClient.reconfigure).toHaveBeenCalledWith({
122
+ logger: expect.any(Logger.Logger),
123
+ port: newConf.control.port,
124
+ appConfig: newConf
125
+ });
126
+ expect(server.testServer.reconfigure).toHaveBeenCalledTimes(1);
127
+ expect(server.testServer.reconfigure).toHaveBeenCalledWith({
128
+ logger: expect.any(Logger.Logger),
129
+ cache: expect.any(index.Cache),
130
+ port: newConf.test.port
131
+ });
132
+ expect(server.oauthTestServer.reconfigure).toHaveBeenCalledTimes(1);
133
+ expect(server.oauthTestServer.reconfigure).toHaveBeenCalledWith({
134
+ logger: expect.any(Logger.Logger),
135
+ clientKey: newConf.oauthTestServer.clientKey,
136
+ clientSecret: newConf.oauthTestServer.clientSecret,
137
+ port: newConf.oauthTestServer.listenPort,
138
+ });
139
+
140
+ expect(restartInbound).toHaveBeenCalledTimes(1);
141
+ expect(restartOutbound).toHaveBeenCalledTimes(1);
142
+ expect(restartTest).toHaveBeenCalledTimes(1);
143
+ expect(restartOAuthTest).toHaveBeenCalledTimes(1);
144
+ expect(restartControl).toHaveBeenCalledTimes(1);
145
+ });
146
+ });
147
+ });
@@ -15,6 +15,7 @@ jest.mock('@mojaloop/sdk-standard-components');
15
15
  jest.mock('redis');
16
16
 
17
17
  const Cache = require('~/lib/cache');
18
+ const { MetricsClient } = require('~/lib/metrics');
18
19
  const Model = require('~/lib/model').OutboundTransfersModel;
19
20
  const PartiesModel = require('~/lib/model').PartiesModel;
20
21
 
@@ -50,6 +51,7 @@ describe('outboundModel', () => {
50
51
  let config;
51
52
  let logger;
52
53
  let cache;
54
+ let metricsClient;
53
55
 
54
56
  /**
55
57
  *
@@ -91,6 +93,7 @@ describe('outboundModel', () => {
91
93
  ...config,
92
94
  cache,
93
95
  logger,
96
+ metricsClient,
94
97
  });
95
98
 
96
99
  await model.initialize(JSON.parse(JSON.stringify(transferRequest)));
@@ -113,6 +116,7 @@ describe('outboundModel', () => {
113
116
  beforeAll(async () => {
114
117
  logger = new Logger.Logger({ context: { app: 'outbound-model-unit-tests-cache' }, stringify: () => '' });
115
118
  quoteResponse = JSON.parse(JSON.stringify(quoteResponseTemplate));
119
+ metricsClient = new MetricsClient();
116
120
  });
117
121
 
118
122
  beforeEach(async () => {
@@ -140,6 +144,7 @@ describe('outboundModel', () => {
140
144
  const model = new Model({
141
145
  cache,
142
146
  logger,
147
+ metricsClient,
143
148
  ...config,
144
149
  });
145
150
 
@@ -194,6 +199,7 @@ describe('outboundModel', () => {
194
199
  const model = new Model({
195
200
  cache,
196
201
  logger,
202
+ metricsClient,
197
203
  ...config,
198
204
  });
199
205
 
@@ -274,6 +280,7 @@ describe('outboundModel', () => {
274
280
  const model = new Model({
275
281
  cache,
276
282
  logger,
283
+ metricsClient,
277
284
  ...config,
278
285
  });
279
286
 
@@ -303,6 +310,7 @@ describe('outboundModel', () => {
303
310
  const model = new Model({
304
311
  cache,
305
312
  logger,
313
+ metricsClient,
306
314
  ...config,
307
315
  });
308
316
 
@@ -333,6 +341,7 @@ describe('outboundModel', () => {
333
341
  const model = new Model({
334
342
  cache,
335
343
  logger,
344
+ metricsClient,
336
345
  ...config,
337
346
  });
338
347
 
@@ -360,6 +369,7 @@ describe('outboundModel', () => {
360
369
  const model = new Model({
361
370
  cache,
362
371
  logger,
372
+ metricsClient,
363
373
  ...config,
364
374
  });
365
375
 
@@ -395,6 +405,7 @@ describe('outboundModel', () => {
395
405
  let model = new Model({
396
406
  cache,
397
407
  logger,
408
+ metricsClient,
398
409
  ...config,
399
410
  });
400
411
 
@@ -421,6 +432,7 @@ describe('outboundModel', () => {
421
432
  model = new Model({
422
433
  cache,
423
434
  logger,
435
+ metricsClient,
424
436
  ...config,
425
437
  });
426
438
 
@@ -451,6 +463,7 @@ describe('outboundModel', () => {
451
463
  let model = new Model({
452
464
  cache,
453
465
  logger,
466
+ metricsClient,
454
467
  ...config,
455
468
  });
456
469
 
@@ -477,6 +490,7 @@ describe('outboundModel', () => {
477
490
  model = new Model({
478
491
  cache,
479
492
  logger,
493
+ metricsClient,
480
494
  ...config,
481
495
  });
482
496
 
@@ -502,6 +516,7 @@ describe('outboundModel', () => {
502
516
  model = new Model({
503
517
  cache,
504
518
  logger,
519
+ metricsClient,
505
520
  ...config,
506
521
  });
507
522
 
@@ -557,6 +572,7 @@ describe('outboundModel', () => {
557
572
  const model = new Model({
558
573
  cache,
559
574
  logger,
575
+ metricsClient,
560
576
  ...config,
561
577
  });
562
578
 
@@ -608,6 +624,7 @@ describe('outboundModel', () => {
608
624
  const model = new Model({
609
625
  cache,
610
626
  logger,
627
+ metricsClient,
611
628
  ...config,
612
629
  });
613
630
 
@@ -701,6 +718,7 @@ describe('outboundModel', () => {
701
718
  const model = new Model({
702
719
  cache,
703
720
  logger,
721
+ metricsClient,
704
722
  ...config,
705
723
  });
706
724
 
@@ -763,6 +781,7 @@ describe('outboundModel', () => {
763
781
  const model = new Model({
764
782
  cache,
765
783
  logger,
784
+ metricsClient,
766
785
  ...config,
767
786
  });
768
787
 
@@ -823,6 +842,7 @@ describe('outboundModel', () => {
823
842
  const model = new Model({
824
843
  cache,
825
844
  logger,
845
+ metricsClient,
826
846
  ...config,
827
847
  });
828
848
 
@@ -849,11 +869,12 @@ describe('outboundModel', () => {
849
869
 
850
870
 
851
871
  async function testTlsServer(enableTls) {
852
- config.tls.enabled = enableTls;
872
+ config.outbound.tls.mutualTLS.enabled = enableTls;
853
873
 
854
874
  new Model({
855
875
  cache,
856
876
  logger,
877
+ metricsClient,
857
878
  ...config
858
879
  });
859
880
 
@@ -866,4 +887,19 @@ describe('outboundModel', () => {
866
887
 
867
888
  test('Outbound server should use HTTP if outbound mTLS disabled', () =>
868
889
  testTlsServer(false));
890
+
891
+ test('Outbound transfers model should record metrics', async () => {
892
+ const metrics = metricsClient._prometheusRegister.metrics();
893
+ expect(metrics).toBeTruthy();
894
+
895
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_party_lookup_request_count'));
896
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_party_lookup_response_count'));
897
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_quote_request_count'));
898
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_quote_response_count'));
899
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_transfer_prepare_count'));
900
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_transfer_fulfil_response_count'));
901
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_quote_request_latency'));
902
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_transfer_latency'));
903
+ expect(metrics).toEqual(expect.stringContaining('mojaloop_connector_outbound_party_lookup_latency'));
904
+ });
869
905
  });
@@ -1,14 +1,26 @@
1
1
  {
2
- "tls": {
3
- "enabled": false,
4
- "creds": {
5
- "ca": null,
6
- "cert": null,
7
- "key": null
2
+ "inbound": {
3
+ "port": 4000,
4
+ "tls": {
5
+ "mutualTLS": { "enabled": false },
6
+ "creds": {
7
+ "ca": null,
8
+ "cert": null,
9
+ "key": null
10
+ }
8
11
  }
9
12
  },
10
- "inboundServerPort": 4000,
11
- "outboundServerPort": 4001,
13
+ "outbound": {
14
+ "port": 4001,
15
+ "tls": {
16
+ "mutualTLS": { "enabled": false },
17
+ "creds": {
18
+ "ca": null,
19
+ "cert": null,
20
+ "key": null
21
+ }
22
+ }
23
+ },
12
24
  "peerEndpoint": "172.17.0.2:3001",
13
25
  "backendEndpoint": "172.17.0.2:3001",
14
26
  "alsEndpoint": "127.0.0.1:6500",
@@ -43,5 +55,8 @@
43
55
  "rejectExpiredQuoteResponses": false,
44
56
  "rejectExpiredTransferFulfils": false,
45
57
  "rejectTransfersOnExpiredQuotes": false,
46
- "logIndent": 2
58
+ "logIndent": 2,
59
+ "metrics": {
60
+ "port": 4004
61
+ }
47
62
  }
@@ -1,12 +0,0 @@
1
- class ApiServer {
2
- constructor(conf) {
3
- this.conf = conf;
4
- this.api = null;
5
- this.server = null;
6
- this.logger = null;
7
- }
8
-
9
-
10
- }
11
-
12
- module.exports = ApiServer;
@@ -1,21 +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
- * Matt Kingston - matt.kingston@modusbox.com *
9
- **************************************************************************/
10
-
11
- 'use strict';
12
-
13
- const words = require('./words.json');
14
-
15
- const randomEl = arr => arr[Math.floor(Math.random() * arr.length)];
16
- module.exports = (separator = '-') => [
17
- randomEl(words.adjectives),
18
- randomEl(words.nouns),
19
- randomEl(words.adjectives),
20
- randomEl(words.nouns)
21
- ].join(separator);