Skip to content

Commit 0cd8d5e

Browse files
committed
feat(DecisionListener): Adds experiment decision listener.
1 parent c2a0931 commit 0cd8d5e

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

lib/optimizely.rb

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,19 @@ def get_variation(experiment_key, user_id, attributes = nil)
143143
end
144144

145145
variation_id = @decision_service.get_variation(experiment_key, user_id, attributes)
146+
variation = @config.get_variation_from_id(experiment_key, variation_id) unless variation_id.nil?
147+
variation_key = variation['key'] if variation
146148

147-
unless variation_id.nil?
148-
variation = @config.get_variation_from_id(experiment_key, variation_id)
149-
return variation['key'] if variation
150-
end
151-
nil
149+
@notification_center.send_notifications(
150+
NotificationCenter::NOTIFICATION_TYPES[:ON_DECISION],
151+
Helpers::Constants::DECISION_INFO_TYPES['EXPERIMENT'], user_id, attributes,
152+
decision_info: {
153+
experiment_key: experiment_key,
154+
variation_key: variation_key
155+
}
156+
)
157+
158+
variation_key
152159
end
153160

154161
# Force a user into a variation for a given experiment.

lib/optimizely/helpers/constants.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ module Constants
352352
'UNKNOWN_MATCH_TYPE' => 'Audience condition %s uses an unknown match type. You may need ' \
353353
'to upgrade to a newer release of the Optimizely SDK.'
354354
}.freeze
355+
356+
DECISION_INFO_TYPES = {
357+
'EXPERIMENT' => 'experiment',
358+
'FEATURE' => 'feature',
359+
'FEATURE_VARIABLE' => 'feature_variable'
360+
}.freeze
355361
end
356362
end
357363
end

lib/optimizely/notification_center.rb

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

33
#
4-
# Copyright 2017-2018, Optimizely and contributors
4+
# Copyright 2017-2019, 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.
@@ -22,6 +22,7 @@ class NotificationCenter
2222

2323
NOTIFICATION_TYPES = {
2424
ACTIVATE: 'ACTIVATE: experiment, user_id, attributes, variation, event',
25+
ON_DECISION: 'ON_DECISION: type, user_id, attributes, decision_info',
2526
TRACK: 'TRACK: event_key, user_id, attributes, event_tags, event'
2627
}.freeze
2728

spec/project_spec.rb

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,21 @@ class InvalidErrorHandler; end
498498
expect(project_instance.activate('test_experiment_not_started', 'test_user')).to eq(nil)
499499
end
500500

501-
it 'should return nil when audience conditions do not match' do
501+
it 'should log, return nil and call decision listener with variation key nil when audience conditions do not match' do
502502
user_attributes = {'browser_type' => 'chrome'}
503+
504+
expect(project_instance.notification_center).to receive(:send_notifications).with(
505+
Optimizely::NotificationCenter::NOTIFICATION_TYPES[:ON_DECISION],
506+
'experiment', 'test_user', {'browser_type' => 'chrome'},
507+
decision_info: {
508+
experiment_key: 'test_experiment_with_audience', variation_key: nil
509+
}
510+
)
511+
503512
expect(project_instance.activate('test_experiment_with_audience', 'test_user', user_attributes)).to eq(nil)
513+
514+
expect(spy_logger).to have_received(:log)
515+
.once.with(Logger::INFO, "User 'test_user' does not meet the conditions to be in experiment 'test_experiment_with_audience'.")
504516
end
505517

506518
it 'should return nil when attributes are invalid' do
@@ -583,7 +595,7 @@ class InvalidErrorHandler; end
583595
expect(project_instance.event_dispatcher).to_not have_received(:dispatch_event)
584596
end
585597

586-
it 'should log and send activate notification when an impression event is dispatched' do
598+
it 'should log and send activate and decision notifications when an impression event is dispatched' do
587599
params = @expected_activate_params
588600
variation_to_return = project_instance.config.get_variation_from_id('test_experiment', '111128')
589601
allow(project_instance.decision_service.bucketer).to receive(:bucket).and_return(variation_to_return)
@@ -592,11 +604,19 @@ class InvalidErrorHandler; end
592604
.with('test_experiment')
593605
.and_return([])
594606
experiment = project_instance.config.get_experiment_from_key('test_experiment')
607+
608+
expect(project_instance.notification_center).to receive(:send_notifications).with(
609+
Optimizely::NotificationCenter::NOTIFICATION_TYPES[:ON_DECISION],
610+
'experiment', 'test_user', nil,
611+
decision_info: {experiment_key: 'test_experiment', variation_key: 'control'}
612+
).ordered
613+
595614
expect(project_instance.notification_center).to receive(:send_notifications).with(
596615
Optimizely::NotificationCenter::NOTIFICATION_TYPES[:ACTIVATE],
597616
experiment, 'test_user', nil, variation_to_return,
598617
instance_of(Optimizely::Event)
599-
)
618+
).ordered
619+
600620
project_instance.activate('test_experiment', 'test_user')
601621

602622
expect(spy_logger).to have_received(:log).once.with(Logger::INFO, include('Dispatching impression event to' \
@@ -999,6 +1019,13 @@ class InvalidErrorHandler; end
9991019

10001020
it 'should have get_variation return expected variation when audience conditions match' do
10011021
user_attributes = {'browser_type' => 'firefox'}
1022+
1023+
expect(project_instance.notification_center).to receive(:send_notifications).with(
1024+
Optimizely::NotificationCenter::NOTIFICATION_TYPES[:ON_DECISION],
1025+
'experiment', 'test_user', {'browser_type' => 'firefox'},
1026+
decision_info: {experiment_key: 'test_experiment_with_audience', variation_key: 'control_with_audience'}
1027+
)
1028+
10021029
expect(project_instance.get_variation('test_experiment_with_audience', 'test_user', user_attributes))
10031030
.to eq('control_with_audience')
10041031
end
@@ -1020,6 +1047,13 @@ class InvalidErrorHandler; end
10201047

10211048
it 'should have get_variation return nil when audience conditions do not match' do
10221049
user_attributes = {'browser_type' => 'chrome'}
1050+
1051+
expect(project_instance.notification_center).to receive(:send_notifications).with(
1052+
Optimizely::NotificationCenter::NOTIFICATION_TYPES[:ON_DECISION],
1053+
'experiment', 'test_user', {'browser_type' => 'chrome'},
1054+
decision_info: {experiment_key: 'test_experiment_with_audience', variation_key: nil}
1055+
)
1056+
10231057
expect(project_instance.get_variation('test_experiment_with_audience', 'test_user', user_attributes))
10241058
.to eq(nil)
10251059
end

0 commit comments

Comments
 (0)