@adobe/acc-js-sdk 1.1.6 → 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/test/mock.js CHANGED
@@ -12,37 +12,37 @@ governing permissions and limitations under the License.
12
12
 
13
13
 
14
14
  /**********************************************************************************
15
- *
15
+ *
16
16
  * Mock functions for unit tests
17
- *
17
+ *
18
18
  *********************************************************************************/
19
- const sdk = require('../src/index.js');
20
- const crypto = require("crypto");
21
-
22
- const makeKey = () => {
23
- const a = [];
24
- for (let i=0; i<32; i++) {
25
- a.push(Math.floor(crypto.randomInt(0, 256)));
26
- }
27
- const buffer = Buffer.from(a);
28
- const s = buffer.toString('base64');
29
- return s;
30
- }
31
-
32
- async function makeAnonymousClient(options) {
33
- const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080", options);
34
- const client = await sdk.init(connectionParameters);
35
- if (!options || !options.transport) // allow tests to explicitely set the transport
36
- client._transport = jest.fn();
37
- return client;
19
+ const sdk = require('../src/index.js');
20
+ const crypto = require("crypto");
21
+
22
+ const makeKey = () => {
23
+ const a = [];
24
+ for (let i=0; i<32; i++) {
25
+ a.push(Math.floor(crypto.randomInt(0, 256)));
26
+ }
27
+ const buffer = Buffer.from(a);
28
+ const s = buffer.toString('base64');
29
+ return s;
30
+ }
31
+
32
+ async function makeAnonymousClient(options) {
33
+ const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080", options);
34
+ const client = await sdk.init(connectionParameters);
35
+ if (!options || !options.transport) // allow tests to explicitely set the transport
36
+ client._transport = jest.fn();
37
+ return client;
38
38
  }
39
39
 
40
40
  async function makeClient(options) {
41
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", options);
42
- const client = await sdk.init(connectionParameters);
43
- if (!options || !options.transport) // allow tests to explicitely set the transport
44
- client._transport = jest.fn();
45
- return client;
41
+ const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", options);
42
+ const client = await sdk.init(connectionParameters);
43
+ if (!options || !options.transport) // allow tests to explicitely set the transport
44
+ client._transport = jest.fn();
45
+ return client;
46
46
  }
47
47
 
48
48
  /**
@@ -51,16 +51,16 @@ async function makeClient(options) {
51
51
  * @returns an array of logged messages
52
52
  */
53
53
  async function withMockConsole(fn) {
54
- const logs = [];
55
- jest.spyOn(console, 'log').mockImplementation((message) => {
56
- logs.push(message);
57
- });
58
- try {
59
- await fn();
60
- return logs;
61
- } finally {
62
- console.log.mockRestore();
63
- }
54
+ const logs = [];
55
+ jest.spyOn(console, 'log').mockImplementation((message) => {
56
+ logs.push(message);
57
+ });
58
+ try {
59
+ await fn();
60
+ return logs;
61
+ } finally {
62
+ console.log.mockRestore();
63
+ }
64
64
  }
65
65
 
66
66
  const R_TEST = Promise.resolve(`<redir status='OK' date='2021-08-27 08:02:07.963-07' build='9236' sha1='cc45440' instance='xxx_mkt_prod1' sourceIP='193.104.215.11' host='xxxol.campaign.adobe.com' localHost='xxxol-mkt-prod1-1'/>`);
@@ -91,7 +91,7 @@ const LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
91
91
  </SOAP-ENV:Body>
92
92
  </SOAP-ENV:Envelope>`);
93
93
 
94
- const BEARER_LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
94
+ const BEARER_LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
95
95
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
96
96
  <SOAP-ENV:Body>
97
97
  <BearerTokenLogonResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
@@ -302,7 +302,7 @@ const GET_XTK_QUERY_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
302
302
  </SOAP-ENV:Envelope>`);
303
303
 
304
304
  const GET_MID_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
305
- return Promise.resolve(`<?xml version='1.0'?>
305
+ return Promise.resolve(`<?xml version='1.0'?>
306
306
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:queryDef' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
307
307
  <SOAP-ENV:Body>
308
308
  <ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
@@ -315,7 +315,7 @@ const GET_MID_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
315
315
  }
316
316
 
317
317
  const GET_BAD_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
318
- return Promise.resolve(`<?xml version='1.0'?>
318
+ return Promise.resolve(`<?xml version='1.0'?>
319
319
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:queryDef' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
320
320
  <SOAP-ENV:Body>
321
321
  <ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
@@ -328,7 +328,7 @@ const GET_BAD_EXT_ACCOUNT_RESPONSE = (encryptedPassword) => {
328
328
  }
329
329
 
330
330
  const GET_SECRET_KEY_OPTION_RESPONSE = (key) => {
331
- return Promise.resolve(`<?xml version='1.0'?>
331
+ return Promise.resolve(`<?xml version='1.0'?>
332
332
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
333
333
  <SOAP-ENV:Body>
334
334
  <GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
@@ -354,7 +354,7 @@ const GET_LOGON_MID_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
354
354
  </LogonResponse>
355
355
  </SOAP-ENV:Body>
356
356
  </SOAP-ENV:Envelope>`);
357
-
357
+
358
358
  const GET_TSTCNX_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
359
359
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
360
360
  <SOAP-ENV:Body>
@@ -432,7 +432,7 @@ const GET_XTK_ALL_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
432
432
  </GetEntityIfMoreRecentResponse>
433
433
  </SOAP-ENV:Body>
434
434
  </SOAP-ENV:Envelope>`);
435
-
435
+
436
436
  const GET_XTK_ALL_TYPES_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
437
437
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
438
438
  <SOAP-ENV:Body>
@@ -473,7 +473,7 @@ const GET_USER_INFO_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
473
473
  </pUserInfo>
474
474
  </GetUserInfoResponse>
475
475
  </SOAP-ENV:Body>
476
- </SOAP-ENV:Envelope>`);
476
+ </SOAP-ENV:Envelope>`);
477
477
 
478
478
  const GET_MISSING_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
479
479
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
@@ -483,8 +483,8 @@ const GET_MISSING_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
483
483
  </pdomDoc>
484
484
  </GetEntityIfMoreRecentResponse>
485
485
  </SOAP-ENV:Body>
486
- </SOAP-ENV:Envelope>`);
487
-
486
+ </SOAP-ENV:Envelope>`);
487
+
488
488
  const GET_XTK_WORKFLOW_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
489
489
  <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
490
490
  <SOAP-ENV:Body>
@@ -635,6 +635,114 @@ const GETMODIFIEDENTITIES_CLEAR_RESPONSE = Promise.resolve(`<?xml version='1.0'?
635
635
  </GetModifiedEntitiesResponse>
636
636
  </SOAP-ENV:Body>
637
637
  </SOAP-ENV:Envelope>`);
638
+ const GET_XTK_COUNTER_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
639
+ <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
640
+ <SOAP-ENV:Body>
641
+ <GetEntityIfMoreRecentResponse xmlns='urn:wpp:default' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
642
+ <pdomDoc xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
643
+ <schema name="counter" namespace="xtk" xtkschema="xtk:schema">
644
+ <element name="counter"></element>
645
+ <methods>
646
+ <method name="IncreaseValue" static="true">
647
+ <parameters>
648
+ <param name="name" type="string" label="Name" desc="Counter name"/>
649
+ <param name="value" type="long" inout="out" label="Value" desc="New value of counter"/>
650
+ </parameters>
651
+ </method>
652
+ </methods>
653
+ </schema>
654
+ </pdomDoc>
655
+ </GetEntityIfMoreRecentResponse>
656
+ </SOAP-ENV:Body>
657
+ </SOAP-ENV:Envelope>`);
658
+
659
+ const GET_FILERES_QUERY_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
660
+ <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
661
+ <SOAP-ENV:Body>
662
+ <GetEntityIfMoreRecentResponse xmlns='urn:wpp:default' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
663
+ <pdomDoc xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
664
+ <schema name="fileRes" namespace="xtk" xtkschema="xtk:schema">
665
+ <element name="fileRes"></element>
666
+ <methods>
667
+ <method name="PublishIfNeeded">
668
+ </method>
669
+ <method name="GetURL">
670
+ <parameters>
671
+ <param name="url" type="string" inout="out"/>
672
+ </parameters>
673
+ </method>
674
+ </methods>
675
+ </schema>
676
+ </pdomDoc>
677
+ </GetEntityIfMoreRecentResponse>
678
+ </SOAP-ENV:Body>
679
+ </SOAP-ENV:Envelope>`);
680
+
681
+ const INCREASE_VALUE_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
682
+ <SOAP-ENV:Envelope
683
+ xmlns:xsd='http://www.w3.org/2001/XMLSchema'
684
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
685
+ xmlns:ns='urn:xtk:counter'
686
+ xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
687
+ <SOAP-ENV:Body>
688
+ <IncreaseValueResponse
689
+ xmlns='urn:xtk:counter' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
690
+ <plValue xsi:type='xsd:int'>1</plValue>
691
+ </IncreaseValueResponse>
692
+ </SOAP-ENV:Body>
693
+ </SOAP-ENV:Envelope>
694
+
695
+ `);
696
+
697
+ const FILE_RES_WRITE_RESPONSE = Promise.resolve(`<?xml version='1.0'?><SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:wpp:default' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'><SOAP-ENV:Body><GetEntityIfMoreRecentResponse xmlns='urn:wpp:default' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'><pdomDoc xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'><schema _cs="Sessions to the application server (xtk)" created="2022-02-03 12:55:02.621Z" createdBy-id="0" dependingSchemas="" desc="Sessions to the application server" entitySchema="xtk:schema" img="" implements="xtk:persist" label="Sessions to the application server" labelSingular="Session" lastModified="2022-07-11 02:29:30.026Z" library="true" mappingType="xmlFile" md5="9D716FE59E174E87C5BA8A834DD4B11B" modifiedBy-id="0" name="session" namespace="xtk" xtkschema="xtk:schema">
698
+
699
+ <interface async="true" label="Persistence" name="persist">
700
+ <method name="Write" static="true">
701
+ <help>Update an entity</help>
702
+ <parameters>
703
+ <param desc="Document of difference" name="doc" type="DOMDocument"/>
704
+ </parameters>
705
+ <example><para>A simple recipient creation:</para>
706
+ \t <programlisting>
707
+ xtk.session.Write(
708
+ {recipient: {xtkschema: "nms:recipient", firstName: "Raul", lastName: "Endymion"}})
709
+ \t</programlisting>
710
+ </example>
711
+ </method>
712
+ </interface>
713
+
714
+ </schema></pdomDoc></GetEntityIfMoreRecentResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
715
+
716
+ `);
717
+
718
+ const PUBLISH_IF_NEEDED_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
719
+ <SOAP-ENV:Envelope
720
+ xmlns:xsd='http://www.w3.org/2001/XMLSchema'
721
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
722
+ xmlns:ns='urn:xtk:fileRes'
723
+ xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
724
+ <SOAP-ENV:Body>
725
+ <PublishIfNeededResponse
726
+ xmlns='urn:xtk:fileRes' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
727
+ </PublishIfNeededResponse>
728
+ </SOAP-ENV:Body>
729
+ </SOAP-ENV:Envelope>`);
730
+
731
+ const GET_URL_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
732
+ <SOAP-ENV:Envelope
733
+ xmlns:xsd='http://www.w3.org/2001/XMLSchema'
734
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
735
+ xmlns:ns='urn:xtk:fileRes'
736
+ xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
737
+ <SOAP-ENV:Body>
738
+ <GetURLResponse
739
+ xmlns='urn:xtk:fileRes' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
740
+ <pUrl xsi:type='xsd:string'>http://hello.com</pUrl>
741
+ </GetURLResponse>
742
+ </SOAP-ENV:Body>
743
+ </SOAP-ENV:Envelope>`);
744
+
745
+
638
746
 
639
747
 
640
748
  const GETMODIFIEDENTITIES_SCHEMA_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
@@ -721,5 +829,11 @@ exports.Mock = {
721
829
  GETMODIFIEDENTITIES_CLEAR_RESPONSE: GETMODIFIEDENTITIES_CLEAR_RESPONSE,
722
830
  GETMODIFIEDENTITIES_SCHEMA_RESPONSE: GETMODIFIEDENTITIES_SCHEMA_RESPONSE,
723
831
  GETMODIFIEDENTITIES_UNDEFINED_RESPONSE: GETMODIFIEDENTITIES_UNDEFINED_RESPONSE,
724
- GETMODIFIEDENTITIES_ERROR_RESPONSE: GETMODIFIEDENTITIES_ERROR_RESPONSE
832
+ GETMODIFIEDENTITIES_ERROR_RESPONSE: GETMODIFIEDENTITIES_ERROR_RESPONSE,
833
+ GET_XTK_COUNTER_RESPONSE: GET_XTK_COUNTER_RESPONSE,
834
+ GET_FILERES_QUERY_SCHEMA_RESPONSE: GET_FILERES_QUERY_SCHEMA_RESPONSE,
835
+ INCREASE_VALUE_RESPONSE: INCREASE_VALUE_RESPONSE,
836
+ FILE_RES_WRITE_RESPONSE: FILE_RES_WRITE_RESPONSE,
837
+ PUBLISH_IF_NEEDED_RESPONSE: PUBLISH_IF_NEEDED_RESPONSE,
838
+ GET_URL_RESPONSE: GET_URL_RESPONSE
725
839
  }
@@ -0,0 +1,267 @@
1
+ /*
2
+ Copyright 2020 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 ACC client observability hooks
17
+ *
18
+ *********************************************************************************/
19
+ const sdk = require('../src/index.js');
20
+ const Mock = require('./mock.js').Mock;
21
+
22
+ const makeObservableClient = async(options, callback) => {
23
+ // No TTL for option cache so that we can test that we send cache stats every 5 mins
24
+ const client = await Mock.makeClient({ ...options, optionCacheTTL: 999999000 });
25
+ return [client, new ObservabilityAssertion(client, callback)];
26
+ }
27
+
28
+ class ObservabilityAssertion {
29
+ constructor(client, callback) {
30
+ const that = this;
31
+ this._callback = callback;
32
+ client.registerObserver({
33
+ event: (event, parentEvent) => { return that.onEvent(event, parentEvent); },
34
+ });
35
+ this._eventsByName = {};
36
+ }
37
+
38
+ onEvent(event, parentEvent) {
39
+ if (!this._eventsByName[event.eventName]) this._eventsByName[event.eventName] = [];
40
+ this._eventsByName[event.eventName].push({ event: event, parentEvent: parentEvent });
41
+ if (this._callback) this._callback.call(this, event, parentEvent);
42
+ }
43
+
44
+ hasObserved(eventName) {
45
+ if (!this._eventsByName[eventName]) return false;
46
+ return this._eventsByName[eventName].length > 0;
47
+ }
48
+
49
+ getFirstObserved(eventName) {
50
+ if (!this._eventsByName[eventName]) return;
51
+ return this._eventsByName[eventName][0];
52
+ }
53
+
54
+ getObserved(eventName) {
55
+ if (!this._eventsByName[eventName]) [];
56
+ return this._eventsByName[eventName].filter(o => o.event.eventName === eventName).map(o => o.event);
57
+ }
58
+ }
59
+
60
+ describe('ACC Client Observability', function () {
61
+
62
+ it('Should observe logon and logoff', async function () {
63
+ const [client, assertion] = await makeObservableClient();
64
+
65
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
66
+ await client.NLWS.xtkSession.logon();
67
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
68
+ expect(assertion.hasObserved("SDK//logoff")).toBe(false);;
69
+ const logon = assertion.getFirstObserved("SDK//logon");
70
+ expect(logon.parentEvent).toBeUndefined();
71
+ expect(logon.event).toMatchObject({ eventId: 1, eventName: "SDK//logon" });
72
+ expect(logon.event.timestamp).toBeGreaterThan(0);
73
+
74
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
75
+ await client.NLWS.xtkSession.logoff();
76
+ expect(assertion.hasObserved("SDK//logoff")).toBe(true);
77
+ const logoff = assertion.getFirstObserved("SDK//logoff");
78
+ expect(logoff.event).toMatchObject({ eventName: "SDK//logoff" });
79
+ expect(logoff.event.eventId).toBeGreaterThan(1);
80
+ expect(logoff.event.timestamp).toBeGreaterThanOrEqual(logon.event.timestamp);
81
+
82
+ // there should not be an auto refresh event if auto-refresh mechanism
83
+ // is off
84
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(false);
85
+ });
86
+
87
+ it('Should ignore exceptions throws from observer', async () => {
88
+ const [client, assertion] = await makeObservableClient({}, (event, parentEvent) => {
89
+ throw new Error("Simulated failure in observer");
90
+ });
91
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
92
+ // logon will send an observability event, but the error will be logged and ignored
93
+ await client.NLWS.xtkSession.logon();
94
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
95
+ });
96
+
97
+ it('Should send internal stats every 5 minutes', async () => {
98
+ jest.useFakeTimers();
99
+ const [client, assertion] = await makeObservableClient();
100
+
101
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
102
+ await client.NLWS.xtkSession.logon();
103
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
104
+
105
+ // Calling get option should generate some cache hits
106
+ client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
107
+ client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
108
+ var databaseId = await client.getOption("XtkDatabaseId");
109
+ expect(databaseId).toBe("uFE80000000000000F1FA913DD7CC7C480041161C");
110
+
111
+ jest.advanceTimersByTime(310000);
112
+ client._trackEvent("TEST/dummy", undefined, {});
113
+ // Note: options cache is written twice: once in the SOAP call itself, and once by the getOption method
114
+ // entity cache is also written twice: once for xtk:session and once from xtk:persist
115
+ expect(assertion.getObserved("CACHE//stats")).toEqual(expect.arrayContaining(
116
+ [
117
+ expect.objectContaining({ payload: { name: 'entityCache', clears: 0, loads: 1, memoryHits: 0, reads: 1, removals: 0, saves: 2, storageHits: 0, writes: 2 } }),
118
+ expect.objectContaining({ payload: { name: 'optionCache', clears: 0, loads: 1, memoryHits: 0, reads: 1, removals: 0, saves: 2, storageHits: 0, writes: 2 } }),
119
+ ]
120
+ ));
121
+
122
+ // Calling get option again should make a cache hit
123
+ // Only work if options cache TTL is very high
124
+ databaseId = await client.getOption("XtkDatabaseId");
125
+ expect(databaseId).toBe("uFE80000000000000F1FA913DD7CC7C480041161C");
126
+ jest.advanceTimersByTime(310000);
127
+ client._trackEvent("TEST/dummy", undefined, {});
128
+ expect(assertion.getObserved("CACHE//stats")).toEqual(expect.arrayContaining(
129
+ [
130
+ expect.objectContaining({ payload: { name: 'entityCache', clears: 0, loads: 1, memoryHits: 0, reads: 1, removals: 0, saves: 2, storageHits: 0, writes: 2 } }),
131
+ expect.objectContaining({ payload: { name: 'optionCache', clears: 0, loads: 1, memoryHits: 1, reads: 2, removals: 0, saves: 2, storageHits: 0, writes: 2 } }),
132
+ ]
133
+ ));
134
+
135
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
136
+ await client.NLWS.xtkSession.logoff();
137
+ expect(assertion.hasObserved("SDK//logoff")).toBe(true);
138
+
139
+ jest.useRealTimers();
140
+ });
141
+
142
+ it('_trackCacheStats should support cache with no stats', async () => {
143
+ const [client, assertion] = await makeObservableClient();
144
+ client._trackEvent = jest.fn();
145
+ client._trackCacheStats('hello', undefined);
146
+ expect(client._trackEvent.mock.calls.length).toBe(0);
147
+ client._trackCacheStats('hello', {});
148
+ expect(client._trackEvent.mock.calls.length).toBe(0);
149
+ client._trackCacheStats('hello', { _stats: {} });
150
+ expect(client._trackEvent.mock.calls.length).toBe(1);
151
+ });
152
+
153
+ it('Should track SOAP calls', async () => {
154
+ const [client, assertion] = await makeObservableClient();
155
+
156
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
157
+ await client.NLWS.xtkSession.logon();
158
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
159
+
160
+ // Calling get option should generate some cache hits
161
+ client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
162
+ client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
163
+ var databaseId = await client.getOption("XtkDatabaseId");
164
+ expect(databaseId).toBe("uFE80000000000000F1FA913DD7CC7C480041161C");
165
+ const requests = assertion.getObserved("SOAP//request");
166
+ expect(requests.length).toBe(3);
167
+ expect(requests[0].payload).toMatchObject({ internal: false, urn: 'xtk:session', methodName: 'Logon', retry: false, retryCount: 0 });
168
+ expect(requests[1].payload).toMatchObject({ internal: true, urn: 'xtk:persist', methodName: 'GetEntityIfMoreRecent', retry: false, retryCount: 0 });
169
+ expect(requests[2].payload).toMatchObject({ internal: false, urn: 'xtk:session', methodName: 'GetOption', retry: false, retryCount: 0 });
170
+
171
+ const responses = assertion.getObserved("SOAP//response");
172
+ expect(responses.length).toBe(3);
173
+ expect(responses[0].payload).toMatchObject({ });
174
+ expect(responses[1].payload).toMatchObject({ });
175
+ expect(responses[2].payload).toMatchObject({ });
176
+ });
177
+
178
+ it('Should track caches auto-refresh (error in GetModifiedEntities API)', async () => {
179
+ jest.useFakeTimers();
180
+ const [client, assertion] = await makeObservableClient();
181
+
182
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
183
+ await client.NLWS.xtkSession.logon();
184
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
185
+
186
+ client.startRefreshCaches();
187
+ expect(assertion.hasObserved("CACHE_REFRESHER//start")).toBe(true);
188
+ const start = assertion.getFirstObserved("CACHE_REFRESHER//start");
189
+ expect(start.event).toMatchObject({ eventName:"CACHE_REFRESHER//start", payload:{ cacheSchemaId: "xtk:option", refreshFrequency: 10000 } });
190
+
191
+ // No mock implementation => the API call to get modified entities will fail generating a CACHE_REFRESHER//error event
192
+ await client._optionCacheRefresher._safeCallAndRefresh();
193
+ expect(assertion.hasObserved("CACHE_REFRESHER//tick")).toBe(true);
194
+ const tick = assertion.getFirstObserved("CACHE_REFRESHER//tick");
195
+ expect(tick.event).toMatchObject({ eventName:"CACHE_REFRESHER//tick", payload:{ cacheSchemaId: "xtk:option" } });
196
+ expect(assertion.hasObserved("CACHE_REFRESHER//error")).toBe(true);
197
+ const error = assertion.getFirstObserved("CACHE_REFRESHER//error");
198
+ expect(error.event).toMatchObject({ eventName:"CACHE_REFRESHER//error", payload:{ cacheSchemaId: "xtk:option" } });
199
+ // An error in the API should not stop the auto-refresh mechanism
200
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(false);
201
+
202
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
203
+ await client.NLWS.xtkSession.logoff();
204
+ expect(assertion.hasObserved("SDK//logoff")).toBe(true);
205
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(true);
206
+ jest.useRealTimers();
207
+ });
208
+
209
+ it('Should track caches auto-refresh (success in GetModifiedEntities API)', async () => {
210
+ jest.useFakeTimers();
211
+ const [client, assertion] = await makeObservableClient();
212
+
213
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
214
+ await client.NLWS.xtkSession.logon();
215
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
216
+
217
+ client.startRefreshCaches();
218
+ expect(assertion.hasObserved("CACHE_REFRESHER//start")).toBe(true);
219
+ const start = assertion.getFirstObserved("CACHE_REFRESHER//start");
220
+ expect(start.event).toMatchObject({ eventName:"CACHE_REFRESHER//start", payload:{ cacheSchemaId: "xtk:option", refreshFrequency: 10000 } });
221
+
222
+ client._transport.mockReturnValue(Promise.resolve(Mock.GETMODIFIEDENTITIES_RESPONSE));
223
+ await client._optionCacheRefresher._safeCallAndRefresh();
224
+ expect(assertion.hasObserved("CACHE_REFRESHER//tick")).toBe(true);
225
+ const tick = assertion.getFirstObserved("CACHE_REFRESHER//tick");
226
+ expect(tick.event).toMatchObject({ eventName:"CACHE_REFRESHER//tick", payload:{ cacheSchemaId: "xtk:option" } });
227
+ expect(assertion.hasObserved("CACHE_REFRESHER//error")).toBe(false);
228
+ expect(assertion.hasObserved("CACHE_REFRESHER//abort")).toBe(false);
229
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(false);
230
+
231
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
232
+ await client.NLWS.xtkSession.logoff();
233
+ expect(assertion.hasObserved("SDK//logoff")).toBe(true);
234
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(true);
235
+ jest.useRealTimers();
236
+ });
237
+
238
+ it('Should track caches auto-refresh (GetModifiedEntities API missing)', async () => {
239
+ jest.useFakeTimers();
240
+ const [client, assertion] = await makeObservableClient();
241
+
242
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
243
+ await client.NLWS.xtkSession.logon();
244
+ expect(assertion.hasObserved("SDK//logon")).toBe(true);
245
+
246
+ client.startRefreshCaches();
247
+ expect(assertion.hasObserved("CACHE_REFRESHER//start")).toBe(true);
248
+ const start = assertion.getFirstObserved("CACHE_REFRESHER//start");
249
+ expect(start.event).toMatchObject({ eventName:"CACHE_REFRESHER//start", payload:{ cacheSchemaId: "xtk:option", refreshFrequency: 10000 } });
250
+
251
+ client._transport.mockReturnValue(Promise.resolve(Mock.GETMODIFIEDENTITIES_UNDEFINED_RESPONSE));
252
+ await client._optionCacheRefresher._safeCallAndRefresh();
253
+ expect(assertion.hasObserved("CACHE_REFRESHER//tick")).toBe(true);
254
+ const tick = assertion.getFirstObserved("CACHE_REFRESHER//tick");
255
+ expect(tick.event).toMatchObject({ eventName:"CACHE_REFRESHER//tick", payload:{ cacheSchemaId: "xtk:option" } });
256
+ expect(assertion.hasObserved("CACHE_REFRESHER//error")).toBe(false);
257
+ // Should send an abort event and stop the auto-refresher
258
+ expect(assertion.hasObserved("CACHE_REFRESHER//abort")).toBe(true);
259
+ expect(assertion.hasObserved("CACHE_REFRESHER//stop")).toBe(true);
260
+
261
+ client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
262
+ await client.NLWS.xtkSession.logoff();
263
+ jest.useRealTimers();
264
+ });
265
+
266
+ });
267
+