Skip to content

Commit b0d426c

Browse files
Todd AndersonTodd Anderson
Todd Anderson
authored and
Todd Anderson
committed
chore: adds LDTransactionalFeatureStore, LDTransactionalDataSourceUpdates, and FDv2 DataSource impls.
1 parent a3b816b commit b0d426c

19 files changed

+1413
-72
lines changed

packages/shared/sdk-server/__tests__/data_sources/DataSourceUpdates.test.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { AsyncQueue } from 'launchdarkly-js-test-helpers';
22

33
import { internal } from '@launchdarkly/js-sdk-common';
44

5-
import { LDFeatureStore } from '../../src/api/subsystems';
5+
import { LDTransactionalFeatureStore } from '../../src/api/subsystems';
66
import promisify from '../../src/async/promisify';
7-
import DataSourceUpdates from '../../src/data_sources/DataSourceUpdates';
7+
import DataSourceUpdates from '../../src/data_sources/TransactionalDataSourceUpdates';
88
import InMemoryFeatureStore from '../../src/store/InMemoryFeatureStore';
99
import VersionedDataKinds from '../../src/store/VersionedDataKinds';
1010

@@ -13,21 +13,28 @@ type InitMetadata = internal.InitMetadata;
1313
it('passes initialization metadata to underlying feature store', () => {
1414
const metadata: InitMetadata = { environmentId: '12345' };
1515
const store = new InMemoryFeatureStore();
16-
store.init = jest.fn();
16+
store.applyChanges = jest.fn();
1717
const updates = new DataSourceUpdates(
1818
store,
1919
() => false,
2020
() => {},
2121
);
2222
updates.init({}, () => {}, metadata);
23-
expect(store.init).toHaveBeenCalledTimes(1);
24-
expect(store.init).toHaveBeenNthCalledWith(1, expect.any(Object), expect.any(Function), metadata);
23+
expect(store.applyChanges).toHaveBeenCalledTimes(1);
24+
expect(store.applyChanges).toHaveBeenNthCalledWith(
25+
1,
26+
true,
27+
expect.any(Object),
28+
expect.any(Function),
29+
metadata,
30+
undefined,
31+
);
2532
});
2633

2734
describe.each([true, false])(
2835
'given a DataSourceUpdates with in memory store and change listeners: %s',
2936
(listen) => {
30-
let store: LDFeatureStore;
37+
let store: LDTransactionalFeatureStore;
3138
let updates: DataSourceUpdates;
3239

3340
const queue = new AsyncQueue<string>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { subsystem } from '../../src';
2+
import OneShotInitializerFDv2 from '../../src/data_sources/OneShotInitializerFDv2';
3+
import Requestor from '../../src/data_sources/Requestor';
4+
import TestLogger from '../Logger';
5+
6+
describe('given a one shot initializer', () => {
7+
const requestor = {
8+
requestAllData: jest.fn(),
9+
};
10+
const allEvents = {
11+
events: [
12+
{
13+
event: 'server-intent',
14+
data: { payloads: [{ code: 'xfer-full', id: 'mockId' }] },
15+
},
16+
{
17+
event: 'put-object',
18+
data: {
19+
kind: 'flag',
20+
key: 'flagA',
21+
version: 123,
22+
object: { objectFieldA: 'objectValueA' },
23+
},
24+
},
25+
{
26+
event: 'payload-transferred',
27+
data: { state: 'mockState', version: 1 },
28+
},
29+
],
30+
};
31+
const jsonData = JSON.stringify(allEvents);
32+
33+
let initializer: OneShotInitializerFDv2;
34+
const mockDataCallback = jest.fn();
35+
const mockStatusCallback = jest.fn();
36+
let testLogger: TestLogger;
37+
38+
beforeEach(() => {
39+
testLogger = new TestLogger();
40+
initializer = new OneShotInitializerFDv2(requestor as unknown as Requestor, testLogger);
41+
});
42+
43+
afterEach(() => {
44+
initializer.stop();
45+
jest.restoreAllMocks();
46+
});
47+
48+
it('makes no requests before being started', () => {
49+
expect(requestor.requestAllData).not.toHaveBeenCalled();
50+
});
51+
52+
it('polls immediately on start', () => {
53+
initializer.start(mockDataCallback, mockStatusCallback);
54+
expect(requestor.requestAllData).toHaveBeenCalledTimes(1);
55+
expect(mockDataCallback).not.toHaveBeenCalled();
56+
expect(mockStatusCallback).toHaveBeenNthCalledWith(1, subsystem.DataSourceState.Initializing);
57+
});
58+
59+
it('calls callback on success', () => {
60+
requestor.requestAllData = jest.fn((cb) => cb(undefined, jsonData));
61+
initializer.start(mockDataCallback, mockStatusCallback);
62+
expect(mockDataCallback).toHaveBeenNthCalledWith(1, true, {
63+
basis: true,
64+
id: `mockId`,
65+
state: `mockState`,
66+
updates: [
67+
{
68+
kind: `flag`,
69+
key: `flagA`,
70+
version: 123,
71+
object: { objectFieldA: 'objectValueA' },
72+
},
73+
],
74+
version: 1,
75+
});
76+
});
77+
});

packages/shared/sdk-server/__tests__/data_sources/PollingProcessor.test.ts

+8-25
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
import { ClientContext } from '@launchdarkly/js-sdk-common';
2-
31
import { LDFeatureStore } from '../../src';
42
import PollingProcessor from '../../src/data_sources/PollingProcessor';
53
import Requestor from '../../src/data_sources/Requestor';
6-
import Configuration from '../../src/options/Configuration';
74
import AsyncStoreFacade from '../../src/store/AsyncStoreFacade';
85
import InMemoryFeatureStore from '../../src/store/InMemoryFeatureStore';
96
import VersionedDataKinds from '../../src/store/VersionedDataKinds';
10-
import { createBasicPlatform } from '../createBasicPlatform';
117
import TestLogger, { LogLevel } from '../Logger';
128

139
describe('given an event processor', () => {
@@ -23,24 +19,19 @@ describe('given an event processor', () => {
2319

2420
let store: LDFeatureStore;
2521
let storeFacade: AsyncStoreFacade;
26-
let config: Configuration;
2722
let processor: PollingProcessor;
2823
let initSuccessHandler: jest.Mock;
2924

3025
beforeEach(() => {
3126
store = new InMemoryFeatureStore();
3227
storeFacade = new AsyncStoreFacade(store);
33-
config = new Configuration({
34-
featureStore: store,
35-
pollInterval: longInterval,
36-
logger: new TestLogger(),
37-
});
3828
initSuccessHandler = jest.fn();
3929

4030
processor = new PollingProcessor(
41-
config,
4231
requestor as unknown as Requestor,
43-
config.featureStoreFactory(new ClientContext('', config, createBasicPlatform())),
32+
longInterval,
33+
store,
34+
new TestLogger(),
4435
initSuccessHandler,
4536
);
4637
});
@@ -99,27 +90,22 @@ describe('given a polling processor with a short poll duration', () => {
9990
const jsonData = JSON.stringify(allData);
10091

10192
let store: LDFeatureStore;
102-
let config: Configuration;
93+
let testLogger: TestLogger;
10394
let processor: PollingProcessor;
10495
let initSuccessHandler: jest.Mock;
10596
let errorHandler: jest.Mock;
10697

10798
beforeEach(() => {
10899
store = new InMemoryFeatureStore();
109-
config = new Configuration({
110-
featureStore: store,
111-
pollInterval: shortInterval,
112-
logger: new TestLogger(),
113-
});
100+
testLogger = new TestLogger();
114101
initSuccessHandler = jest.fn();
115102
errorHandler = jest.fn();
116103

117-
// Configuration will not let us set this as low as needed for the test.
118-
Object.defineProperty(config, 'pollInterval', { value: 0.1 });
119104
processor = new PollingProcessor(
120-
config,
121105
requestor as unknown as Requestor,
122-
config.featureStoreFactory(new ClientContext('', config, createBasicPlatform())),
106+
shortInterval,
107+
store,
108+
testLogger,
123109
initSuccessHandler,
124110
errorHandler,
125111
);
@@ -158,7 +144,6 @@ describe('given a polling processor with a short poll duration', () => {
158144
expect(errorHandler).not.toBeCalled();
159145
setTimeout(() => {
160146
expect(requestor.requestAllData.mock.calls.length).toBeGreaterThanOrEqual(2);
161-
const testLogger = config.logger as TestLogger;
162147
expect(testLogger.getCount(LogLevel.Error)).toBe(0);
163148
expect(testLogger.getCount(LogLevel.Warn)).toBeGreaterThan(2);
164149
(done as jest.DoneCallback)();
@@ -176,7 +161,6 @@ describe('given a polling processor with a short poll duration', () => {
176161

177162
setTimeout(() => {
178163
expect(requestor.requestAllData.mock.calls.length).toBeGreaterThanOrEqual(2);
179-
const testLogger = config.logger as TestLogger;
180164
expect(testLogger.getCount(LogLevel.Error)).toBeGreaterThan(2);
181165
(done as jest.DoneCallback)();
182166
}, 300);
@@ -199,7 +183,6 @@ describe('given a polling processor with a short poll duration', () => {
199183

200184
setTimeout(() => {
201185
expect(requestor.requestAllData.mock.calls.length).toBe(1);
202-
const testLogger = config.logger as TestLogger;
203186
expect(testLogger.getCount(LogLevel.Error)).toBe(1);
204187
(done as jest.DoneCallback)();
205188
}, 300);

0 commit comments

Comments
 (0)