diff --git a/src/Optimizely/Optimizely.php b/src/Optimizely/Optimizely.php index 4cd71783..f975b33a 100644 --- a/src/Optimizely/Optimizely.php +++ b/src/Optimizely/Optimizely.php @@ -94,13 +94,14 @@ class Optimizely * @param $skipJsonValidation boolean representing whether JSON schema validation needs to be performed. * @param $userProfileService UserProfileServiceInterface */ - public function __construct($datafile, - EventDispatcherInterface $eventDispatcher = null, - LoggerInterface $logger = null, - ErrorHandlerInterface $errorHandler = null, - $skipJsonValidation = false, - UserProfileServiceInterface $userProfileService = null) - { + public function __construct( + $datafile, + EventDispatcherInterface $eventDispatcher = null, + LoggerInterface $logger = null, + ErrorHandlerInterface $errorHandler = null, + $skipJsonValidation = false, + UserProfileServiceInterface $userProfileService = null + ) { $this->_isValid = true; $this->_eventDispatcher = $eventDispatcher ?: new DefaultEventDispatcher(); $this->_logger = $logger ?: new NoOpLogger(); @@ -114,15 +115,13 @@ public function __construct($datafile, } try { - $this->_config = new ProjectConfig($datafile, $this->_logger, $this->_errorHandler); - } - catch (Throwable $exception) { + $this->_config = new ProjectConfig($datafile, $this->_logger, $this->_errorHandler); + } catch (Throwable $exception) { $this->_isValid = false; $this->_logger = new DefaultLogger(); $this->_logger->log(Logger::ERROR, 'Provided "datafile" is in an invalid format.'); return; - } - catch (Exception $exception) { + } catch (Exception $exception) { $this->_isValid = false; $this->_logger = new DefaultLogger(); $this->_logger->log(Logger::ERROR, 'Provided "datafile" is in an invalid format.'); @@ -157,7 +156,8 @@ private function validateDatafile($datafile, $skipJsonValidation) * * @return boolean Representing whether all user inputs are valid. */ - private function validateUserInputs($attributes, $eventTags = null) { + private function validateUserInputs($attributes, $eventTags = null) + { if (!is_null($attributes) && !Validator::areAttributesValid($attributes)) { $this->_logger->log(Logger::ERROR, 'Provided attributes are in an invalid format.'); $this->_errorHandler->handleError( @@ -189,16 +189,20 @@ private function validateUserInputs($attributes, $eventTags = null) { * * @return Array Of objects where each object contains the ID of the experiment to track and the ID of the variation the user is bucketed into. */ - private function getValidExperimentsForEvent($event, $userId, $attributes = null) { + private function getValidExperimentsForEvent($event, $userId, $attributes = null) + { $validExperiments = []; - forEach ($event->getExperimentIds() as $experimentId) { + foreach ($event->getExperimentIds() as $experimentId) { $experiment = $this->_config->getExperimentFromId($experimentId); $experimentKey = $experiment->getKey(); $variationKey = $this->getVariation($experimentKey, $userId, $attributes); if (is_null($variationKey)) { - $this->_logger->log(Logger::INFO, sprintf('Not tracking user "%s" for experiment "%s".', - $userId, $experimentKey)); + $this->_logger->log(Logger::INFO, sprintf( + 'Not tracking user "%s" for experiment "%s".', + $userId, + $experimentKey + )); continue; } @@ -209,6 +213,52 @@ private function getValidExperimentsForEvent($event, $userId, $attributes = null return $validExperiments; } + /** + * @param string Experiment key + * @param string Variation key + * @param string User ID + * @param array Associative array of user attributes + */ + protected function sendImpressionEvent($experimentKey, $variationKey, $userId, $attributes) + { + $impressionEvent = $this->_eventBuilder + ->createImpressionEvent($this->_config, $experimentKey, $variationKey, $userId, $attributes); + $this->_logger->log(Logger::INFO, sprintf('Activating user "%s" in experiment "%s".', $userId, $experimentKey)); + $this->_logger->log( + Logger::DEBUG, + sprintf( + 'Dispatching impression event to URL %s with params %s.', + $impressionEvent->getUrl(), + http_build_query($impressionEvent->getParams()) + ) + ); + + try { + $this->_eventDispatcher->dispatchEvent($impressionEvent); + } catch (Throwable $exception) { + $this->_logger->log(Logger::ERROR, sprintf( + 'Unable to dispatch impression event. Error %s', + $exception->getMessage() + )); + } catch (Exception $exception) { + $this->_logger->log(Logger::ERROR, sprintf( + 'Unable to dispatch impression event. Error %s', + $exception->getMessage() + )); + } + + $this->_notificationCenter->sendNotifications( + NotificationType::ACTIVATE, + array( + $this->_config->getExperimentFromKey($experimentKey), + $userId, + $attributes, + $this->_config->getVariationFromKey($experimentKey, $variationKey), + $impressionEvent + ) + ); + } + /** * Buckets visitor and sends impression event to Optimizely. * @@ -228,30 +278,10 @@ public function activate($experimentKey, $userId, $attributes = null) $variationKey = $this->getVariation($experimentKey, $userId, $attributes); if (is_null($variationKey)) { $this->_logger->log(Logger::INFO, sprintf('Not activating user "%s".', $userId)); - return $variationKey; + return null; } - $impressionEvent = $this->_eventBuilder - ->createImpressionEvent($this->_config, $experimentKey, $variationKey, $userId, $attributes); - $this->_logger->log(Logger::INFO, sprintf('Activating user "%s" in experiment "%s".', $userId, $experimentKey)); - $this->_logger->log( - Logger::DEBUG, - sprintf('Dispatching impression event to URL %s with params %s.', - $impressionEvent->getUrl(), http_build_query($impressionEvent->getParams()) - ) - ); - - try { - $this->_eventDispatcher->dispatchEvent($impressionEvent); - } - catch (Throwable $exception) { - $this->_logger->log(Logger::ERROR, sprintf( - 'Unable to dispatch impression event. Error %s', $exception->getMessage())); - } - catch (Exception $exception) { - $this->_logger->log(Logger::ERROR, sprintf( - 'Unable to dispatch impression event. Error %s', $exception->getMessage())); - } + $this->sendImpressionEvent($experimentKey, $variationKey, $userId, $attributes); return $variationKey; } @@ -307,20 +337,25 @@ public function track($eventKey, $userId, $attributes = null, $eventTags = null) $this->_logger->log(Logger::INFO, sprintf('Tracking event "%s" for user "%s".', $eventKey, $userId)); $this->_logger->log( Logger::DEBUG, - sprintf('Dispatching conversion event to URL %s with params %s.', - $conversionEvent->getUrl(), http_build_query($conversionEvent->getParams()) - )); + sprintf( + 'Dispatching conversion event to URL %s with params %s.', + $conversionEvent->getUrl(), + http_build_query($conversionEvent->getParams()) + ) + ); try { $this->_eventDispatcher->dispatchEvent($conversionEvent); - } - catch (Throwable $exception) { + } catch (Throwable $exception) { $this->_logger->log(Logger::ERROR, sprintf( - 'Unable to dispatch conversion event. Error %s', $exception->getMessage())); - } - catch (Exception $exception) { + 'Unable to dispatch conversion event. Error %s', + $exception->getMessage() + )); + } catch (Exception $exception) { $this->_logger->log(Logger::ERROR, sprintf( - 'Unable to dispatch conversion event. Error %s', $exception->getMessage())); + 'Unable to dispatch conversion event. Error %s', + $exception->getMessage() + )); } $this->_notificationCenter->sendNotifications( @@ -333,7 +368,6 @@ public function track($eventKey, $userId, $attributes = null, $eventTags = null) $conversionEvent ) ); - } else { $this->_logger->log( Logger::INFO, @@ -377,16 +411,16 @@ public function getVariation($experimentKey, $userId, $attributes = null) } /** - * Force a user into a variation for a given experiment. - * - * @param $experimentKey string Key identifying the experiment. - * @param $userId string The user ID to be used for bucketing. - * @param $variationKey string The variation key specifies the variation which the user - * will be forced into. If null, then clear the existing experiment-to-variation mapping. - * + * Force a user into a variation for a given experiment. + * + * @param $experimentKey string Key identifying the experiment. + * @param $userId string The user ID to be used for bucketing. + * @param $variationKey string The variation key specifies the variation which the user + * will be forced into. If null, then clear the existing experiment-to-variation mapping. + * * @return boolean A boolean value that indicates if the set completed successfully. - */ - public function setForcedVariation($experimentKey, $userId, $variationKey) + */ + public function setForcedVariation($experimentKey, $userId, $variationKey) { return $this->_config->setForcedVariation($experimentKey, $userId, $variationKey); } diff --git a/tests/OptimizelyTest.php b/tests/OptimizelyTest.php index 11c3c9b3..b80f7b36 100644 --- a/tests/OptimizelyTest.php +++ b/tests/OptimizelyTest.php @@ -32,7 +32,6 @@ use Optimizely\Logger\DefaultLogger; use Optimizely\Optimizely; - class OptimizelyTest extends \PHPUnit_Framework_TestCase { private $datafile; @@ -136,9 +135,11 @@ public function testValidateDatafileInvalidFileJsonValidationNotSkipped() $validateInputsMethod->setAccessible(true); $this->assertFalse( - $validateInputsMethod->invoke(new Optimizely('Random datafile'), + $validateInputsMethod->invoke( + new Optimizely('Random datafile'), 'Random datafile', - false) + false + ) ); $this->expectOutputRegex('/Provided "datafile" has invalid schema./'); @@ -150,8 +151,11 @@ public function testValidateDatafileInvalidFileJsonValidationSkipped() $validateInputsMethod->setAccessible(true); $this->assertTrue( - $validateInputsMethod->invoke(new Optimizely('Random datafile', null, null, null, true), - 'Random datafile', true) + $validateInputsMethod->invoke( + new Optimizely('Random datafile', null, null, null, true), + 'Random datafile', + true + ) ); } @@ -223,8 +227,10 @@ public function testActivateUserInNoVariation() ->with(Logger::DEBUG, 'Assigned bucket 8495 to user "not_in_variation_user" with bucketing ID "not_in_variation_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "not_in_variation_user" is in no variation.'); + ->with( + Logger::INFO, + 'User "not_in_variation_user" is in no variation.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::INFO, 'Not activating user "not_in_variation_user".'); @@ -264,16 +270,22 @@ public function testActivateNoAudienceNoAttributes() ->with(Logger::DEBUG, 'Assigned bucket 1922 to user "user_1" with bucketing ID "user_1".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "user_1" is in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "user_1" is in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9525 to user "user_1" with bucketing ID "user_1".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9525 to user "user_1" with bucketing ID "user_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "user_1" is in variation group_exp_1_var_2 of experiment group_experiment_1.'); + ->with( + Logger::INFO, + 'User "user_1" is in variation group_exp_1_var_2 of experiment group_experiment_1.' + ); // Verify that sendImpression is called with expected params $optimizelyMock->expects($this->exactly(1)) @@ -311,16 +323,22 @@ public function testActivateNoAudienceNoAttributesAfterSetForcedVariation() ->with(Logger::DEBUG, 'Assigned bucket 1922 to user "user_1" with bucketing ID "user_1".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "user_1" is in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "user_1" is in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9525 to user "user_1" with bucketing ID "user_1".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9525 to user "user_1" with bucketing ID "user_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "user_1" is in variation group_exp_1_var_2 of experiment group_experiment_1.'); + ->with( + Logger::INFO, + 'User "user_1" is in variation group_exp_1_var_2 of experiment group_experiment_1.' + ); // Verify that sendImpression is called with expected params $optimizelyMock->expects($this->exactly(1)) @@ -356,8 +374,10 @@ public function testActivateAudienceNoAttributes() ->with(Logger::INFO, 'User "test_user" does not meet conditions to be in experiment "test_experiment".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not activating user "test_user".'); + ->with( + Logger::INFO, + 'Not activating user "test_user".' + ); // Call activate $this->assertNull($optimizelyMock->activate('test_experiment', 'test_user')); @@ -387,8 +407,10 @@ public function testActivateWithAttributes() ->with(Logger::DEBUG, 'Assigned bucket 3037 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation control of experiment test_experiment.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation control of experiment test_experiment.' + ); // Verify that sendImpressionEvent is called with expected attributes $optimizelyMock->expects($this->exactly(1)) @@ -417,10 +439,12 @@ public function testActivateExperimentNotRunning() ->with(Logger::INFO, 'Experiment "paused_experiment" is not running.'); $this->loggerMock->expects($this->at(1)) ->method('log') - ->with(Logger::INFO, - 'Not activating user "test_user".'); + ->with( + Logger::INFO, + 'Not activating user "test_user".' + ); - // Call activate + // Call activate $this->assertNull($optimizelyMock->activate('paused_experiment', 'test_user', null)); } @@ -445,7 +469,10 @@ public function testGetVariationInvalidAttributes() ->with(new InvalidAttributeException('Provided attributes are in an invalid format.')); $optlyObject = new Optimizely( - $this->datafile, new ValidEventDispatcher(), $this->loggerMock, $errorHandlerMock + $this->datafile, + new ValidEventDispatcher(), + $this->loggerMock, + $errorHandlerMock ); // Call activate @@ -465,8 +492,10 @@ public function testGetVariationAudienceMatch() ->with(Logger::DEBUG, 'Assigned bucket 3037 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation control of experiment test_experiment.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation control of experiment test_experiment.' + ); $this->assertEquals( 'control', @@ -584,7 +613,7 @@ public function testGetVariationWhitelistedUserAfterSetForcedVariation() ->with(Logger::DEBUG, sprintf('Set variation "%s" for experiment "%s" and user "%s" in the forced variation map.', $variationId, $experimentId, $userId)); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, sprintf('Variation "%s" is mapped to experiment "%s" and user "%s" in the forced variation map',$variationKey, $experimentKey, $userId)); + ->with(Logger::DEBUG, sprintf('Variation "%s" is mapped to experiment "%s" and user "%s" in the forced variation map', $variationKey, $experimentKey, $userId)); $this->assertTrue($this->optimizelyObject->setForcedVariation($experimentKey, $userId, $variationKey), 'Set variation for paused experiment should have passed.'); $this->assertEquals($this->optimizelyObject->getVariation($experimentKey, $userId), $variationKey); @@ -662,7 +691,10 @@ public function testTrackInvalidAttributes() ->with(new InvalidAttributeException('Provided attributes are in an invalid format.')); $optlyObject = new Optimizely( - $this->datafile, new ValidEventDispatcher(), $this->loggerMock, $errorHandlerMock + $this->datafile, + new ValidEventDispatcher(), + $this->loggerMock, + $errorHandlerMock ); $notificationCenter = new \ReflectionProperty(Optimizely::class, '_notificationCenter'); @@ -678,7 +710,7 @@ public function testTrackInvalidAttributes() } public function testTrackInvalidEventTags() - { + { $this->loggerMock->expects($this->once()) ->method('log') ->with(Logger::ERROR, 'Provided event tags are in an invalid format.'); @@ -691,10 +723,13 @@ public function testTrackInvalidEventTags() ->with(new InvalidEventTagException('Provided event tags are in an invalid format.')); $optlyObject = new Optimizely( - $this->datafile, null, $this->loggerMock, $errorHandlerMock + $this->datafile, + null, + $this->loggerMock, + $errorHandlerMock ); - $optlyObject->track('purchase', 'test_user', [], [1=>2]); + $optlyObject->track('purchase', 'test_user', [], [1=>2]); } public function testTrackUnknownEventKey() @@ -720,8 +755,8 @@ public function testActivateGivenEventKeyWithNoExperiments() $this->optimizelyObject->track('unlinked_event', 'test_user'); } - public function testTrackEventDispatchFailure(){ - + public function testTrackEventDispatchFailure() + { $eventDispatcherMock = $this->getMockBuilder(DefaultEventDispatcher::class) ->setMethods(array('dispatchEvent')) ->getMock(); @@ -782,58 +817,82 @@ public function testTrackNoAttributesNoEventValue() ->with(Logger::INFO, 'User "test_user" does not meet conditions to be in experiment "test_experiment".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "test_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "test_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -899,58 +958,82 @@ public function testTrackNoAttributesNoEventValueAfterSetForcedVariation() ->with(Logger::INFO, 'User "test_user" does not meet conditions to be in experiment "test_experiment".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "test_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "test_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1018,58 +1101,82 @@ public function testTrackWithAttributesNoEventValue() ->with(Logger::DEBUG, 'Assigned bucket 3037 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation control of experiment test_experiment.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation control of experiment test_experiment.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1120,8 +1227,10 @@ public function testTrackNoAttributesWithDeprecatedEventValue() ->method('log'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::WARNING, - 'Event value is deprecated in track call. Use event tags to pass in revenue value instead.'); + ->with( + Logger::WARNING, + 'Event value is deprecated in track call. Use event tags to pass in revenue value instead.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); @@ -1130,58 +1239,82 @@ public function testTrackNoAttributesWithDeprecatedEventValue() ->with(Logger::INFO, 'User "test_user" does not meet conditions to be in experiment "test_experiment".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "test_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "test_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1238,8 +1371,10 @@ public function testTrackNoAttributesWithEventValue() ->with(Logger::INFO, 'User "test_user" does not meet conditions to be in experiment "test_experiment".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "test_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "test_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); @@ -1248,47 +1383,67 @@ public function testTrackNoAttributesWithEventValue() ->with(Logger::DEBUG, 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1444,8 +1599,10 @@ public function testTrackWithAttributesWithDeprecatedEventValue() ->method('log'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::WARNING, - 'Event value is deprecated in track call. Use event tags to pass in revenue value instead.'); + ->with( + Logger::WARNING, + 'Event value is deprecated in track call. Use event tags to pass in revenue value instead.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); @@ -1454,58 +1611,82 @@ public function testTrackWithAttributesWithDeprecatedEventValue() ->with(Logger::DEBUG, 'Assigned bucket 3037 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation control of experiment test_experiment.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation control of experiment test_experiment.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1572,58 +1753,82 @@ public function testTrackWithAttributesWithEventValue() ->with(Logger::DEBUG, 'Assigned bucket 3037 to user "test_user" with bucketing ID "test_user".'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation control of experiment test_experiment.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation control of experiment test_experiment.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is not in experiment group_experiment_1 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "group_experiment_1".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "group_experiment_1".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') ->with(Logger::DEBUG, 'User "test_user" is not in the forced variation map.'); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 4517 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in experiment group_experiment_2 of group 7722400015.'); + ->with( + Logger::INFO, + 'User "test_user" is in experiment group_experiment_2 of group 7722400015.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".'); + ->with( + Logger::DEBUG, + 'Assigned bucket 9871 to user "test_user" with bucketing ID "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.'); + ->with( + Logger::INFO, + 'User "test_user" is in variation group_exp_2_var_2 of experiment group_experiment_2.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Experiment "paused_experiment" is not running.'); + ->with( + Logger::INFO, + 'Experiment "paused_experiment" is not running.' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Not tracking user "test_user" for experiment "paused_experiment".'); + ->with( + Logger::INFO, + 'Not tracking user "test_user" for experiment "paused_experiment".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::INFO, - 'Tracking event "purchase" for user "test_user".'); + ->with( + Logger::INFO, + 'Tracking event "purchase" for user "test_user".' + ); $this->loggerMock->expects($this->at($callIndex++)) ->method('log') - ->with(Logger::DEBUG, - 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.'); + ->with( + Logger::DEBUG, + 'Dispatching conversion event to URL logx.optimizely.com/track with params param1=val1.' + ); $optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock); @@ -1895,7 +2100,7 @@ public function testSetForcedVariationLogs() $optlyObject->setForcedVariation($invalidExperimentKey, $userId, $variationKey); $optlyObject->setForcedVariation($experimentKey, $userId, null); - $optlyObject->setForcedVariation($experimentKey, $userId, $invalidVariationKey ); + $optlyObject->setForcedVariation($experimentKey, $userId, $invalidVariationKey); $optlyObject->setForcedVariation($experimentKey, $userId, $variationKey); $optlyObject->setForcedVariation($experimentKey, null, $variationKey); } @@ -1937,7 +2142,6 @@ public function testGetForcedVariationLogs() $optlyObject->getForcedVariation($invalidExperimentKey, $userId); $optlyObject->getForcedVariation($experimentKey, $userId); $optlyObject->getForcedVariation($experimentKey, null); - } public function testGetVariationBucketingIdAttribute() @@ -1974,4 +2178,158 @@ public function testGetVariationBucketingIdAttribute() $this->assertEquals(null, $variationKey, sprintf('Invalid variation key "%s" for getVariation with bucketing ID "%s".', $variationKey, $this->testBucketingIdControl)); } + public function testSendImpressionEventWithNoAttributes() + { + $optlyObject = new OptimizelyTester($this->datafile, new ValidEventDispatcher(), $this->loggerMock); + + // verify that createImpressionEvent is called + $this->eventBuilderMock->expects($this->once()) + ->method('createImpressionEvent') + ->with( + $this->projectConfig, + 'group_experiment_1', + 'group_exp_1_var_2', + 'user_1', + null + ) + ->willReturn( + new LogEvent( + 'logx.optimizely.com/decision', + ['param1' => 'val1', 'param2' => 'val2'], + 'POST', + [] + ) + ); + + // verify that sendNotifications is called with expected params + $arrayParam = array( + $this->projectConfig->getExperimentFromKey('group_experiment_1'), + 'user_1', + null, + $this->projectConfig->getVariationFromKey('group_experiment_1', 'group_exp_1_var_2'), + new LogEvent( + 'logx.optimizely.com/decision', + ['param1' => 'val1', 'param2' => 'val2'], + 'POST', + [] + ) + ); + + $this->notificationCenterMock->expects($this->once()) + ->method('sendNotifications') + ->with( + NotificationType::ACTIVATE, + $arrayParam + ); + + $eventBuilder = new \ReflectionProperty(Optimizely::class, '_eventBuilder'); + $eventBuilder->setAccessible(true); + $eventBuilder->setValue($optlyObject, $this->eventBuilderMock); + + $notificationCenter = new \ReflectionProperty(Optimizely::class, '_notificationCenter'); + $notificationCenter->setAccessible(true); + $notificationCenter->setValue($optlyObject, $this->notificationCenterMock); + + $this->loggerMock->expects($this->at(0)) + ->method('log') + ->with( + Logger::INFO, + 'Activating user "user_1" in experiment "group_experiment_1".' + ); + $this->loggerMock->expects($this->at(1)) + ->method('log') + ->with( + Logger::DEBUG, + 'Dispatching impression event to URL logx.optimizely.com/decision with params param1=val1¶m2=val2.' + ); + + $optlyObject->sendImpressionEvent('group_experiment_1', 'group_exp_1_var_2', 'user_1', null); + } + + public function testSendImpressionEventDispatchFailure() + { + $optlyObject = new OptimizelyTester($this->datafile, new ValidEventDispatcher(), $this->loggerMock); + + $eventDispatcherMock = $this->getMockBuilder(DefaultEventDispatcher::class) + ->setMethods(array('dispatchEvent')) + ->getMock(); + + $eventDispatcher = new \ReflectionProperty(Optimizely::class, '_eventDispatcher'); + $eventDispatcher->setAccessible(true); + $eventDispatcher->setValue($optlyObject, $eventDispatcherMock); + + $eventDispatcherMock->expects($this->once()) + ->method('dispatchEvent') + ->will($this->throwException(new Exception)); + + $this->loggerMock->expects($this->at(2)) + ->method('log') + ->with(Logger::ERROR, 'Unable to dispatch impression event. Error '); + + $optlyObject->sendImpressionEvent('test_experiment', 'control', 'test_user', []); + } + + public function testSendImpressionEventWithAttributes() + { + $optlyObject = new OptimizelyTester($this->datafile, new ValidEventDispatcher(), $this->loggerMock); + + $userAttributes = [ + 'device_type' => 'iPhone', + 'company' => 'Optimizely', + 'location' => 'San Francisco' + ]; + + // verify that createImpressionEvent is called + $this->eventBuilderMock->expects($this->once()) + ->method('createImpressionEvent') + ->with( + $this->projectConfig, + 'test_experiment', + 'control', + 'test_user', + $userAttributes + ) + ->willReturn(new LogEvent('logx.optimizely.com/decision', ['param1' => 'val1'], 'POST', [])); + + // verify that sendNotifications is called with expected params + $arrayParam = array( + $this->projectConfig->getExperimentFromKey('test_experiment'), + 'test_user', + $userAttributes, + $this->projectConfig->getVariationFromKey('test_experiment', 'control'), + new LogEvent( + 'logx.optimizely.com/decision', + ['param1' => 'val1'], + 'POST', + [] + ) + ); + + $this->notificationCenterMock->expects($this->once()) + ->method('sendNotifications') + ->with( + NotificationType::ACTIVATE, + $arrayParam + ); + + $this->loggerMock->expects($this->at(0)) + ->method('log') + ->with(Logger::INFO, 'Activating user "test_user" in experiment "test_experiment".'); + $this->loggerMock->expects($this->at(1)) + ->method('log') + ->with( + Logger::DEBUG, + 'Dispatching impression event to URL logx.optimizely.com/decision with params param1=val1.' + ); + + $eventBuilder = new \ReflectionProperty(Optimizely::class, '_eventBuilder'); + $eventBuilder->setAccessible(true); + $eventBuilder->setValue($optlyObject, $this->eventBuilderMock); + + $notificationCenter = new \ReflectionProperty(Optimizely::class, '_notificationCenter'); + $notificationCenter->setAccessible(true); + $notificationCenter->setValue($optlyObject, $this->notificationCenterMock); + + $optlyObject->sendImpressionEvent('test_experiment', 'control', 'test_user', $userAttributes); + } } diff --git a/tests/TestData.php b/tests/TestData.php index 5107afa7..07323484 100644 --- a/tests/TestData.php +++ b/tests/TestData.php @@ -37,7 +37,7 @@ "variations": [{"id": "7713030086", "key": "group_exp_2_var_1"}, {"id": "7725250007", "key": "group_exp_2_var_2"}], "forcedVariations": {}, "id": "7718750065"}], "id": "7722400015"}], "attributes": [{"id": "7723280020", "key": "device_type"}, {"id": "7723340004", "key": "location"}], "projectId": "7720880029", "accountId": "1592310167", - "events": [{"experimentIds": ["7716830082", "7723330021", "7718750065", "7716830585"], "id": "7718020063", "key": "purchase"}],"anonymizeIP": false, + "events": [{"experimentIds": ["7716830082", "7723330021", "7718750065", "7716830585"], "id": "7718020063", "key": "purchase"}, {"experimentIds": [], "id": "7718020064", "key": "unlinked_event"}],"anonymizeIP": false, "revision": "15"}'); define('DATAFILE_V3', @@ -99,6 +99,16 @@ public function generateBucketValue($bucketingId) } } +/** + * Class OptimizelyTester + * Extending Optimizely for the sake of tests. + */ +class OptimizelyTester extends Optimizely +{ + public function sendImpressionEvent($experimentKey, $variationKey, $userId, $attributes){ + parent::sendImpressionEvent($experimentKey, $variationKey, $userId, $attributes); + } +} class FireNotificationTester{ public function decision_callback_no_args(){}