Skip to content

Commit 1643628

Browse files
committed
add tests
1 parent f57c315 commit 1643628

File tree

6 files changed

+112
-208
lines changed

6 files changed

+112
-208
lines changed

lib/core/odp/odp_event_api_manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import { LogHandler, LogLevel } from '../../modules/logging';
1818
import { OdpEvent } from './odp_event';
19-
import { RequestHandler } from '../../utils/http_request_handler/http';
19+
import { HttpMethod, RequestHandler } from '../../utils/http_request_handler/http';
2020
import { OdpConfig } from './odp_config';
2121
import { ERROR_MESSAGES } from '../../utils/enums';
2222

@@ -109,7 +109,7 @@ export abstract class OdpEventApiManager implements IOdpEventApiManager {
109109
odpConfig: OdpConfig,
110110
events: OdpEvent[]
111111
): {
112-
method: string;
112+
method: HttpMethod;
113113
endpoint: string;
114114
headers: { [key: string]: string };
115115
data: string;

lib/plugins/odp/event_api_manager/index.browser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { OdpEvent } from '../../../core/odp/odp_event';
1818
import { OdpEventApiManager } from '../../../core/odp/odp_event_api_manager';
1919
import { LogLevel } from '../../../modules/logging';
2020
import { OdpConfig, OdpIntegrationConfig } from '../../../core/odp/odp_config';
21+
import { HttpMethod } from '../../../utils/http_request_handler/http';
2122

2223
const EVENT_SENDING_FAILURE_MESSAGE = 'ODP event send failed';
2324

@@ -41,7 +42,7 @@ export class BrowserOdpEventApiManager extends OdpEventApiManager {
4142
protected generateRequestData(
4243
odpConfig: OdpConfig,
4344
events: OdpEvent[]
44-
): { method: string; endpoint: string; headers: { [key: string]: string }; data: string } {
45+
): { method: HttpMethod; endpoint: string; headers: { [key: string]: string }; data: string } {
4546
const pixelApiEndpoint = this.getPixelApiEndpoint(odpConfig);
4647

4748
const apiKey = odpConfig.apiKey;

lib/plugins/odp/event_api_manager/index.node.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { OdpConfig, OdpIntegrationConfig } from '../../../core/odp/odp_config';
1818
import { OdpEvent } from '../../../core/odp/odp_event';
1919
import { OdpEventApiManager } from '../../../core/odp/odp_event_api_manager';
2020
import { LogLevel } from '../../../modules/logging';
21+
import { HttpMethod } from '../../../utils/http_request_handler/http';
2122
export class NodeOdpEventApiManager extends OdpEventApiManager {
2223
protected shouldSendEvents(events: OdpEvent[]): boolean {
2324
return true;
@@ -26,7 +27,7 @@ export class NodeOdpEventApiManager extends OdpEventApiManager {
2627
protected generateRequestData(
2728
odpConfig: OdpConfig,
2829
events: OdpEvent[]
29-
): { method: string; endpoint: string; headers: { [key: string]: string }; data: string } {
30+
): { method: HttpMethod; endpoint: string; headers: { [key: string]: string }; data: string } {
3031

3132
const { apiHost, apiKey } = odpConfig;
3233

lib/project_config/polling_datafile_manager.spec.ts

Lines changed: 90 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import PersistentKeyValueCache from '../../lib/plugins/key_value_cache/persisten
2525
import { getMockLogger } from '../tests/mock/mockLogger';
2626
import { DEFAULT_URL_TEMPLATE, MIN_UPDATE_INTERVAL, UPDATE_INTERVAL_BELOW_MINIMUM_MESSAGE } from './config';
2727
import { resolvablePromise } from '../utils/promise/resolvablePromise';
28+
import { ServiceState } from '../service';
2829

2930
const testCache = (): PersistentKeyValueCache => ({
3031
get(key: string): Promise<string | undefined> {
@@ -51,7 +52,7 @@ const testCache = (): PersistentKeyValueCache => ({
5152
});
5253

5354
describe('PollingDatafileManager', () => {
54-
it('should log polling interval below 30 seconds', () => {
55+
it('should log polling interval below MIN_UPDATE_INTERVAL', () => {
5556
const repeater = getMockRepeater();
5657
const requestHandler = getMockRequestHandler();
5758
const logger = getMockLogger();
@@ -60,13 +61,13 @@ describe('PollingDatafileManager', () => {
6061
requestHandler,
6162
sdkKey: '123',
6263
logger,
63-
updateInterval: 29000,
64+
updateInterval: MIN_UPDATE_INTERVAL - 1000,
6465
});
6566
manager.start();
6667
expect(logger.warn).toHaveBeenCalledWith(UPDATE_INTERVAL_BELOW_MINIMUM_MESSAGE);
6768
});
6869

69-
it('should not log polling interval above 30 seconds', () => {
70+
it('should not log polling interval above MIN_UPDATE_INTERVAL', () => {
7071
const repeater = getMockRepeater();
7172
const requestHandler = getMockRequestHandler();
7273
const logger = getMockLogger();
@@ -75,7 +76,7 @@ describe('PollingDatafileManager', () => {
7576
requestHandler,
7677
sdkKey: '123',
7778
logger,
78-
updateInterval: 31000,
79+
updateInterval: MIN_UPDATE_INTERVAL + 1000,
7980
});
8081
manager.start();
8182
expect(logger.warn).not.toHaveBeenCalled();
@@ -251,7 +252,7 @@ describe('PollingDatafileManager', () => {
251252
await expect(ret).resolves.not.toThrow();
252253
});
253254

254-
describe('initialization', () => {
255+
describe('start', () => {
255256
it('retries specified number of times before rejecting onRunning() and onTerminated() when autoupdate is true', async () => {
256257
const repeater = getMockRepeater();
257258
const requestHandler = getMockRequestHandler();
@@ -829,199 +830,87 @@ describe('PollingDatafileManager', () => {
829830
expect(listener).toHaveBeenCalledTimes(1);
830831
});
831832

832-
// describe('when constructed with sdkKey and datafile and autoUpdate: false,', () => {
833-
// beforeEach(() => {
834-
// manager = new TestDatafileManager({
835-
// datafile: JSON.stringify({ foo: 'abcd' }),
836-
// sdkKey: '123',
837-
// autoUpdate: false,
838-
// });
839-
// });
840-
841-
// it('returns the passed datafile from get', () => {
842-
// expect(JSON.parse(manager.get())).toEqual({ foo: 'abcd' });
843-
// });
844-
845-
// it('after being started, fetches the datafile, updates itself once, but does not schedule a future update', async () => {
846-
// manager.queuedResponses.push({
847-
// statusCode: 200,
848-
// body: '{"foo": "bar"}',
849-
// headers: {},
850-
// });
851-
// manager.start();
852-
// expect(manager.responsePromises.length).toBe(1);
853-
// await manager.responsePromises[0];
854-
// expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
855-
// expect(getTimerCount()).toBe(0);
856-
// });
857-
// });
858-
859-
// describe('when constructed with sdkKey and autoUpdate: true', () => {
860-
// beforeEach(() => {
861-
// manager = new TestDatafileManager({ sdkKey: '123', updateInterval: 1000, autoUpdate: true });
862-
// });
863-
864-
// it('logs an error if fetching datafile fails', async () => {
865-
// manager.queuedResponses.push(
866-
// {
867-
// statusCode: 500,
868-
// body: '',
869-
// headers: {},
870-
// }
871-
// );
872-
873-
// manager.start();
874-
// await advanceTimersByTime(1000);
875-
// await manager.responsePromises[0];
876-
877-
// verify(spiedLogger.error('Datafile fetch request failed with status: 500')).once();
878-
// });
879-
880-
// describe('initial state', () => {
881-
// it('returns null from get before becoming ready', () => {
882-
// expect(manager.get()).toEqual('');
883-
// });
884-
// });
885-
886-
// describe('started state', () => {
887-
// it('passes the default datafile URL to the makeGetRequest method', async () => {
888-
// const makeGetRequestSpy = vi.spyOn(manager, 'makeGetRequest');
889-
// manager.queuedResponses.push({
890-
// statusCode: 200,
891-
// body: '{"foo": "bar"}',
892-
// headers: {},
893-
// });
894-
// manager.start();
895-
// expect(makeGetRequestSpy).toBeCalledTimes(1);
896-
// expect(makeGetRequestSpy.mock.calls[0][0]).toBe('https://cdn.optimizely.com/datafiles/123.json');
897-
// await manager.onReady();
898-
// });
899-
900-
901-
// describe('live updates', () => {
902-
903-
// it('cancels a pending timeout when stop is called', async () => {
904-
// manager.queuedResponses.push({
905-
// statusCode: 200,
906-
// body: '{"foo": "bar"}',
907-
// headers: {},
908-
// });
909-
910-
// manager.start();
911-
// await manager.onReady();
912-
913-
// expect(getTimerCount()).toBe(1);
914-
// manager.stop();
915-
// expect(getTimerCount()).toBe(0);
916-
// });
917-
918-
// it('cancels reactions to a pending fetch when stop is called', async () => {
919-
// manager.queuedResponses.push(
920-
// {
921-
// statusCode: 200,
922-
// body: '{"foo2": "bar2"}',
923-
// headers: {},
924-
// },
925-
// {
926-
// statusCode: 200,
927-
// body: '{"foo": "bar"}',
928-
// headers: {},
929-
// }
930-
// );
931-
932-
// manager.start();
933-
// await manager.onReady();
934-
// expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
935-
936-
// await advanceTimersByTime(1000);
937-
938-
// expect(manager.responsePromises.length).toBe(2);
939-
// manager.stop();
940-
// await manager.responsePromises[1];
941-
// // Should not have updated datafile since manager was stopped
942-
// expect(JSON.parse(manager.get())).toEqual({ foo: 'bar' });
943-
// });
944-
945-
// it('calls abort on the current request if there is a current request when stop is called', async () => {
946-
// manager.queuedResponses.push({
947-
// statusCode: 200,
948-
// body: '{"foo2": "bar2"}',
949-
// headers: {},
950-
// });
951-
// const makeGetRequestSpy = vi.spyOn(manager, 'makeGetRequest');
952-
// manager.start();
953-
// const currentRequest = makeGetRequestSpy.mock.results[0];
954-
// // @ts-ignore
955-
// expect(currentRequest.type).toBe('return');
956-
// expect(currentRequest.value.abort).toBeCalledTimes(0);
957-
// manager.stop();
958-
// expect(currentRequest.value.abort).toBeCalledTimes(1);
959-
// });
960-
961-
// TODO: figure out what's wrong with this test
962-
// it.skip('rejects the onReady promise if the initial request promise rejects', async () => {
963-
// manager.queuedResponses.push({
964-
// statusCode: 200,
965-
// body: '{"foo": "bar"}',
966-
// headers: {},
967-
// });
968-
// manager.makeGetRequest = (): AbortableRequest => ({
969-
// abort(): void {},
970-
// responsePromise: Promise.reject(new Error('Could not connect')),
971-
// });
972-
// manager.start();
973-
// let didReject = false;
974-
// try {
975-
// await manager.onReady();
976-
// } catch (e) {
977-
// didReject = true;
978-
// }
979-
// expect(didReject).toBe(true);
980-
// });
981-
// });
982-
983-
// describe('when constructed with sdkKey and a valid urlTemplate', () => {
984-
// beforeEach(() => {
985-
// manager = new TestDatafileManager({
986-
// sdkKey: '456',
987-
// updateInterval: 1000,
988-
// urlTemplate: 'https://localhost:5556/datafiles/%s',
989-
// });
990-
// });
991-
992-
// it('uses the urlTemplate to create the url passed to the makeGetRequest method', async () => {
993-
// const makeGetRequestSpy = vi.spyOn(manager, 'makeGetRequest');
994-
// manager.queuedResponses.push({
995-
// statusCode: 200,
996-
// body: '{"foo": "bar"}',
997-
// headers: {},
998-
// });
999-
// manager.start();
1000-
// expect(makeGetRequestSpy).toBeCalledTimes(1);
1001-
// expect(makeGetRequestSpy.mock.calls[0][0]).toBe('https://localhost:5556/datafiles/456');
1002-
// await manager.onReady();
1003-
// });
1004-
// });
1005-
1006-
// describe('when constructed with an update interval below the minimum', () => {
1007-
// beforeEach(() => {
1008-
// manager = new TestDatafileManager({ sdkKey: '123', updateInterval: 500, autoUpdate: true });
1009-
// });
1010-
1011-
// it('uses the default update interval', async () => {
1012-
// const makeGetRequestSpy = vi.spyOn(manager, 'makeGetRequest');
1013-
1014-
// manager.queuedResponses.push({
1015-
// statusCode: 200,
1016-
// body: '{"foo3": "bar3"}',
1017-
// headers: {},
1018-
// });
1019-
1020-
// manager.start();
1021-
// await manager.onReady();
1022-
// expect(makeGetRequestSpy).toBeCalledTimes(1);
1023-
// await advanceTimersByTime(300000);
1024-
// expect(makeGetRequestSpy).toBeCalledTimes(2);
1025-
// });
1026-
// });
1027-
});
833+
describe('stop', () => {
834+
it('rejects onRunning when stop is called if manager is new', async () => {
835+
const repeater = getMockRepeater();
836+
const requestHandler = getMockRequestHandler();
837+
const manager = new PollingDatafileManager({
838+
repeater,
839+
requestHandler,
840+
sdkKey: 'keyThatExists',
841+
autoUpdate: true,
842+
});
843+
844+
manager.start();
845+
manager.stop();
846+
await expect(manager.onRunning()).rejects.toThrow();
847+
});
848+
849+
it('stops the repeater, set state to Termimated, and resolve onTerminated when stop is called', async () => {
850+
const repeater = getMockRepeater();
851+
const requestHandler = getMockRequestHandler();
852+
const mockResponse = getMockAbortableRequest(Promise.resolve({ statusCode: 200, body: '{"foo": "bar"}', headers: {} }));
853+
requestHandler.makeRequest.mockReturnValueOnce(mockResponse);
854+
855+
const manager = new PollingDatafileManager({
856+
repeater,
857+
requestHandler,
858+
sdkKey: 'keyThatExists',
859+
autoUpdate: true,
860+
});
861+
862+
manager.start();
863+
await repeater.execute(0);
864+
await expect(manager.onRunning()).resolves.not.toThrow();
865+
866+
manager.stop();
867+
await expect(manager.onTerminated()).resolves.not.toThrow();
868+
expect(repeater.stop).toHaveBeenCalled();
869+
expect(manager.getState()).toBe(ServiceState.Terminated);
870+
});
871+
872+
it('aborts the current request if stop is called', async () => {
873+
const repeater = getMockRepeater();
874+
const requestHandler = getMockRequestHandler();
875+
const mockResponse = getMockAbortableRequest();
876+
requestHandler.makeRequest.mockReturnValueOnce(mockResponse);
877+
878+
const manager = new PollingDatafileManager({
879+
repeater,
880+
requestHandler,
881+
sdkKey: 'keyThatExists',
882+
autoUpdate: true,
883+
});
884+
885+
manager.start();
886+
repeater.execute(0);
887+
888+
expect(requestHandler.makeRequest).toHaveBeenCalledOnce();
889+
manager.stop();
890+
expect(mockResponse.abort).toHaveBeenCalled();
891+
});
892+
893+
it('does not call onUpdate handler after stop is called', async () => {
894+
const repeater = getMockRepeater();
895+
const requestHandler = getMockRequestHandler();
896+
const mockResponse = getMockAbortableRequest(Promise.resolve({ statusCode: 200, body: '{"foo": "bar"}', headers: {} }));
897+
requestHandler.makeRequest.mockReturnValueOnce(mockResponse);
898+
899+
const manager = new PollingDatafileManager({
900+
repeater,
901+
requestHandler,
902+
sdkKey: 'keyThatExists',
903+
autoUpdate: true,
904+
});
905+
906+
const listener = vi.fn();
907+
manager.onUpdate(listener);
908+
909+
manager.start();
910+
repeater.execute(0);
911+
manager.stop();
912+
913+
expect(listener).not.toHaveBeenCalled();
914+
});
915+
})
916+
});

0 commit comments

Comments
 (0)