Skip to content

Commit 9cea0b6

Browse files
authored
feat: modify datafile managers to use datafile strings instead of objects (#542)
* feat: modify datafile managers to work with datafile string instead of object * fix: revert/discard unneeded changes that were accidentally pushed * test: update tests to comply with change in datafile format * fix: updated overlooked test case to ensure that TestDatafileManager was correctly created with a datafile string * style: fix linting * docs: update CHANGELOG unreleased changes * refactor: modify cache implementations to store values as a string instead of 'any' type and update corresponding tests * docs: update CHANGELOG unreleased changes to include changes to cache implementation
1 parent d00751b commit 9cea0b6

File tree

7 files changed

+75
-135
lines changed

7 files changed

+75
-135
lines changed

packages/datafile-manager/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
## [Unreleased]
88
Changes that have landed but are not yet released.
99

10+
### Changed
11+
12+
- Modified datafile manager to accept, process, and return the datafile's string representation instead of the datafile object.
13+
- Remove JSON parsing of response received from datafile fetch request
14+
- Responsibility of validating the datafile now solely belongs to the project config manager
15+
- Modified React Native async storage cache and persistent value cache implementation to store strings instead of objects as values.
16+
1017
## [0.7.0] - July 28, 2020
1118

1219
### Changed

packages/datafile-manager/__test__/httpPollingDatafileManager.spec.ts

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ class TestDatafileManager extends HttpPollingDatafileManager {
6969
}
7070

7171
const testCache: PersistentKeyValueCache = {
72-
get(key: string): Promise<any | null> {
73-
let val = null;
72+
get(key: string): Promise<string> {
73+
let val = '';
7474
switch (key) {
7575
case 'opt-datafile-keyThatExists':
76-
val = { name: 'keyThatExists' };
76+
val = JSON.stringify({ name: 'keyThatExists' });
7777
break;
7878
}
7979
return Promise.resolve(val);
@@ -109,11 +109,11 @@ describe('httpPollingDatafileManager', () => {
109109

110110
describe('when constructed with sdkKey and datafile and autoUpdate: true,', () => {
111111
beforeEach(() => {
112-
manager = new TestDatafileManager({ datafile: { foo: 'abcd' }, sdkKey: '123', autoUpdate: true });
112+
manager = new TestDatafileManager({ datafile: JSON.stringify({ foo: 'abcd' }), sdkKey: '123', autoUpdate: true });
113113
});
114114

115115
it('returns the passed datafile from get', () => {
116-
expect(manager.get()).toEqual({ foo: 'abcd' });
116+
expect(JSON.parse(manager.get())).toEqual({ foo: 'abcd' });
117117
});
118118

119119
it('after being started, fetches the datafile, updates itself, and updates itself again after a timeout', async () => {
@@ -134,28 +134,30 @@ describe('httpPollingDatafileManager', () => {
134134
manager.start();
135135
expect(manager.responsePromises.length).toBe(1);
136136
await manager.responsePromises[0];
137-
expect(manager.get()).toEqual({ foo: 'bar' });
137+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
138138
updateFn.mockReset();
139139

140140
await advanceTimersByTime(300000);
141141

142142
expect(manager.responsePromises.length).toBe(2);
143143
await manager.responsePromises[1];
144144
expect(updateFn).toBeCalledTimes(1);
145-
expect(updateFn).toBeCalledWith({
146-
datafile: { fooz: 'barz' },
147-
});
148-
expect(manager.get()).toEqual({ fooz: 'barz' });
145+
expect(updateFn.mock.calls[0][0]).toEqual({ datafile: '{"fooz": "barz"}' });
146+
expect(JSON.parse(manager.get())).toEqual({ fooz: 'barz' });
149147
});
150148
});
151149

152150
describe('when constructed with sdkKey and datafile and autoUpdate: false,', () => {
153151
beforeEach(() => {
154-
manager = new TestDatafileManager({ datafile: { foo: 'abcd' }, sdkKey: '123', autoUpdate: false });
152+
manager = new TestDatafileManager({
153+
datafile: JSON.stringify({ foo: 'abcd' }),
154+
sdkKey: '123',
155+
autoUpdate: false,
156+
});
155157
});
156158

157159
it('returns the passed datafile from get', () => {
158-
expect(manager.get()).toEqual({ foo: 'abcd' });
160+
expect(JSON.parse(manager.get())).toEqual({ foo: 'abcd' });
159161
});
160162

161163
it('after being started, fetches the datafile, updates itself once, but does not schedule a future update', async () => {
@@ -167,7 +169,7 @@ describe('httpPollingDatafileManager', () => {
167169
manager.start();
168170
expect(manager.responsePromises.length).toBe(1);
169171
await manager.responsePromises[0];
170-
expect(manager.get()).toEqual({ foo: 'bar' });
172+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
171173
expect(getTimerCount()).toBe(0);
172174
});
173175
});
@@ -179,7 +181,7 @@ describe('httpPollingDatafileManager', () => {
179181

180182
describe('initial state', () => {
181183
it('returns null from get before becoming ready', () => {
182-
expect(manager.get()).toBeNull();
184+
expect(manager.get()).toEqual('');
183185
});
184186
});
185187

@@ -205,28 +207,7 @@ describe('httpPollingDatafileManager', () => {
205207
});
206208
manager.start();
207209
await manager.onReady();
208-
expect(manager.get()).toEqual({ foo: 'bar' });
209-
});
210-
211-
it('does not update if the response body is not valid json', async () => {
212-
manager.queuedResponses.push(
213-
{
214-
statusCode: 200,
215-
body: '{"foo" "',
216-
headers: {},
217-
},
218-
{
219-
statusCode: 200,
220-
body: '{"foo": "bar"}',
221-
headers: {},
222-
}
223-
);
224-
manager.start();
225-
await manager.onReady();
226-
await advanceTimersByTime(1000);
227-
expect(manager.responsePromises.length).toBe(2);
228-
await manager.responsePromises[1];
229-
expect(manager.get()).toEqual({ foo: 'bar' });
210+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
230211
});
231212

232213
describe('live updates', () => {
@@ -275,22 +256,22 @@ describe('httpPollingDatafileManager', () => {
275256

276257
manager.start();
277258
await manager.onReady();
278-
expect(manager.get()).toEqual({ foo: 'bar' });
259+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
279260
expect(updateFn).toBeCalledTimes(0);
280261

281262
await advanceTimersByTime(1000);
282263
await manager.responsePromises[1];
283264
expect(updateFn).toBeCalledTimes(1);
284-
expect(updateFn.mock.calls[0][0]).toEqual({ datafile: { foo2: 'bar2' } });
285-
expect(manager.get()).toEqual({ foo2: 'bar2' });
265+
expect(updateFn.mock.calls[0][0]).toEqual({ datafile: '{"foo2": "bar2"}' });
266+
expect(JSON.parse(manager.get())).toEqual({ foo2: 'bar2' });
286267

287268
updateFn.mockReset();
288269

289270
await advanceTimersByTime(1000);
290271
await manager.responsePromises[2];
291272
expect(updateFn).toBeCalledTimes(1);
292-
expect(updateFn.mock.calls[0][0]).toEqual({ datafile: { foo3: 'bar3' } });
293-
expect(manager.get()).toEqual({ foo3: 'bar3' });
273+
expect(updateFn.mock.calls[0][0]).toEqual({ datafile: '{"foo3": "bar3"}' });
274+
expect(JSON.parse(manager.get())).toEqual({ foo3: 'bar3' });
294275
});
295276

296277
describe('when the update interval time fires before the request is complete', () => {
@@ -351,15 +332,15 @@ describe('httpPollingDatafileManager', () => {
351332

352333
manager.start();
353334
await manager.onReady();
354-
expect(manager.get()).toEqual({ foo: 'bar' });
335+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
355336

356337
advanceTimersByTime(1000);
357338

358339
expect(manager.responsePromises.length).toBe(2);
359340
manager.stop();
360341
await manager.responsePromises[1];
361342
// Should not have updated datafile since manager was stopped
362-
expect(manager.get()).toEqual({ foo: 'bar' });
343+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
363344
});
364345

365346
it('calls abort on the current request if there is a current request when stop is called', async () => {
@@ -399,7 +380,7 @@ describe('httpPollingDatafileManager', () => {
399380
// Trigger the update, should fetch the next response which should succeed, then we get ready
400381
advanceTimersByTime(1000);
401382
await manager.onReady();
402-
expect(manager.get()).toEqual({ foo: 'bar' });
383+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
403384
});
404385

405386
describe('newness checking', () => {
@@ -424,7 +405,7 @@ describe('httpPollingDatafileManager', () => {
424405

425406
manager.start();
426407
await manager.onReady();
427-
expect(manager.get()).toEqual({ foo: 'bar' });
408+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
428409
// First response promise was for the initial 200 response
429410
expect(manager.responsePromises.length).toBe(1);
430411
// Trigger the queued update
@@ -434,7 +415,7 @@ describe('httpPollingDatafileManager', () => {
434415
await manager.responsePromises[1];
435416
// Since the response was 304, updateFn should not have been called
436417
expect(updateFn).toBeCalledTimes(0);
437-
expect(manager.get()).toEqual({ foo: 'bar' });
418+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
438419
});
439420

440421
it('sends if-modified-since using the last observed response last-modified', async () => {
@@ -559,7 +540,7 @@ describe('httpPollingDatafileManager', () => {
559540
});
560541
manager.start();
561542
await manager.onReady();
562-
expect(manager.get()).toEqual({ foo: 'bar' });
543+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
563544
});
564545

565546
it('does not schedule a live update after ready', async () => {
@@ -659,9 +640,9 @@ describe('httpPollingDatafileManager', () => {
659640
manager.on('update', updateFn);
660641
manager.start();
661642
await manager.onReady();
662-
expect(manager.get()).toEqual({ name: 'keyThatExists' });
643+
expect(JSON.parse(manager.get())).toEqual({ name: 'keyThatExists' });
663644
await advanceTimersByTime(50);
664-
expect(manager.get()).toEqual({ name: 'keyThatExists' });
645+
expect(JSON.parse(manager.get())).toEqual({ name: 'keyThatExists' });
665646
expect(updateFn).toBeCalledTimes(0);
666647
});
667648

@@ -676,10 +657,10 @@ describe('httpPollingDatafileManager', () => {
676657
manager.on('update', updateFn);
677658
manager.start();
678659
await manager.onReady();
679-
expect(manager.get()).toEqual({ name: 'keyThatExists' });
660+
expect(JSON.parse(manager.get())).toEqual({ name: 'keyThatExists' });
680661
expect(updateFn).toBeCalledTimes(0);
681662
await advanceTimersByTime(50);
682-
expect(manager.get()).toEqual({ foo: 'bar' });
663+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
683664
expect(updateFn).toBeCalledTimes(1);
684665
});
685666

@@ -693,8 +674,9 @@ describe('httpPollingDatafileManager', () => {
693674
manager.start();
694675
await manager.onReady();
695676
await advanceTimersByTime(50);
696-
expect(manager.get()).toEqual({ foo: 'bar' });
697-
expect(cacheSetSpy).toBeCalledWith('opt-datafile-keyThatExists', { foo: 'bar' });
677+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
678+
expect(cacheSetSpy.mock.calls[0][0]).toEqual('opt-datafile-keyThatExists');
679+
expect(JSON.parse(cacheSetSpy.mock.calls[0][1])).toEqual({ foo: 'bar' });
698680
});
699681
});
700682

@@ -721,7 +703,7 @@ describe('httpPollingDatafileManager', () => {
721703
manager.start();
722704
await advanceTimersByTime(50);
723705
await manager.onReady();
724-
expect(manager.get()).toEqual({ foo: 'bar' });
706+
expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
725707
expect(updateFn).toBeCalledTimes(0);
726708
});
727709
});

packages/datafile-manager/__test__/reactNativeAsyncStorageCache.spec.ts

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,46 +24,28 @@ describe('reactNativeAsyncStorageCache', () => {
2424
});
2525

2626
describe('get', function() {
27-
it('should return correct object when item is found in cache', function() {
28-
return cacheInstance.get('keyThatExists').then(v => expect(v).toEqual({ name: 'Awesome Object' }));
27+
it('should return correct string when item is found in cache', function() {
28+
return cacheInstance.get('keyThatExists').then(v => expect(JSON.parse(v)).toEqual({ name: 'Awesome Object' }));
2929
});
3030

31-
it('should return null if item is not found in cache', function() {
32-
return cacheInstance.get('keyThatDoesNotExist').then(v => expect(v).toBeNull());
33-
});
34-
35-
it('should reject promise error if string has an incorrect JSON format', function() {
36-
return cacheInstance
37-
.get('keyWithInvalidJsonObject')
38-
.catch(() => 'exception caught')
39-
.then(v => {
40-
expect(v).toEqual('exception caught');
41-
});
31+
it('should return empty string if item is not found in cache', function() {
32+
return cacheInstance.get('keyThatDoesNotExist').then(v => expect(v).toEqual(''));
4233
});
4334
});
4435

4536
describe('set', function() {
4637
it('should resolve promise if item was successfully set in the cache', function() {
4738
const testObj = { name: 'Awesome Object' };
48-
return cacheInstance.set('testKey', testObj);
49-
});
50-
51-
it('should reject promise if item was not set in the cache because of json stringifying error', function() {
52-
const testObj: any = { name: 'Awesome Object' };
53-
testObj.myOwnReference = testObj;
54-
return cacheInstance
55-
.set('testKey', testObj)
56-
.catch(() => 'exception caught')
57-
.then(v => expect(v).toEqual('exception caught'));
39+
return cacheInstance.set('testKey', JSON.stringify(testObj));
5840
});
5941
});
6042

6143
describe('contains', function() {
62-
it('should return true if object with key exists', function() {
44+
it('should return true if value with key exists', function() {
6345
return cacheInstance.contains('keyThatExists').then(v => expect(v).toBeTruthy());
6446
});
6547

66-
it('should return false if object with key does not exist', function() {
48+
it('should return false if value with key does not exist', function() {
6749
return cacheInstance.contains('keyThatDoesNotExist').then(v => expect(v).toBeFalsy());
6850
});
6951
});

packages/datafile-manager/src/datafileManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import PersistentKeyValueCache from './persistentKeyValueCache';
1717

1818
export interface DatafileUpdate {
19-
datafile: object;
19+
datafile: string;
2020
}
2121

2222
export interface DatafileUpdateListener {
@@ -31,14 +31,14 @@ interface Managed {
3131
}
3232

3333
export interface DatafileManager extends Managed {
34-
get: () => object | null;
34+
get: () => string;
3535
on: (eventName: string, listener: DatafileUpdateListener) => () => void;
3636
onReady: () => Promise<void>;
3737
}
3838

3939
export interface DatafileManagerConfig {
4040
autoUpdate?: boolean;
41-
datafile?: object;
41+
datafile?: string;
4242
sdkKey: string;
4343
updateInterval?: number;
4444
urlTemplate?: string;

0 commit comments

Comments
 (0)