Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
38f9db1
Add bug bash autoloader
mikechu-optimizely May 30, 2023
91aa14c
Initial version of decide tests
mikechu-optimizely May 30, 2023
0051573
Fix autoloads; DRY print to console
mikechu-optimizely May 30, 2023
c31820a
Refactor and clean using
mikechu-optimizely May 30, 2023
833e6bb
Refactor; Fix array outputs
mikechu-optimizely May 31, 2023
785389f
Better output in linux env
mikechu-optimizely May 31, 2023
47fcac7
Add notification on decide test
mikechu-optimizely May 31, 2023
e7c18c7
Output log to ensure logx impression sent
mikechu-optimizely May 31, 2023
610279a
Verify error is logged for invalid flag
mikechu-optimizely May 31, 2023
2d1b5a1
Add devcontainer config
mikechu-optimizely Jun 1, 2023
af21844
Install dependencies in devcontainer
mikechu-optimizely Jun 1, 2023
1567ac2
Update decide instructions
mikechu-optimizely Jun 1, 2023
12a9b70
Add postCreateCommand shell postCreateCommand
mikechu-optimizely Jun 1, 2023
e59ed4b
Fix path on postCreateCommand
mikechu-optimizely Jun 1, 2023
a15ce19
Finish devcontainer config
mikechu-optimizely Jun 1, 2023
3a13a5e
Refine decide.php
mikechu-optimizely Jun 1, 2023
82faf92
Renamed files & their refs
mikechu-optimizely Jun 2, 2023
e05a86f
Instruction update
mikechu-optimizely Jun 2, 2023
00a2522
Add DecideAll skeleton
mikechu-optimizely Jun 2, 2023
cc16486
Initial DecideAll test
mikechu-optimizely Jun 2, 2023
8453c4a
Finish DecideAll test; Decide fixes
mikechu-optimizely Jun 2, 2023
8774b37
DecideForKeys skeleton
mikechu-optimizely Jun 2, 2023
626c7d4
Add decide for keys; update other decide classes
mikechu-optimizely Jun 5, 2023
96bb0c0
Comment DecideForKeys test calls
mikechu-optimizely Jun 5, 2023
fcb1ee4
Track event test class skeleton
mikechu-optimizely Jun 5, 2023
aabd432
Update attributes in decide tests
mikechu-optimizely Jun 5, 2023
5378d93
Add track event tests
mikechu-optimizely Jun 5, 2023
165c566
DRY $onTrackEvent and use in negative test
mikechu-optimizely Jun 5, 2023
bb0eeaf
Event Key instead of "name"
mikechu-optimizely Jun 5, 2023
b29dead
Forced Decision skeleton
mikechu-optimizely Jun 5, 2023
e7781de
Add PHP documentation links
mikechu-optimizely Jun 5, 2023
035747e
Initial attempt forced decision tests
mikechu-optimizely Jun 5, 2023
01af3ee
Remove sensitive info
mikechu-optimizely Jun 5, 2023
94d211e
Added second part for forced decisions - not necessary, just a advanc…
Mat001 Jun 6, 2023
353aa31
Delete ForcedDecision.php
Mat001 Jun 9, 2023
155dc12
Rename ForcedDecisionPart2.php to ForcedDecision.php
Mat001 Jun 9, 2023
df5089b
Update ForcedDecision.php
Mat001 Jun 9, 2023
79c7e7b
Update OptiConfig.php
Mat001 Jun 9, 2023
aab2a60
Update EventBuilder.php SDK minor release bump
Mat001 Jun 9, 2023
ead6580
Update EventBuilderTest.php release version bump in the test to 3.10.0
Mat001 Jun 9, 2023
4eae743
Update EventBuilder.php-revert
Mat001 Jun 9, 2023
d714b04
Update EventBuilderTest.php - revert
Mat001 Jun 9, 2023
52808f8
Merge branch 'master' into mike/bug-bash-php8
mikechu-optimizely Jun 22, 2023
3810ed3
Merge remote-tracking branch 'origin/mike/bug-bash-php8' into mike/bu…
mikechu-optimizely Jun 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/php
{
"name": "PHP",

"remoteEnv": {
"SDK_ROOT": "/workspaces/php-sdk",
"XDEBUG_CONFIG": "log_level=0",
},

// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/php:0-8.2",

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

"postStartCommand": "composer install",

// Configure tool-specific properties.
// "customizations": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
8080
],
"customizations": {
"vscode": {
"extensions": [
"bmewburn.vscode-intelephense-client",
"xdebug.php-debug",
"DEVSENSE.composer-php-vscode"
]
}
}

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html"

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
144 changes: 144 additions & 0 deletions bug-bash/Decide.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace Optimizely\BugBash;

require_once '../vendor/autoload.php';
require_once '../bug-bash/_bug-bash-autoload.php';

use Monolog\Logger;
use Optimizely\Decide\OptimizelyDecideOption;
use Optimizely\Logger\DefaultLogger;
use Optimizely\Notification\NotificationType;
use Optimizely\Optimizely;
use Optimizely\OptimizelyFactory;
use Optimizely\OptimizelyUserContext;

// 1. Change this SDK key to your project's SDK Key
const SDK_KEY = '<your-sdk-key>';

// 2. Change this to your flag key
const FLAG_KEY = '<your-flag-key>';

// 3. Uncomment each scenario 1 by 1 modifying the contents of the method
// to test additional scenarios.

$test = new DecideTests();
$test->verifyDecisionProperties();
// $test->testWithVariationsOfDecideOptions();
// $test->verifyLogsImpressionsEventsDispatched();
// $test->verifyResultsPageInYourProjectShowsImpressionEvent();
// $test->verifyDecisionListenerWasCalled();
// $test->verifyAnInvalidFlagKeyIsHandledCorrectly();

// 4. Change the current folder into the bug-bash directory
// cd bug-bash/

// 5. Run the following command to execute the uncommented tests above:
// php Decide.php

// https://docs.developers.optimizely.com/feature-experimentation/docs/decide-methods-php
class DecideTests
{
// verify decision return properties with default DecideOptions
public function verifyDecisionProperties(): void
{
$decision = $this->userContext->decide(FLAG_KEY);

$this->printDecision($decision, "Check that the following decision properties are expected for user $this->userId");
}

// test decide w all options: DISABLE_DECISION_EVENT, ENABLED_FLAGS_ONLY, IGNORE_USER_PROFILE_SERVICE, INCLUDE_REASONS, EXCLUDE_VARIABLES (will need to add variables)
public function testWithVariationsOfDecideOptions(): void
{
$options = [
OptimizelyDecideOption::INCLUDE_REASONS,
// OptimizelyDecideOption::DISABLE_DECISION_EVENT,
// OptimizelyDecideOption::ENABLED_FLAGS_ONLY, // ⬅️ Disable some of your flags
// OptimizelyDecideOption::IGNORE_USER_PROFILE_SERVICE,
// OptimizelyDecideOption::EXCLUDE_VARIABLES,
];

$decision = $this->userContext->decide(FLAG_KEY, $options);

$this->printDecision($decision, 'Modify the OptimizelyDecideOptions and check the decision variables expected');
}

// verify in logs that impression event of this decision was dispatched
public function verifyLogsImpressionsEventsDispatched(): void
{
// 💡️ Create a new flag with an A/B Test eg "product_version"
$featureFlagKey = 'product_version';
$logger = new DefaultLogger(Logger::DEBUG);
$localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY);
$localUserContext = $localOptimizelyClient->createUserContext($this->userId);

// review the DEBUG output, ensuring you see an impression log
// "Dispatching impression event to URL https://logx.optimizely.com/v1/events with params..."
$localUserContext->decide($featureFlagKey);
}

// verify on Results page that impression even was created
public function verifyResultsPageInYourProjectShowsImpressionEvent(): void
{
print "Go to your project's results page and verify decisions events are showing (5 min delay)";
}

// verify that decision listener contains correct information
public function verifyDecisionListenerWasCalled(): void
{
// Check that this was called during the...
$onDecision = function ($type, $userId, $attributes, $decisionInfo) {
print ">>> [$this->outputTag] OnDecision:
type: $type,
userId: $userId,
attributes: " . print_r($attributes, true) . "
decisionInfo: " . print_r($decisionInfo, true) . "\r\n";
};
$this->optimizelyClient->notificationCenter->addNotificationListener(
NotificationType::DECISION,
$onDecision
);

// ...decide.
$this->userContext->decide(FLAG_KEY);
}

// verify that invalid flag key is handled correctly
public function verifyAnInvalidFlagKeyIsHandledCorrectly(): void
{
$logger = new DefaultLogger(Logger::ERROR);
$localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY);
$userId = 'user-' . mt_rand(10, 99);
$localUserContext = $localOptimizelyClient->createUserContext($userId);

// ensure you see an error -- Optimizely.ERROR: FeatureFlag Key "a_key_not_in_the_project" is not in datafile.
$localUserContext->decide("a_key_not_in_the_project");
}

private Optimizely $optimizelyClient;
private string $userId;
private ?OptimizelyUserContext $userContext;
private string $outputTag = "Decide";

public function __construct()
{
$this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY);

$this->userId = 'user-' . mt_rand(10, 99);
$attributes = ['age' => 25, 'country' => 'canada', 'abandoned_cart' => false];
$this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes);
}

private function printDecision($decision, $message): void
{
$enabled = $decision->getEnabled() ? "true" : "false";

print ">>> [$this->outputTag] $message:
enabled: $enabled,
flagKey: {$decision->getFlagKey()},
ruleKey: {$decision->getRuleKey()},
variationKey: {$decision->getVariationKey()},
variables: " . print_r($decision->getVariables(), true) . ",
reasons: " . print_r($decision->getReasons(), true) . "\r\n";
}
}
134 changes: 134 additions & 0 deletions bug-bash/DecideAll.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

namespace Optimizely\BugBash;

require_once '../vendor/autoload.php';
require_once '../bug-bash/_bug-bash-autoload.php';

use Monolog\Logger;
use Optimizely\Decide\OptimizelyDecideOption;
use Optimizely\Logger\DefaultLogger;
use Optimizely\Notification\NotificationType;
use Optimizely\Optimizely;
use Optimizely\OptimizelyFactory;
use Optimizely\OptimizelyUserContext;

// 1. Change this SDK key to your project's SDK Key
const SDK_KEY = '<your-sdk-key>';

// 2. Create additional flag keys in your project (2+)

// 3. Uncomment each scenario 1 by 1 modifying the contents of the method
// to test additional scenarios.

$test = new DecideAllTests();
$test->verifyDecisionProperties();
// $test->testWithVariousCombinationsOfOptions();
// $test->verifyLogImpressionEventDispatched();
// $test->verifyResultsPageShowsImpressionEvents();
// $test->verifyDecisionListenerContainsCorrectInformation();

// 4. Change the current folder into the bug-bash directory if you're not already there:
// cd bug-bash/

// 5. Run the following command to execute the uncommented tests above:
// php DecideAll.php

// https://docs.developers.optimizely.com/feature-experimentation/docs/decide-methods-php
class DecideAllTests
{
// verify decide all returns properties without specifying default options
public function verifyDecisionProperties(): void
{
$decision = $this->userContext->decideAll();

$this->printDecisions($decision, "Check that all of the decisions' multiple properties are expected for user `$this->userId`");
}

// test with all and variations/combinations of options
public function testWithVariousCombinationsOfOptions(): void
{
$options = [
OptimizelyDecideOption::INCLUDE_REASONS,
// OptimizelyDecideOption::DISABLE_DECISION_EVENT,
// OptimizelyDecideOption::ENABLED_FLAGS_ONLY, // ⬅️ Disable some of your flags
// OptimizelyDecideOption::IGNORE_USER_PROFILE_SERVICE,
OptimizelyDecideOption::EXCLUDE_VARIABLES,
];

$decisions = $this->userContext->decideAll($options);

$this->printDecisions($decisions, "Check that all of your flags' decisions respected the options passed.");
}

// verify in logs that impression event of this decision was dispatched
public function verifyLogImpressionEventDispatched(): void
{
// 💡️ Be sure you have >=1 of your project's flags has an EXPERIMENT type
$logger = new DefaultLogger(Logger::DEBUG);
$localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY);
$localUserContext = $localOptimizelyClient->createUserContext($this->userId);

// review the DEBUG output, ensuring you see an impression log for each *EXPERIMENT* with a message like
// "Dispatching impression event to URL https://logx.optimizely.com/v1/events with params..."
// ⚠️ Rollout flag types should not dispatch and impression event
$localUserContext->decideAll();
}

// verify on Results page that impression events was created
public function verifyResultsPageShowsImpressionEvents(): void
{
print "After about 5-10 minutes, go to your project's results page and verify decisions events are showing.";
}

// verify that decision listener contains correct information
public function verifyDecisionListenerContainsCorrectInformation(): void
{
// Check that this was called for each of your project flag keys
$onDecision = function ($type, $userId, $attributes, $decisionInfo) {
print ">>> [$this->outputTag] OnDecision:
type: $type,
userId: $userId,
attributes: " . print_r($attributes, true) . "
decisionInfo: " . print_r($decisionInfo, true) . "\r\n";
};
$this->optimizelyClient->notificationCenter->addNotificationListener(
NotificationType::DECISION,
$onDecision
);

$this->userContext->decideAll();
}

private Optimizely $optimizelyClient;
private string $userId;
private ?OptimizelyUserContext $userContext;
private string $outputTag = "Decide All";

public function __construct()
{
$this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY);

$this->userId = 'user-' . mt_rand(10, 99);
$attributes = ['country' => 'nederland', 'age' => 43, 'is_return_visitor' => true];
$this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes);
}

private function printDecisions($decisions, $message): void
{
$count = 0;
foreach ($decisions as $decision) {
$enabled = $decision->getEnabled() ? "true" : "false";

print ">>> [$this->outputTag #$count] $message:
enabled: $enabled,
flagKey: {$decision->getFlagKey()},
ruleKey: {$decision->getRuleKey()},
variationKey: {$decision->getVariationKey()},
variables: " . print_r($decision->getVariables(), true) . ",
reasons: " . print_r($decision->getReasons(), true) . "\r\n";

$count++;
}
}
}
Loading