Skip to content

Commit

Permalink
fix: ensure local overrides work with param stores (#348)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-statsig authored Oct 22, 2024
1 parent af9725f commit 2a8d199
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 83 deletions.
7 changes: 4 additions & 3 deletions packages/combo/src/__tests__/MemoryLeak.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ async function runGarbageCollection() {
}

describe('Memory Usage', () => {
beforeAll(() => {
beforeAll(async () => {
fetchMock.enableMocks();
fetchMock.mockResponse(InitResponseString);

MockLocalStorage.enabledMockStorage();
});

it('clears all used memory when done', async () => {
for (let i = 0; i < 1000; i++) {
const instance = new StatsigClient(
'client-key',
Expand All @@ -39,6 +37,9 @@ describe('Memory Usage', () => {
await instance.initializeAsync();
instance.checkGate('gate1');
}
});

it('clears all used memory when done', async () => {
const initialMemory = process.memoryUsage().heapUsed;

for (let i = 0; i < 10000; i++) {
Expand Down
118 changes: 118 additions & 0 deletions packages/combo/src/__tests__/ParamStoreLocalOverrides.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import fetchMock from 'jest-fetch-mock';
import { InitResponseString } from 'statsig-test-helpers';

import {
ParameterStore,
StatsigClient,
StatsigEvent,
_DJB2,
} from '@statsig/js-client';
import { LocalOverrideAdapter } from '@statsig/js-local-overrides';

describe('Parameter Stores - Local Overrides', () => {
let client: StatsigClient;
let store: ParameterStore;
let events: StatsigEvent[] = [];

beforeAll(async () => {
fetchMock.enableMocks();
fetchMock.mockResponse(InitResponseString);

const overrideAdapter = new LocalOverrideAdapter();
overrideAdapter.overrideGate('partial_gate', false);
overrideAdapter.overrideExperiment('three_groups', { a_num: 99 });
overrideAdapter.overrideLayer('a_layer', { my_obj: { key: 'override' } });

client = new StatsigClient(
'client-key',
{ userID: 'a-user' },
{ overrideAdapter },
);
await client.initializeAsync();

fetchMock.mockImplementation(async (url, payload) => {
if (!url?.toString().includes('/rgstr')) {
return Promise.resolve(new Response());
}

const body = JSON.parse(String(payload?.body ?? '{}'));
events.push(
...body.events.filter((e: StatsigEvent) =>
e.eventName.includes('_exposure'),
),
);
return Promise.resolve(new Response());
});

store = client.getParameterStore('a_param_store');
});

describe('mapped gate params', () => {
let result: string;

beforeAll(async () => {
events = [];

result = store.get('a_string_param', 'fallback');
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toEqual('Nah');
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::gate_exposure');
expect(events[0].metadata?.['gate']).toEqual(_DJB2('partial_gate'));
expect(events[0].metadata?.['reason']).toEqual(
'LocalOverride:Recognized',
);
});
});

describe('mapped experiment params', () => {
let result: number;

beforeAll(async () => {
events = [];

result = store.get('a_num_param', -1);
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toBe(99);
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::config_exposure');
expect(events[0].metadata?.['config']).toEqual(_DJB2('three_groups'));
expect(events[0].metadata?.['reason']).toEqual(
'LocalOverride:Recognized',
);
});
});

describe('mapped layer params', () => {
let result: object;

beforeAll(async () => {
events = [];

result = store.get('an_object_param', { key: 'fallback' });
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toEqual({ key: 'override' });
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::layer_exposure');
expect(events[0].metadata?.['config']).toEqual(_DJB2('a_layer'));
expect(events[0].metadata?.['reason']).toEqual(
'LocalOverride:Recognized',
);
});
});
});
102 changes: 102 additions & 0 deletions packages/combo/src/__tests__/ParamStores.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import fetchMock from 'jest-fetch-mock';
import { InitResponseString } from 'statsig-test-helpers';

import {
ParameterStore,
StatsigClient,
StatsigEvent,
_DJB2,
} from '@statsig/js-client';

describe('Parameter Stores', () => {
let client: StatsigClient;
let store: ParameterStore;
let events: StatsigEvent[] = [];

beforeAll(async () => {
fetchMock.enableMocks();
fetchMock.mockResponse(InitResponseString);

client = new StatsigClient('client-key', { userID: 'a-user' });
await client.initializeAsync();

fetchMock.mockImplementation(async (url, payload) => {
if (!url?.toString().includes('/rgstr')) {
return Promise.resolve(new Response());
}

const body = JSON.parse(String(payload?.body ?? '{}'));
events.push(
...body.events.filter((e: StatsigEvent) =>
e.eventName.includes('_exposure'),
),
);
return Promise.resolve(new Response());
});

store = client.getParameterStore('a_param_store');
});

describe('mapped gate params', () => {
let result: string;

beforeAll(async () => {
events = [];

result = store.get('a_string_param', 'fallback');
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toEqual('Yea');
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::gate_exposure');
expect(events[0].metadata?.['gate']).toEqual(_DJB2('partial_gate'));
expect(events[0].metadata?.['reason']).toEqual('Network:Recognized');
});
});

describe('mapped experiment params', () => {
let result: number;

beforeAll(async () => {
events = [];

result = store.get('a_num_param', -1);
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toBe(2);
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::config_exposure');
expect(events[0].metadata?.['config']).toEqual(_DJB2('three_groups'));
expect(events[0].metadata?.['reason']).toEqual('Network:Recognized');
});
});

describe('mapped layer params', () => {
let result: object;

beforeAll(async () => {
events = [];

result = store.get('an_object_param', { key: 'fallback' });
await client.flush();
});

it('gets the correct value', async () => {
expect(result).toEqual({});
});

it('logs a gate exposure event', () => {
expect(events[0].eventName).toEqual('statsig::layer_exposure');
expect(events[0].metadata?.['config']).toEqual(_DJB2('a_layer'));
expect(events[0].metadata?.['reason']).toEqual('Network:Recognized');
});
});
});
20 changes: 11 additions & 9 deletions packages/combo/src/__tests__/StatsigClientLocalOverrides.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ describe('Local Overrides - StatsigClient', () => {
});

it('has the eval reason to "LocalOverride"', () => {
expect(gate.details.reason).toBe('LocalOverride');
expect(gate.details.reason).toBe('LocalOverride:Recognized');
});

it('emits the correct client event', () => {
const emission = emissions[0] as any;
expect(emission.name).toBe('gate_evaluation');
expect(emission.gate.details.reason).toBe('LocalOverride');
expect(emission.gate.details.reason).toBe('LocalOverride:Recognized');
expect(emission.gate.value).toBe(true);
});

Expand All @@ -71,7 +71,7 @@ describe('Local Overrides - StatsigClient', () => {
const body = JSON.parse(String(payload?.body)) as any;
const event = body.events[0];
expect(event.metadata.gate).toBe('a_gate');
expect(event.metadata.reason).toBe('LocalOverride');
expect(event.metadata.reason).toBe('LocalOverride:Recognized');
});
});

Expand All @@ -93,13 +93,15 @@ describe('Local Overrides - StatsigClient', () => {
});

it('has the eval reason to "LocalOverride"', () => {
expect(config.details.reason).toBe('LocalOverride');
expect(config.details.reason).toBe('LocalOverride:Recognized');
});

it('emits the correct client event', () => {
const emission = emissions[0] as any;
expect(emission.name).toBe('dynamic_config_evaluation');
expect(emission.dynamicConfig.details.reason).toBe('LocalOverride');
expect(emission.dynamicConfig.details.reason).toBe(
'LocalOverride:Recognized',
);
expect(emission.dynamicConfig.value).toEqual({ a_string: 'foo' });
});

Expand All @@ -110,7 +112,7 @@ describe('Local Overrides - StatsigClient', () => {
const body = JSON.parse(String(payload?.body)) as any;
const event = body.events[0];
expect(event.metadata.config).toBe('a_config');
expect(event.metadata.reason).toBe('LocalOverride');
expect(event.metadata.reason).toBe('LocalOverride:Recognized');
});
});

Expand All @@ -134,13 +136,13 @@ describe('Local Overrides - StatsigClient', () => {
});

it('has the eval reason to "LocalOverride"', () => {
expect(layer.details.reason).toBe('LocalOverride');
expect(layer.details.reason).toBe('LocalOverride:Recognized');
});

it('emits the correct client event', () => {
const emission = emissions[0] as any;
expect(emission.name).toBe('layer_evaluation');
expect(emission.layer.details.reason).toBe('LocalOverride');
expect(emission.layer.details.reason).toBe('LocalOverride:Recognized');
expect(emission.layer.__value).toEqual({ a_string: 'foo' });
});

Expand All @@ -151,7 +153,7 @@ describe('Local Overrides - StatsigClient', () => {
const body = JSON.parse(String(payload?.body)) as any;
const event = body.events[0];
expect(event.metadata.config).toBe('a_layer');
expect(event.metadata.reason).toBe('LocalOverride');
expect(event.metadata.reason).toBe('LocalOverride:Recognized');
});
});
});
Loading

0 comments on commit 2a8d199

Please sign in to comment.