Skip to content

Commit 7c0e854

Browse files
rashidspthomaszurkan-optimizely
authored andcommitted
checks audience for every one else (#94)
1 parent 086962e commit 7c0e854

File tree

2 files changed

+53
-49
lines changed

2 files changed

+53
-49
lines changed

lib/optimizely/decision_service.rb

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

33
#
4-
# Copyright 2017, Optimizely and contributors
4+
# Copyright 2017-2018, Optimizely and contributors
55
#
66
# Licensed under the Apache License, Version 2.0 (the "License");
77
# you may not use this file except in compliance with the License.
@@ -235,33 +235,27 @@ def get_variation_for_feature_rollout(feature_flag, user_id, attributes = nil)
235235
next
236236
end
237237

238-
# User failed traffic allocation, jump to Everyone Else rule
239-
@config.logger.log(
240-
Logger::DEBUG,
241-
"Attempting to bucket user '#{user_id}' into rollout rule for audience '#{audience_name}'."
242-
)
243-
244238
# Evaluate if user satisfies the traffic allocation for this rollout rule
245239
variation = @bucketer.bucket(rollout_rule, bucketing_id, user_id)
246240
return Decision.new(rollout_rule, variation, DECISION_SOURCE_ROLLOUT) unless variation.nil?
247-
# User failed traffic allocation, jump to Everyone Else rule
248-
@config.logger.log(
249-
Logger::DEBUG,
250-
"User '#{user_id}' was excluded due to traffic allocation. Checking 'Everyone Else' rule now."
251-
)
252-
253241
break
254242
end
255243

256244
# get last rule which is the everyone else rule
257245
everyone_else_experiment = rollout_rules[number_of_rules]
246+
# Check that user meets audience conditions for last rule
247+
unless Audience.user_in_experiment?(@config, everyone_else_experiment, attributes)
248+
audience_id = everyone_else_experiment['audienceIds'][0]
249+
audience = @config.get_audience_from_id(audience_id)
250+
audience_name = audience['name']
251+
@config.logger.log(
252+
Logger::DEBUG,
253+
"User '#{user_id}' does not meet the conditions to be in rollout rule for audience '#{audience_name}'."
254+
)
255+
return nil
256+
end
258257
variation = @bucketer.bucket(everyone_else_experiment, bucketing_id, user_id)
259258
return Decision.new(everyone_else_experiment, variation, DECISION_SOURCE_ROLLOUT) unless variation.nil?
260-
261-
@config.logger.log(
262-
Logger::DEBUG,
263-
"User '#{user_id}' was excluded from the 'Everyone Else' rule for feature flag"
264-
)
265259
nil
266260
end
267261

spec/decision_service_spec.rb

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

33
#
4-
# Copyright 2017, Optimizely and contributors
4+
# Copyright 2017-2018, Optimizely and contributors
55
#
66
# Licensed under the Apache License, Version 2.0 (the "License");
77
# you may not use this file except in compliance with the License.
@@ -487,17 +487,12 @@
487487
feature_flag = config.feature_flag_key_map['boolean_single_variable_feature']
488488
rollout_experiment = config.rollout_id_map[feature_flag['rolloutId']]['experiments'][0]
489489
variation = rollout_experiment['variations'][0]
490-
audience_id = rollout_experiment['audienceIds'][0]
491-
audience_name = config.get_audience_from_id(audience_id)['name']
492490
expected_decision = Optimizely::DecisionService::Decision.new(rollout_experiment, variation, Optimizely::DecisionService::DECISION_SOURCE_ROLLOUT)
493491
allow(Optimizely::Audience).to receive(:user_in_experiment?).and_return(true)
494492
allow(decision_service.bucketer).to receive(:bucket)
495493
.with(rollout_experiment, user_id, user_id)
496494
.and_return(variation)
497495
expect(decision_service.get_variation_for_feature_rollout(feature_flag, user_id, user_attributes)).to eq(expected_decision)
498-
expect(spy_logger).to have_received(:log).once
499-
.with(Logger::DEBUG, "Attempting to bucket user '#{user_id}' into rollout rule "\
500-
"for audience '#{audience_name}'.")
501496
end
502497
end
503498

@@ -523,19 +518,6 @@
523518
.with(config, rollout['experiments'][0], user_attributes)
524519
expect(Optimizely::Audience).not_to have_received(:user_in_experiment?)
525520
.with(config, rollout['experiments'][1], user_attributes)
526-
527-
# verify log messages
528-
experiment = rollout['experiments'][0]
529-
audience_id = experiment['audienceIds'][0]
530-
audience_name = config.get_audience_from_id(audience_id)['name']
531-
532-
expect(spy_logger).to have_received(:log).once
533-
.with(Logger::DEBUG, "Attempting to bucket user '#{user_id}' into rollout rule "\
534-
"for audience '#{audience_name}'.")
535-
expect(spy_logger).to have_received(:log).once
536-
.with(Logger::DEBUG, "User '#{user_id}' was excluded due to traffic allocation. Checking 'Everyone Else' rule now.")
537-
expect(spy_logger).to have_received(:log).once
538-
.with(Logger::DEBUG, "User '#{user_id}' was excluded from the 'Everyone Else' rule for feature flag")
539521
end
540522
end
541523

@@ -561,16 +543,6 @@
561543
.with(config, rollout['experiments'][0], user_attributes)
562544
expect(Optimizely::Audience).not_to have_received(:user_in_experiment?)
563545
.with(config, rollout['experiments'][1], user_attributes)
564-
565-
# verify log messages
566-
experiment = rollout['experiments'][0]
567-
audience_id = experiment['audienceIds'][0]
568-
audience_name = config.get_audience_from_id(audience_id)['name']
569-
570-
expect(spy_logger).to have_received(:log).once
571-
.with(Logger::DEBUG, "Attempting to bucket user '#{user_id}' into rollout rule for audience '#{audience_name}'.")
572-
expect(spy_logger).to have_received(:log).once
573-
.with(Logger::DEBUG, "User '#{user_id}' was excluded due to traffic allocation. Checking 'Everyone Else' rule now.")
574546
end
575547
end
576548
end
@@ -584,18 +556,22 @@
584556
variation = everyone_else_experiment['variations'][0]
585557
expected_decision = Optimizely::DecisionService::Decision.new(everyone_else_experiment, variation, Optimizely::DecisionService::DECISION_SOURCE_ROLLOUT)
586558
allow(Optimizely::Audience).to receive(:user_in_experiment?).and_return(false)
559+
560+
allow(Optimizely::Audience).to receive(:user_in_experiment?)
561+
.with(config, everyone_else_experiment, user_attributes)
562+
.and_return(true)
587563
allow(decision_service.bucketer).to receive(:bucket)
588564
.with(everyone_else_experiment, user_id, user_id)
589565
.and_return(variation)
590566

591567
expect(decision_service.get_variation_for_feature_rollout(feature_flag, user_id, user_attributes)).to eq(expected_decision)
592568

593-
# verify we tried to bucket in all targeting rules except for the everyone else rule
569+
# verify we tried to bucket in all targeting rules and the everyone else rule
594570
expect(Optimizely::Audience).to have_received(:user_in_experiment?).once
595571
.with(config, rollout['experiments'][0], user_attributes)
596572
expect(Optimizely::Audience).to have_received(:user_in_experiment?)
597573
.with(config, rollout['experiments'][1], user_attributes)
598-
expect(Optimizely::Audience).not_to have_received(:user_in_experiment?)
574+
expect(Optimizely::Audience).to have_received(:user_in_experiment?)
599575
.with(config, rollout['experiments'][2], user_attributes)
600576

601577
# verify log messages
@@ -611,6 +587,40 @@
611587
expect(spy_logger).to have_received(:log).once
612588
.with(Logger::DEBUG, "User '#{user_id}' does not meet the conditions to be in rollout rule for audience '#{audience_name}'.")
613589
end
590+
591+
it 'should not bucket the user into the "Everyone Else" rule when audience mismatch' do
592+
feature_flag = config.feature_flag_key_map['boolean_single_variable_feature']
593+
rollout = config.rollout_id_map[feature_flag['rolloutId']]
594+
everyone_else_experiment = rollout['experiments'][2]
595+
everyone_else_experiment['audienceIds'] = ['11155']
596+
allow(Optimizely::Audience).to receive(:user_in_experiment?).and_return(false)
597+
598+
expect(decision_service.bucketer).not_to receive(:bucket)
599+
.with(everyone_else_experiment, user_id, user_id)
600+
601+
expect(decision_service.get_variation_for_feature_rollout(feature_flag, user_id, user_attributes)).to eq(nil)
602+
603+
# verify we tried to bucket in all targeting rules and the everyone else rule
604+
expect(Optimizely::Audience).to have_received(:user_in_experiment?).once
605+
.with(config, rollout['experiments'][0], user_attributes)
606+
expect(Optimizely::Audience).to have_received(:user_in_experiment?)
607+
.with(config, rollout['experiments'][1], user_attributes)
608+
expect(Optimizely::Audience).to have_received(:user_in_experiment?)
609+
.with(config, rollout['experiments'][2], user_attributes)
610+
611+
# verify log messages
612+
experiment = rollout['experiments'][0]
613+
audience_id = experiment['audienceIds'][0]
614+
audience_name = config.get_audience_from_id(audience_id)['name']
615+
expect(spy_logger).to have_received(:log).once
616+
.with(Logger::DEBUG, "User '#{user_id}' does not meet the conditions to be in rollout rule for audience '#{audience_name}'.")
617+
618+
experiment = rollout['experiments'][1]
619+
audience_id = experiment['audienceIds'][0]
620+
audience_name = config.get_audience_from_id(audience_id)['name']
621+
expect(spy_logger).to have_received(:log).twice
622+
.with(Logger::DEBUG, "User '#{user_id}' does not meet the conditions to be in rollout rule for audience '#{audience_name}'.")
623+
end
614624
end
615625
end
616626

0 commit comments

Comments
 (0)