-
Notifications
You must be signed in to change notification settings - Fork 30
feat(Decide): Add Decide API #220
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
Conversation
2 similar comments
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.
It looks great!
A couple of fixes necessary and more tests suggested.
$this->_logger->log(Logger::DEBUG, sprintf('No experiment "%s" mapped to user "%s" in the forced variation map.', $experimentKey, $userId)); | ||
$message = sprintf('No experiment "%s" mapped to user "%s" in the forced variation map.', $experimentKey, $userId); | ||
$this->_logger->log(Logger::DEBUG, $message); | ||
$decideReasons[] = $message; |
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 do not think we should include this message into reasons. It may be too much.
src/Optimizely/Optimizely.php
Outdated
$userId, | ||
$userAttributes, | ||
$decideOptions, | ||
$decideReasons |
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 do not need collect reasons if INCLUDE_REASONS not set.
Any optimization instead of collecting and throwing away?
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 this is a clean approach.
- Here decideReasons is passed by reference. If we choose not to pass here based on INCLUDE_REASONS flag, each internal method would create a default array inside method, push log into it and eventually lose it's scope.
- The other thing that we can do is to pass decideOptions in each method with the decideReasons. And check for INCLUDE_REASONS flag inside decideOptions before pushing any log in decideReasons array. This would add an additonal array item check before each log.
return []; | ||
} | ||
|
||
$enabledFlagsOnly = in_array(OptimizelyDecideOption::ENABLED_FLAGS_ONLY, $decideOptions); |
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.
Should check with "default_decide_options" as well
* | ||
* @return OptimizelyDecision A decision result | ||
*/ | ||
public function decide(OptimizelyUserContext $userContext, $key, array $decideOptions = []) |
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 should not open "decide", "decide_all" and "decide_for_keys" to public.
We'll let them use those apis through userContext always.
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.
If I am correct, this won't be possible in PHP as it doesn't provide package level visibility. Making any of these methods protected / private, would make them unreachable from OptimizelyUserContext class.
$optUserContext->setAttribute('browser', 'firefox'); | ||
$this->assertEquals(["browser" => "firefox"], $optUserContext->getAttributes()); | ||
} | ||
|
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.
Can we add a test:
- no attributes given at init and added later with setAttribute
tests/OptimizelyTest.php
Outdated
$this->assertEquals($expectedOptimizelyDecision->getRuleKey(), $optimizelyDecision->getRuleKey()); | ||
$this->assertEquals($expectedOptimizelyDecision->getFlagKey(), $optimizelyDecision->getFlagKey()); | ||
$this->assertEquals($expectedOptimizelyDecision->getUserContext(), $optimizelyDecision->getUserContext()); | ||
$this->assertEquals($expectedOptimizelyDecision->getFlagKey(), $optimizelyDecision->getFlagKey()); |
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 line is redundant. "reasons" not compared. Is it intentional?
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.
Yes, left out reasons comparison intentionally. As in all those tests, where INCLUDE_REASONS flag is included, we will have to create a verbose expected OptimizelyDecision object. Reasons are asserted separately.
->with( | ||
$this->projectConfig, | ||
'test_experiment_double_feature', | ||
'control', | ||
'double_single_variable_feature', | ||
'test_experiment_double_feature', | ||
FeatureDecision::DECISION_SOURCE_FEATURE_TEST, | ||
true, | ||
'test_user', | ||
['device_type' => 'iPhone'] | ||
); |
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.
remove?
$optimizelyDecision = $optimizelyMock->decide($userContext, 'double_single_variable_feature', ['DISABLE_DECISION_EVENT', 'ENABLED_FLAGS_ONLY', 'IGNORE_USER_PROFILE_SERVICE', 'INCLUDE_REASONS', 'EXCLUDE_VARIABLES']); | ||
$this->compareOptimizelyDecisions($expectedOptimizelyDecision, $optimizelyDecision); | ||
} | ||
|
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 do not see tests for
- INCLUDE_REASONS
- IGNORE_USER_PROFILE (skip read/write UPS both)
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.
Also need the same set of tests for "default_decide_options".
And I'd like to see a test validating options in "default_decide_options" (EXCLUDE_VARIABLES) and decide parameter option (DISABLE_DECIDE_EVENTS) work together ok.
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.
All changes look good!
One last missing test is IGNORE_USER_PROFILE option testing. Add a test validating both reading and updating skipped on the option.
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
…ameter (#221) * impact * fix Decision Service Tests * fix: test cases affected due to bucketer * fix: unit tests affected by reasons * fix: incompatible syntax for < php 7.0 * fix: some more tests * audience eval logs * tests: bucketer reasons * tests: Decision Service reasons * tests: decision service further * update: copyright headers
@msohailhussain @jaeopt ready to merge |
Summary
Added new APIs to support the decide feature. Introduced a new
OptimizelyUserContext
class throughcreateUserContext
class api. This creates an optimizely instance with memoized user context and exposes the following APIssetAttribute
decide
decideAll
decideForKeys
trackEvent
Test plan
Testapp PR: https://github.com/optimizely/php-testapp/pull/66