Skip to content

feat(api): Decision Notification Listener for isFeatureEnabled and getEnabledFeatures APIs. #245

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

Merged
merged 13 commits into from
Mar 26, 2019

Conversation

mfahadahmed
Copy link
Contributor

Summary

  • Implemented isFeatureEnabled in activate and getEnabledFeatures APIs.

Test plan

  • Added unit tests.

@coveralls
Copy link

coveralls commented Mar 8, 2019

Coverage Status

Coverage increased (+0.03%) to 97.758% when pulling 6365632 on fahad/on-decision-listener-feature-enabled into b9a9fd0 on master.

Copy link
Contributor

@aliabbasrizvi aliabbasrizvi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Minor feedback. Please address and this will be good to merge.

*/
exports.NOTIFICATION_TYPES = {
ACTIVATE: 'ACTIVATE:experiment, user_id,attributes, variation, event',
TRACK: 'TRACK:event_key, user_id, attributes, event_tags, event',
ON_DECISION: 'ON_DECISION:type, userId, attributes, decisionInfo',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. It is DECISION and not ON_DECISION.

this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId));
featureEnabled = false;
} else {
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be featureEnabled = true here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The possible values of variation.featureEnabled are true, false or undefined. For falsy values, we explicitly set it to false. Otherwise the value is already true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed this condition to explicitly check for true.

@@ -2519,6 +2521,199 @@ describe('lib/optimizely', function() {
};
sinon.assert.calledWith(trackListener, expectedArgument);
});

describe('OnDecision Listener', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit Decision Listener

@msohailhussain msohailhussain requested a review from a team March 11, 2019 21:14
Copy link
Contributor

@jordangarcia jordangarcia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make attributes default to {} if not provided

{
type: DECISION_INFO_TYPES.FEATURE,
userId: userId,
attributes: attributes,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure attributes defaults to {} if not defined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

@aliabbasrizvi aliabbasrizvi changed the title feat(api): OnDecision Notification Listener for isFeatureEnabled and getEnabledFeatures APIs. feat(api): Decision Notification Listener for isFeatureEnabled and getEnabledFeatures APIs. Mar 12, 2019
@aliabbasrizvi
Copy link
Contributor

@jordangarcia can you take a look again?
LGTM after the changes.

if (!!variation) {
featureEnabled = variation.featureEnabled;
if (decision.decisionSource === DECISION_SOURCES.EXPERIMENT) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DECISION_SOURCES.EXPERIMENT is experiment (lower case) and not EXPERIMENT (upper case). Similarly, DECISION_SOURCES.ROLLOUT is rollout (lower case) and not ROLLOUT (upper case). We should update that,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capitalized decision source values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about this comment. @aliabbasrizvi are you saying that the values (not the enum key) should be lower case or upper case.

This PR is changing it from lowercase to uppercase.

It's unclear what we want the final state to be (uppercase or lowercase)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, should have been clear. The value should be EXPERIMENT/ROLLOUT.

@msohailhussain msohailhussain requested a review from a team March 12, 2019 19:47
@aliabbasrizvi
Copy link
Contributor

@jordangarcia can you re-review

this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId));
} else {
this.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, featureKey, userId));
featureEnabled = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this value already be false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be undefined when featureEnabled property is missing from the variation as specified in this test

describe('when the variation is missing the toggle', function() {

featureEnabled = false;
}

var decisionSource = decision.decisionSource || DECISION_SOURCES.ROLLOUT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what cases is the decision.decisionSource not a truthy value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the user was not bucketed into an experiment or a rollout, DecisionSource returned as null from decision service. But as per the comments in feature variables PR #246 this implementation has been changed. Updating it accordingly.

optlyInstance.notificationCenter.addNotificationListener(enums.NOTIFICATION_TYPES.DECISION, decisionListener);
var result = optlyInstance.getEnabledFeatures('test_user', attributes);
assert.strictEqual(result.length, 3);
assert.isAbove(result.indexOf('test_feature_2'), -1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use

assert.deepEqual(result, ['test_feature2', 'test_feature_for_experiment', 'shared_feature'])

assert.isAbove(result.indexOf('test_feature_for_experiment'), -1);
assert.isAbove(result.indexOf('shared_feature'), -1);

assert.isTrue(decisionListener.getCall(0).calledWith({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use sinon assertion here

sinon.assert.calledWithExactly(spy.getCall(1), arg1, arg2, ...);

This will give a better error message than assert.isTrue

Copy link
Contributor

@jordangarcia jordangarcia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor changes to the test, and a couple questions. Please answer and I will re-review

…if the user is not evaluated into the experiment.
…istener-feature-enabled

# Conflicts:
#	packages/optimizely-sdk/lib/optimizely/index.js
#	packages/optimizely-sdk/lib/optimizely/index.tests.js
#	packages/optimizely-sdk/lib/utils/enums/index.js
@jordangarcia
Copy link
Contributor

@ mfahadahmed this needs to be rebased before it can be merged.

…istener-feature-enabled

# Conflicts:
#	packages/optimizely-sdk/lib/optimizely/index.js
This reverts commit 9c3ec8a.
@aliabbasrizvi aliabbasrizvi merged commit 09d9433 into master Mar 26, 2019
@aliabbasrizvi aliabbasrizvi deleted the fahad/on-decision-listener-feature-enabled branch March 26, 2019 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants