-
Notifications
You must be signed in to change notification settings - Fork 83
feat(api): Decision Notification Listener for feature variable APIs. #246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(api): Decision Notification Listener for feature variable APIs. #246
Conversation
…istener-feature-variables
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@mjc1283 or @jordangarcia can one of you take a look as well?
sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ | ||
experiment: null, | ||
variation: null, | ||
decisionSource: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel the actual decisionService
needs to be updated to set decisionSource as rollout.
Thoughts @jordangarcia @mjc1283 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think decisionSource
should be rollout even if the user is not evaluated into the experiment, as it's jkind of the bottom of evaluation chain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is some logic that was not implemented correctly around the value of the variable when feature is not enabled.
Also please change the decision service to return ROLLOUT
when the variation
is null.
Lastly the tests need to be updated to not directly modify configObj that's loaded in the Optimizely
instance.
variableValue = projectConfig.getVariableValueForVariation(this.configObj, variable, decision.variation, this.logger); | ||
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, MODULE_NAME, variableKey, featureFlag.key, variableValue, userId)); | ||
featureEnabled = decision.variation.featureEnabled; | ||
if (featureEnabled === true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is incorrect.
Feature variables should always be the variation variable value, even if the feature is disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jordangarcia it is actually supposed to be the default feature value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aliabbasrizvi, agree that this is the default behavior. And the datafile constraint of a feature experiment variation (where featureEnabled == false
) always has variables that mirror the variable defaults makes it so this works today.
Given the scope of this PR (just adding notificationCenter listener), i'd prefer not to change this core logic.
Java also mirrors the existing JS implementation https://github.com/optimizely/java-sdk/blob/master/core-api/src/main/java/com/optimizely/ab/Optimizely.java#L615-L668
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified the logic to return variation's variable value even when the featureEnabled property is set to false.
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.USER_RECEIVED_VARIABLE_VALUE, MODULE_NAME, variableKey, featureFlag.key, variableValue, userId)); | ||
} else { | ||
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_RETURN_DEFAULT_VARIABLE_VALUE, MODULE_NAME, featureFlag.key, userId, variableKey)); | ||
featureEnabled = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason to re-card featureEnabled
here.
optlyInstance = new Optimizely({ | ||
clientEngine: 'node-sdk', | ||
datafile: testData.getTestProjectConfigWithFeatures(), | ||
eventBuilder: eventBuilder, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eventBuilder
isn't a valid option to pass to new Optimizely
describe('when the variation is toggled OFF', function() { | ||
beforeEach(function() { | ||
// Setting featureEnabled to false for verifying feature toggle off. | ||
optlyInstance.configObj.experimentKeyMap.testing_my_feature.variations[0].featureEnabled = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be reaching into the configObj
like this.
We should change the test datafile that were using to include a feature where a variation has featureEnabled = false
beforeEach(function() { | ||
// Setting featureEnabled to false for verifying feature toggle off. | ||
optlyInstance.configObj.experimentKeyMap.testing_my_feature.variations[0].featureEnabled = false; | ||
var experiment = optlyInstance.configObj.experimentKeyMap.testing_my_feature; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use projectConfig.getExperimentFromKey(optlyInstance.configObj, 'testing_my_feature')
instead of directly inspecting the configObj
describe('bucketed into variation of a rollout with variable values', function() { | ||
describe('when the variation is toggled ON', function() { | ||
beforeEach(function() { | ||
var experiment = optlyInstance.configObj.experimentKeyMap['594031']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use projectConfig
function here instead.
sandbox.stub(optlyInstance.decisionService, 'getVariationForFeature').returns({ | ||
experiment: null, | ||
variation: null, | ||
decisionSource: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think decisionSource
should be rollout even if the user is not evaluated into the experiment, as it's jkind of the bottom of evaluation chain.
@@ -2608,6 +3117,7 @@ describe('lib/optimizely', function() { | |||
sandbox.stub(uuid, 'v4').returns('a68cf1ad-0393-4e18-af87-efe8f01a7c9c'); | |||
sandbox.stub(fns, 'currentTimestamp').returns(1509489766569); | |||
clock = sinon.useFakeTimers(new Date().getTime()); | |||
onDecisionListener = sinon.spy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed?
…if the user is not evaluated into the experiment.
…istener-feature-variables # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.js # packages/optimizely-sdk/lib/optimizely/index.tests.js # packages/optimizely-sdk/lib/utils/enums/index.js
…istener-feature-variables # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.js # packages/optimizely-sdk/lib/tests/test_data.js
LOG_LEVEL.INFO, | ||
sprintf(LOG_MESSAGES.USER_RECEIVED_DEFAULT_VARIABLE_VALUE, MODULE_NAME, userId, variableKey, featureFlag.key) | ||
); | ||
variableValue = variable.defaultValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix this indentation.
@@ -199,8 +199,8 @@ exports.DECISION_INFO_TYPES = { | |||
* Optimizely. | |||
*/ | |||
exports.DECISION_SOURCES = { | |||
EXPERIMENT: 'experiment', | |||
ROLLOUT: 'rollout', | |||
EXPERIMENT: 'EXPERIMENT', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be lowercase, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it will be upper case as @aliabbasrizvi suggested here
#245 (comment)
@jordangarcia can you take a look again and approve/decline? |
…istener-feature-variables # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.tests.js # packages/optimizely-sdk/lib/utils/enums/index.js
@jordangarcia can you please rereview and let me know if any change is needed? |
…istener-feature-variables # Conflicts: # packages/optimizely-sdk/lib/optimizely/index.js
…istener-feature-variables
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM, but I am leaving it for @jordangarcia to approve.
LGTM |
Summary
Test plan