Skip to content

Commit 95deaca

Browse files
committed
Ctd: Integrate ODP w/User Context & Client
1 parent 41df6e6 commit 95deaca

File tree

10 files changed

+194
-131
lines changed

10 files changed

+194
-131
lines changed

packages/optimizely-sdk/lib/core/odp/odp_manager.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class OdpManager {
8888
this.logger = logger || getLogger();
8989

9090
if (!this.enabled) {
91-
this.logger.log(LogLevel.INFO, ERROR_MESSAGES.ODP_NOT_ENABLED);
91+
this.logger.log(LogLevel.INFO, LOG_MESSAGES.ODP_DISABLED);
9292
return;
9393
}
9494

@@ -181,7 +181,8 @@ export class OdpManager {
181181
}
182182

183183
if (!this.segmentManager) {
184-
throw new Error(ERROR_MESSAGES.ODP_FETCH_QUALIFIED_SEGMENTS_SEGMENTS_MANAGER_MISSING);
184+
this.logger.log(LogLevel.ERROR, ERROR_MESSAGES.ODP_FETCH_QUALIFIED_SEGMENTS_SEGMENTS_MANAGER_MISSING);
185+
return null;
185186
}
186187

187188
if (VuidManager.isVuid(userId)) {
@@ -209,7 +210,8 @@ export class OdpManager {
209210
}
210211

211212
if (!this.eventManager) {
212-
throw new Error(ERROR_MESSAGES.ODP_IDENTIFY_FAILED_EVENT_MANAGER_MISSING);
213+
this.logger.log(LogLevel.ERROR, ERROR_MESSAGES.ODP_IDENTIFY_FAILED_EVENT_MANAGER_MISSING);
214+
return;
213215
}
214216

215217
if (userId && VuidManager.isVuid(userId)) {

packages/optimizely-sdk/lib/index.browser.tests.js

Lines changed: 147 additions & 90 deletions
Large diffs are not rendered by default.

packages/optimizely-sdk/lib/optimizely/index.tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10139,6 +10139,8 @@ describe('lib/optimizely', function() {
1013910139
});
1014010140
});
1014110141

10142+
10143+
// TODO: Finish these tests for ODP general ODP Manager
1014210144
describe('odp', () => {
1014310145
it('should call logger with log level of "info" when odp disabled', () => {
1014410146
//...

packages/optimizely-sdk/lib/optimizely/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,10 +1763,9 @@ export default class Optimizely {
17631763
public identifyUser(userId: string): void {
17641764
if (!this.odpManager) {
17651765
this.logger.error(ERROR_MESSAGES.ODP_IDENTIFY_USER_FAILED_ODP_MANAGER_MISSING)
1766-
return;
1766+
} else {
1767+
this.odpManager.identifyUser(userId);
17671768
}
1768-
1769-
this.odpManager.identifyUser(userId);
17701769
}
17711770

17721771
/**

packages/optimizely-sdk/lib/optimizely_user_context/index.tests.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2020-2022, Optimizely, Inc. and contributors *
2+
* Copyright 2020-2023, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -325,7 +325,7 @@ describe('lib/optimizely_user_context', function() {
325325
});
326326
var result = user.setForcedDecision({ flagKey: 'feature_1' }, '3324490562');
327327
assert.strictEqual(result, true);
328-
sinon.assert.notCalled(stubLogHandler.log);
328+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
329329
});
330330

331331
it('should return true when provided empty string flagKey', function() {
@@ -338,7 +338,7 @@ describe('lib/optimizely_user_context', function() {
338338
});
339339
var result = user.setForcedDecision({ flagKey: '' }, '3324490562');
340340
assert.strictEqual(result, true);
341-
sinon.assert.notCalled(stubLogHandler.log);
341+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
342342
});
343343

344344
it('should return true when provided flagKey and variationKey', function() {
@@ -351,7 +351,7 @@ describe('lib/optimizely_user_context', function() {
351351
});
352352
var result = user.setForcedDecision({ flagKey: 'feature_1' }, '3324490562');
353353
assert.strictEqual(result, true);
354-
sinon.assert.notCalled(stubLogHandler.log);
354+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
355355
});
356356

357357
describe('when valid forced decision is set', function() {
@@ -891,7 +891,7 @@ describe('lib/optimizely_user_context', function() {
891891
var result2 = user.removeForcedDecision('non-existent_feature');
892892
assert.strictEqual(result2, false);
893893

894-
sinon.assert.notCalled(stubLogHandler.log);
894+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
895895
});
896896

897897
it('should successfully remove forced decision when multiple forced decisions set with same feature key', function() {
@@ -947,7 +947,7 @@ describe('lib/optimizely_user_context', function() {
947947
});
948948
var result = user.removeAllForcedDecisions();
949949
assert.strictEqual(result, true);
950-
sinon.assert.notCalled(stubLogHandler.log);
950+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
951951
});
952952

953953
it('should return true when all forced decisions have been removed successfully', function() {
@@ -973,7 +973,7 @@ describe('lib/optimizely_user_context', function() {
973973
assert.strictEqual(user.getForcedDecision({ flagKey: 'feature_1' }), null);
974974
assert.strictEqual(user.getForcedDecision({ flagKey: 'feature_1', ruleKey: 'exp_with_audience' }), null);
975975

976-
sinon.assert.notCalled(stubLogHandler.log);
976+
sinon.assert.calledOnce(stubLogHandler.log); // Called once in the case of User Context logging an error when failing to run identifyUser
977977
});
978978
});
979979

packages/optimizely-sdk/lib/optimizely_user_context/index.ts

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2020-2022, Optimizely, Inc. and contributors *
2+
* Copyright 2020-2023, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -22,8 +22,9 @@ import {
2222
OptimizelyForcedDecision,
2323
UserAttributes,
2424
} from '../../lib/shared_types';
25-
import { CONTROL_ATTRIBUTES } from '../utils/enums';
25+
import { CONTROL_ATTRIBUTES, ERROR_MESSAGES } from '../utils/enums';
2626
import { OptimizelySegmentOption } from '../core/odp/optimizely_segment_option';
27+
import { getLogger } from '../modules/logging';
2728

2829
interface OptimizelyUserContextConfig {
2930
optimizely: Optimizely;
@@ -39,20 +40,25 @@ export default class OptimizelyUserContext {
3940
private forcedDecisionsMap: { [key: string]: { [key: string]: OptimizelyForcedDecision } };
4041
private _qualifiedSegments: string[] = [];
4142

42-
constructor({
43-
optimizely,
44-
userId,
45-
attributes,
46-
qualifiedSegments,
47-
}: OptimizelyUserContextConfig) {
43+
constructor({ optimizely, userId, attributes, qualifiedSegments }: OptimizelyUserContextConfig) {
4844
this.optimizely = optimizely;
4945
this.userId = userId;
5046
this.attributes = { ...attributes } ?? {};
5147
this.forcedDecisionsMap = {};
5248
this.qualifiedSegments = qualifiedSegments ?? [];
5349

54-
if (optimizely && userId) {
55-
optimizely.identifyUser(userId);
50+
this.identifyUser();
51+
}
52+
53+
/**
54+
* On user context instantiation, fire event to attempt to identify user to ODP.
55+
*/
56+
identifyUser(): void {
57+
try {
58+
this.optimizely.identifyUser(this.userId);
59+
} catch (e) {
60+
const logger = getLogger('Optimizely User Context');
61+
logger.error(ERROR_MESSAGES.ODP_IDENTIFY_USER_FAILED_USER_CONTEXT_INITIALIZATION);
5662
}
5763
}
5864

@@ -92,11 +98,7 @@ export default class OptimizelyUserContext {
9298
* @param {OptimizelyDecideOption} options An array of options for decision-making.
9399
* @return {OptimizelyDecision} A decision result.
94100
*/
95-
decide(
96-
key: string,
97-
options: OptimizelyDecideOption[] = []
98-
): OptimizelyDecision {
99-
101+
decide(key: string, options: OptimizelyDecideOption[] = []): OptimizelyDecision {
100102
return this.optimizely.decide(this.cloneUserContext(), key, options);
101103
}
102104

@@ -108,11 +110,7 @@ export default class OptimizelyUserContext {
108110
* @param {OptimizelyDecideOption[]} options An array of options for decision-making.
109111
* @return {[key: string]: OptimizelyDecision} An object of decision results mapped by flag keys.
110112
*/
111-
decideForKeys(
112-
keys: string[],
113-
options: OptimizelyDecideOption[] = [],
114-
): { [key: string]: OptimizelyDecision } {
115-
113+
decideForKeys(keys: string[], options: OptimizelyDecideOption[] = []): { [key: string]: OptimizelyDecision } {
116114
return this.optimizely.decideForKeys(this.cloneUserContext(), keys, options);
117115
}
118116

@@ -121,10 +119,7 @@ export default class OptimizelyUserContext {
121119
* @param {OptimizelyDecideOption[]} options An array of options for decision-making.
122120
* @return {[key: string]: OptimizelyDecision} An object of all decision results mapped by flag keys.
123121
*/
124-
decideAll(
125-
options: OptimizelyDecideOption[] = []
126-
): { [key: string]: OptimizelyDecision } {
127-
122+
decideAll(options: OptimizelyDecideOption[] = []): { [key: string]: OptimizelyDecision } {
128123
return this.optimizely.decideAll(this.cloneUserContext(), options);
129124
}
130125

@@ -246,7 +241,7 @@ export default class OptimizelyUserContext {
246241
* @returns Boolean representing if segments were populated.
247242
*/
248243
public async fetchQualifiedSegments(options?: OptimizelySegmentOption[]): Promise<boolean> {
249-
const segments = await this.optimizely.fetchQualifiedSegments(this.userId, options)
244+
const segments = await this.optimizely.fetchQualifiedSegments(this.userId, options);
250245
if (segments) {
251246
this.qualifiedSegments = [...segments];
252247
}
@@ -256,7 +251,7 @@ export default class OptimizelyUserContext {
256251

257252
/**
258253
* Returns a boolean representing if a user is qualified for a particular segment.
259-
* @param {string} segment Target segment to be evaluated for user qualification.
254+
* @param {string} segment Target segment to be evaluated for user qualification.
260255
* @returns {boolean} Boolean representing if a user qualified for the passed in segment.
261256
*/
262257
public isQualifiedFor(segment: string): boolean {

packages/optimizely-sdk/lib/plugins/odp_manager/index.browser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ export class BrowserOdpManager extends OdpManager {
123123
}
124124
}
125125

126+
/**
127+
* Instantiates and returns the Browser variation of ODP Manager.
128+
* @param {OdpServiceConfig} config Configuration for Browser ODP Manager
129+
* @returns Configured ODP Manager of the Browser variant.
130+
*/
126131
export const createBrowserOdpManager = (config?: OdpServiceConfig): BrowserOdpManager => {
127132
if (!config) {
128133
return new BrowserOdpManager({

packages/optimizely-sdk/lib/utils/enums/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export const ERROR_MESSAGES = {
6666
ODP_FETCH_QUALIFIED_SEGMENTS_FAILED_ODP_MANAGER_MISSING:
6767
'%s: ODP failed to Fetch Qualified Segments. (ODP Manager not initialized).',
6868
ODP_IDENTIFY_USER_FAILED_ODP_MANAGER_MISSING: '%s: ODP failed to Identify User. (ODP Manager not initialized).',
69+
ODP_IDENTIFY_USER_FAILED_USER_CONTEXT_INITIALIZATION:
70+
'%s: ODP failed to Identify User. (Failed during User Context Initialization).',
6971
ODP_MANAGER_UPDATE_SETTINGS_FAILED_EVENT_MANAGER_MISSING:
7072
'%s: ODP Manager failed to update OdpConfig settings for internal event manager. (Event Manager not initialized).',
7173
ODP_MANAGER_UPDATE_SETTINGS_FAILED_SEGMENTS_MANAGER_MISSING:
@@ -117,6 +119,7 @@ export const LOG_MESSAGES = {
117119
NO_ROLLOUT_EXISTS: '%s: There is no rollout of feature %s.',
118120
NOT_ACTIVATING_USER: '%s: Not activating user %s for experiment %s.',
119121
NOT_TRACKING_USER: '%s: Not tracking user %s.',
122+
ODP_DISABLED: 'ODP Disabled.',
120123
ODP_IDENTIFY_FAILED_ODP_DISABLED: '%s: ODP identify event for user %s is not dispatched (ODP disabled).',
121124
ODP_IDENTIFY_FAILED_ODP_NOT_INTEGRATED: '%s: ODP identify event %s is not dispatched (ODP not integrated).',
122125
PARSED_REVENUE_VALUE: '%s: Parsed revenue value "%s" from event tags.',

packages/optimizely-sdk/tests/odpManager.browser.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ describe('OdpManager', () => {
106106
it('should drop relevant calls when OdpManager is initialized with the disabled flag, except for VUID', async () => {
107107
const browserOdpManager = new BrowserOdpManager({ disable: true, logger });
108108

109-
verify(mockLogger.log(LogLevel.INFO, ERROR_MESSAGES.ODP_NOT_ENABLED)).once();
109+
verify(mockLogger.log(LogLevel.INFO, LOG_MESSAGES.ODP_DISABLED)).once();
110110

111111
browserOdpManager.updateSettings(new OdpConfig('valid', 'host', []));
112112
expect(browserOdpManager.odpConfig).toBeUndefined;

packages/optimizely-sdk/tests/odpManager.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ describe('OdpManager', () => {
9696

9797
it('should drop relevant calls when OdpManager is initialized with the disabled flag', async () => {
9898
const odpManager = new OdpManager({ disable: true, requestHandler, logger });
99-
verify(mockLogger.log(LogLevel.INFO, ERROR_MESSAGES.ODP_NOT_ENABLED)).once();
99+
verify(mockLogger.log(LogLevel.INFO, LOG_MESSAGES.ODP_DISABLED)).once();
100100

101101
odpManager.updateSettings(new OdpConfig('valid', 'host', []));
102102
expect(odpManager.odpConfig).toBeUndefined;

0 commit comments

Comments
 (0)