From 707f0f008451c8f88e9506977e9b8c5de64f918b Mon Sep 17 00:00:00 2001 From: Andy Leap Date: Wed, 21 Sep 2022 12:53:52 -0400 Subject: [PATCH 1/4] remove odp_config from event manager constructor --- lib/optimizely/odp/odp_event_manager.rb | 29 +++++--- spec/odp/odp_event_manager_spec.rb | 93 ++++++++++++++----------- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/lib/optimizely/odp/odp_event_manager.rb b/lib/optimizely/odp/odp_event_manager.rb index c68012dc..d23951ee 100644 --- a/lib/optimizely/odp/odp_event_manager.rb +++ b/lib/optimizely/odp/odp_event_manager.rb @@ -26,19 +26,19 @@ class OdpEventManager # the BlockingQueue and buffers them for either a configured batch size or for a # maximum duration before the resulting LogEvent is sent to the NotificationCenter. - attr_reader :batch_size, :odp_config, :zaius_manager, :logger + attr_reader :batch_size, :zaius_manager, :logger + attr_accessor :odp_config def initialize( - odp_config, api_manager: nil, logger: NoOpLogger.new, proxy_config: nil ) super() - @odp_config = odp_config - @api_host = odp_config.api_host - @api_key = odp_config.api_key + @odp_config = nil + @api_host = nil + @api_key = nil @mutex = Mutex.new @event_queue = SizedQueue.new(Optimizely::Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_QUEUE_CAPACITY]) @@ -53,14 +53,20 @@ def initialize( @retry_count = Helpers::Constants::ODP_EVENT_MANAGER[:DEFAULT_RETRY_COUNT] # current_batch should only be accessed by processing thread @current_batch = [] + @thread = nil @thread_exception = false end - def start! + def start!(odp_config) if running? @logger.log(Logger::WARN, 'Service already started.') return end + + @odp_config = odp_config + @api_host = odp_config.api_host + @api_key = odp_config.api_key + @thread = Thread.new { run } @logger.log(Logger::INFO, 'Starting scheduler.') end @@ -117,7 +123,10 @@ def dispatch(event) end def send_event(type:, action:, identifiers:, data:) - case @odp_config.odp_state + case @odp_config&.odp_state + when nil + @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before config has been set.') + return when OdpConfig::ODP_CONFIG_STATE[:UNDETERMINED] @logger.log(Logger::DEBUG, 'ODP event queue: cannot send before the datafile has loaded.') return @@ -154,7 +163,7 @@ def stop! end def running? - @thread && !!@thread.status && !@event_queue.closed? + !!@thread && !!@thread.status && !@event_queue.closed? end private @@ -270,8 +279,8 @@ def process_config_update # Updates the configuration used to send events. flush_batch! unless @current_batch.empty? - @api_key = @odp_config.api_key - @api_host = @odp_config.api_host + @api_key = @odp_config&.api_key + @api_host = @odp_config&.api_host end end end diff --git a/spec/odp/odp_event_manager_spec.rb b/spec/odp/odp_event_manager_spec.rb index 351802d2..fa68a4a7 100644 --- a/spec/odp/odp_event_manager_spec.rb +++ b/spec/odp/odp_event_manager_spec.rb @@ -99,13 +99,15 @@ config = Optimizely::OdpConfig.new api_manager = Optimizely::ZaiusRestApiManager.new - event_manager = Optimizely::OdpEventManager.new(config, api_manager: api_manager, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(api_manager: api_manager, logger: spy_logger) + event_manager.start!(config) expect(event_manager.odp_config).to be config expect(event_manager.zaius_manager).to be api_manager expect(event_manager.logger).to be spy_logger + event_manager.stop! - event_manager = Optimizely::OdpEventManager.new(config) + event_manager = Optimizely::OdpEventManager.new expect(event_manager.logger).to be_a Optimizely::NoOpLogger expect(event_manager.zaius_manager).to be_a Optimizely::ZaiusRestApiManager end @@ -115,8 +117,8 @@ it 'should process events successfully' do stub_request(:post, "#{api_host}/v3/events") .to_return(status: 200) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) - event_manager.start! + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -132,9 +134,9 @@ it 'should flush at batch size' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.instance_variable_set('@batch_size', 2) @@ -152,9 +154,9 @@ batch_count = 4 allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).exactly(batch_count).times.and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.instance_variable_set('@batch_size', 2) @@ -174,7 +176,8 @@ it 'should process backlog successfully' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + event_manager.odp_config = odp_config event_manager.instance_variable_set('@batch_size', 2) batch_count = 4 @@ -187,7 +190,7 @@ event_manager.send_event(**events[1]) end RSpec::Mocks.space.proxy_for(event_manager).remove_stub(:running?) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) event_manager.stop! @@ -201,9 +204,9 @@ it 'should flush with flush signal' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -218,9 +221,9 @@ it 'should flush multiple times successfully' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).exactly(4).times.with(api_key, api_host, odp_events).and_return(false) - event_manager.start! + event_manager.start!(odp_config) flush_count = 4 flush_count.times do @@ -241,10 +244,10 @@ it 'should log error on retry failure' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) retry_count = event_manager.instance_variable_get('@retry_count') allow(event_manager.zaius_manager).to receive(:send_odp_events).exactly(retry_count + 1).times.with(api_key, api_host, odp_events).and_return(true) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -260,9 +263,9 @@ it 'should retry on network failure' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(true, true, false) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -278,9 +281,9 @@ it 'should log error on send failure' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_raise(StandardError, 'Unexpected error') - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -297,8 +300,8 @@ allow(SecureRandom).to receive(:uuid).and_return(test_uuid) odp_config = Optimizely::OdpConfig.new odp_config.update(nil, nil, nil) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) - event_manager.start! + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -314,7 +317,8 @@ it 'should log error when queue is full' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) stub_const('Optimizely::Helpers::Constants::ODP_EVENT_MANAGER', {DEFAULT_QUEUE_CAPACITY: 1}) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + event_manager.odp_config = odp_config allow(event_manager).to receive(:running?).and_return(true) event_manager.send_event(**events[0]) @@ -329,9 +333,9 @@ it 'should log error on exception within thread' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager).to receive(:add_to_batch).and_raise(StandardError, 'Unexpected error') - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) sleep(0.1) @@ -346,7 +350,7 @@ it 'should work with overriden event data' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) event = events[0] event[:data][:data_source] = 'my-app' @@ -355,7 +359,7 @@ expect(odp_event.instance_variable_get('@data')[:data_source]).to eq 'my-app' allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, [odp_event]).and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**event) event_manager.flush @@ -366,10 +370,10 @@ it 'should flush when timeout is reached' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(false) event_manager.instance_variable_set('@flush_interval', 0.5) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -384,9 +388,9 @@ it 'should discard events received before datafile is ready and process normally' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) odp_config = Optimizely::OdpConfig.new - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -414,9 +418,9 @@ it 'should discard events before and after odp is disabled' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) odp_config = Optimizely::OdpConfig.new - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) expect(event_manager.zaius_manager).not_to receive(:send_odp_events) - event_manager.start! + event_manager.start!(odp_config) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) @@ -441,9 +445,9 @@ it 'should begin discarding events if odp is disabled after being enabled' do allow(SecureRandom).to receive(:uuid).and_return(test_uuid) odp_config = Optimizely::OdpConfig.new(api_key, api_host) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(false) - event_manager.start! + event_manager.start!(odp_config) event_manager.instance_variable_set('@batch_size', 2) @@ -471,19 +475,21 @@ allow(SecureRandom).to receive(:uuid).and_return(test_uuid) odp_config = Optimizely::OdpConfig.new(api_key, api_host) - event_manager = Optimizely::OdpEventManager.new(odp_config, logger: spy_logger) + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + event_manager.odp_config = odp_config event_manager.instance_variable_set('@batch_size', 3) allow(event_manager.zaius_manager).to receive(:send_odp_events).once.with(api_key, api_host, odp_events).and_return(false) allow(event_manager).to receive(:running?).and_return(true) event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) - odp_config.update(nil, nil, []) - event_manager.update_config RSpec::Mocks.space.proxy_for(event_manager).remove_stub(:running?) - event_manager.start! + event_manager.start!(odp_config) + odp_config.update(nil, nil, []) + event_manager.update_config + event_manager.send_event(**events[0]) event_manager.send_event(**events[1]) event_manager.send_event(**events[0]) @@ -494,5 +500,14 @@ expect(spy_logger).not_to have_received(:log).with(Logger::ERROR, anything) event_manager.stop! end + + it 'should reject events submitted before odp_config is set' do + event_manager = Optimizely::OdpEventManager.new(logger: spy_logger) + expect(event_manager).not_to receive(:dispatch) + event_manager.send_event(**events[0]) + + expect(spy_logger).to have_received(:log).once.with(Logger::DEBUG, 'ODP event queue: cannot send before config has been set.') + expect(spy_logger).not_to have_received(:log).with(Logger::ERROR, anything) + end end end From 1a82033a839dd3048a27b227bc20e9a086e6711a Mon Sep 17 00:00:00 2001 From: Andy Leap Date: Wed, 21 Sep 2022 13:24:47 -0400 Subject: [PATCH 2/4] remove odp_config from segment manager constructor --- lib/optimizely/odp/odp_segment_manager.rb | 11 ++--- spec/odp/odp_segment_manager_spec.rb | 51 +++++++++++++---------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/lib/optimizely/odp/odp_segment_manager.rb b/lib/optimizely/odp/odp_segment_manager.rb index ea76114a..b89a4443 100644 --- a/lib/optimizely/odp/odp_segment_manager.rb +++ b/lib/optimizely/odp/odp_segment_manager.rb @@ -22,10 +22,11 @@ module Optimizely class OdpSegmentManager # Schedules connections to ODP for audience segmentation and caches the results - attr_reader :odp_config, :segments_cache, :zaius_manager, :logger + attr_accessor :odp_config + attr_reader :segments_cache, :zaius_manager, :logger - def initialize(odp_config, segments_cache, api_manager = nil, logger = nil, proxy_config = nil) - @odp_config = odp_config + def initialize(segments_cache, api_manager = nil, logger = nil, proxy_config = nil) + @odp_config = nil @logger = logger || NoOpLogger.new @zaius_manager = api_manager || ZaiusGraphQLApiManager.new(logger: @logger, proxy_config: proxy_config) @segments_cache = segments_cache @@ -39,8 +40,8 @@ def initialize(odp_config, segments_cache, api_manager = nil, logger = nil, prox # # @return - Array of qualified segments. def fetch_qualified_segments(user_key, user_value, options) - odp_api_key = @odp_config.api_key - odp_api_host = @odp_config.api_host + odp_api_key = @odp_config&.api_key + odp_api_host = @odp_config&.api_host segments_to_check = @odp_config&.segments_to_check if odp_api_key.nil? || odp_api_host.nil? diff --git a/spec/odp/odp_segment_manager_spec.rb b/spec/odp/odp_segment_manager_spec.rb index 7de2598e..4910eea4 100644 --- a/spec/odp/odp_segment_manager_spec.rb +++ b/spec/odp/odp_segment_manager_spec.rb @@ -63,17 +63,16 @@ describe '#initialize' do it 'should return OdpSegmentManager instance' do - config = Optimizely::OdpConfig.new - api_manager = Optimizely::ZaiusGraphQLApiManager.new - segment_manager = Optimizely::OdpSegmentManager.new(config, segments_cache, api_manager, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, api_manager, spy_logger) expect(segment_manager.segments_cache).to be_a Optimizely::LRUCache - expect(segment_manager.odp_config).to be config + expect(segment_manager.segments_cache).to be segments_cache + expect(segment_manager.odp_config).to be nil expect(segment_manager.zaius_manager).to be api_manager expect(segment_manager.logger).to be spy_logger - segment_manager = Optimizely::OdpSegmentManager.new(config, segments_cache) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache) expect(segment_manager.logger).to be_a Optimizely::NoOpLogger expect(segment_manager.zaius_manager).to be_a Optimizely::ZaiusGraphQLApiManager end @@ -88,8 +87,8 @@ }}) .to_return(status: 200, body: good_response_data) - odp_config = Optimizely::OdpConfig.new(api_key, api_host, segments_to_check) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, segments_to_check) segments = segment_manager.fetch_qualified_segments(user_key, user_value, []) @@ -101,8 +100,8 @@ stub_request(:post, "#{api_host}/v3/graphql") .to_return(status: 200, body: good_response_data) - odp_config = Optimizely::OdpConfig.new(api_key, api_host, []) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, []) segments = segment_manager.fetch_qualified_segments(user_key, user_value, []) @@ -114,8 +113,8 @@ stub_request(:post, "#{api_host}/v3/graphql") .to_return(status: 200, body: good_response_data) - odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) cache_key = segment_manager.send(:make_cache_key, user_key, '123') segment_manager.segments_cache.save(cache_key, %w[d]) @@ -129,9 +128,8 @@ end it 'should return success with cache hit' do - odp_config = Optimizely::OdpConfig.new - odp_config.update(api_key, api_host, %w[a b c]) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) cache_key = segment_manager.send(:make_cache_key, user_key, user_value) segment_manager.segments_cache.save(cache_key, %w[c]) @@ -143,9 +141,8 @@ end it 'should return nil and log error with missing api_host/api_key' do - odp_config = Optimizely::OdpConfig.new - - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new segments = segment_manager.fetch_qualified_segments(user_key, user_value, []) @@ -157,8 +154,8 @@ stub_request(:post, "#{api_host}/v3/graphql") .to_return(status: 500, body: '{}') - odp_config = Optimizely::OdpConfig.new(api_key, api_host, segments_to_check) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, segments_to_check) segments = segment_manager.fetch_qualified_segments(user_key, user_value, []) @@ -170,8 +167,8 @@ stub_request(:post, "#{api_host}/v3/graphql") .to_return(status: 200, body: good_response_data) - odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) cache_key = segment_manager.send(:make_cache_key, user_key, user_value) segment_manager.segments_cache.save(cache_key, %w[d]) @@ -187,8 +184,8 @@ stub_request(:post, "#{api_host}/v3/graphql") .to_return(status: 200, body: good_response_data) - odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) - segment_manager = Optimizely::OdpSegmentManager.new(odp_config, segments_cache, nil, spy_logger) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + segment_manager.odp_config = Optimizely::OdpConfig.new(api_key, api_host, %w[a b c]) cache_key = segment_manager.send(:make_cache_key, user_key, user_value) segment_manager.segments_cache.save(cache_key, %w[d]) @@ -207,5 +204,13 @@ cache_key = segment_manager.send(:make_cache_key, user_key, user_value) expect(cache_key).to be == "#{user_key}-$-#{user_value}" end + + it 'should log error if odp_config not set' do + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + + response = segment_manager.fetch_qualified_segments(user_key, user_value, []) + expect(response).to be_nil + expect(spy_logger).to have_received(:log).with(Logger::ERROR, 'Audience segments fetch failed (ODP is not enabled).') + end end end From aed83362a81de3684c21fb5ce7ac0257bc4e1349 Mon Sep 17 00:00:00 2001 From: Andy Leap Date: Wed, 21 Sep 2022 17:13:43 -0400 Subject: [PATCH 3/4] add odp manager --- lib/optimizely/helpers/constants.rb | 13 +- lib/optimizely/odp/odp_manager.rb | 125 +++++++++++ spec/odp/odp_manager_spec.rb | 313 ++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 lib/optimizely/odp/odp_manager.rb create mode 100644 spec/odp/odp_manager_spec.rb diff --git a/lib/optimizely/helpers/constants.rb b/lib/optimizely/helpers/constants.rb index 1d3988d1..64ffbe85 100644 --- a/lib/optimizely/helpers/constants.rb +++ b/lib/optimizely/helpers/constants.rb @@ -386,7 +386,8 @@ module Constants FETCH_SEGMENTS_FAILED: 'Audience segments fetch failed (%s).', ODP_EVENT_FAILED: 'ODP event send failed (%s).', ODP_NOT_ENABLED: 'ODP is not enabled.', - ODP_NOT_INTEGRATED: 'ODP is not integrated.' + ODP_NOT_INTEGRATED: 'ODP is not integrated.', + ODP_EVENT_NOT_DISPATCHED: "ODP '%s' event is not dispatched (%s)" }.freeze DECISION_NOTIFICATION_TYPES = { @@ -425,6 +426,16 @@ module Constants REQUEST_TIMEOUT: 10 }.freeze + ODP_SEGMENTS_CACHE_CONFIG = { + DEFAULT_CAPACITY: 10_000, + DEFAULT_TIMEOUT_SECONDS: 600 + }.freeze + + ODP_MANAGER_CONFIG = { + KEY_FOR_USER_ID: 'fs_user_id', + EVENT_TYPE: 'fullstack' + }.freeze + ODP_CONFIG_STATE = { UNDETERMINED: 'UNDETERMINED', INTEGRATED: 'INTEGRATED', diff --git a/lib/optimizely/odp/odp_manager.rb b/lib/optimizely/odp/odp_manager.rb new file mode 100644 index 00000000..42abc792 --- /dev/null +++ b/lib/optimizely/odp/odp_manager.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +# +# Copyright 2022, Optimizely and contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'optimizely/logger' +require_relative '../helpers/constants' +require_relative '../helpers/validator' +require_relative '../exceptions' +require_relative 'odp_config' +require_relative 'lru_cache' +require_relative 'odp_segment_manager' +require_relative 'odp_event_manager' + +module Optimizely + class OdpManager + ODP_LOGS = Helpers::Constants::ODP_LOGS + def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manager: nil, logger: nil) + @enabled = !disable + @segment_manager = segment_manager + @event_manager = event_manager + @logger = logger || NoOpLogger.new + @odp_config = OdpConfig.new + + unless @enabled + @logger.log(Logger::DEBUG, 'ODP is disabled') + return + end + + unless @segment_manager + segments_cache ||= LRUCache.new( + Helpers::Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_CAPACITY], + Helpers::Constants::ODP_SEGMENTS_CACHE_CONFIG[:DEFAULT_TIMEOUT_SECONDS] + ) + @segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, @logger) + end + + @event_manager ||= Optimizely::OdpEventManager.new(logger: @logger) + + @segment_manager.odp_config = @odp_config + @event_manager.start!(@odp_config) + end + + def fetch_qualified_segments(user_id:, options:) + # Returns qualified segments for the user from the cache or the ODP server if not in the cache. + # + # @param user_id - The user id. + # @param options - An array of OptimizelySegmentOptions used to ignore and/or reset the cache. + # + # @return - Array of qualified segments or nil. + options ||= [] + unless @enabled && @segment_manager + @logger.log(Logger::ERROR, ODP_LOGS[:ODP_NOT_ENABLED]) + return nil + end + + if @odp_config.odp_state == Helpers::Constants::ODP_CONFIG_STATE[:UNDETERMINED] + @logger.log(Logger::ERROR, 'Cannot fetch segments before the datafile has loaded.') + return nil + end + + @segment_manager.fetch_qualified_segments(Helpers::Constants::ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID], user_id, options) + end + + def identify_user(user_id:) + send_event( + type: Helpers::Constants::ODP_MANAGER_CONFIG[:EVENT_TYPE], + action: 'identified', + identifiers: {Helpers::Constants::ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID] => user_id}, + data: {} + ) + end + + def send_event(type:, action:, identifiers:, data:) + # Send an event to the ODP server. + # + # @param type - the event type. + # @param action - the event action name. + # @param identifiers - a hash for identifiers. + # @param data - a hash for associated data. The default event data will be added to this data before sending to the ODP server. + unless @enabled && @event_manager + @logger.log(Logger::DEBUG, format(ODP_LOGS[:ODP_EVENT_NOT_DISPATCHED], action, 'ODP disabled')) + return + end + + unless Helpers::Validator.odp_data_types_valid?(data) + @logger.log(Logger::DEBUG, format(ODP_LOGS[:ODP_EVENT_NOT_DISPATCHED], action, 'ODP data is not valid')) + return + end + + @event_manager.send_event(type: type, action: action, identifiers: identifiers, data: data) + end + + def update_odp_config(api_key, api_host, segments_to_check) + # Update the odp config, reset the cache and send signal to the event processor to update its config. + return unless @enabled + + config_changed = @odp_config.update(api_key, api_host, segments_to_check) + unless config_changed + @logger.log(Logger::DEBUG, 'Odp config was not changed.') + return + end + + @segment_manager&.reset + @event_manager&.update_config + end + + def close! + @event_manager&.stop! + end + end +end diff --git a/spec/odp/odp_manager_spec.rb b/spec/odp/odp_manager_spec.rb new file mode 100644 index 00000000..6319bfa7 --- /dev/null +++ b/spec/odp/odp_manager_spec.rb @@ -0,0 +1,313 @@ +# frozen_string_literal: true + +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +require 'spec_helper' +require 'optimizely/odp/odp_manager' +require 'optimizely/odp/odp_event_manager' +require 'optimizely/odp/odp_event' +require 'optimizely/odp/lru_cache' +require 'optimizely/odp/odp_config' +require 'optimizely/odp/zaius_rest_api_manager' +require 'optimizely/logger' +require 'optimizely/helpers/validator' +require 'optimizely/helpers/constants' + +describe Optimizely::OdpManager do + let(:spy_logger) { spy('logger') } + let(:api_host) { 'https://test-host' } + let(:user_key) { 'fs_user_id' } + let(:user_value) { 'test-user-value' } + let(:api_key) { 'test-api-key' } + let(:segments_to_check) { %w[a b c] } + let(:test_uuid) { SecureRandom.uuid } + let(:event) { {type: 't1', action: 'a1', identifiers: {'id-key-1': 'id-value-1'}, data: {'key-1': 'value1', "key-2": 2, "key-3": 3.0, "key-4": nil, 'key-5': true, 'key-6': false}} } + let(:odp_event) { Optimizely::OdpEvent.new(**event) } + + describe '#initialize' do + it 'should return default OdpManager instance' do + manager = Optimizely::OdpManager.new(disable: false) + + odp_config = manager.instance_variable_get('@odp_config') + expect(odp_config).to be_a Optimizely::OdpConfig + + logger = manager.instance_variable_get('@logger') + expect(logger).to be_a Optimizely::NoOpLogger + + event_manager = manager.instance_variable_get('@event_manager') + expect(event_manager).to be_a Optimizely::OdpEventManager + expect(event_manager.odp_config).to be odp_config + expect(event_manager.logger).to be logger + expect(event_manager.running?).to be true + + segment_manager = manager.instance_variable_get('@segment_manager') + expect(segment_manager).to be_a Optimizely::OdpSegmentManager + expect(segment_manager.odp_config).to be odp_config + expect(segment_manager.logger).to be logger + + segments_cache = segment_manager.segments_cache + expect(segments_cache).to be_a Optimizely::LRUCache + expect(segments_cache.instance_variable_get('@capacity')).to eq 10_000 + expect(segments_cache.instance_variable_get('@timeout')).to eq 600 + + manager.close! + expect(event_manager.running?).to be false + end + + it 'should allow custom segment_manager' do + segments_cache = Optimizely::LRUCache.new(1, 1) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: false, segments_cache: nil, segment_manager: segment_manager, logger: spy_logger) + + expect(manager.instance_variable_get('@segment_manager')).to be segment_manager + expect(manager.instance_variable_get('@segment_manager').instance_variable_get('@segments_cache')).to be segments_cache + + manager.close! + end + + it 'should allow custom segments_cache' do + segments_cache = Optimizely::LRUCache.new(1, 1) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: false, segments_cache: segments_cache, logger: spy_logger) + + expect(manager.instance_variable_get('@segment_manager').instance_variable_get('@segments_cache')).to be segments_cache + + manager.close! + end + + it 'should allow custom event_manager' do + event_manager = Optimizely::OdpEventManager.new + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: false, event_manager: event_manager, logger: spy_logger) + + expect(manager.instance_variable_get('@event_manager')).to be event_manager + + manager.close! + end + + it 'should not instantiate event/segment managers when disabled' do + expect(spy_logger).to receive(:log).once.with(Logger::DEBUG, 'ODP is disabled') + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: true, logger: spy_logger) + + expect(manager.instance_variable_get('@event_manager')).to be_nil + expect(manager.instance_variable_get('@segment_manager')).to be_nil + end + end + + describe '#fetch_qualified_segments' do + it 'should retrieve segments' do + segments_cache = Optimizely::LRUCache.new(500, 500) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: false, segment_manager: segment_manager, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + + cache_key = segment_manager.send(:make_cache_key, user_key, user_value) + segments_cache.save(cache_key, [segments_to_check[0]]) + + segments = manager.fetch_qualified_segments(user_id: user_value, options: nil) + + expect(segments).to eq [segments_to_check[0]] + manager.close! + end + + it 'should log error if disabled' do + expect(spy_logger).to receive(:log).once.with(Logger::ERROR, Optimizely::Helpers::Constants::ODP_LOGS[:ODP_NOT_ENABLED]) + manager = Optimizely::OdpManager.new(disable: true, logger: spy_logger) + + response = manager.fetch_qualified_segments(user_id: 'user1', options: nil) + expect(response).to be_nil + end + + it 'should log error if datafile not ready' do + expect(spy_logger).to receive(:log).with(Logger::ERROR, 'Cannot fetch segments before the datafile has loaded.') + manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) + + response = manager.fetch_qualified_segments(user_id: 'user1', options: nil) + expect(response).to be_nil + manager.close! + end + + it 'should ignore cache' do + segments_cache = Optimizely::LRUCache.new(500, 500) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache, nil, spy_logger) + + expect(segment_manager.zaius_manager) + .to receive(:fetch_segments) + .once + .with(api_key, api_host, user_key, user_value, segments_to_check) + .and_return([segments_to_check[0]]) + + manager = Optimizely::OdpManager.new(disable: false, segment_manager: segment_manager, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + + cache_key = segment_manager.send(:make_cache_key, user_key, user_value) + segments_cache.save(cache_key, [segments_to_check[1]]) + + segments = manager.fetch_qualified_segments(user_id: user_value, options: [Optimizely::OptimizelySegmentOption::IGNORE_CACHE]) + + expect(segments).to eq [segments_to_check[0]] + manager.close! + end + + it 'should reset cache' do + segments_cache = Optimizely::LRUCache.new(500, 500) + segment_manager = Optimizely::OdpSegmentManager.new(segments_cache) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + + expect(segment_manager.zaius_manager) + .to receive(:fetch_segments) + .once + .with(api_key, api_host, user_key, user_value, segments_to_check) + .and_return([segments_to_check[0]]) + + manager = Optimizely::OdpManager.new(disable: false, segment_manager: segment_manager, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + + segments_cache.save('wow', 'great') + expect(segments_cache.lookup('wow')).to eq 'great' + + segments = manager.fetch_qualified_segments(user_id: user_value, options: [Optimizely::OptimizelySegmentOption::RESET_CACHE]) + + expect(segments).to eq [segments_to_check[0]] + expect(segments_cache.lookup('wow')).to be_nil + manager.close! + end + end + + describe '#send_event' do + it 'should send event' do + allow(SecureRandom).to receive(:uuid).and_return(test_uuid) + event_manager = Optimizely::OdpEventManager.new + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + + expect(event_manager.zaius_manager) + .to receive(:send_odp_events) + .once + .with(api_key, api_host, [odp_event]) + .and_return(false) + + manager = Optimizely::OdpManager.new(disable: false, event_manager: event_manager, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + + manager.send_event(**event) + + manager.close! + end + + it 'should log debug if data is invalid' do + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + expect(spy_logger).to receive(:log).with(Logger::DEBUG, "ODP 'a1' event is not dispatched (ODP data is not valid)") + + manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + event[:data][:bad_value] = {} + + manager.send_event(**event) + + manager.close! + end + end + + describe '#identify_user' do + it 'should send event' do + allow(SecureRandom).to receive(:uuid).and_return(test_uuid) + event_manager = Optimizely::OdpEventManager.new + event = Optimizely::OdpEvent.new(type: 'fullstack', action: 'identified', identifiers: {user_key => user_value}, data: {}) + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + + expect(event_manager.zaius_manager) + .to receive(:send_odp_events) + .once + .with(api_key, api_host, [event]) + .and_return(false) + + manager = Optimizely::OdpManager.new(disable: false, event_manager: event_manager, logger: spy_logger) + manager.update_odp_config(api_key, api_host, segments_to_check) + + manager.identify_user(user_id: user_value) + + manager.close! + end + + it 'should log debug if disabled' do + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + expect(spy_logger).to receive(:log).with(Logger::DEBUG, "ODP 'identified' event is not dispatched (ODP disabled)") + + manager = Optimizely::OdpManager.new(disable: true, logger: spy_logger) + manager.identify_user(user_id: user_value) + + manager.close! + end + + it 'should log debug if not integrated' do + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + expect(spy_logger).to receive(:log).with(Logger::DEBUG, Optimizely::Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED]) + manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) + manager.update_odp_config(nil, nil, []) + manager.identify_user(user_id: user_value) + + manager.close! + end + + it 'should log debug if datafile not ready' do + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + expect(spy_logger).to receive(:log).with(Logger::DEBUG, 'ODP event queue: cannot send before the datafile has loaded.') + + manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) + manager.identify_user(user_id: user_value) + + manager.close! + end + end + + describe '#update_odp_config' do + it 'update config' do + expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) + manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) + segment_manager = manager.instance_variable_get('@segment_manager') + segments_cache = segment_manager.instance_variable_get('@segments_cache') + segments_cache.save('wow', 'great') + expect(segments_cache.lookup('wow')).to eq 'great' + + manager.update_odp_config(api_key, api_host, segments_to_check) + + manager_config = manager.instance_variable_get('@odp_config') + expect(manager_config.api_host).to eq api_host + expect(manager_config.api_key).to eq api_key + expect(manager_config.segments_to_check).to eq segments_to_check + + segment_manager_config = segment_manager.odp_config + expect(segment_manager_config.api_host).to eq api_host + expect(segment_manager_config.api_key).to eq api_key + expect(segment_manager_config.segments_to_check).to eq segments_to_check + # confirm cache was reset + expect(segments_cache.lookup('wow')).to be_nil + + event_manager = manager.instance_variable_get('@event_manager') + sleep(0.1) until event_manager.instance_variable_get('@event_queue').empty? + event_manager_config = event_manager.odp_config + expect(event_manager_config.api_host).to eq api_host + expect(event_manager_config.api_key).to eq api_key + expect(event_manager_config.segments_to_check).to eq segments_to_check + # confirm event_manager cached values were updated + expect(event_manager.instance_variable_get('@api_host')).to eq api_host + expect(event_manager.instance_variable_get('@api_key')).to eq api_key + + manager.close! + end + end +end From fe4bbd5edf3c09408619cbaaaf5c9f231650cc16 Mon Sep 17 00:00:00 2001 From: Andy Leap Date: Fri, 23 Sep 2022 10:56:33 -0400 Subject: [PATCH 4/4] address comments --- lib/optimizely/helpers/constants.rb | 2 +- lib/optimizely/odp/odp_manager.rb | 45 ++++++++++++++++++++--------- spec/odp/odp_manager_spec.rb | 13 ++++----- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/lib/optimizely/helpers/constants.rb b/lib/optimizely/helpers/constants.rb index 64ffbe85..5ed52353 100644 --- a/lib/optimizely/helpers/constants.rb +++ b/lib/optimizely/helpers/constants.rb @@ -387,7 +387,7 @@ module Constants ODP_EVENT_FAILED: 'ODP event send failed (%s).', ODP_NOT_ENABLED: 'ODP is not enabled.', ODP_NOT_INTEGRATED: 'ODP is not integrated.', - ODP_EVENT_NOT_DISPATCHED: "ODP '%s' event is not dispatched (%s)" + ODP_INVALID_DATA: 'ODP data is not valid.' }.freeze DECISION_NOTIFICATION_TYPES = { diff --git a/lib/optimizely/odp/odp_manager.rb b/lib/optimizely/odp/odp_manager.rb index 42abc792..d90deee9 100644 --- a/lib/optimizely/odp/odp_manager.rb +++ b/lib/optimizely/odp/odp_manager.rb @@ -28,6 +28,9 @@ module Optimizely class OdpManager ODP_LOGS = Helpers::Constants::ODP_LOGS + ODP_MANAGER_CONFIG = Helpers::Constants::ODP_MANAGER_CONFIG + ODP_CONFIG_STATE = Helpers::Constants::ODP_CONFIG_STATE + def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manager: nil, logger: nil) @enabled = !disable @segment_manager = segment_manager @@ -36,7 +39,7 @@ def initialize(disable:, segments_cache: nil, segment_manager: nil, event_manage @odp_config = OdpConfig.new unless @enabled - @logger.log(Logger::DEBUG, 'ODP is disabled') + @logger.log(Logger::INFO, ODP_LOGS[:ODP_NOT_ENABLED]) return end @@ -62,24 +65,38 @@ def fetch_qualified_segments(user_id:, options:) # # @return - Array of qualified segments or nil. options ||= [] - unless @enabled && @segment_manager + unless @enabled @logger.log(Logger::ERROR, ODP_LOGS[:ODP_NOT_ENABLED]) return nil end - if @odp_config.odp_state == Helpers::Constants::ODP_CONFIG_STATE[:UNDETERMINED] + if @odp_config.odp_state == ODP_CONFIG_STATE[:UNDETERMINED] @logger.log(Logger::ERROR, 'Cannot fetch segments before the datafile has loaded.') return nil end - @segment_manager.fetch_qualified_segments(Helpers::Constants::ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID], user_id, options) + @segment_manager.fetch_qualified_segments(ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID], user_id, options) end def identify_user(user_id:) - send_event( - type: Helpers::Constants::ODP_MANAGER_CONFIG[:EVENT_TYPE], + unless @enabled + @logger.log(Logger::DEBUG, 'ODP identify event is not dispatched (ODP disabled).') + return + end + + case @odp_config.odp_state + when ODP_CONFIG_STATE[:UNDETERMINED] + @logger.log(Logger::DEBUG, 'ODP identify event is not dispatched (datafile not ready).') + return + when ODP_CONFIG_STATE[:NOT_INTEGRATED] + @logger.log(Logger::DEBUG, 'ODP identify event is not dispatched (ODP not integrated).') + return + end + + @event_manager.send_event( + type: ODP_MANAGER_CONFIG[:EVENT_TYPE], action: 'identified', - identifiers: {Helpers::Constants::ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID] => user_id}, + identifiers: {ODP_MANAGER_CONFIG[:KEY_FOR_USER_ID] => user_id}, data: {} ) end @@ -91,13 +108,13 @@ def send_event(type:, action:, identifiers:, data:) # @param action - the event action name. # @param identifiers - a hash for identifiers. # @param data - a hash for associated data. The default event data will be added to this data before sending to the ODP server. - unless @enabled && @event_manager - @logger.log(Logger::DEBUG, format(ODP_LOGS[:ODP_EVENT_NOT_DISPATCHED], action, 'ODP disabled')) + unless @enabled + @logger.log(Logger::ERROR, ODP_LOGS[:ODP_NOT_ENABLED]) return end unless Helpers::Validator.odp_data_types_valid?(data) - @logger.log(Logger::DEBUG, format(ODP_LOGS[:ODP_EVENT_NOT_DISPATCHED], action, 'ODP data is not valid')) + @logger.log(Logger::ERROR, ODP_LOGS[:ODP_INVALID_DATA]) return end @@ -114,12 +131,14 @@ def update_odp_config(api_key, api_host, segments_to_check) return end - @segment_manager&.reset - @event_manager&.update_config + @segment_manager.reset + @event_manager.update_config end def close! - @event_manager&.stop! + return unless @enabled + + @event_manager.stop! end end end diff --git a/spec/odp/odp_manager_spec.rb b/spec/odp/odp_manager_spec.rb index 6319bfa7..6fb2d204 100644 --- a/spec/odp/odp_manager_spec.rb +++ b/spec/odp/odp_manager_spec.rb @@ -97,7 +97,7 @@ end it 'should not instantiate event/segment managers when disabled' do - expect(spy_logger).to receive(:log).once.with(Logger::DEBUG, 'ODP is disabled') + expect(spy_logger).to receive(:log).once.with(Logger::INFO, 'ODP is not enabled.') expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) manager = Optimizely::OdpManager.new(disable: true, logger: spy_logger) @@ -208,9 +208,8 @@ manager.close! end - it 'should log debug if data is invalid' do - expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) - expect(spy_logger).to receive(:log).with(Logger::DEBUG, "ODP 'a1' event is not dispatched (ODP data is not valid)") + it 'should log error if data is invalid' do + expect(spy_logger).to receive(:log).with(Logger::ERROR, 'ODP data is not valid.') manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) manager.update_odp_config(api_key, api_host, segments_to_check) @@ -245,7 +244,7 @@ it 'should log debug if disabled' do expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) - expect(spy_logger).to receive(:log).with(Logger::DEBUG, "ODP 'identified' event is not dispatched (ODP disabled)") + expect(spy_logger).to receive(:log).with(Logger::DEBUG, 'ODP identify event is not dispatched (ODP disabled).') manager = Optimizely::OdpManager.new(disable: true, logger: spy_logger) manager.identify_user(user_id: user_value) @@ -255,7 +254,7 @@ it 'should log debug if not integrated' do expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) - expect(spy_logger).to receive(:log).with(Logger::DEBUG, Optimizely::Helpers::Constants::ODP_LOGS[:ODP_NOT_INTEGRATED]) + expect(spy_logger).to receive(:log).with(Logger::DEBUG, 'ODP identify event is not dispatched (ODP not integrated).') manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) manager.update_odp_config(nil, nil, []) manager.identify_user(user_id: user_value) @@ -265,7 +264,7 @@ it 'should log debug if datafile not ready' do expect(spy_logger).not_to receive(:log).with(Logger::ERROR, anything) - expect(spy_logger).to receive(:log).with(Logger::DEBUG, 'ODP event queue: cannot send before the datafile has loaded.') + expect(spy_logger).to receive(:log).with(Logger::DEBUG, 'ODP identify event is not dispatched (datafile not ready).') manager = Optimizely::OdpManager.new(disable: false, logger: spy_logger) manager.identify_user(user_id: user_value)