Skip to content

Commit a3b816b

Browse files
tanderson-ldTodd Anderson
and
Todd Anderson
authored
chore: adds DataSource interface, CompositeDataSource, and FDv2 paylo… (#830)
**Requirements** - [x] I have added test coverage for new or changed functionality - [x] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [ ] I have validated my changes against all supported platform versions Classes are independent of platforms for the moment, and also not reachable. (Except for Backoff which was moved). This PR moves shared/common changes for FDv2 from the temporary holding branch to main. All code has been previously reviewed and was picked from the temporary holding branch using file pick commands. Additional prettier fix commits. --------- Co-authored-by: Todd Anderson <[email protected]>
1 parent 2a86640 commit a3b816b

File tree

20 files changed

+1892
-134
lines changed

20 files changed

+1892
-134
lines changed

.github/workflows/common.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ jobs:
3333
target_file: 'packages/shared/common/dist/esm/index.mjs'
3434
package_name: '@launchdarkly/js-sdk-common'
3535
pr_number: ${{ github.event.number }}
36-
size_limit: 21000
36+
size_limit: 25000

packages/sdk/browser/src/platform/DefaultBrowserEventSource.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import {
2+
DefaultBackoff,
23
EventListener,
34
EventName,
45
EventSourceInitDict,
56
HttpErrorResponse,
67
EventSource as LDEventSource,
78
} from '@launchdarkly/js-client-sdk-common';
89

9-
import Backoff from './Backoff';
10-
1110
/**
1211
* Implementation Notes:
1312
*
@@ -22,7 +21,7 @@ import Backoff from './Backoff';
2221
*/
2322
export default class DefaultBrowserEventSource implements LDEventSource {
2423
private _es?: EventSource;
25-
private _backoff: Backoff;
24+
private _backoff: DefaultBackoff;
2625
private _errorFilter: (err: HttpErrorResponse) => boolean;
2726

2827
// The type of the handle can be platform specific and we treat is opaquely.
@@ -34,7 +33,10 @@ export default class DefaultBrowserEventSource implements LDEventSource {
3433
private readonly _url: string,
3534
options: EventSourceInitDict,
3635
) {
37-
this._backoff = new Backoff(options.initialRetryDelayMillis, options.retryResetIntervalMillis);
36+
this._backoff = new DefaultBackoff(
37+
options.initialRetryDelayMillis,
38+
options.retryResetIntervalMillis,
39+
);
3840
this._errorFilter = options.errorFilter;
3941
this._openConnection();
4042
}

packages/sdk/browser/__tests__/platform/Backoff.test.ts renamed to packages/shared/common/__tests__/datasource/Backoff.test.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
import Backoff from '../../src/platform/Backoff';
1+
import { DefaultBackoff } from '../../src/datasource/Backoff';
22

33
const noJitter = (): number => 0;
44
const maxJitter = (): number => 1;
55
const defaultResetInterval = 60 * 1000;
66

77
it.each([1, 1000, 5000])('has the correct starting delay', (initialDelay) => {
8-
const backoff = new Backoff(initialDelay, defaultResetInterval, noJitter);
8+
const backoff = new DefaultBackoff(initialDelay, defaultResetInterval, noJitter);
99
expect(backoff.fail()).toEqual(initialDelay);
1010
});
1111

1212
it.each([1, 1000, 5000])('doubles delay on consecutive failures', (initialDelay) => {
13-
const backoff = new Backoff(initialDelay, defaultResetInterval, noJitter);
13+
const backoff = new DefaultBackoff(initialDelay, defaultResetInterval, noJitter);
1414
expect(backoff.fail()).toEqual(initialDelay);
1515
expect(backoff.fail()).toEqual(initialDelay * 2);
1616
expect(backoff.fail()).toEqual(initialDelay * 4);
1717
});
1818

1919
it('stops increasing delay when the max backoff is encountered', () => {
20-
const backoff = new Backoff(5000, defaultResetInterval, noJitter);
20+
const backoff = new DefaultBackoff(5000, defaultResetInterval, noJitter);
2121
expect(backoff.fail()).toEqual(5000);
2222
expect(backoff.fail()).toEqual(10000);
2323
expect(backoff.fail()).toEqual(20000);
2424
expect(backoff.fail()).toEqual(30000);
2525

26-
const backoff2 = new Backoff(1000, defaultResetInterval, noJitter);
26+
const backoff2 = new DefaultBackoff(1000, defaultResetInterval, noJitter);
2727
expect(backoff2.fail()).toEqual(1000);
2828
expect(backoff2.fail()).toEqual(2000);
2929
expect(backoff2.fail()).toEqual(4000);
@@ -33,12 +33,12 @@ it('stops increasing delay when the max backoff is encountered', () => {
3333
});
3434

3535
it('handles an initial retry delay longer than the maximum retry delay', () => {
36-
const backoff = new Backoff(40000, defaultResetInterval, noJitter);
36+
const backoff = new DefaultBackoff(40000, defaultResetInterval, noJitter);
3737
expect(backoff.fail()).toEqual(30000);
3838
});
3939

4040
it('jitters the backoff value', () => {
41-
const backoff = new Backoff(1000, defaultResetInterval, maxJitter);
41+
const backoff = new DefaultBackoff(1000, defaultResetInterval, maxJitter);
4242
expect(backoff.fail()).toEqual(500);
4343
expect(backoff.fail()).toEqual(1000);
4444
expect(backoff.fail()).toEqual(2000);
@@ -51,7 +51,7 @@ it.each([10 * 1000, 60 * 1000])(
5151
'resets the delay when the last successful connection was connected greater than the retry reset interval',
5252
(retryResetInterval) => {
5353
let time = 1000;
54-
const backoff = new Backoff(1000, retryResetInterval, noJitter);
54+
const backoff = new DefaultBackoff(1000, retryResetInterval, noJitter);
5555
expect(backoff.fail(time)).toEqual(1000);
5656
time += 1;
5757
backoff.success(time);
@@ -69,7 +69,7 @@ it.each([10 * 1000, 60 * 1000])(
6969
it.each([10 * 1000, 60 * 1000])(
7070
'does not reset the delay when the connection did not persist longer than the retry reset interval',
7171
(retryResetInterval) => {
72-
const backoff = new Backoff(1000, retryResetInterval, noJitter);
72+
const backoff = new DefaultBackoff(1000, retryResetInterval, noJitter);
7373

7474
let time = 1000;
7575
expect(backoff.fail(time)).toEqual(1000);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { DataSourceList } from '../../src/datasource/dataSourceList';
2+
3+
it('replace is well behaved', async () => {
4+
const underTest = new DataSourceList(true, [1, 2, 3]);
5+
expect(underTest.next()).toEqual(1);
6+
expect(underTest.next()).toEqual(2);
7+
underTest.replace([4, 5, 6]);
8+
expect(underTest.next()).toEqual(4);
9+
expect(underTest.next()).toEqual(5);
10+
expect(underTest.next()).toEqual(6);
11+
expect(underTest.next()).toEqual(4);
12+
expect(underTest.next()).toEqual(5);
13+
});
14+
15+
it('it cycles correctly after replacing non-empty list', async () => {
16+
const underTest = new DataSourceList(true, [1, 2, 3]);
17+
expect(underTest.next()).toEqual(1);
18+
expect(underTest.next()).toEqual(2);
19+
expect(underTest.next()).toEqual(3);
20+
21+
underTest.remove(1);
22+
expect(underTest.next()).toEqual(2);
23+
expect(underTest.next()).toEqual(3);
24+
expect(underTest.next()).toEqual(2);
25+
expect(underTest.next()).toEqual(3);
26+
27+
underTest.remove(3);
28+
expect(underTest.next()).toEqual(2);
29+
expect(underTest.next()).toEqual(2);
30+
31+
underTest.remove(2);
32+
expect(underTest.next()).toBeUndefined();
33+
expect(underTest.next()).toBeUndefined();
34+
expect(underTest.next()).toBeUndefined();
35+
36+
underTest.replace([4, 5, 6]);
37+
38+
expect(underTest.next()).toEqual(4);
39+
expect(underTest.next()).toEqual(5);
40+
expect(underTest.next()).toEqual(6);
41+
42+
underTest.remove(4);
43+
expect(underTest.next()).toEqual(5);
44+
expect(underTest.next()).toEqual(6);
45+
expect(underTest.next()).toEqual(5);
46+
expect(underTest.next()).toEqual(6);
47+
48+
underTest.remove(6);
49+
expect(underTest.next()).toEqual(5);
50+
expect(underTest.next()).toEqual(5);
51+
52+
underTest.remove(5);
53+
expect(underTest.next()).toBeUndefined();
54+
expect(underTest.next()).toBeUndefined();
55+
});
56+
57+
it('cycles correctly after replacing empty list', async () => {
58+
const underTest = new DataSourceList<number>(true, []);
59+
60+
underTest.replace([1, 2, 3]);
61+
62+
expect(underTest.next()).toEqual(1);
63+
expect(underTest.next()).toEqual(2);
64+
expect(underTest.next()).toEqual(3);
65+
66+
underTest.remove(1);
67+
expect(underTest.next()).toEqual(2);
68+
expect(underTest.next()).toEqual(3);
69+
expect(underTest.next()).toEqual(2);
70+
expect(underTest.next()).toEqual(3);
71+
72+
underTest.remove(3);
73+
expect(underTest.next()).toEqual(2);
74+
expect(underTest.next()).toEqual(2);
75+
76+
underTest.remove(2);
77+
expect(underTest.next()).toBeUndefined();
78+
expect(underTest.next()).toBeUndefined();
79+
});
80+
81+
it('removing head is well behaved at start', async () => {
82+
const underTest = new DataSourceList(true, [1, 2, 3]);
83+
// head is now pointing to 1
84+
underTest.remove(1);
85+
expect(underTest.next()).toEqual(2);
86+
expect(underTest.next()).toEqual(3);
87+
expect(underTest.next()).toEqual(2);
88+
});
89+
90+
it('removing head is well behaved in middle', async () => {
91+
const underTest = new DataSourceList(true, [1, 2, 3]);
92+
expect(underTest.next()).toEqual(1);
93+
// head is now pointing to 2
94+
underTest.remove(2);
95+
expect(underTest.next()).toEqual(3);
96+
expect(underTest.next()).toEqual(1);
97+
expect(underTest.next()).toEqual(3);
98+
});
99+
100+
it('removing head is well behaved at end', async () => {
101+
const underTest = new DataSourceList(true, [1, 2, 3]);
102+
expect(underTest.next()).toEqual(1);
103+
expect(underTest.next()).toEqual(2);
104+
// head is now pointing to 3
105+
underTest.remove(3);
106+
expect(underTest.next()).toEqual(1);
107+
expect(underTest.next()).toEqual(2);
108+
expect(underTest.next()).toEqual(1);
109+
});
110+
111+
it('removing existing returns true', async () => {
112+
const underTest = new DataSourceList<number>(true, [1]);
113+
expect(underTest.remove(1)).toEqual(true);
114+
expect(underTest.next()).toBeUndefined();
115+
});
116+
117+
it('removing nonexistent returns false', async () => {
118+
const underTest = new DataSourceList<number>(true, []);
119+
expect(underTest.remove(1)).toEqual(false);
120+
expect(underTest.next()).toBeUndefined();
121+
});
122+
123+
it('single element removed and next called', async () => {
124+
const underTest = new DataSourceList<number>(true, [1]);
125+
expect(underTest.remove(1)).toEqual(true);
126+
expect(underTest.next()).toBeUndefined();
127+
});

0 commit comments

Comments
 (0)