Skip to content

Commit b276b7e

Browse files
committed
tests
1 parent 3c8a57c commit b276b7e

10 files changed

+768
-602
lines changed

lib/project_config/config_manager_factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { RequestHandler } from "../utils/http_request_handler/http";
22
import { Transformer } from "../utils/type";
3-
import { DatafileManagerConfig } from "./datafileManager";
3+
import { DatafileManagerConfig } from "./datafile_manager";
44
import { ProjectConfigManagerImpl, ProjectConfigManager } from "./project_config_manager";
55
import { HttpPollingDatafileManager } from "./httpPollingDatafileManager";
66
import PersistentKeyValueCache from "../plugins/key_value_cache/persistentKeyValueCache";

lib/project_config/httpPollingDatafileManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import { getLogger } from '../modules/logging';
1818
import { sprintf } from '../utils/fns';
19-
import { DatafileManager, DatafileManagerConfig } from './datafileManager';
19+
import { DatafileManager, DatafileManagerConfig } from './datafile_manager';
2020
import { EventEmitter } from '../utils/event_emitter/eventEmitter';
2121
import { DEFAULT_UPDATE_INTERVAL, MIN_UPDATE_INTERVAL, DEFAULT_URL_TEMPLATE, UPDATE_INTERVAL_BELOW_MINIMUM_MESSAGE } from './config';
2222
import PersistentKeyValueCache from '../plugins/key_value_cache/persistentKeyValueCache';

lib/project_config/project_config_manager.spec.ts

Lines changed: 678 additions & 0 deletions
Large diffs are not rendered by default.

lib/project_config/project_config_manager.tests.js

Lines changed: 0 additions & 490 deletions
This file was deleted.

lib/project_config/project_config_manager.ts

Lines changed: 15 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,28 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import { getLogger, LoggerFacade } from '../modules/logging';
16+
import { LoggerFacade } from '../modules/logging';
1717
import { sprintf } from '../utils/fns';
1818

1919
import { ERROR_MESSAGES } from '../utils/enums';
2020
import { createOptimizelyConfig } from '../core/optimizely_config';
2121
import { OptimizelyConfig } from '../shared_types';
22-
import { DatafileManager } from './datafileManager';
22+
import { DatafileManager } from './datafile_manager';
2323
import { ProjectConfig, toDatafile, tryCreatingProjectConfig } from '../project_config';
2424
import { scheduleMicrotask } from '../utils/microtask';
2525
import { Service, ServiceState, BaseService } from '../service';
2626
import { Consumer, Fn, Transformer } from '../utils/type';
2727
import { EventEmitter } from '../utils/event_emitter/eventEmitter';
2828

29-
30-
const logger = getLogger();
3129
const MODULE_NAME = 'PROJECT_CONFIG_MANAGER';
3230

3331
interface ProjectConfigManagerConfig {
34-
// TODO[OASIS-6649]: Don't use object type
32+
// TODO: Don't use object type
3533
// eslint-disable-next-line @typescript-eslint/ban-types
3634
datafile?: string | object;
3735
jsonSchemaValidator?: Transformer<unknown, boolean>,
3836
datafileManager?: DatafileManager;
37+
logger?: LoggerFacade;
3938
}
4039

4140
export interface ProjectConfigManager extends Service {
@@ -63,7 +62,7 @@ export class ProjectConfigManagerImpl extends BaseService implements ProjectConf
6362

6463
constructor(config: ProjectConfigManagerConfig) {
6564
super();
66-
65+
this.logger = config.logger;
6766
this.jsonSchemaValidator = config.jsonSchemaValidator;
6867
this.datafile = config.datafile;
6968
this.datafileManager = config.datafileManager;
@@ -73,18 +72,6 @@ export class ProjectConfigManagerImpl extends BaseService implements ProjectConf
7372
this.logger = logger;
7473
}
7574

76-
getState(): ServiceState {
77-
return this.state;
78-
}
79-
80-
onRunning(): Promise<void> {
81-
return this.startPromise.promise;
82-
}
83-
84-
onTerminated(): Promise<void> {
85-
return this.stopPromise.promise;
86-
}
87-
8875
start() {
8976
if (!this.datafile && !this.datafileManager) {
9077
this.handleInitError(new Error('You must provide at least one of sdkKey or datafile'));
@@ -96,99 +83,30 @@ export class ProjectConfigManagerImpl extends BaseService implements ProjectConf
9683
}
9784

9885
this.datafileManager?.start();
99-
this.datafileManager?.onUpdate((this.handleNewDatafile.bind(this)));
86+
this.datafileManager?.onUpdate(this.handleNewDatafile.bind(this));
87+
88+
// If the datafile manager runs successfully, it will emit a onUpdate event. We can
89+
// handle the success case in the onUpdate handler. Hanlding the error case in the.
90+
// catch callback
10091
this.datafileManager?.onRunning().catch((err) => {
10192
this.handleDatafileManagerError(err);
10293
});
10394
}
10495

105-
// try {
106-
// if (!config.datafile && !config.sdkKey) {
107-
// const datafileAndSdkKeyMissingError = new Error(
108-
// sprintf(ERROR_MESSAGES.DATAFILE_AND_SDK_KEY_MISSING, MODULE_NAME)
109-
// );
110-
// this.readyPromise = Promise.resolve({
111-
// success: false,
112-
// reason: getErrorMessage(datafileAndSdkKeyMissingError),
113-
// });
114-
// logger.error(datafileAndSdkKeyMissingError);
115-
// return;
116-
// }
117-
118-
// let handleNewDatafileException = null;
119-
// if (config.datafile) {
120-
// handleNewDatafileException = this.handleNewDatafile(config.datafile);
121-
// }
122-
123-
// if (config.sdkKey && config.datafileManager) {
124-
// this.datafileManager = config.datafileManager;
125-
// this.datafileManager.start();
126-
127-
// this.readyPromise = this.datafileManager
128-
// .onReady()
129-
// .then(this.onDatafileManagerReadyFulfill.bind(this), this.onDatafileManagerReadyReject.bind(this));
130-
// this.datafileManager.on('update', this.onDatafileManagerUpdate.bind(this));
131-
// } else if (this.projectConfig) {
132-
// this.readyPromise = Promise.resolve({
133-
// success: true,
134-
// });
135-
// } else {
136-
// this.readyPromise = Promise.resolve({
137-
// success: false,
138-
// reason: getErrorMessage(handleNewDatafileException, 'Invalid datafile'),
139-
// });
140-
// }
141-
// } catch (ex) {
142-
// logger.error(ex);
143-
// this.readyPromise = Promise.resolve({
144-
// success: false,
145-
// reason: getErrorMessage(ex, 'Error in initialize'),
146-
// });
147-
// }
148-
// }
149-
15096
private handleInitError(error: Error): void {
151-
logger.error(error);
97+
this.logger?.error(error);
15298
this.state = ServiceState.Failed;
15399
this.datafileManager?.stop();
154100
this.startPromise.reject(error);
155101
this.stopPromise.reject(error);
156102
}
157103

158-
/**
159-
* Respond to datafile manager's onReady promise becoming fulfilled.
160-
* If there are validation or parse failures using the datafile provided by
161-
* DatafileManager, ProjectConfigManager's ready promise is resolved with an
162-
* unsuccessful result. Otherwise, ProjectConfigManager updates its own project
163-
* config object from the new datafile, and its ready promise is resolved with a
164-
* successful result.
165-
*/
166-
// private onDatafileManagerReadyFulfill(): OnReadyResult {
167-
// if (this.datafileManager) {
168-
// const newDatafileError = this.handleNewDatafile(this.datafileManager.get());
169-
// if (newDatafileError) {
170-
// return {
171-
// success: false,
172-
// reason: getErrorMessage(newDatafileError),
173-
// };
174-
// }
175-
// return { success: true };
176-
// }
177-
178-
// return {
179-
// success: false,
180-
// reason: getErrorMessage(null, 'Datafile manager is not provided'),
181-
// };
182-
// }
183-
184104
/**
185105
* Respond to datafile manager's onRunning promise becoming rejected.
186106
* When DatafileManager's onReady promise is rejected, if a datafile was not provided and therefore
187107
* the projectConfigManager is still in New state, there is no possibility
188108
* of obtaining a datafile. In this case, ProjectConfigManager's ready promise
189109
* is fulfilled with an unsuccessful result.
190-
* @param {Error} err
191-
* @returns {Object}
192110
*/
193111
private handleDatafileManagerError(err: Error): void {
194112
if (this.isNew()) {
@@ -201,18 +119,16 @@ export class ProjectConfigManagerImpl extends BaseService implements ProjectConf
201119
* the new config object's revision is newer than the current one, sets/updates the project config
202120
* and optimizely config object instance variables and returns null for the error. If unsuccessful,
203121
* the project config and optimizely config objects will not be updated, and the error is returned.
204-
* @param {string | object} newDatafile
205-
* @returns {Error|null} error or null
206122
*/
207123
private handleNewDatafile(newDatafile: string | object): void {
208124
const configOrError = tryCreatingProjectConfig({
209125
datafile: newDatafile,
210126
jsonSchemaValidator: this.jsonSchemaValidator,
211-
logger: logger,
127+
logger: this.logger,
212128
});
213129

214130
if (configOrError instanceof Error) {
215-
logger.error(configOrError);
131+
this.logger?.error(configOrError);
216132
// the provided datafile is invalid
217133
// and no datafile manager is provided
218134
// so there is no way to recover
@@ -238,22 +154,14 @@ export class ProjectConfigManagerImpl extends BaseService implements ProjectConf
238154
}
239155
}
240156

241-
/**
242-
* Returns the current project config object, or null if no project config object
243-
* is available
244-
* @return {ProjectConfig|null}
245-
*/
157+
246158
getConfig(): ProjectConfig | undefined {
247159
return this.projectConfig;
248160
}
249161

250-
/**
251-
* Returns the optimizely config object or null
252-
* @return {OptimizelyConfig|null}
253-
*/
254162
getOptimizelyConfig(): OptimizelyConfig | undefined {
255163
if (!this.optimizelyConfig && this.projectConfig) {
256-
this.optimizelyConfig = createOptimizelyConfig(this.projectConfig, toDatafile(this.projectConfig), logger);
164+
this.optimizelyConfig = createOptimizelyConfig(this.projectConfig, toDatafile(this.projectConfig), this.logger);
257165
}
258166
return this.optimizelyConfig;
259167
}

lib/tests/mock/mockDatafileManager.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Consumer } from '../../utils/type';
2+
import { vi } from 'vitest';
3+
import { DatafileManager } from '../../project_config/datafile_manager';
4+
import { EventEmitter } from '../../utils/event_emitter/eventEmitter';
5+
import { BaseService } from '../../service';
6+
7+
type MockConfig = {
8+
datafile?: string | object;
9+
onRunning?: Promise<void>,
10+
onTerminated?: Promise<void>,
11+
}
12+
13+
class MockDatafileManager extends BaseService implements DatafileManager {
14+
eventEmitter: EventEmitter<{ update: string}> = new EventEmitter();
15+
datafile: string | object | undefined;
16+
17+
constructor(opt: MockConfig) {
18+
super();
19+
this.datafile = opt.datafile;
20+
this.startPromise.resolve(opt.onRunning || Promise.resolve());
21+
this.stopPromise.resolve(opt.onTerminated || Promise.resolve());
22+
}
23+
24+
start(): void {
25+
return;
26+
}
27+
28+
stop(): void {
29+
return;
30+
}
31+
32+
get(): string | undefined {
33+
if (typeof this.datafile === 'object') {
34+
return JSON.stringify(this.datafile);
35+
}
36+
return this.datafile;
37+
}
38+
39+
setDatafile(datafile: string): void {
40+
this.datafile = datafile;
41+
}
42+
43+
onUpdate(listener: Consumer<string>): () => void {
44+
return this.eventEmitter.on('update', listener)
45+
}
46+
47+
pushUpdate(datafile: string | object): void {
48+
if (typeof datafile === 'object') {
49+
datafile = JSON.stringify(datafile);
50+
}
51+
this.datafile = datafile;
52+
this.eventEmitter.emit('update', datafile);
53+
}
54+
}
55+
56+
export const getMockDatafileManager = (opt: MockConfig): MockDatafileManager => {
57+
return new MockDatafileManager(opt);
58+
};

lib/tests/mock/mockLogger.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { vi } from 'vitest';
2+
import { LoggerFacade } from '../../modules/logging';
3+
4+
export const mockLogger = () : LoggerFacade => {
5+
return {
6+
info: vi.fn(),
7+
log: vi.fn(),
8+
error: vi.fn(),
9+
warn: vi.fn(),
10+
debug: vi.fn(),
11+
};
12+
};

lib/tests/test_data.js renamed to lib/tests/test_data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import cloneDeep from 'lodash/cloneDeep';
16+
const cloneDeep = (x: any) => JSON.parse(JSON.stringify(x));
1717

18-
var config = {
18+
const config: any = {
1919
revision: '42',
2020
version: '2',
2121
events: [

vitest.config.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default defineConfig({
44
test: {
55
onConsoleLog: () => true,
66
environment: 'happy-dom',
7-
include: ["**/service.spec.ts"],
7+
include: ["**/project_config_manager.spec.ts"],
88
typecheck: {
99
tsconfig: 'tsconfig.spec.json',
1010
exclude: ['**/index.react_native.spec.ts'],

0 commit comments

Comments
 (0)