@adobe/acc-js-sdk 1.0.2 → 1.0.6
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/.vscode/launch.json +0 -1
- package/CHANGELOG.md +31 -1
- package/README.md +96 -3
- package/compile.js +2 -0
- package/package-lock.json +1084 -825
- package/package.json +8 -4
- package/samples/000 - basics - logon.js +9 -0
- package/src/application.js +11 -5
- package/src/cache.js +275 -0
- package/src/campaign.js +31 -22
- package/src/client.js +234 -130
- package/src/crypto.js +5 -2
- package/src/domUtil.js +53 -20
- package/src/entityAccessor.js +4 -2
- package/src/index.js +124 -84
- package/src/methodCache.js +55 -46
- package/src/optionCache.js +40 -28
- package/src/soap.js +20 -9
- package/src/transport.js +12 -8
- package/src/util.js +103 -64
- package/src/xtkCaster.js +9 -6
- package/src/xtkEntityCache.js +42 -24
- package/test/caches.test.js +214 -14
- package/test/client.test.js +342 -20
- package/test/domUtil.test.js +23 -0
- package/test/index.test.js +15 -0
- package/test/mock.js +28 -4
- package/test/soap.test.js +17 -3
- package/test/util.test.js +151 -1
package/test/client.test.js
CHANGED
|
@@ -27,7 +27,6 @@ const { HttpError } = require('../src/transport.js');
|
|
|
27
27
|
describe('ACC Client', function () {
|
|
28
28
|
|
|
29
29
|
describe('Init', function () {
|
|
30
|
-
|
|
31
30
|
it('Should create client', async function () {
|
|
32
31
|
const client = await Mock.makeClient();
|
|
33
32
|
const NLWS = client.NLWS;
|
|
@@ -1193,13 +1192,13 @@ describe('ACC Client', function () {
|
|
|
1193
1192
|
|
|
1194
1193
|
it("from default representation", async () => {
|
|
1195
1194
|
const client = await Mock.makeClient();
|
|
1196
|
-
var xml = DomUtil.toXMLString(client.
|
|
1195
|
+
var xml = DomUtil.toXMLString(client._fromRepresentation("root", {}));
|
|
1197
1196
|
expect(xml).toBe("<root/>");
|
|
1198
1197
|
})
|
|
1199
1198
|
|
|
1200
1199
|
it("from SimpleJson representation", async () => {
|
|
1201
1200
|
const client = await Mock.makeClient();
|
|
1202
|
-
var xml = DomUtil.toXMLString(client.
|
|
1201
|
+
var xml = DomUtil.toXMLString(client._fromRepresentation("root", {}, "SimpleJson"));
|
|
1203
1202
|
expect(xml).toBe("<root/>");
|
|
1204
1203
|
})
|
|
1205
1204
|
|
|
@@ -1208,14 +1207,14 @@ describe('ACC Client', function () {
|
|
|
1208
1207
|
it("Should convert from BadgerFish to BadgerFish", async () => {
|
|
1209
1208
|
const client = await Mock.makeClient();
|
|
1210
1209
|
var from = { "@id": "1", "child": {} };
|
|
1211
|
-
var to = client.
|
|
1210
|
+
var to = client._convertToRepresentation(from, "BadgerFish", "BadgerFish");
|
|
1212
1211
|
expect(to).toStrictEqual(from);
|
|
1213
1212
|
})
|
|
1214
1213
|
|
|
1215
1214
|
it("Should convert from BadgerFish to SimpleJson", async () => {
|
|
1216
1215
|
const client = await Mock.makeClient();
|
|
1217
1216
|
var from = { "@id": "1", "child": {} };
|
|
1218
|
-
var to = client.
|
|
1217
|
+
var to = client._convertToRepresentation(from, "BadgerFish", "SimpleJson");
|
|
1219
1218
|
expect(to).toStrictEqual({ id: "1", child: {} });
|
|
1220
1219
|
})
|
|
1221
1220
|
|
|
@@ -1224,20 +1223,20 @@ describe('ACC Client', function () {
|
|
|
1224
1223
|
|
|
1225
1224
|
it("Compare representations", async () => {
|
|
1226
1225
|
const client = await Mock.makeClient();
|
|
1227
|
-
expect(() => { client.
|
|
1228
|
-
expect(() => { client.
|
|
1229
|
-
expect(() => { client.
|
|
1230
|
-
expect(client.
|
|
1231
|
-
expect(client.
|
|
1232
|
-
expect(client.
|
|
1233
|
-
expect(client.
|
|
1234
|
-
expect(client.
|
|
1235
|
-
expect(() => { client.
|
|
1236
|
-
expect(() => { client.
|
|
1237
|
-
expect(() => { client.
|
|
1238
|
-
expect(() => { client.
|
|
1239
|
-
expect(() => { client.
|
|
1240
|
-
expect(() => { client.
|
|
1226
|
+
expect(() => { client._isSameRepresentation("json", "json") }).toThrow("SDK-000004");
|
|
1227
|
+
expect(() => { client._isSameRepresentation("json", "BadgerFish") }).toThrow("SDK-000004");
|
|
1228
|
+
expect(() => { client._isSameRepresentation("BadgerFish", "json") }).toThrow("SDK-000004");
|
|
1229
|
+
expect(client._isSameRepresentation("SimpleJson", "SimpleJson")).toBeTruthy();
|
|
1230
|
+
expect(client._isSameRepresentation("BadgerFish", "SimpleJson")).toBeFalsy();
|
|
1231
|
+
expect(client._isSameRepresentation("SimpleJson", "BadgerFish")).toBeFalsy();
|
|
1232
|
+
expect(client._isSameRepresentation("xml", "BadgerFish")).toBeFalsy();
|
|
1233
|
+
expect(client._isSameRepresentation("SimpleJson", "xml")).toBeFalsy();
|
|
1234
|
+
expect(() => { client._isSameRepresentation("Xml", "Xml") }).toThrow("SDK-000004");
|
|
1235
|
+
expect(() => { client._isSameRepresentation("xml", "Xml") }).toThrow("SDK-000004");
|
|
1236
|
+
expect(() => { client._isSameRepresentation("Xml", "xml") }).toThrow("SDK-000004");
|
|
1237
|
+
expect(() => { client._isSameRepresentation("", "xml") }).toThrow("SDK-000004");
|
|
1238
|
+
expect(() => { client._isSameRepresentation("xml", "") }).toThrow("SDK-000004");
|
|
1239
|
+
expect(() => { client._isSameRepresentation("xml", null) }).toThrow("SDK-000004");
|
|
1241
1240
|
})
|
|
1242
1241
|
});
|
|
1243
1242
|
|
|
@@ -1310,7 +1309,7 @@ describe('ACC Client', function () {
|
|
|
1310
1309
|
|
|
1311
1310
|
it("User agent string", async () => {
|
|
1312
1311
|
const client = await Mock.makeClient();
|
|
1313
|
-
const ua = client.
|
|
1312
|
+
const ua = client._getUserAgentString();
|
|
1314
1313
|
expect(ua.startsWith("@adobe/acc-js-sdk/")).toBeTruthy();
|
|
1315
1314
|
expect(ua.endsWith(" ACC Javascript SDK")).toBeTruthy();
|
|
1316
1315
|
})
|
|
@@ -1877,4 +1876,327 @@ describe('ACC Client', function () {
|
|
|
1877
1876
|
expect(calls[0][0].data).toMatch("Logon");
|
|
1878
1877
|
});
|
|
1879
1878
|
})
|
|
1879
|
+
|
|
1880
|
+
describe("Security token authentication", () => {
|
|
1881
|
+
// Security token authentication is used when embedding the SDK in Campaign: the session token
|
|
1882
|
+
// is provided by the browser as a cookie. The cookie is not readable by JavaScript code and
|
|
1883
|
+
// should be passed automatically by the browser, not by the SDK
|
|
1884
|
+
it("Should create logged client", async() => {
|
|
1885
|
+
const connectionParameters = sdk.ConnectionParameters.ofSecurityToken("http://acc-sdk:8080", "$security_token$");
|
|
1886
|
+
const client = await sdk.init(connectionParameters);
|
|
1887
|
+
client._transport = jest.fn();
|
|
1888
|
+
expect(client.isLogged()).toBeFalsy();
|
|
1889
|
+
await client.logon();
|
|
1890
|
+
expect(client.isLogged()).toBeTruthy();
|
|
1891
|
+
const logoff = client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
|
|
1892
|
+
await client.logoff();
|
|
1893
|
+
expect(client.isLogged()).toBeFalsy();
|
|
1894
|
+
// Ensure logoff has been called
|
|
1895
|
+
expect(logoff.mock.calls.length).toBe(1);
|
|
1896
|
+
})
|
|
1897
|
+
})
|
|
1898
|
+
|
|
1899
|
+
describe("Bearer token authentication", () => {
|
|
1900
|
+
// Bearer token authentication is used when embedding IMS for authentication
|
|
1901
|
+
it("Should create logged client", async() => {
|
|
1902
|
+
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080", "$token$");
|
|
1903
|
+
const client = await sdk.init(connectionParameters);
|
|
1904
|
+
client._transport = jest.fn();
|
|
1905
|
+
client._transport.mockReturnValueOnce(Mock.BEARER_LOGON_RESPONSE);
|
|
1906
|
+
expect(client.isLogged()).toBeFalsy();
|
|
1907
|
+
await client.logon();
|
|
1908
|
+
expect(client.isLogged()).toBeTruthy();
|
|
1909
|
+
const transport = client._transport.mockReturnValueOnce(Mock.LOGOFF_RESPONSE);
|
|
1910
|
+
await client.logoff();
|
|
1911
|
+
expect(client.isLogged()).toBeFalsy();
|
|
1912
|
+
// Ensure logoff has been called
|
|
1913
|
+
expect(transport.mock.calls.length).toBe(2);
|
|
1914
|
+
})
|
|
1915
|
+
|
|
1916
|
+
it("Call SAOP method", async () => {
|
|
1917
|
+
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080", "$token$");
|
|
1918
|
+
const client = await sdk.init(connectionParameters);
|
|
1919
|
+
client._transport = jest.fn();
|
|
1920
|
+
client._transport.mockReturnValueOnce(Mock.BEARER_LOGON_RESPONSE);
|
|
1921
|
+
await client.logon();
|
|
1922
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_QUERY_SCHEMA_RESPONSE);
|
|
1923
|
+
var queryDef = {
|
|
1924
|
+
"schema": "nms:extAccount",
|
|
1925
|
+
"operation": "select",
|
|
1926
|
+
"select": {
|
|
1927
|
+
"node": [
|
|
1928
|
+
{ "expr": "@id" },
|
|
1929
|
+
{ "expr": "@name" }
|
|
1930
|
+
]
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
|
|
1934
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
1935
|
+
<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/'>
|
|
1936
|
+
<SOAP-ENV:Body>
|
|
1937
|
+
<ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
1938
|
+
<pdomOutput xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
1939
|
+
<extAccount-collection/>
|
|
1940
|
+
</pdomOutput></ExecuteQueryResponse>
|
|
1941
|
+
</SOAP-ENV:Body>
|
|
1942
|
+
</SOAP-ENV:Envelope>`));
|
|
1943
|
+
|
|
1944
|
+
// Select should return empty array
|
|
1945
|
+
var query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
1946
|
+
var extAccount = await query.executeQuery();
|
|
1947
|
+
expect(extAccount).toEqual({ extAccount: [] });
|
|
1948
|
+
});
|
|
1949
|
+
})
|
|
1950
|
+
|
|
1951
|
+
describe("Logon should always return a promise", () => {
|
|
1952
|
+
|
|
1953
|
+
it("Should return a promise with UserPassword", async () => {
|
|
1954
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "$user$", "$password$");
|
|
1955
|
+
const client = await sdk.init(connectionParameters);
|
|
1956
|
+
client._transport = jest.fn();
|
|
1957
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
1958
|
+
const result = client.logon();
|
|
1959
|
+
expect(result instanceof Promise).toBe(true);
|
|
1960
|
+
await result;
|
|
1961
|
+
})
|
|
1962
|
+
|
|
1963
|
+
it("Should return a promise with bearer token", async () => {
|
|
1964
|
+
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080", "$token$");
|
|
1965
|
+
const client = await sdk.init(connectionParameters);
|
|
1966
|
+
client._transport = jest.fn();
|
|
1967
|
+
client._transport.mockReturnValueOnce(Mock.BEARER_LOGON_RESPONSE);
|
|
1968
|
+
const result = client.logon();
|
|
1969
|
+
expect(result instanceof Promise).toBe(true);
|
|
1970
|
+
await result;
|
|
1971
|
+
})
|
|
1972
|
+
|
|
1973
|
+
it("Should return a promise with UserAndServiceToken", async () => {
|
|
1974
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndServiceToken("http://acc-sdk:8080", "$user$", "$service_token$");
|
|
1975
|
+
const client = await sdk.init(connectionParameters);
|
|
1976
|
+
client._transport = jest.fn();
|
|
1977
|
+
const result = client.logon();
|
|
1978
|
+
expect(result instanceof Promise).toBe(true);
|
|
1979
|
+
try {
|
|
1980
|
+
await result;
|
|
1981
|
+
} catch(ex) { /* result or exception is not handled */ }
|
|
1982
|
+
})
|
|
1983
|
+
|
|
1984
|
+
it("Should return a promise with SessionToken", async () => {
|
|
1985
|
+
const connectionParameters = sdk.ConnectionParameters.ofSessionToken("http://acc-sdk:8080", "$session_token$");
|
|
1986
|
+
const client = await sdk.init(connectionParameters);
|
|
1987
|
+
client._transport = jest.fn();
|
|
1988
|
+
const result = client.logon();
|
|
1989
|
+
expect(result instanceof Promise).toBe(true);
|
|
1990
|
+
await result;
|
|
1991
|
+
})
|
|
1992
|
+
|
|
1993
|
+
it("Should return a promise with SecurityToken", async () => {
|
|
1994
|
+
const connectionParameters = sdk.ConnectionParameters.ofSecurityToken("http://acc-sdk:8080", "$security_token$");
|
|
1995
|
+
const client = await sdk.init(connectionParameters);
|
|
1996
|
+
client._transport = jest.fn();
|
|
1997
|
+
const result = client.logon();
|
|
1998
|
+
expect(result instanceof Promise).toBe(true);
|
|
1999
|
+
await result;
|
|
2000
|
+
})
|
|
2001
|
+
|
|
2002
|
+
it("Should return a promise with AnonymousUser", async () => {
|
|
2003
|
+
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080");
|
|
2004
|
+
const client = await sdk.init(connectionParameters);
|
|
2005
|
+
client._transport = jest.fn();
|
|
2006
|
+
const result = client.logon();
|
|
2007
|
+
expect(result instanceof Promise).toBe(true);
|
|
2008
|
+
await result;
|
|
2009
|
+
})
|
|
2010
|
+
})
|
|
2011
|
+
|
|
2012
|
+
|
|
2013
|
+
describe("Should simulate server down", () => {
|
|
2014
|
+
it("Should simulate server down and up again", async () => {
|
|
2015
|
+
// Server is up and getOption
|
|
2016
|
+
const client = await Mock.makeClient();
|
|
2017
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2018
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
2019
|
+
await client.NLWS.xtkSession.logon();
|
|
2020
|
+
client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
|
|
2021
|
+
var databaseId = await client.getOption("XtkDatabaseId", false);
|
|
2022
|
+
expect(databaseId).toBe("uFE80000000000000F1FA913DD7CC7C480041161C");
|
|
2023
|
+
|
|
2024
|
+
// Now simulate a connection error (server is down)
|
|
2025
|
+
const error = new Error("connect ECONNREFUSED 3.225.73.178:8080");
|
|
2026
|
+
error.code="ECONNREFUSED";
|
|
2027
|
+
error.errno="ECONNREFUSED";
|
|
2028
|
+
client._transport.mockReturnValueOnce(Promise.reject(error));
|
|
2029
|
+
await expect(client.getOption("XtkDatabaseId", false)).rejects.toMatchObject({
|
|
2030
|
+
message: "500 - Error calling method 'xtk:session#GetOption': Error (connect ECONNREFUSED 3.225.73.178:8080)"
|
|
2031
|
+
});
|
|
2032
|
+
|
|
2033
|
+
// Server is back up again
|
|
2034
|
+
client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
|
|
2035
|
+
databaseId = await client.getOption("XtkDatabaseId", false);
|
|
2036
|
+
expect(databaseId).toBe("uFE80000000000000F1FA913DD7CC7C480041161C")
|
|
2037
|
+
});
|
|
2038
|
+
})
|
|
2039
|
+
|
|
2040
|
+
describe("Connection options", () => {
|
|
2041
|
+
it("Should set options cache TTL", async () => {
|
|
2042
|
+
const client = await Mock.makeClient({ optionCacheTTL: -1 });
|
|
2043
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2044
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
2045
|
+
await client.NLWS.xtkSession.logon();
|
|
2046
|
+
// Get Option and cache result. Check the value is in cache
|
|
2047
|
+
client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
|
|
2048
|
+
await client.getOption("XtkDatabaseId", true);
|
|
2049
|
+
expect(client._optionCache._cache["XtkDatabaseId"].value).toMatchObject({ type: 6, rawValue: "uFE80000000000000F1FA913DD7CC7C480041161C" });
|
|
2050
|
+
// Get it again, it should not use the cache (=> it should make a SOAP call)
|
|
2051
|
+
// To test if the SOAP call is made, we mock the SOAP call answer with a different result
|
|
2052
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2053
|
+
<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/'>
|
|
2054
|
+
<SOAP-ENV:Body>
|
|
2055
|
+
<GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
2056
|
+
<pstrValue xsi:type='xsd:string'>uFE80000000000000F1FA913DD7CC7C48004116FF</pstrValue>
|
|
2057
|
+
<pbtType xsi:type='xsd:byte'>6</pbtType>
|
|
2058
|
+
</GetOptionResponse>
|
|
2059
|
+
</SOAP-ENV:Body>
|
|
2060
|
+
</SOAP-ENV:Envelope>`));
|
|
2061
|
+
await client.getOption("XtkDatabaseId", true);
|
|
2062
|
+
expect(client._optionCache._cache["XtkDatabaseId"].value).toMatchObject({ type: 6, rawValue: "uFE80000000000000F1FA913DD7CC7C48004116FF" });
|
|
2063
|
+
})
|
|
2064
|
+
|
|
2065
|
+
it("Should set default value for traceAPICalls", async () => {
|
|
2066
|
+
var client = await Mock.makeClient({ traceAPICalls: undefined });
|
|
2067
|
+
expect(client._traceAPICalls).toBeFalsy();
|
|
2068
|
+
client = await Mock.makeClient({ traceAPICalls: null });
|
|
2069
|
+
expect(client._traceAPICalls).toBeFalsy();
|
|
2070
|
+
client = await Mock.makeClient({ traceAPICalls: false });
|
|
2071
|
+
expect(client._traceAPICalls).toBeFalsy();
|
|
2072
|
+
client = await Mock.makeClient({ traceAPICalls: true });
|
|
2073
|
+
expect(client._traceAPICalls).toBeTruthy();
|
|
2074
|
+
})
|
|
2075
|
+
|
|
2076
|
+
it("Should set default transport", async () => {
|
|
2077
|
+
var client = await Mock.makeClient({ transport: async () => {
|
|
2078
|
+
return "Hello";
|
|
2079
|
+
}});
|
|
2080
|
+
await expect(client._transport()).resolves.toBe("Hello");
|
|
2081
|
+
});
|
|
2082
|
+
})
|
|
2083
|
+
|
|
2084
|
+
|
|
2085
|
+
describe("Local storage", () => {
|
|
2086
|
+
it("Shoud read from local storage", async () => {
|
|
2087
|
+
const storage = {
|
|
2088
|
+
getItem: jest.fn(),
|
|
2089
|
+
setItem: jest.fn(),
|
|
2090
|
+
}
|
|
2091
|
+
const client = await Mock.makeClient({ storage: storage });
|
|
2092
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2093
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
2094
|
+
await client.NLWS.xtkSession.logon();
|
|
2095
|
+
storage.getItem.mockReturnValueOnce(JSON.stringify({value: { value: "Hello", type: 6 }, cachedAt: 1633715996021 }));
|
|
2096
|
+
const value = await client.getOption("XtkDatabaseId");
|
|
2097
|
+
expect(value).toBe("Hello");
|
|
2098
|
+
})
|
|
2099
|
+
|
|
2100
|
+
it("Should write to local storage", async () => {
|
|
2101
|
+
const storage = {
|
|
2102
|
+
getItem: jest.fn(),
|
|
2103
|
+
setItem: jest.fn(),
|
|
2104
|
+
}
|
|
2105
|
+
const client = await Mock.makeClient({ storage: storage });
|
|
2106
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2107
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
2108
|
+
await client.NLWS.xtkSession.logon();
|
|
2109
|
+
storage.getItem.mockReturnValueOnce(JSON.stringify({value: { value: "Hello", type: 6 }, cachedAt: 1633715996021 }));
|
|
2110
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2111
|
+
<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/'>
|
|
2112
|
+
<SOAP-ENV:Body>
|
|
2113
|
+
<WriteResponse xmlns='urn:wpp:default' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
2114
|
+
</WriteResponse>
|
|
2115
|
+
</SOAP-ENV:Body>
|
|
2116
|
+
</SOAP-ENV:Envelope>`));
|
|
2117
|
+
await client.setOption("XtkDatabaseId", "World");
|
|
2118
|
+
var call = undefined;
|
|
2119
|
+
for (var i=0; i<storage.setItem.mock.calls.length; i++) {
|
|
2120
|
+
if (storage.setItem.mock.calls[i][0].endsWith("OptionCache$XtkDatabaseId")) {
|
|
2121
|
+
call = storage.setItem.mock.calls[i];
|
|
2122
|
+
break;
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
expect(JSON.parse(call[1])).toMatchObject({
|
|
2126
|
+
value: { value: "World", type: 6 }
|
|
2127
|
+
})
|
|
2128
|
+
});
|
|
2129
|
+
|
|
2130
|
+
it("Should ignore protocol for local storage root key", async () => {
|
|
2131
|
+
var connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", {});
|
|
2132
|
+
var client = await sdk.init(connectionParameters);
|
|
2133
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.0.6.acc-sdk:8080.cache.OptionCache$");
|
|
2134
|
+
|
|
2135
|
+
connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("https://acc-sdk:8080", "admin", "admin", {});
|
|
2136
|
+
client = await sdk.init(connectionParameters);
|
|
2137
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.0.6.acc-sdk:8080.cache.OptionCache$");
|
|
2138
|
+
|
|
2139
|
+
connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("acc-sdk:8080", "admin", "admin", {});
|
|
2140
|
+
client = await sdk.init(connectionParameters);
|
|
2141
|
+
expect(client._optionCache._storage._rootKey).toBe("acc.js.sdk.1.0.6.acc-sdk:8080.cache.OptionCache$");
|
|
2142
|
+
})
|
|
2143
|
+
|
|
2144
|
+
it("Should support no storage", async () => {
|
|
2145
|
+
const storage = {
|
|
2146
|
+
getItem: jest.fn(),
|
|
2147
|
+
setItem: jest.fn(),
|
|
2148
|
+
}
|
|
2149
|
+
const client = await Mock.makeClient({ storage: storage, noStorage: true });
|
|
2150
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2151
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
2152
|
+
await client.NLWS.xtkSession.logon();
|
|
2153
|
+
client._transport.mockReturnValueOnce(Mock.GET_DATABASEID_RESPONSE);
|
|
2154
|
+
const value = await client.getOption("XtkDatabaseId");
|
|
2155
|
+
expect(value).toBe('uFE80000000000000F1FA913DD7CC7C480041161C');
|
|
2156
|
+
expect(storage.getItem.mock.calls.length).toBe(0); // storage is disabled and should not have been called
|
|
2157
|
+
})
|
|
2158
|
+
|
|
2159
|
+
it("Should cache XML in storage", async () => {
|
|
2160
|
+
const map = {};
|
|
2161
|
+
const storage = {
|
|
2162
|
+
getItem: jest.fn((key) => map[key]),
|
|
2163
|
+
setItem: jest.fn((key, value) => map[key] = value)
|
|
2164
|
+
}
|
|
2165
|
+
let client = await Mock.makeClient({ storage: storage });
|
|
2166
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2167
|
+
await client.NLWS.xtkSession.logon();
|
|
2168
|
+
client._transport.mockReturnValueOnce(Mock.GET_NMS_EXTACCOUNT_SCHEMA_RESPONSE);
|
|
2169
|
+
await client.getSchema("nms:extAccount");
|
|
2170
|
+
// Schema should have been cached to local storage
|
|
2171
|
+
expect(storage.setItem.mock.calls.length).toBe(1);
|
|
2172
|
+
expect(storage.setItem.mock.calls[0][0]).toMatch("cache.XtkEntityCache$xtk:schema|nms:extAccount");
|
|
2173
|
+
// Value is the cached object, it should not be an empty object
|
|
2174
|
+
const cached = JSON.parse(storage.setItem.mock.calls[0][1]);
|
|
2175
|
+
expect(Object.keys(cached.value).length).toBeGreaterThan(0);
|
|
2176
|
+
expect(cached.value).toMatch("<schema");
|
|
2177
|
+
|
|
2178
|
+
// Now simulate reusing the local storage. We need a new client to make sure we do not reuse
|
|
2179
|
+
// the in-memory cache of the client.
|
|
2180
|
+
client = await Mock.makeClient({ storage: storage });
|
|
2181
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2182
|
+
await client.NLWS.xtkSession.logon();
|
|
2183
|
+
client._transport.mockReturnValueOnce(Mock.GET_NMS_EXTACCOUNT_SCHEMA_RESPONSE);
|
|
2184
|
+
await client.getSchema("nms:extAccount");
|
|
2185
|
+
})
|
|
2186
|
+
})
|
|
2187
|
+
|
|
2188
|
+
describe("Get Schema, cache and representations", () => {
|
|
2189
|
+
it("Should get schema with no cache", async () => {
|
|
2190
|
+
const client = await Mock.makeClient();
|
|
2191
|
+
client.clearAllCaches();
|
|
2192
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2193
|
+
await client.NLWS.xtkSession.logon();
|
|
2194
|
+
|
|
2195
|
+
client._transport.mockReturnValueOnce(Mock.GET_NMS_EXTACCOUNT_SCHEMA_RESPONSE);
|
|
2196
|
+
var schema = await client.getSchema("nms:extAccount");
|
|
2197
|
+
expect(schema["namespace"]).toBe("nms");
|
|
2198
|
+
expect(schema["name"]).toBe("extAccount");
|
|
2199
|
+
});
|
|
2200
|
+
|
|
2201
|
+
});
|
|
1880
2202
|
});
|
package/test/domUtil.test.js
CHANGED
|
@@ -523,4 +523,27 @@ describe('DomUtil', function() {
|
|
|
523
523
|
});
|
|
524
524
|
});
|
|
525
525
|
|
|
526
|
+
describe("Text and CDATA nodes", () => {
|
|
527
|
+
it("Should handle cdata node", () => {
|
|
528
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc><![CDATA[Ensure that obsolete data are deleted from the database.]]></desc></workflow></workflow-collection>`);
|
|
529
|
+
const json = DomUtil.toJSON(xml);
|
|
530
|
+
expect(json.workflow[0]["$desc"]).toBe("Ensure that obsolete data are deleted from the database.");
|
|
531
|
+
expect(json.workflow[0]["desc"]).toBeUndefined();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it("Should handle text node", () => {
|
|
535
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc>Ensure that obsolete data are deleted from the database.</desc></workflow></workflow-collection>`);
|
|
536
|
+
const json = DomUtil.toJSON(xml);
|
|
537
|
+
expect(json.workflow[0]["$desc"]).toBe("Ensure that obsolete data are deleted from the database.");
|
|
538
|
+
expect(json.workflow[0]["desc"]).toBeUndefined();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it("Should handle empty node", () => {
|
|
542
|
+
const xml = DomUtil.parse(`<workflow-collection><workflow id="1840" internalName="cleanup" label="Database cleanup"><desc/></workflow></workflow-collection>`);
|
|
543
|
+
const json = DomUtil.toJSON(xml);
|
|
544
|
+
expect(json.workflow[0]["$desc"]).toBeUndefined();
|
|
545
|
+
expect(json.workflow[0]["desc"]).toStrictEqual({});
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
|
|
526
549
|
});
|
package/test/index.test.js
CHANGED
|
@@ -60,4 +60,19 @@ describe('ACC SDK', function() {
|
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
|
|
64
|
+
describe("IP", () => {
|
|
65
|
+
it("Should get IP address", async () => {
|
|
66
|
+
const t = jest.fn();
|
|
67
|
+
const old = sdk._transport(t);
|
|
68
|
+
try {
|
|
69
|
+
t.mockReturnValueOnce(Promise.resolve({ "ipAddress":"AAA.BBB.CCC.DDD","continentCode":"EU","continentName":"Europe","countryCode":"FR","countryName":"France","stateProv":"Centre-Val de Loire","city":"Bourges" }));
|
|
70
|
+
const ip = await sdk.ip();
|
|
71
|
+
expect(ip).toMatchObject({ "ipAddress":"AAA.BBB.CCC.DDD" });
|
|
72
|
+
} finally {
|
|
73
|
+
sdk._transport(old);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
})
|
|
77
|
+
|
|
63
78
|
});
|
package/test/mock.js
CHANGED
|
@@ -21,14 +21,16 @@ governing permissions and limitations under the License.
|
|
|
21
21
|
async function makeAnonymousClient(options) {
|
|
22
22
|
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080", options);
|
|
23
23
|
const client = await sdk.init(connectionParameters);
|
|
24
|
-
|
|
24
|
+
if (!options || !options.transport) // allow tests to explicitely set the transport
|
|
25
|
+
client._transport = jest.fn();
|
|
25
26
|
return client;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
async function makeClient(options) {
|
|
29
30
|
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword("http://acc-sdk:8080", "admin", "admin", options);
|
|
30
31
|
const client = await sdk.init(connectionParameters);
|
|
31
|
-
|
|
32
|
+
if (!options || !options.transport) // allow tests to explicitely set the transport
|
|
33
|
+
client._transport = jest.fn();
|
|
32
34
|
return client;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -61,7 +63,7 @@ const LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
|
61
63
|
<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/'>
|
|
62
64
|
<SOAP-ENV:Body>
|
|
63
65
|
<LogonResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
64
|
-
<pstrSessionToken xsi:type='xsd:string'>
|
|
66
|
+
<pstrSessionToken xsi:type='xsd:string'>___$session_token$</pstrSessionToken>
|
|
65
67
|
<pSessionInfo xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
66
68
|
<sessionInfo>
|
|
67
69
|
<serverInfo advisedClientBuildNumber="0" allowSQL="false" buildNumber="9219" commitId="f5f3ec3" databaseId="uFE80000000000000F1FA913DD7CC7C480041161C" defaultNameSpace="cus" fohVersion="2" instanceName="ffdamkt" majNumber="6" minClientBuildNumber="8969" minNumber="7" minNumberTechnical="0" releaseName="20.3" securityTimeOut="86400" serverDate="2020-07-05 14:11:31.986Z" servicePack="0" sessionTimeOut="86400" useVault="false"/>
|
|
@@ -73,11 +75,32 @@ const LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
|
73
75
|
</userInfo>
|
|
74
76
|
</sessionInfo>
|
|
75
77
|
</pSessionInfo>
|
|
76
|
-
<pstrSecurityToken xsi:type='xsd:string'
|
|
78
|
+
<pstrSecurityToken xsi:type='xsd:string'>@$security_token$==</pstrSecurityToken>
|
|
77
79
|
</LogonResponse>
|
|
78
80
|
</SOAP-ENV:Body>
|
|
79
81
|
</SOAP-ENV:Envelope>`);
|
|
80
82
|
|
|
83
|
+
const BEARER_LOGON_RESPONSE = Promise.resolve(`<?xml version='1.0'?>
|
|
84
|
+
<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/'>
|
|
85
|
+
<SOAP-ENV:Body>
|
|
86
|
+
<BearerTokenLogonResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
87
|
+
<pstrSessionToken xsi:type='xsd:string'>___$session_token$</pstrSessionToken>
|
|
88
|
+
<pSessionInfo xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
|
|
89
|
+
<sessionInfo>
|
|
90
|
+
<serverInfo advisedClientBuildNumber="0" allowSQL="false" buildNumber="9219" commitId="f5f3ec3" databaseId="uFE80000000000000F1FA913DD7CC7C480041161C" defaultNameSpace="cus" fohVersion="2" instanceName="ffdamkt" majNumber="6" minClientBuildNumber="8969" minNumber="7" minNumberTechnical="0" releaseName="20.3" securityTimeOut="86400" serverDate="2020-07-05 14:11:31.986Z" servicePack="0" sessionTimeOut="86400" useVault="false"/>
|
|
91
|
+
<userInfo datakitInDatabase="true" homeDir="" instanceLocale="en" locale="en" login="admin" loginCS="Administrator (admin)" loginId="1059" noConsoleCnx="false" orgUnitId="0" theme="" timezone="Europe/Paris">
|
|
92
|
+
<login-group id="1060"/>
|
|
93
|
+
<login-right right="admin"/>
|
|
94
|
+
<installed-package name="campaign" namespace="nms"/>
|
|
95
|
+
<installed-package name="core" namespace="nms"/>
|
|
96
|
+
</userInfo>
|
|
97
|
+
</sessionInfo>
|
|
98
|
+
</pSessionInfo>
|
|
99
|
+
<pstrSecurityToken xsi:type='xsd:string'>@$security_token$==</pstrSecurityToken>
|
|
100
|
+
</BearerTokenLogonResponse>
|
|
101
|
+
</SOAP-ENV:Body>
|
|
102
|
+
</SOAP-ENV:Envelope>`);
|
|
103
|
+
|
|
81
104
|
const LOGON_RESPONSE_NO_USERINFO = Promise.resolve(`<?xml version='1.0'?>
|
|
82
105
|
<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/'>
|
|
83
106
|
<SOAP-ENV:Body>
|
|
@@ -576,6 +599,7 @@ exports.Mock = {
|
|
|
576
599
|
MC_PING: MC_PING,
|
|
577
600
|
MC_PING_ERROR: MC_PING_ERROR,
|
|
578
601
|
LOGON_RESPONSE: LOGON_RESPONSE,
|
|
602
|
+
BEARER_LOGON_RESPONSE: BEARER_LOGON_RESPONSE,
|
|
579
603
|
LOGON_RESPONSE_NO_SESSIONTOKEN: LOGON_RESPONSE_NO_SESSIONTOKEN,
|
|
580
604
|
LOGON_RESPONSE_NO_SECURITYTOKEN: LOGON_RESPONSE_NO_SECURITYTOKEN,
|
|
581
605
|
LOGOFF_RESPONSE: LOGOFF_RESPONSE,
|
package/test/soap.test.js
CHANGED
|
@@ -150,14 +150,15 @@ describe('SOAP', function() {
|
|
|
150
150
|
assert.equal(request.headers["Content-type"], "application/soap+xml");
|
|
151
151
|
assert.equal(request.headers["SoapAction"], "xtk:session#Empty");
|
|
152
152
|
assert.equal(request.headers["X-Security-Token"], "");
|
|
153
|
-
|
|
153
|
+
expect(request.headers["Cookie"]).toBeUndefined();
|
|
154
154
|
const env = DomUtil.parse(request.data).documentElement;
|
|
155
155
|
const header = hasChildElement(env, "SOAP-ENV:Header");
|
|
156
|
-
|
|
156
|
+
expect(DomUtil.findElement(header, "Cookie")).toBeFalsy();
|
|
157
157
|
hasChildElement(header, "X-Security-Token");
|
|
158
158
|
const body = hasChildElement(env, "SOAP-ENV:Body");
|
|
159
159
|
const method = hasChildElement(body, "m:Empty", undefined, "xmlns:m", "urn:xtk:session", "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
|
|
160
|
-
|
|
160
|
+
// sessiontoken is always required as first parameter, even if not set
|
|
161
|
+
expect(DomUtil.findElement(method, "sessiontoken")).toBeTruthy();
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
it('Should have set authentication tokens', function() {
|
|
@@ -791,5 +792,18 @@ describe("Campaign exception", () => {
|
|
|
791
792
|
})
|
|
792
793
|
})
|
|
793
794
|
|
|
795
|
+
it("CampaignException should hide sensitive information", () => {
|
|
796
|
+
const call = makeSoapMethodCall(undefined, "xtk:session", "Date", "$session$", "$security$", "My User Agent");
|
|
797
|
+
call.finalize("http://ffdamkt:8080/nl/jsp/soaprouter.jsp")
|
|
798
|
+
const ex = makeCampaignException(call, new Error("Failed"));
|
|
799
|
+
const req = ex.methodCall.request;
|
|
800
|
+
expect(req.data.indexOf("$session$")).toBe(-1);
|
|
801
|
+
expect(req.data.indexOf("$security$")).toBe(-1);
|
|
802
|
+
expect(req.headers.Cookie.indexOf("$session$")).toBe(-1);
|
|
803
|
+
expect(req.headers.Cookie.indexOf("$security$")).toBe(-1);
|
|
804
|
+
expect(req.headers["X-Security-Token"].indexOf("$session$")).toBe(-1);
|
|
805
|
+
expect(req.headers["X-Security-Token"].indexOf("$security$")).toBe(-1);
|
|
806
|
+
})
|
|
807
|
+
|
|
794
808
|
});
|
|
795
809
|
|