Skip to content
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(Decide): Add Decide API #220

Merged
merged 23 commits into from
Jan 21, 2021
Merged

feat(Decide): Add Decide API #220

merged 23 commits into from
Jan 21, 2021

Conversation

oakbani
Copy link
Contributor

@oakbani oakbani commented Nov 24, 2020

Summary

Added new APIs to support the decide feature. Introduced a new OptimizelyUserContext class through createUserContext class api. This creates an optimizely instance with memoized user context and exposes the following APIs

  1. setAttribute
  2. decide
  3. decideAll
  4. decideForKeys
  5. trackEvent

Test plan

  1. Manually tested thoroughly.
  2. Added unit tests to cover new functionality.
  3. Tested with FSC manually.

Testapp PR: https://github.com/optimizely/php-testapp/pull/66

@coveralls
Copy link

Coverage Status

Coverage decreased (-2.4%) to 95.706% when pulling bc47a63 on oakbani/decide-api into 5f73a01 on master.

2 similar comments
@coveralls
Copy link

Coverage Status

Coverage decreased (-2.4%) to 95.706% when pulling bc47a63 on oakbani/decide-api into 5f73a01 on master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-2.4%) to 95.706% when pulling bc47a63 on oakbani/decide-api into 5f73a01 on master.

@coveralls
Copy link

coveralls commented Nov 24, 2020

Coverage Status

Coverage decreased (-0.5%) to 97.61% when pulling b6d0bd5 on oakbani/decide-api into 5f73a01 on master.

@oakbani oakbani marked this pull request as ready for review December 9, 2020 14:53
@oakbani oakbani requested a review from a team as a code owner December 9, 2020 14:53
@oakbani oakbani removed their assignment Dec 9, 2020
Copy link
Contributor

@jaeopt jaeopt left a 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;
Copy link
Contributor

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.

$userId,
$userAttributes,
$decideOptions,
$decideReasons
Copy link
Contributor

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?

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 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.

src/Optimizely/Optimizely.php Outdated Show resolved Hide resolved
return [];
}

$enabledFlagsOnly = in_array(OptimizelyDecideOption::ENABLED_FLAGS_ONLY, $decideOptions);
Copy link
Contributor

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 = [])
Copy link
Contributor

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.

Copy link
Contributor Author

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());
}

Copy link
Contributor

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 Show resolved Hide resolved
$this->assertEquals($expectedOptimizelyDecision->getRuleKey(), $optimizelyDecision->getRuleKey());
$this->assertEquals($expectedOptimizelyDecision->getFlagKey(), $optimizelyDecision->getFlagKey());
$this->assertEquals($expectedOptimizelyDecision->getUserContext(), $optimizelyDecision->getUserContext());
$this->assertEquals($expectedOptimizelyDecision->getFlagKey(), $optimizelyDecision->getFlagKey());
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Comment on lines +1183 to +1193
->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']
);
Copy link
Contributor

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);
}

Copy link
Contributor

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)

Copy link
Contributor

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.

@oakbani oakbani removed their assignment Dec 11, 2020
Copy link
Contributor

@jaeopt jaeopt left a 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.

@oakbani oakbani removed their assignment Dec 14, 2020
Copy link
Contributor

@jaeopt jaeopt left a 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
@oakbani oakbani closed this Jan 20, 2021
@oakbani oakbani reopened this Jan 20, 2021
@oakbani oakbani removed their assignment Jan 20, 2021
@oakbani
Copy link
Contributor Author

oakbani commented Jan 20, 2021

@msohailhussain @jaeopt ready to merge

@jaeopt jaeopt closed this Jan 21, 2021
@jaeopt jaeopt reopened this Jan 21, 2021
@jaeopt jaeopt closed this Jan 21, 2021
@jaeopt jaeopt reopened this Jan 21, 2021
@jaeopt jaeopt closed this Jan 21, 2021
@jaeopt jaeopt reopened this Jan 21, 2021
@jaeopt jaeopt merged commit c687e53 into master Jan 21, 2021
@jaeopt jaeopt deleted the oakbani/decide-api branch January 21, 2021 19:37
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