@adobe/acc-js-sdk 1.1.4 → 1.1.7

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.
package/src/soap.js CHANGED
@@ -600,7 +600,7 @@ class SoapMethodCall {
600
600
  this._method.prepend(sessionTokenElem);
601
601
  }
602
602
  const noMethodInURL = !!this._pushDownOptions.noMethodInURL;
603
- const actualUrl = noMethodInURL ? url : `${url}?${this.urn}#${this.methodName}`;
603
+ const actualUrl = noMethodInURL ? url : `${url}?${this.urn}:${this.methodName}`;
604
604
 
605
605
  // Prepare request and empty response objects
606
606
  [this.request, this.requestOptions] = this._createHTTPRequest(actualUrl);
package/src/transport.js CHANGED
@@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
10
10
  governing permissions and limitations under the License.
11
11
  */
12
12
  (function() {
13
- "use strict";
13
+ "use strict";
14
14
 
15
15
  const { Util } = require('./util.js');
16
16
 
@@ -41,9 +41,9 @@ class HttpError {
41
41
  }
42
42
 
43
43
  /**********************************************************************************
44
- *
44
+ *
45
45
  * Node implementation
46
- *
46
+ *
47
47
  *********************************************************************************/
48
48
  /* istanbul ignore else */
49
49
  if (!Util.isBrowser()) {
@@ -52,13 +52,13 @@ if (!Util.isBrowser()) {
52
52
  const axios = require('axios');
53
53
 
54
54
  /**
55
- *
55
+ *
56
56
  * Request body (options)
57
57
  * - headers (kv)
58
58
  * - method
59
59
  * - url
60
60
  * - data
61
- *
61
+ *
62
62
  * Response
63
63
  * - data
64
64
  * - statusCode
@@ -96,11 +96,11 @@ if (!Util.isBrowser()) {
96
96
  }
97
97
 
98
98
  /**********************************************************************************
99
- *
99
+ *
100
100
  * Browser-side implementation of the request-promise-native node module.
101
101
  * This simply wraps the fetch API
102
102
  * From https://www.npmjs.com/package/request-promise-native
103
- *
103
+ *
104
104
  *********************************************************************************/
105
105
  else {
106
106
 
@@ -109,11 +109,12 @@ if (!Util.isBrowser()) {
109
109
  const headers = new Headers();
110
110
  for (var k in options.headers) {
111
111
  headers.append(k, options.headers[k]);
112
- }
112
+ }
113
113
  const r = new Request(options.url, {
114
114
  method: options.method,
115
115
  headers: headers,
116
- body: options.data
116
+ body: options.data,
117
+ credentials: options.credentials || 'same-origin'
117
118
  });
118
119
 
119
120
  const p = fetch(r).then(async (response) => {
@@ -135,4 +136,4 @@ if (!Util.isBrowser()) {
135
136
 
136
137
  }
137
138
 
138
- })();
139
+ })();
@@ -1097,7 +1097,6 @@ describe('Application', () => {
1097
1097
  </GetEntityIfMoreRecentResponse>
1098
1098
  </SOAP-ENV:Body>
1099
1099
  </SOAP-ENV:Envelope>`));
1100
-
1101
1100
  const nodes = await link.joinNodes();
1102
1101
  expect(nodes).toMatchObject([]);
1103
1102
  const reverseLink = await link.reverseLink();
@@ -2156,4 +2155,5 @@ describe('Application', () => {
2156
2155
  expect(client.application.version).toBe('6.7.0');
2157
2156
  })
2158
2157
  })
2159
- });
2158
+ });
2159
+
@@ -0,0 +1,338 @@
1
+ /*
2
+ Copyright 2022 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ /**********************************************************************************
15
+ *
16
+ * Unit tests for the cache refresher
17
+ *
18
+ *********************************************************************************/
19
+
20
+
21
+ const sdk = require('../src/index.js');
22
+ const { Cache } = require('../src/cache.js');
23
+ const Mock = require('./mock.js').Mock;
24
+ const CacheRefresher = require('../src/cacheRefresher.js').CacheRefresher;
25
+
26
+
27
+ describe("CacheRefresher cache", function () {
28
+
29
+ it('Should call refresh', async () => {
30
+ const client = await Mock.makeClient();
31
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
32
+
33
+ await client.NLWS.xtkSession.logon();
34
+ const cache = new Cache();
35
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
36
+
37
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_CLEAR_RESPONSE);
38
+ await cacheRefresher._callAndRefresh();
39
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
40
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T14:38:55.766Z");
41
+
42
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_CLEAR_RESPONSE);
43
+ await cacheRefresher._callAndRefresh();
44
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
45
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T14:38:55.766Z");
46
+
47
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
48
+ await client.NLWS.xtkSession.logoff();
49
+ });
50
+
51
+ it('Should call refresh after 1 seconds', async () => {
52
+ const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin");
53
+ const client = await sdk.init(connectionParameters);
54
+ client._transport = jest.fn();
55
+
56
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
57
+
58
+ await client.NLWS.xtkSession.logon();
59
+ expect(client.isLogged()).toBeTruthy();
60
+ const cache = new Cache();
61
+
62
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
63
+
64
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBeUndefined();
65
+ expect(cacheRefresher._refresherStateCache.get("time")).toBeUndefined();
66
+ client._transport.mockReturnValue(Promise.resolve(Mock.GETMODIFIEDENTITIES_CLEAR_RESPONSE));
67
+ jest.useFakeTimers();
68
+ cacheRefresher.startAutoRefresh(5000);
69
+ jest.advanceTimersByTime(6000);
70
+ jest.useRealTimers();
71
+
72
+ // to allow soap call to finish
73
+ await new Promise(process.nextTick);
74
+
75
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
76
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T14:38:55.766Z");
77
+
78
+ cacheRefresher.stopAutoRefresh();
79
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
80
+ await client.NLWS.xtkSession.logoff();
81
+ });
82
+
83
+ it('Should send buildNumber when call refresh', async () => {
84
+ const client = await Mock.makeClient();
85
+ const logs = await Mock.withMockConsole(async () => {
86
+ client.traceAPICalls(true);
87
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
88
+
89
+ await client.NLWS.xtkSession.logon();
90
+
91
+ const cache = new Cache();
92
+
93
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
94
+ cacheRefresher._refresherStateCache.put("buildNumber", "9469");
95
+ cacheRefresher._refresherStateCache.put("time", "2022-07-28T14:38:55.766Z");
96
+
97
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_CLEAR_RESPONSE);
98
+ await cacheRefresher._callAndRefresh();
99
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
100
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T14:38:55.766Z");
101
+
102
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
103
+
104
+
105
+ await client.NLWS.xtkSession.logoff();
106
+
107
+ })
108
+ expect(logs.length).toBe(6);
109
+ expect(logs[0]).toMatch(/SOAP.*request.*Logon/is)
110
+ expect(logs[1]).toMatch(/SOAP.*response.*LogonResponse/is)
111
+ expect(logs[2]).toMatch(/SOAP.*request.*buildNumber.*9469.*2022-07-28T14:38:55.766Z.*GetModifiedEntities*/is)
112
+ expect(logs[3]).toMatch(/SOAP.*response.*GetModifiedEntitiesResponse/is)
113
+ expect(logs[4]).toMatch(/SOAP.*request.*Logoff/is)
114
+ expect(logs[5]).toMatch(/SOAP.*response.*LogoffResponse/is)
115
+ });
116
+
117
+ it('Should refresh cache', async () => {
118
+ const client = await Mock.makeClient();
119
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
120
+
121
+ await client.NLWS.xtkSession.logon();
122
+ const cache = new Cache();
123
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
124
+
125
+ cache.put("xtk:schema|nms:recipient", "<content recipient>");
126
+ cache.put("xtk:schema|nms:replicationStrategy", "<content xtk:schema|nms:replicationStrategy>");
127
+ cache.put("xtk:schema|nms:operation", "<content xtk:schema|nms:operation>");
128
+ expect(cache.get("xtk:schema|nms:recipient")).toBe("<content recipient>");
129
+ expect(cache.get("xtk:schema|nms:replicationStrategy")).toBe("<content xtk:schema|nms:replicationStrategy>");
130
+ expect(cache.get("xtk:schema|nms:operation")).toBe("<content xtk:schema|nms:operation>");
131
+
132
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_SCHEMA_RESPONSE);
133
+ await cacheRefresher._callAndRefresh();
134
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
135
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T15:32:00.785Z");
136
+ expect(cache.get("xtk:schema|nms:recipient")).toBeUndefined();
137
+ expect(cache.get("xtk:schema|nms:replicationStrategy")).toBeUndefined();
138
+ expect(cache.get("xtk:schema|nms:operation")).toBe("<content xtk:schema|nms:operation>");
139
+
140
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
141
+ await client.NLWS.xtkSession.logoff();
142
+ });
143
+
144
+ it('Should stop refresh if method not exist', async () => {
145
+ const client = await Mock.makeClient();
146
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
147
+
148
+ await client.NLWS.xtkSession.logon();
149
+ const cache = new Cache();
150
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
151
+
152
+ cacheRefresher.startAutoRefresh();
153
+
154
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_UNDEFINED_RESPONSE);
155
+ await cacheRefresher._callAndRefresh();
156
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBeUndefined();
157
+ expect(cacheRefresher._refresherStateCache.get("time")).toBeUndefined();
158
+ expect(cacheRefresher._intervalId).toBeNull();
159
+
160
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
161
+ await client.NLWS.xtkSession.logoff();
162
+ });
163
+
164
+ it('Should not stop refresh if error different from undefined', async () => {
165
+ const client = await Mock.makeClient();
166
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
167
+
168
+ await client.NLWS.xtkSession.logon();
169
+ const cache = new Cache();
170
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
171
+
172
+ cacheRefresher.startAutoRefresh();
173
+
174
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_ERROR_RESPONSE);
175
+ try {
176
+ await cacheRefresher._callAndRefresh();
177
+ fail('exception is expected');
178
+ } catch (e) {
179
+ expect(e).not.toBeNull();
180
+ }
181
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBeUndefined();
182
+ expect(cacheRefresher._refresherStateCache.get("time")).toBeUndefined();
183
+ expect(cacheRefresher._intervalId).not.toBeNull();
184
+
185
+ cacheRefresher.stopAutoRefresh();
186
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
187
+ await client.NLWS.xtkSession.logoff();
188
+ });
189
+
190
+ it('Should be able to call start refresh twice', async () => {
191
+ const client = await Mock.makeClient();
192
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
193
+
194
+ await client.NLWS.xtkSession.logon();
195
+ const cache = new Cache();
196
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
197
+
198
+ jest.useFakeTimers();
199
+ cacheRefresher.startAutoRefresh(100000);
200
+ expect(cacheRefresher._intervalId).not.toBeNull();
201
+ const firstIntervalId = cacheRefresher._intervalId;
202
+ cacheRefresher.startAutoRefresh(5000);
203
+ expect(cacheRefresher._intervalId).not.toBeNull();
204
+ expect(cacheRefresher._intervalId != firstIntervalId);
205
+
206
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_CLEAR_RESPONSE);
207
+
208
+ jest.advanceTimersByTime(6000);
209
+ jest.useRealTimers();
210
+
211
+ // to allow soap call to finish
212
+ await new Promise(process.nextTick);
213
+
214
+ expect(cacheRefresher._refresherStateCache.get("buildNumber")).toBe("9469");
215
+ expect(cacheRefresher._refresherStateCache.get("time")).toBe("2022-07-28T14:38:55.766Z");
216
+
217
+ cacheRefresher.stopAutoRefresh();
218
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
219
+ await client.NLWS.xtkSession.logoff();
220
+ });
221
+
222
+ it('Should notify when refresh cache', async () => {
223
+ const client = await Mock.makeClient();
224
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
225
+
226
+
227
+ class Listener {
228
+ constructor() {
229
+ this._schemas = {};
230
+ }
231
+ add(schemaId) {
232
+ this._schemas[schemaId] = "1";
233
+ }
234
+
235
+ invalidateCacheItem(schemaId) {
236
+ this._schemas[schemaId] = undefined;
237
+ }
238
+ getSchema(schemaId) {
239
+ return this._schemas[schemaId];
240
+ }
241
+ }
242
+
243
+ let listener = new Listener();
244
+ client._registerCacheChangeListener(listener);
245
+
246
+ await client.NLWS.xtkSession.logon();
247
+ const cache = new Cache();
248
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
249
+
250
+ cache.put("xtk:schema|nms:recipient", "<content recipient>");
251
+ cache.put("xtk:schema|nms:replicationStrategy", "<content xtk:schema|nms:replicationStrategy>");
252
+ cache.put("xtk:schema|nms:operation", "<content xtk:schema|nms:operation>");
253
+
254
+ listener.add("nms:recipient");
255
+
256
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_SCHEMA_RESPONSE);
257
+ await cacheRefresher._callAndRefresh();
258
+
259
+ expect(listener.getSchema("nms:recipient")).toBeUndefined();
260
+
261
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
262
+ await client.NLWS.xtkSession.logoff();
263
+ client._unregisterCacheChangeListener(listener);
264
+ });
265
+
266
+ it('Should protect callAndRefresh from re-entrance', async () => {
267
+ const client = await Mock.makeClient();
268
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
269
+ await client.NLWS.xtkSession.logon();
270
+ const cache = new Cache();
271
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
272
+ let count = 0;
273
+ cacheRefresher._callAndRefresh = jest.fn(() => { count = count + 1 });
274
+ expect(cacheRefresher._running).toBe(false);
275
+ await cacheRefresher._callAndRefresh();
276
+ expect(count).toBe(1);
277
+ expect(cacheRefresher._running).toBe(false);
278
+ await cacheRefresher._safeCallAndRefresh();
279
+ expect(count).toBe(2);
280
+ expect(cacheRefresher._running).toBe(false);
281
+
282
+ cacheRefresher._running = true;
283
+ await cacheRefresher._safeCallAndRefresh();
284
+ expect(count).toBe(2); // should not have been called since already executing
285
+ })
286
+
287
+ it('Throw CampaignException when calling _callAndRefresh without logon', async () => {
288
+ const client = await Mock.makeClient();
289
+ const cache = new Cache();
290
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
291
+
292
+ try {
293
+ await cacheRefresher._callAndRefresh();
294
+ fail('exception is expected');
295
+ } catch (e) {
296
+ expect(e.name).toBe("CampaignException");
297
+ expect(e.errorCode).toBe("SDK-000010");
298
+ }
299
+ });
300
+
301
+ it('Ignore error when calling _safeCallAndRefresh without logon', async () => {
302
+ const client = await Mock.makeClient();
303
+ const cache = new Cache();
304
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
305
+
306
+ try {
307
+ await cacheRefresher._safeCallAndRefresh();
308
+ } catch (e) {
309
+ fail('exception is not expected');
310
+ }
311
+ });
312
+
313
+ it('Catch error in soap call GetModifiedEntities and display a warning', async () => {
314
+ const client = await Mock.makeClient();
315
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
316
+
317
+ await client.NLWS.xtkSession.logon();
318
+ const cache = new Cache();
319
+ const cacheRefresher = new CacheRefresher(cache, client, "xtk:schema", "rootkey");
320
+
321
+ client._transport.mockReturnValueOnce(Mock.GETMODIFIEDENTITIES_ERROR_RESPONSE);
322
+ try {
323
+ jest.useFakeTimers();
324
+ cacheRefresher.startAutoRefresh(5000);
325
+ jest.advanceTimersByTime(6000);
326
+ jest.useRealTimers();
327
+
328
+ // to allow soap call to finish
329
+ await new Promise(process.nextTick);
330
+ } catch (e) {
331
+ fail('exception is not expected');
332
+ }
333
+
334
+ cacheRefresher.stopAutoRefresh();
335
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
336
+ await client.NLWS.xtkSession.logoff();
337
+ });
338
+ });
@@ -30,13 +30,16 @@ describe('Caches', function() {
30
30
  it("Should cache with default TTL and default key function", () => {
31
31
  const cache = new Cache();
32
32
  cache.put("Hello", "World");
33
+ expect(cache._stats).toMatchObject({ reads: 0, writes: 1 });
33
34
  expect(cache.get("Hello")).toBe("World");
35
+ expect(cache._stats).toMatchObject({ reads: 1, writes: 1, memoryHits: 1, storageHits: 0 });
34
36
  })
35
37
 
36
38
  it("Should expires after TTL", () => {
37
39
  const cache = new Cache(undefined, undefined, -1); // negative TTL => will immediately expire
38
40
  cache.put("Hello", "World");
39
41
  expect(cache.get("Hello")).toBeUndefined();
42
+ expect(cache._stats).toMatchObject({ reads: 1, writes: 1, memoryHits: 0, storageHits: 0 });
40
43
  })
41
44
 
42
45
  it("Should support custom key function", () => {
@@ -53,8 +56,26 @@ describe('Caches', function() {
53
56
  expect(cache.get("Hello")).toBe("World");
54
57
  cache.clear();
55
58
  expect(cache.get("Hello")).toBeUndefined();
59
+ expect(cache._stats).toMatchObject({ reads: 2, writes: 1, memoryHits: 1, storageHits: 0, clears: 1 });
56
60
  })
57
- })
61
+
62
+ it("Should remove key in cache", () => {
63
+ const cache = new Cache();
64
+ cache.put("Hello", "World");
65
+ cache.put("Hi", "A");
66
+ expect(cache.get("Hello")).toBe("World");
67
+ expect(cache.get("Hi")).toBe("A");
68
+ expect(cache._stats).toMatchObject({ reads: 2, writes: 2, memoryHits: 2 });
69
+ cache.remove("Hello");
70
+ expect(cache.get("Hello")).toBeUndefined();
71
+ expect(cache.get("Hi")).toBe("A");
72
+ expect(cache._stats).toMatchObject({ reads: 4, writes: 2, memoryHits: 3, removals: 1 });
73
+ // should support removing a key which has already been removed
74
+ cache.remove("Hello");
75
+ expect(cache.get("Hello")).toBeUndefined();
76
+ expect(cache.get("Hi")).toBe("A");
77
+ })
78
+ });
58
79
 
59
80
  describe("Entity cache", function() {
60
81
  it("Should cache value", function() {