Skip to content

Commit 44b96dd

Browse files
Revise rollout bucketing to check audience in last rollout rule. (#97)
1 parent 641bd4a commit 44b96dd

File tree

2 files changed

+66
-65
lines changed

2 files changed

+66
-65
lines changed

src/Optimizely/DecisionService/DecisionService.php

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
/**
3-
* Copyright 2017, Optimizely Inc and Contributors
3+
* Copyright 2017-2018, Optimizely Inc and Contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -304,35 +304,28 @@ public function getVariationForFeatureRollout(FeatureFlag $featureFlag, $userId,
304304
continue;
305305
}
306306

307-
$this->_logger->log(
308-
Logger::DEBUG,
309-
sprintf("Attempting to bucket user '{$userId}' into rollout rule '%s'.", $experiment->getKey())
310-
);
311-
312307
// Evaluate if user satisfies the traffic allocation for this rollout rule
313308
$variation = $this->_bucketer->bucket($this->_projectConfig, $experiment, $bucketing_id, $userId);
314309
if ($variation && $variation->getKey()) {
315310
return new FeatureDecision($experiment, $variation, FeatureDecision::DECISION_SOURCE_ROLLOUT);
316-
} else {
317-
$this->_logger->log(
318-
Logger::DEBUG,
319-
"User '{$userId}' was excluded due to traffic allocation. Checking 'Everyone Else' rule now."
320-
);
321-
break;
322311
}
312+
break;
323313
}
324314
// Evaluate Everyone Else Rule / Last Rule now
325-
$experiment = $rolloutRules[sizeof($rolloutRules)-1];
326-
$variation = $this->_bucketer->bucket($this->_projectConfig, $experiment, $bucketing_id, $userId);
327-
if ($variation && $variation->getKey()) {
328-
return new FeatureDecision($experiment, $variation, FeatureDecision::DECISION_SOURCE_ROLLOUT);
329-
} else {
330-
$this->_logger->log(
331-
Logger::DEBUG,
332-
"User '{$userId}' was excluded from the 'Everyone Else' rule for feature flag"
333-
);
334-
return null;
335-
}
315+
$experiment = $rolloutRules[sizeof($rolloutRules)-1];
316+
317+
// Evaluate if user meets the audience condition of Everyone Else Rule / Last Rule now
318+
if (Validator::isUserInExperiment($this->_projectConfig, $experiment, $userAttributes)) {
319+
$variation = $this->_bucketer->bucket($this->_projectConfig, $experiment, $bucketing_id, $userId);
320+
if ($variation && $variation->getKey()) {
321+
return new FeatureDecision($experiment, $variation, FeatureDecision::DECISION_SOURCE_ROLLOUT);
322+
}
323+
}
324+
$this->_logger->log(
325+
Logger::DEBUG,
326+
sprintf("User '%s' did not meet the audience conditions to be in rollout rule '%s'.", $userId, $experiment->getKey()));
327+
328+
return null;
336329
}
337330

338331
/**

tests/DecisionServiceTests/DecisionServiceTest.php

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
/**
3-
* Copyright 2017, Optimizely
3+
* Copyright 2017-2018, Optimizely
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -955,13 +955,6 @@ public function testGetVariationForFeatureRolloutWhenUserIsBucketedInTheTargetin
955955
->method('bucket')
956956
->willReturn($expected_variation);
957957

958-
$this->loggerMock->expects($this->at(0))
959-
->method('log')
960-
->with(
961-
Logger::DEBUG,
962-
"Attempting to bucket user 'user_1' into rollout rule '{$experiment->getKey()}'."
963-
);
964-
965958
$this->assertEquals(
966959
$expected_decision,
967960
$this->decisionService->getVariationForFeatureRollout($feature_flag, 'user_1', $user_attributes)
@@ -1000,20 +993,6 @@ public function testGetVariationForFeatureRolloutWhenUserIsNotBucketedInTheTarge
1000993
->method('bucket')
1001994
->willReturn($expected_variation);
1002995

1003-
$this->loggerMock->expects($this->at(0))
1004-
->method('log')
1005-
->with(
1006-
Logger::DEBUG,
1007-
"Attempting to bucket user 'user_1' into rollout rule '{$experiment0->getKey()}'."
1008-
);
1009-
$this->loggerMock->expects($this->at(1))
1010-
->method('log')
1011-
->with(
1012-
Logger::DEBUG,
1013-
"User 'user_1' was excluded due to traffic allocation. Checking 'Everyone Else' rule now."
1014-
);
1015-
1016-
1017996
$this->assertEquals(
1018997
$expected_decision,
1019998
$this->decisionService->getVariationForFeatureRollout($feature_flag, 'user_1', $user_attributes)
@@ -1046,25 +1025,6 @@ public function testGetVariationForFeatureRolloutWhenUserIsNeitherBucketedInTheT
10461025
->method('bucket')
10471026
->willReturn(null);
10481027

1049-
$this->loggerMock->expects($this->at(0))
1050-
->method('log')
1051-
->with(
1052-
Logger::DEBUG,
1053-
"Attempting to bucket user 'user_1' into rollout rule '{$experiment0->getKey()}'."
1054-
);
1055-
$this->loggerMock->expects($this->at(1))
1056-
->method('log')
1057-
->with(
1058-
Logger::DEBUG,
1059-
"User 'user_1' was excluded due to traffic allocation. Checking 'Everyone Else' rule now."
1060-
);
1061-
$this->loggerMock->expects($this->at(2))
1062-
->method('log')
1063-
->with(
1064-
Logger::DEBUG,
1065-
"User 'user_1' was excluded from the 'Everyone Else' rule for feature flag"
1066-
);
1067-
10681028
$this->assertEquals(
10691029
null,
10701030
$this->decisionService->getVariationForFeatureRollout($feature_flag, 'user_1', $user_attributes)
@@ -1101,7 +1061,6 @@ public function testGetVariationForFeatureRolloutWhenUserDoesNotQualifyForAnyTar
11011061
$bucketer->setValue($this->decisionService, $this->bucketerMock);
11021062

11031063
// Expect bucket to be called exactly once for the everyone else/last rule.
1104-
// As we ignore Audience check only for thelast rule
11051064
$this->bucketerMock->expects($this->exactly(1))
11061065
->method('bucket')
11071066
->willReturn($expected_variation);
@@ -1125,4 +1084,53 @@ public function testGetVariationForFeatureRolloutWhenUserDoesNotQualifyForAnyTar
11251084
$this->decisionService->getVariationForFeatureRollout($feature_flag, 'user_1', $user_attributes)
11261085
);
11271086
}
1087+
1088+
public function testGetVariationForFeatureRolloutWhenUserDoesNotQualifyForAnyTargetingRuleOrEveryoneElseRule()
1089+
{
1090+
$feature_flag = $this->config->getFeatureFlagFromKey('boolean_single_variable_feature');
1091+
$rollout_id = $feature_flag->getRolloutId();
1092+
$rollout = $this->config->getRolloutFromId($rollout_id);
1093+
$experiment0 = $rollout->getExperiments()[0];
1094+
$experiment1 = $rollout->getExperiments()[1];
1095+
// Everyone Else Rule
1096+
$experiment2 = $rollout->getExperiments()[2];
1097+
1098+
// Set an AudienceId for everyone else/last rule so that user does not qualify for audience
1099+
$experiment2->setAudienceIds(["11154"]);
1100+
$expected_variation = $experiment2->getVariations()[0];
1101+
1102+
// Provide null attributes so that user does not qualify for audience
1103+
$user_attributes = [];
1104+
$this->decisionService = new DecisionService($this->loggerMock, $this->config);
1105+
$bucketer = new \ReflectionProperty(DecisionService::class, '_bucketer');
1106+
$bucketer->setAccessible(true);
1107+
$bucketer->setValue($this->decisionService, $this->bucketerMock);
1108+
1109+
// // Expect bucket never called for the everyone else/last rule.
1110+
$this->bucketerMock->expects($this->never())
1111+
->method('bucket');
1112+
1113+
$this->loggerMock->expects($this->at(0))
1114+
->method('log')
1115+
->with(
1116+
Logger::DEBUG,
1117+
"User 'user_1' did not meet the audience conditions to be in rollout rule '{$experiment0->getKey()}'."
1118+
);
1119+
1120+
$this->loggerMock->expects($this->at(1))
1121+
->method('log')
1122+
->with(
1123+
Logger::DEBUG,
1124+
"User 'user_1' did not meet the audience conditions to be in rollout rule '{$experiment1->getKey()}'."
1125+
);
1126+
1127+
$this->loggerMock->expects($this->at(2))
1128+
->method('log')
1129+
->with(
1130+
Logger::DEBUG,
1131+
"User 'user_1' did not meet the audience conditions to be in rollout rule '{$experiment2->getKey()}'."
1132+
);
1133+
1134+
$this->assertNull($this->decisionService->getVariationForFeatureRollout($feature_flag, 'user_1', $user_attributes));
1135+
}
11281136
}

0 commit comments

Comments
 (0)