Skip to content

Commit

Permalink
Add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilianoSanchez committed Dec 19, 2024
1 parent 956c1df commit 28b7fb9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 2 deletions.
2 changes: 0 additions & 2 deletions src/storages/inLocalStorage/SplitsCacheInLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
*/
clear() {
this.log.info(LOG_PREFIX + 'Flushing Splits data from localStorage');

// collect item keys
const len = localStorage.length;
const accum = [];
Expand Down
125 changes: 125 additions & 0 deletions src/storages/inLocalStorage/__tests__/validateCache.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { validateCache } from '../validateCache';

import { KeyBuilderCS } from '../../KeyBuilderCS';
import { fullSettings } from '../../../utils/settingsValidation/__tests__/settings.mocks';
import { SplitsCacheInLocal } from '../SplitsCacheInLocal';
import { nearlyEqual } from '../../../__tests__/testUtils';
import { MySegmentsCacheInLocal } from '../MySegmentsCacheInLocal';

const FULL_SETTINGS_HASH = '404832b3';

describe('validateCache', () => {
const keys = new KeyBuilderCS('SPLITIO', 'user');
const logSpy = jest.spyOn(fullSettings.log, 'info');
const segments = new MySegmentsCacheInLocal(fullSettings.log, keys);
const largeSegments = new MySegmentsCacheInLocal(fullSettings.log, keys);
const splits = new SplitsCacheInLocal(fullSettings, keys);

jest.spyOn(splits, 'clear');
jest.spyOn(splits, 'getChangeNumber');
jest.spyOn(segments, 'clear');
jest.spyOn(largeSegments, 'clear');

beforeEach(() => {
jest.clearAllMocks();
localStorage.clear();
});

test('if there is no cache, it should return false', () => {
expect(validateCache({}, fullSettings, keys, splits, segments, largeSegments)).toBe(false);

expect(logSpy).not.toHaveBeenCalled();

expect(splits.clear).not.toHaveBeenCalled();
expect(segments.clear).not.toHaveBeenCalled();
expect(largeSegments.clear).not.toHaveBeenCalled();
expect(splits.getChangeNumber).toHaveBeenCalledTimes(1);

expect(localStorage.getItem(keys.buildHashKey())).toBe(FULL_SETTINGS_HASH);
expect(localStorage.getItem(keys.buildLastClear())).toBeNull();
});

test('if there is cache and it must not be cleared, it should return true', () => {
localStorage.setItem(keys.buildSplitsTillKey(), '1');
localStorage.setItem(keys.buildHashKey(), FULL_SETTINGS_HASH);

expect(validateCache({}, fullSettings, keys, splits, segments, largeSegments)).toBe(true);

expect(logSpy).not.toHaveBeenCalled();

expect(splits.clear).not.toHaveBeenCalled();
expect(segments.clear).not.toHaveBeenCalled();
expect(largeSegments.clear).not.toHaveBeenCalled();
expect(splits.getChangeNumber).toHaveBeenCalledTimes(1);

expect(localStorage.getItem(keys.buildHashKey())).toBe(FULL_SETTINGS_HASH);
expect(localStorage.getItem(keys.buildLastClear())).toBeNull();
});

test('if there is cache and it has expired, it should clear cache and return false', () => {
localStorage.setItem(keys.buildSplitsTillKey(), '1');
localStorage.setItem(keys.buildHashKey(), FULL_SETTINGS_HASH);
localStorage.setItem(keys.buildLastUpdatedKey(), Date.now() - 1000 * 60 * 60 * 24 * 2 + ''); // 2 days ago

expect(validateCache({ expirationDays: 1 }, fullSettings, keys, splits, segments, largeSegments)).toBe(false);

expect(logSpy).toHaveBeenCalledWith('storage:localstorage: Cache expired more than 1 days ago. Cleaning up cache');

expect(splits.clear).toHaveBeenCalledTimes(1);
expect(segments.clear).toHaveBeenCalledTimes(1);
expect(largeSegments.clear).toHaveBeenCalledTimes(1);

expect(localStorage.getItem(keys.buildHashKey())).toBe(FULL_SETTINGS_HASH);
expect(nearlyEqual(parseInt(localStorage.getItem(keys.buildLastClear()) as string), Date.now())).toBe(true);
});

test('if there is cache and its hash has changed, it should clear cache and return false', () => {
localStorage.setItem(keys.buildSplitsTillKey(), '1');
localStorage.setItem(keys.buildHashKey(), FULL_SETTINGS_HASH);

expect(validateCache({}, { ...fullSettings, core: { ...fullSettings.core, authorizationKey: 'another' } }, keys, splits, segments, largeSegments)).toBe(false);

expect(logSpy).toHaveBeenCalledWith('storage:localstorage: SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');

expect(splits.clear).toHaveBeenCalledTimes(1);
expect(segments.clear).toHaveBeenCalledTimes(1);
expect(largeSegments.clear).toHaveBeenCalledTimes(1);

expect(localStorage.getItem(keys.buildHashKey())).toBe('aa4877c2');
expect(nearlyEqual(parseInt(localStorage.getItem(keys.buildLastClear()) as string), Date.now())).toBe(true);
});

test('if there is cache and clearOnInit is true, it should clear cache and return false', () => {
// Older cache version (without last clear)
localStorage.setItem(keys.buildSplitsTillKey(), '1');
localStorage.setItem(keys.buildHashKey(), FULL_SETTINGS_HASH);

expect(validateCache({ clearOnInit: true }, fullSettings, keys, splits, segments, largeSegments)).toBe(false);

expect(logSpy).toHaveBeenCalledWith('storage:localstorage: clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');

expect(splits.clear).toHaveBeenCalledTimes(1);
expect(segments.clear).toHaveBeenCalledTimes(1);
expect(largeSegments.clear).toHaveBeenCalledTimes(1);

expect(localStorage.getItem(keys.buildHashKey())).toBe(FULL_SETTINGS_HASH);
const lastClear = localStorage.getItem(keys.buildLastClear());
expect(nearlyEqual(parseInt(lastClear as string), Date.now())).toBe(true);

// If cache is cleared, it should not clear again until a day has passed
logSpy.mockClear();
localStorage.setItem(keys.buildSplitsTillKey(), '1');
expect(validateCache({ clearOnInit: true }, fullSettings, keys, splits, segments, largeSegments)).toBe(true);
expect(logSpy).not.toHaveBeenCalled();
expect(localStorage.getItem(keys.buildLastClear())).toBe(lastClear); // Last clear should not have changed

// If a day has passed, it should clear again
localStorage.setItem(keys.buildLastClear(), (Date.now() - 1000 * 60 * 60 * 24 - 1) + '');
expect(validateCache({ clearOnInit: true }, fullSettings, keys, splits, segments, largeSegments)).toBe(false);
expect(logSpy).toHaveBeenCalledWith('storage:localstorage: clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
expect(splits.clear).toHaveBeenCalledTimes(2);
expect(segments.clear).toHaveBeenCalledTimes(2);
expect(largeSegments.clear).toHaveBeenCalledTimes(2);
expect(nearlyEqual(parseInt(localStorage.getItem(keys.buildLastClear()) as string), Date.now())).toBe(true);
});
});

0 comments on commit 28b7fb9

Please sign in to comment.