-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathpush-refresh-token.spec.js
More file actions
139 lines (116 loc) · 6.41 KB
/
push-refresh-token.spec.js
File metadata and controls
139 lines (116 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json';
import membershipsNicolasMock1 from '../mocks/memberships.nicolas@split.io.json';
import authPushEnabledNicolas from '../mocks/auth.pushEnabled.nicolas@split.io.601secs.json';
import authPushDisabled from '../mocks/auth.pushDisabled.json';
import { nearlyEqual, url } from '../testUtils';
// Replace global EventSource with mock
import EventSourceMock, { setMockListener } from '../testUtils/eventSourceMock';
window.EventSource = EventSourceMock;
import { SplitFactory } from '../../';
import { settingsFactory } from '../../settings';
const userKey = 'nicolas@split.io';
const baseUrls = {
sdk: 'https://sdk.push-refresh-token/api',
events: 'https://events.push-refresh-token/api',
auth: 'https://auth.push-refresh-token/api'
};
const config = {
core: {
authorizationKey: '<fake-token-push-1>',
key: userKey
},
urls: baseUrls,
streamingEnabled: true,
scheduler: {
pushRetryBackoffBase: 0.01 // small value to assert rapidly that push is not retried after auth with push disabled
},
// debug: true,
};
const settings = settingsFactory(config);
const MILLIS_CONNDELAY = 500;
const MILLIS_REFRESH_TOKEN = 1000;
/**
* Sequence of calls:
* 0.0 secs: initial SyncAll, auth, and not delayed SSE connection -> refresh token in 1 second, connection delay 0 seconds
* 1.0 secs: refresh-token: reauth -> refresh token in 1 second, connection delay 0.5 seconds
* 1.5 secs: delayed SSE connection -> syncAll
* 2.0 secs: refresh-token: reauth with pushEnabled false --> SSE connection closed & syncAll
* 2.2 secs: destroy the client. NO NEW REQUESTS SHOULD HAVE BEEN PERFORMED (too early for polling and push is disabled)
*/
export function testRefreshToken(fetchMock, assert) {
fetchMock.reset();
let start, splitio, client;
// mock SSE open and message events
let sseCount = 0;
setMockListener(function (eventSourceInstance) {
sseCount++;
switch (sseCount) {
case 1:
assert.true(nearlyEqual(Date.now() - start, 0), 'first connection is created immediately');
break;
case 2:
assert.true(nearlyEqual(Date.now() - start, MILLIS_REFRESH_TOKEN + MILLIS_CONNDELAY), 'second connection is created with a delay');
break;
default:
assert.fail('expecting only 2 SSE connections');
}
const expectedSSEurl = `${url(settings, '/sse')}?channels=NzM2MDI5Mzc0_NDEzMjQ1MzA0Nw%3D%3D_NTcwOTc3MDQx_mySegments,NzM2MDI5Mzc0_NDEzMjQ1MzA0Nw%3D%3D_splits,%5B%3Foccupancy%3Dmetrics.publishers%5Dcontrol_pri,%5B%3Foccupancy%3Dmetrics.publishers%5Dcontrol_sec&accessToken=${authPushEnabledNicolas.token}&v=1.1&heartbeats=true&SplitSDKVersion=${settings.version}&SplitSDKClientKey=h-1>`;
assert.equals(eventSourceInstance.url, expectedSSEurl, 'EventSource URL is the expected');
eventSourceInstance.emitOpen();
setTimeout(() => {
assert.equal(eventSourceInstance.readyState, EventSourceMock.CLOSED, 'SSE connection must be closed');
}, MILLIS_REFRESH_TOKEN + MILLIS_CONNDELAY + 50); // after refreshing the token and creating a new connection, previous connection is closed
});
// initial sync
fetchMock.getOnce(url(settings, '/splitChanges?s=1.3&since=-1&rbSince=-1'), { status: 200, body: splitChangesMock1 });
fetchMock.getOnce(url(settings, '/memberships/nicolas%40split.io'), { status: 200, body: membershipsNicolasMock1 });
// first auth
fetchMock.getOnce(url(settings, `/v2/auth?s=1.3&users=${encodeURIComponent(userKey)}`), function (url, opts) {
if (!opts.headers['Authorization']) assert.fail('`/v2/auth` request must include `Authorization` header');
assert.pass('auth success');
return { status: 200, body: authPushEnabledNicolas };
});
// sync after SSE opened
fetchMock.getOnce(url(settings, '/splitChanges?s=1.3&since=1457552620999&rbSince=100'), { status: 200, body: splitChangesMock2 });
fetchMock.getOnce(url(settings, '/memberships/nicolas%40split.io'), { status: 200, body: membershipsNicolasMock1 });
// re-auth due to refresh token, with connDelay of 0.5 seconds
fetchMock.getOnce(url(settings, `/v2/auth?s=1.3&users=${encodeURIComponent(userKey)}`), function (url, opts) {
const lapse = Date.now() - start;
assert.true(nearlyEqual(lapse, MILLIS_REFRESH_TOKEN), 'reauthentication for token refresh');
if (!opts.headers['Authorization']) assert.fail('`/v2/auth` request must include `Authorization` header');
return { status: 200, body: { ...authPushEnabledNicolas, connDelay: MILLIS_CONNDELAY / 1000 } };
});
// sync after SSE reopened
fetchMock.getOnce(url(settings, '/splitChanges?s=1.3&since=1457552620999&rbSince=100'), function () {
const lapse = Date.now() - start;
assert.true(nearlyEqual(lapse, MILLIS_REFRESH_TOKEN + MILLIS_CONNDELAY), 'sync after SSE connection is reopened');
return { status: 200, body: { ff: { d: [], s: 1457552620999, t: 1457552620999 } } };
});
fetchMock.getOnce(url(settings, '/memberships/nicolas%40split.io'), { status: 200, body: membershipsNicolasMock1 });
// second re-auth due to refresh token, this time responding with pushEnabled false
fetchMock.getOnce(url(settings, `/v2/auth?s=1.3&users=${encodeURIComponent(userKey)}`), function (url, opts) {
const lapse = Date.now() - start;
assert.true(nearlyEqual(lapse, MILLIS_REFRESH_TOKEN * 2), 'second reauthentication for token refresh');
if (!opts.headers['Authorization']) assert.fail('`/v2/auth` request must include `Authorization` header');
return { status: 200, body: authPushDisabled };
});
// split sync after SSE closed due to push disabled
fetchMock.getOnce(url(settings, '/splitChanges?s=1.3&since=1457552620999&rbSince=100'), function () {
const lapse = Date.now() - start;
assert.true(nearlyEqual(lapse, MILLIS_REFRESH_TOKEN * 2), 'sync after SSE connection is reopened a second time');
setTimeout(() => {
client.destroy().then(() => {
assert.end();
});
}, 200); // destroy the client a little bit latter, to assert that there weren't new requests
return { status: 500, body: 'server error' };
});
fetchMock.getOnce(url(settings, '/memberships/nicolas%40split.io'), { status: 200, body: membershipsNicolasMock1 });
fetchMock.get(new RegExp('.*'), function (url) {
assert.fail('unexpected GET request with url: ' + url);
});
start = Date.now();
splitio = SplitFactory(config);
client = splitio.client();
}