@contrail/flexplm 1.7.7-alpha.e66ae52 → 1.7.7-alpha.eb1d846
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.
|
@@ -6,10 +6,6 @@ export interface FCConfig {
|
|
|
6
6
|
eventObjectClassParam?: string;
|
|
7
7
|
eventFlexTypePathParam?: string;
|
|
8
8
|
flexplmConnect?: any;
|
|
9
|
-
'flexplmConnect.sessionReuse.enabled'?: boolean | string;
|
|
10
|
-
'flexplmConnect.sessionReuse.ttlSeconds'?: number | string;
|
|
11
|
-
'flexplmConnect.sessionReuse.cookieName'?: string;
|
|
12
|
-
'flexplmConnect.sessionReuse.retryStatuses'?: number | number[] | string;
|
|
13
9
|
taskId?: string;
|
|
14
10
|
apiHost: string;
|
|
15
11
|
userName(): string;
|
|
@@ -4,6 +4,19 @@ exports.FlexPLMConnect = void 0;
|
|
|
4
4
|
const app_framework_1 = require("@contrail/app-framework");
|
|
5
5
|
// Module-level on purpose: a new FlexPLMConnect is constructed for every event. Declaring for Session reusing use case.
|
|
6
6
|
const sessionCache = new Map();
|
|
7
|
+
// Upper bound so users/option combinations that are never requested again cannot accumulate cookies forever.
|
|
8
|
+
const MAX_CACHED_SESSIONS = 100;
|
|
9
|
+
const pruneSessionCache = () => {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
for (const [key, session] of sessionCache) {
|
|
12
|
+
if (session.expiresAt <= now)
|
|
13
|
+
sessionCache.delete(key);
|
|
14
|
+
}
|
|
15
|
+
// Still full: drop the oldest entries (Map keeps insertion order).
|
|
16
|
+
while (sessionCache.size >= MAX_CACHED_SESSIONS) {
|
|
17
|
+
sessionCache.delete(sessionCache.keys().next().value);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
7
20
|
// In-flight cold session acquisitions per key, so concurrent events share one FlexPLM session instead of each creating their own.
|
|
8
21
|
const inFlightAcquisitions = new Map();
|
|
9
22
|
const DEFAULT_SESSION_COOKIE_NAME = 'JSESSIONID';
|
|
@@ -58,28 +71,14 @@ class FlexPLMConnect {
|
|
|
58
71
|
/////////////////////////////////////////////////////////////////////////////
|
|
59
72
|
///////// ET-390 - Session reuse: start
|
|
60
73
|
/////////////////////////////////////////////////////////////////////////////
|
|
61
|
-
/*
|
|
62
|
-
private get sessionOptions() {
|
|
63
|
-
const sessReuseBool = this.config?.flexplmConnect?.sessionReuse;
|
|
64
|
-
console.info('sessReuseBool value is --> ' + sessReuseBool);
|
|
65
|
-
console.info('enabled value is --> ' + sessReuseBool?.enabled);
|
|
66
|
-
return {
|
|
67
|
-
enabled: sessReuseBool?.enabled === true || String(sessReuseBool?.enabled).toLowerCase() === 'true',
|
|
68
|
-
ttlMs: (sessReuseBool?.ttlSeconds ?? 900) * 1000,
|
|
69
|
-
cookieName: sessReuseBool?.cookieName ?? 'JSESSIONID',
|
|
70
|
-
retryStatuses: (sessReuseBool?.retryStatuses ?? [401, 403]) as number[],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
*/
|
|
74
74
|
get sessionOptions() {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const enabled = sessReuseEntries('enabled');
|
|
75
|
+
const sessReuse = this.config?.flexplmConnect?.sessionReuse;
|
|
76
|
+
const enabled = sessReuse?.enabled;
|
|
78
77
|
return {
|
|
79
78
|
enabled: enabled === true || String(enabled).toLowerCase() === 'true',
|
|
80
|
-
ttlMs: parseTtlSeconds(
|
|
81
|
-
cookieName: parseCookieName(
|
|
82
|
-
retryStatuses: parseRetryStatuses(
|
|
79
|
+
ttlMs: parseTtlSeconds(sessReuse?.ttlSeconds) * 1000,
|
|
80
|
+
cookieName: parseCookieName(sessReuse?.cookieName),
|
|
81
|
+
retryStatuses: parseRetryStatuses(sessReuse?.retryStatuses),
|
|
83
82
|
};
|
|
84
83
|
}
|
|
85
84
|
/**
|
|
@@ -144,7 +143,11 @@ class FlexPLMConnect {
|
|
|
144
143
|
}
|
|
145
144
|
storeSession(cookie) {
|
|
146
145
|
// sliding expiry: Windchill's session timeout is also sliding
|
|
147
|
-
|
|
146
|
+
const key = this.getSessionKey();
|
|
147
|
+
// delete first so a refreshed entry moves to the newest position (oldest-first eviction then acts as LRU)
|
|
148
|
+
sessionCache.delete(key);
|
|
149
|
+
pruneSessionCache();
|
|
150
|
+
sessionCache.set(key, { cookie, expiresAt: Date.now() + this.sessionOptions.ttlMs });
|
|
148
151
|
}
|
|
149
152
|
clearSession() {
|
|
150
153
|
sessionCache.delete(this.getSessionKey());
|
|
@@ -226,7 +229,7 @@ class FlexPLMConnect {
|
|
|
226
229
|
await wait;
|
|
227
230
|
if (getNewSession) {
|
|
228
231
|
const current = this.getCachedSession();
|
|
229
|
-
if (!current || current === rejectedCookie)
|
|
232
|
+
if (rejectedCookie === undefined || !current || current === rejectedCookie)
|
|
230
233
|
this.clearSession();
|
|
231
234
|
}
|
|
232
235
|
const cached = this.getCachedSession();
|
|
@@ -39,12 +39,8 @@ const resp = (status, setCookie = [], json = csrfBody) => ({
|
|
|
39
39
|
});
|
|
40
40
|
let userCounter = 0;
|
|
41
41
|
const uniqueUser = () => 'sess-user-' + (++userCounter);
|
|
42
|
-
// The connector config
|
|
43
|
-
const sessionConfig = (user, sessionReuse = { enabled: true }) => {
|
|
44
|
-
const flat = {};
|
|
45
|
-
Object.entries(sessionReuse).forEach(([k, v]) => { flat[`flexplmConnect.sessionReuse.${k}`] = v; });
|
|
46
|
-
return createConfig({ userName: () => user, ...flat });
|
|
47
|
-
};
|
|
42
|
+
// The connector config nests the entries: { flexplmConnect: { sessionReuse: { enabled: true, ... } } }
|
|
43
|
+
const sessionConfig = (user, sessionReuse = { enabled: true }) => createConfig({ userName: () => user, flexplmConnect: { sessionReuse } });
|
|
48
44
|
const fetchMock = () => global.fetch;
|
|
49
45
|
const callHeaders = (i) => fetchMock().mock.calls[i][1].headers;
|
|
50
46
|
const callMethod = (i) => fetchMock().mock.calls[i][1].method;
|
|
@@ -156,7 +152,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
156
152
|
expect(callHeaders(1).Cookie).toBe('JSESSIONID=abc.tomcat1');
|
|
157
153
|
expect(callHeaders(1).CSRF_NONCE).toBe('n1');
|
|
158
154
|
});
|
|
159
|
-
it('
|
|
155
|
+
it('should reuse the cached session on the next event (new FlexPLMConnect instance)', async () => {
|
|
160
156
|
const u = uniqueUser();
|
|
161
157
|
fetchMock()
|
|
162
158
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1; Path=/'])) // event 1 GET
|
|
@@ -168,7 +164,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
168
164
|
expect(callHeaders(2).Cookie).toBe('JSESSIONID=abc.tomcat1'); // GET reuses it
|
|
169
165
|
expect(callHeaders(3).Cookie).toBe('JSESSIONID=abc.tomcat1'); // POST reuses it
|
|
170
166
|
});
|
|
171
|
-
it('
|
|
167
|
+
it('should replace the cached session when Windchill answers the GET with a new Set-Cookie', async () => {
|
|
172
168
|
const u = uniqueUser();
|
|
173
169
|
fetchMock()
|
|
174
170
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1; Path=/']))
|
|
@@ -185,7 +181,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
185
181
|
expect(callHeaders(3).Cookie).toBe('JSESSIONID=new.tomcat1'); // POST uses the replacement
|
|
186
182
|
expect(callHeaders(4).Cookie).toBe('JSESSIONID=new.tomcat1'); // event 3 GET sends the replacement
|
|
187
183
|
});
|
|
188
|
-
it('
|
|
184
|
+
it('should retry once with a new session when the POST is rejected with 403', async () => {
|
|
189
185
|
const u = uniqueUser();
|
|
190
186
|
fetchMock()
|
|
191
187
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1; Path=/'])) // GET
|
|
@@ -199,7 +195,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
199
195
|
expect(result.status).toBe(200);
|
|
200
196
|
expect(result.data).toEqual({ ok: true });
|
|
201
197
|
});
|
|
202
|
-
it('also
|
|
198
|
+
it('should also retry on 401', async () => {
|
|
203
199
|
const u = uniqueUser();
|
|
204
200
|
fetchMock()
|
|
205
201
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1']))
|
|
@@ -209,7 +205,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
209
205
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u)).sendToFlexPLM(payload);
|
|
210
206
|
expect(fetchMock()).toHaveBeenCalledTimes(4);
|
|
211
207
|
});
|
|
212
|
-
it('
|
|
208
|
+
it('should not loop: a second 403 after the retry is surfaced as an error', async () => {
|
|
213
209
|
const u = uniqueUser();
|
|
214
210
|
fetchMock()
|
|
215
211
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1']))
|
|
@@ -220,7 +216,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
220
216
|
.rejects.toThrow('Error sending data to FlexPLM:status: 403');
|
|
221
217
|
expect(fetchMock()).toHaveBeenCalledTimes(4);
|
|
222
218
|
});
|
|
223
|
-
it('
|
|
219
|
+
it('should not retry on non-auth errors such as 500 (event may already be processed)', async () => {
|
|
224
220
|
const u = uniqueUser();
|
|
225
221
|
fetchMock()
|
|
226
222
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1']))
|
|
@@ -229,7 +225,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
229
225
|
.rejects.toThrow('Error sending data to FlexPLM:status: 500');
|
|
230
226
|
expect(fetchMock()).toHaveBeenCalledTimes(2);
|
|
231
227
|
});
|
|
232
|
-
it('
|
|
228
|
+
it('should retry the csrf GET without a cookie when the cached session is rejected there', async () => {
|
|
233
229
|
const u = uniqueUser();
|
|
234
230
|
fetchMock()
|
|
235
231
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1'])) // event 1 GET
|
|
@@ -243,7 +239,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
243
239
|
expect(callHeaders(3).Cookie).toBeUndefined();
|
|
244
240
|
expect(callHeaders(4).Cookie).toBe('JSESSIONID=new.tomcat1');
|
|
245
241
|
});
|
|
246
|
-
it('
|
|
242
|
+
it('should expire the cached session after ttlSeconds', async () => {
|
|
247
243
|
const u = uniqueUser();
|
|
248
244
|
const realNow = Date.now();
|
|
249
245
|
const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(realNow);
|
|
@@ -260,7 +256,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
260
256
|
expect(callHeaders(3).Cookie).toBe('JSESSIONID=def.tomcat1');
|
|
261
257
|
nowSpy.mockRestore();
|
|
262
258
|
});
|
|
263
|
-
it('
|
|
259
|
+
it('should use the last JSESSIONID when several Set-Cookie lines are returned', async () => {
|
|
264
260
|
const u = uniqueUser();
|
|
265
261
|
fetchMock()
|
|
266
262
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=first.tomcat1; Path=/', 'OTHER=x; Path=/', 'JSESSIONID=second.tomcat1; Path=/']))
|
|
@@ -268,7 +264,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
268
264
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u)).sendToFlexPLM(payload);
|
|
269
265
|
expect(callHeaders(1).Cookie).toBe('JSESSIONID=second.tomcat1');
|
|
270
266
|
});
|
|
271
|
-
it('
|
|
267
|
+
it('should fall back to headers.get("set-cookie") when getSetCookie is not available', async () => {
|
|
272
268
|
const u = uniqueUser();
|
|
273
269
|
const legacy = {
|
|
274
270
|
status: 200,
|
|
@@ -280,7 +276,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
280
276
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u)).sendToFlexPLM(payload);
|
|
281
277
|
expect(callHeaders(1).Cookie).toBe('JSESSIONID=legacy.tomcat1');
|
|
282
278
|
});
|
|
283
|
-
it('
|
|
279
|
+
it('should honour a custom cookieName', async () => {
|
|
284
280
|
const u = uniqueUser();
|
|
285
281
|
fetchMock()
|
|
286
282
|
.mockResolvedValueOnce(resp(200, ['MYSESSION=zzz; Path=/', 'JSESSIONID=ignored; Path=/']))
|
|
@@ -288,7 +284,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
288
284
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u, { enabled: true, cookieName: 'MYSESSION' })).sendToFlexPLM(payload);
|
|
289
285
|
expect(callHeaders(1).Cookie).toBe('MYSESSION=zzz');
|
|
290
286
|
});
|
|
291
|
-
it('
|
|
287
|
+
it('should accept enabled as the string "true"', async () => {
|
|
292
288
|
const u = uniqueUser();
|
|
293
289
|
fetchMock()
|
|
294
290
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1']))
|
|
@@ -296,7 +292,39 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
296
292
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u, { enabled: 'true' })).sendToFlexPLM(payload);
|
|
297
293
|
expect(callHeaders(1).Cookie).toBe('JSESSIONID=abc.tomcat1');
|
|
298
294
|
});
|
|
299
|
-
it('
|
|
295
|
+
it('should evict expired sessions of other users when a new session is stored', async () => {
|
|
296
|
+
const userA = uniqueUser();
|
|
297
|
+
const userB = uniqueUser();
|
|
298
|
+
const realNow = Date.now();
|
|
299
|
+
const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(realNow);
|
|
300
|
+
fetchMock()
|
|
301
|
+
.mockResolvedValueOnce(resp(200, ['JSESSIONID=a.tomcat1'])) // A GET
|
|
302
|
+
.mockResolvedValueOnce(resp(200, [], {})) // A POST
|
|
303
|
+
.mockResolvedValueOnce(resp(200, ['JSESSIONID=b.tomcat1'])) // B GET
|
|
304
|
+
.mockResolvedValueOnce(resp(200, [], {})) // B POST
|
|
305
|
+
.mockResolvedValueOnce(resp(200, ['JSESSIONID=a2.tomcat1'])) // A GET again
|
|
306
|
+
.mockResolvedValueOnce(resp(200, [], {}));
|
|
307
|
+
const cfg = (u) => sessionConfig(u, { enabled: true, ttlSeconds: 1 });
|
|
308
|
+
await new flexplm_connect_1.FlexPLMConnect(cfg(userA)).sendToFlexPLM(payload);
|
|
309
|
+
nowSpy.mockReturnValue(realNow + 2000); // A has expired
|
|
310
|
+
await new flexplm_connect_1.FlexPLMConnect(cfg(userB)).sendToFlexPLM(payload); // storing B sweeps A
|
|
311
|
+
nowSpy.mockReturnValue(realNow); // rewind: only a swept A has no entry left
|
|
312
|
+
await new flexplm_connect_1.FlexPLMConnect(cfg(userA)).sendToFlexPLM(payload);
|
|
313
|
+
expect(callHeaders(4).Cookie).toBeUndefined();
|
|
314
|
+
nowSpy.mockRestore();
|
|
315
|
+
});
|
|
316
|
+
it('should not hold more than the maximum number of cached sessions', async () => {
|
|
317
|
+
const first = uniqueUser();
|
|
318
|
+
fetchMock().mockImplementation(async () => resp(200, ['JSESSIONID=s.tomcat1']));
|
|
319
|
+
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(first)).sendToFlexPLM(payload);
|
|
320
|
+
for (let i = 0; i < 100; i++) {
|
|
321
|
+
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(uniqueUser())).sendToFlexPLM(payload);
|
|
322
|
+
}
|
|
323
|
+
fetchMock().mockClear();
|
|
324
|
+
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(first)).sendToFlexPLM(payload);
|
|
325
|
+
expect(callHeaders(0).Cookie).toBeUndefined(); // oldest entry was evicted
|
|
326
|
+
});
|
|
327
|
+
it('should keep separate sessions per user', async () => {
|
|
300
328
|
const a = uniqueUser();
|
|
301
329
|
const b = uniqueUser();
|
|
302
330
|
fetchMock()
|
|
@@ -309,7 +337,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
309
337
|
expect(callHeaders(2).Cookie).toBeUndefined(); // user b must not see user a's cookie
|
|
310
338
|
expect(callHeaders(3).Cookie).toBe('JSESSIONID=bbb.tomcat1');
|
|
311
339
|
});
|
|
312
|
-
it('never
|
|
340
|
+
it('should never log the cookie value', async () => {
|
|
313
341
|
const isInfoOn = jest.spyOn(app_framework_1.Logger, 'isInfoOn').mockReturnValue(true);
|
|
314
342
|
const info = jest.spyOn(console, 'info').mockImplementation();
|
|
315
343
|
const u = uniqueUser();
|
|
@@ -340,11 +368,11 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
340
368
|
['a comma separated string', '401, 403'],
|
|
341
369
|
['garbage (falls back to 401/403)', 'abc'],
|
|
342
370
|
['an empty array (falls back to 401/403)', []],
|
|
343
|
-
])('
|
|
371
|
+
])('should not throw and still retry on 403 when retryStatuses is %s', async (_label, retryStatuses) => {
|
|
344
372
|
await rejectedOnceThenOk(uniqueUser(), { retryStatuses });
|
|
345
373
|
expect(fetchMock()).toHaveBeenCalledTimes(4);
|
|
346
374
|
});
|
|
347
|
-
it.each([['abc'], [0], [-5]])('
|
|
375
|
+
it.each([['abc'], [0], [-5]])('should fall back to the 900s default when ttlSeconds is invalid (%p)', async (ttlSeconds) => {
|
|
348
376
|
const u = uniqueUser();
|
|
349
377
|
const realNow = Date.now();
|
|
350
378
|
const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(realNow);
|
|
@@ -360,7 +388,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
360
388
|
expect(callHeaders(2).Cookie).toBe('JSESSIONID=abc.tomcat1');
|
|
361
389
|
nowSpy.mockRestore();
|
|
362
390
|
});
|
|
363
|
-
it('
|
|
391
|
+
it('should fall back to JSESSIONID when cookieName is blank', async () => {
|
|
364
392
|
const u = uniqueUser();
|
|
365
393
|
fetchMock()
|
|
366
394
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1']))
|
|
@@ -473,7 +501,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
473
501
|
});
|
|
474
502
|
});
|
|
475
503
|
describe('cookie names containing regex metacharacters', () => {
|
|
476
|
-
it('
|
|
504
|
+
it('should extract a cookie whose name contains "+"', async () => {
|
|
477
505
|
const u = uniqueUser();
|
|
478
506
|
fetchMock()
|
|
479
507
|
.mockResolvedValueOnce(resp(200, ['SID+=abc; Path=/']))
|
|
@@ -481,7 +509,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
481
509
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u, { enabled: true, cookieName: 'SID+' })).sendToFlexPLM(payload);
|
|
482
510
|
expect(callHeaders(1).Cookie).toBe('SID+=abc');
|
|
483
511
|
});
|
|
484
|
-
it('
|
|
512
|
+
it('should treat "." literally and not match a look-alike cookie', async () => {
|
|
485
513
|
const u = uniqueUser();
|
|
486
514
|
fetchMock()
|
|
487
515
|
.mockResolvedValueOnce(resp(200, ['AxB=wrong; Path=/']))
|
|
@@ -493,7 +521,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
493
521
|
describe('concurrent session acquisition', () => {
|
|
494
522
|
const flush = () => new Promise(r => setImmediate(r));
|
|
495
523
|
const isColdGet = (call) => call[1].method === 'GET' && !call[1].headers.Cookie;
|
|
496
|
-
it('
|
|
524
|
+
it('should share one session across concurrent events on a cold cache', async () => {
|
|
497
525
|
const u = uniqueUser();
|
|
498
526
|
let release;
|
|
499
527
|
const gate = new Promise(r => { release = r; });
|
|
@@ -512,7 +540,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
512
540
|
expect(fetchMock().mock.calls.filter(isColdGet)).toHaveLength(1);
|
|
513
541
|
results.forEach(r => expect(r.sessionCookie).toBe('abc.tomcat1'));
|
|
514
542
|
});
|
|
515
|
-
it('a waiter
|
|
543
|
+
it('should not make a waiter inherit the failure of the first acquisition', async () => {
|
|
516
544
|
const u = uniqueUser();
|
|
517
545
|
let release;
|
|
518
546
|
const gate = new Promise(r => { release = r; });
|
|
@@ -527,7 +555,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
527
555
|
expect(await firstResult).toBeInstanceOf(Error);
|
|
528
556
|
expect((await second).sessionCookie).toBe('abc.tomcat1');
|
|
529
557
|
});
|
|
530
|
-
it('
|
|
558
|
+
it('should create only one replacement session for parallel events rejected with 403', async () => {
|
|
531
559
|
const u = uniqueUser();
|
|
532
560
|
fetchMock().mockResolvedValueOnce(resp(200, ['JSESSIONID=old.tomcat1']));
|
|
533
561
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u)).getCSRF(); // prime the cache with the old session
|
|
@@ -547,7 +575,7 @@ describe('FlexPLMConnect session reuse', () => {
|
|
|
547
575
|
});
|
|
548
576
|
describe('FlexPLMConnect session reuse - feature disabled (default)', () => {
|
|
549
577
|
const payload = { id: '123' };
|
|
550
|
-
it('
|
|
578
|
+
it('should send no Cookie header and make exactly one GET + one POST', async () => {
|
|
551
579
|
const u = uniqueUser();
|
|
552
580
|
fetchMock()
|
|
553
581
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1'])) // Set-Cookie present but must be ignored
|
|
@@ -561,7 +589,7 @@ describe('FlexPLMConnect session reuse - feature disabled (default)', () => {
|
|
|
561
589
|
expect(callHeaders(i).Cookie).toBeUndefined();
|
|
562
590
|
}
|
|
563
591
|
});
|
|
564
|
-
it('
|
|
592
|
+
it('should not retry on 403 (behaves exactly as before)', async () => {
|
|
565
593
|
const u = uniqueUser();
|
|
566
594
|
fetchMock()
|
|
567
595
|
.mockResolvedValueOnce(resp(200))
|
|
@@ -570,7 +598,7 @@ describe('FlexPLMConnect session reuse - feature disabled (default)', () => {
|
|
|
570
598
|
.rejects.toThrow('Error sending data to FlexPLM:status: 403');
|
|
571
599
|
expect(fetchMock()).toHaveBeenCalledTimes(2);
|
|
572
600
|
});
|
|
573
|
-
it('
|
|
601
|
+
it('should behave the same as not configured when enabled is false', async () => {
|
|
574
602
|
const u = uniqueUser();
|
|
575
603
|
fetchMock()
|
|
576
604
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1']))
|
|
@@ -578,9 +606,18 @@ describe('FlexPLMConnect session reuse - feature disabled (default)', () => {
|
|
|
578
606
|
await new flexplm_connect_1.FlexPLMConnect(sessionConfig(u, { enabled: false })).sendToFlexPLM(payload);
|
|
579
607
|
expect(callHeaders(1).Cookie).toBeUndefined();
|
|
580
608
|
});
|
|
609
|
+
it('should ignore the legacy flat key form', async () => {
|
|
610
|
+
const u = uniqueUser();
|
|
611
|
+
fetchMock()
|
|
612
|
+
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1'])) // Set-Cookie present but must be ignored
|
|
613
|
+
.mockResolvedValueOnce(resp(200, [], {}));
|
|
614
|
+
const cfg = createConfig({ userName: () => u, 'flexplmConnect.sessionReuse.enabled': true });
|
|
615
|
+
await new flexplm_connect_1.FlexPLMConnect(cfg).sendToFlexPLM(payload);
|
|
616
|
+
expect(callHeaders(1).Cookie).toBeUndefined();
|
|
617
|
+
});
|
|
581
618
|
});
|
|
582
619
|
describe('FlexPLMConnect.getRequest session reuse', () => {
|
|
583
|
-
it('
|
|
620
|
+
it('should send the cached cookie on image/GET requests', async () => {
|
|
584
621
|
const u = uniqueUser();
|
|
585
622
|
fetchMock()
|
|
586
623
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1'])) // csrf GET primes the cache
|
|
@@ -591,7 +628,7 @@ describe('FlexPLMConnect.getRequest session reuse', () => {
|
|
|
591
628
|
await connect.getRequest();
|
|
592
629
|
expect(callHeaders(2).Cookie).toBe('JSESSIONID=abc.tomcat1');
|
|
593
630
|
});
|
|
594
|
-
it('
|
|
631
|
+
it('should retry once without the cookie when the cached session is rejected on getRequest', async () => {
|
|
595
632
|
const u = uniqueUser();
|
|
596
633
|
fetchMock()
|
|
597
634
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=abc.tomcat1']))
|
|
@@ -604,7 +641,7 @@ describe('FlexPLMConnect.getRequest session reuse', () => {
|
|
|
604
641
|
expect(callHeaders(2).Cookie).toBe('JSESSIONID=abc.tomcat1');
|
|
605
642
|
expect(callHeaders(3).Cookie).toBeUndefined();
|
|
606
643
|
});
|
|
607
|
-
it('
|
|
644
|
+
it('should not re-store the rejected cookie when the retry issues no Set-Cookie', async () => {
|
|
608
645
|
const u = uniqueUser();
|
|
609
646
|
fetchMock()
|
|
610
647
|
.mockResolvedValueOnce(resp(200, ['JSESSIONID=stale.tomcat1']))
|