diff --git a/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb b/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb index 7f45e343..67f339fe 100644 --- a/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +++ b/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb @@ -28,7 +28,7 @@ class RuleBasedSegmentsRepository < Repository RB_SEGMENTS_PREFIX = '.rbsegment.' REGISTERED_PREFIX = '.segments.registered' - def initialize(config) + def initialize(config, internal_events_queue) super(config) @adapter = case @config.cache_adapter.class.to_s when 'SplitIoClient::Cache::Adapters::RedisAdapter' @@ -40,12 +40,25 @@ def initialize(config) @adapter.set_string(namespace_key(TILL_PREFIX), '-1') @adapter.initialize_map(namespace_key(REGISTERED_PREFIX)) end + @internal_events_queue = internal_events_queue end def update(to_add, to_delete, new_change_number) to_add.each{ |rule_based_segment| add_rule_based_segment(rule_based_segment) } to_delete.each{ |rule_based_segment| remove_rule_based_segment(rule_based_segment) } set_change_number(new_change_number) + + if to_add.length > 0 || to_delete.length > 0 + @internal_events_queue.push( + SplitIoClient::Engine::Models::SdkInternalEventNotification.new( + SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED, + SplitIoClient::Engine::Models::EventsMetadata.new( + SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE, + [] + ) + ) + ) + end end def get_rule_based_segment(name) diff --git a/lib/splitclient-rb/cache/repositories/segments_repository.rb b/lib/splitclient-rb/cache/repositories/segments_repository.rb index a45ee167..900da206 100644 --- a/lib/splitclient-rb/cache/repositories/segments_repository.rb +++ b/lib/splitclient-rb/cache/repositories/segments_repository.rb @@ -6,7 +6,7 @@ class SegmentsRepository < Repository attr_reader :adapter - def initialize(config) + def initialize(config, internal_events_queue) super(config) @adapter = case @config.cache_adapter.class.to_s when 'SplitIoClient::Cache::Adapters::RedisAdapter' @@ -15,6 +15,7 @@ def initialize(config) @config.cache_adapter end @adapter.set_bool(namespace_key('.ready'), false) unless @config.mode.equal?(:consumer) + @internal_events_queue = internal_events_queue end # Receives segment data, adds and removes segements from the store @@ -25,6 +26,15 @@ def add_to_segment(segment) add_keys(name, segment[:added]) remove_keys(name, segment[:removed]) + @internal_events_queue.push( + SplitIoClient::Engine::Models::SdkInternalEventNotification.new( + SplitIoClient::Engine::Models::SdkInternalEvent::SEGMENTS_UPDATED, + SplitIoClient::Engine::Models::EventsMetadata.new( + SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE, + [] + ) + ) + ) end def get_segment_keys(name) diff --git a/lib/splitclient-rb/cache/repositories/splits_repository.rb b/lib/splitclient-rb/cache/repositories/splits_repository.rb index 9fcae0e0..f9a8acbb 100644 --- a/lib/splitclient-rb/cache/repositories/splits_repository.rb +++ b/lib/splitclient-rb/cache/repositories/splits_repository.rb @@ -35,7 +35,7 @@ class SplitsRepository < Repository SPLIT_PREFIX = '.split.' READY_PREFIX = '.splits.ready' - def initialize(config, flag_sets_repository, flag_set_filter) + def initialize(config, flag_sets_repository, flag_set_filter, internal_events_queue) super(config) @tt_cache = {} @adapter = case @config.cache_adapter.class.to_s @@ -46,6 +46,7 @@ def initialize(config, flag_sets_repository, flag_set_filter) end @flag_sets = flag_sets_repository @flag_set_filter = flag_set_filter + @internal_events_queue = internal_events_queue initialize_keys end @@ -53,6 +54,18 @@ def update(to_add, to_delete, new_change_number) to_add.each{ |feature_flag| add_feature_flag(feature_flag) } to_delete.each{ |feature_flag| remove_feature_flag(feature_flag) } set_change_number(new_change_number) + + if to_add.length > 0 || to_delete.length > 0 + @internal_events_queue.push( + SplitIoClient::Engine::Models::SdkInternalEventNotification.new( + SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED, + SplitIoClient::Engine::Models::EventsMetadata.new( + SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE, + to_add.map {|flag| flag[:name]} | to_delete.map {|flag| flag[:name]} + ) + ) + ) + end end def get_split(name) @@ -140,6 +153,15 @@ def kill(change_number, split_name, default_treatment) split[:changeNumber] = change_number @adapter.set_string(namespace_key(".split.#{split_name}"), split.to_json) + @internal_events_queue.push( + SplitIoClient::Engine::Models::SdkInternalEventNotification.new( + SplitIoClient::Engine::Models::SdkInternalEvent::FLAG_KILLED_NOTIFICATION, + SplitIoClient::Engine::Models::EventsMetadata.new( + SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE, + [split_name] + ) + ) + ) end def splits_count diff --git a/spec/cache/repositories/rule_based_segments_repository_spec.rb b/spec/cache/repositories/rule_based_segments_repository_spec.rb index 3fdd89ed..f583105e 100644 --- a/spec/cache/repositories/rule_based_segments_repository_spec.rb +++ b/spec/cache/repositories/rule_based_segments_repository_spec.rb @@ -6,7 +6,8 @@ describe SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository do RSpec.shared_examples 'RuleBasedSegments Repository' do |cache_adapter| let(:config) { SplitIoClient::SplitConfig.new(cache_adapter: cache_adapter) } - let(:repository) { described_class.new(config) } + let(:queue) {Queue.new} + let(:repository) { described_class.new(config, queue) } before :all do redis = Redis.new @@ -102,6 +103,33 @@ repository.update([rule_based_segment2], [], -1) expect(repository.get_rule_based_segment('corge2')[:conditions]).to eq SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository::DEFAULT_CONDITIONS_TEMPLATE end + + it 'push to internal event queue' do + queue.clear() + + repository.update([{name: 'flag1', trafficTypeName: 'tt_name_1', conditions: []}, + {name: 'flag2', trafficTypeName: 'tt_name_1', conditions: []}], [], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE) + expect(event.metadata.names).to eq([]) + + repository.update([{name: 'flag1', trafficTypeName: 'tt_name_1', killed: false, default_treatment: 'on', changeNumber: 1, conditions: []}], + [{name: 'flag2', trafficTypeName: 'tt_name_1', conditions: []}], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE) + expect(event.metadata.names).to eq([]) + + repository.update([], [], 123) + expect(queue.empty?).to eq(true) + + repository.update([], [{name: 'flag1', trafficTypeName: 'tt_name_1', killed: false, default_treatment: 'on', changeNumber: 1, conditions: []}], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE) + expect(event.metadata.names).to eq([]) + end end describe 'with Memory Adapter' do diff --git a/spec/cache/repositories/segments_repository_spec.rb b/spec/cache/repositories/segments_repository_spec.rb index cd2dd021..3cfac1ae 100644 --- a/spec/cache/repositories/segments_repository_spec.rb +++ b/spec/cache/repositories/segments_repository_spec.rb @@ -4,10 +4,11 @@ describe SplitIoClient::Cache::Repositories::SegmentsRepository do context 'memory adapter' do - let(:repository) { described_class.new(@default_config) } + let(:queue) {Queue.new} + let(:repository) { described_class.new(@default_config, queue) } let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([]) } let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) } - let(:split_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(@default_config, flag_sets_repository, flag_set_filter) } + let(:split_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(@default_config, flag_sets_repository, flag_set_filter, queue) } it 'removes keys' do repository.add_to_segment(name: 'foo', added: [1, 2, 3], removed: []) @@ -27,10 +28,21 @@ expect(repository.segments_count).to be(3) expect(repository.segment_keys_count).to be(7) end + + it 'push to internal event queue' do + queue.clear() + + repository.add_to_segment(name: 'foo', added: [1, 2, 3], removed: []) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::SEGMENTS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE) + expect(event.metadata.names).to eq([]) + end end context 'redis adapter' do - let(:repository) { described_class.new(SplitIoClient::SplitConfig.new(cache_adapter: :redis)) } + let(:queue) {Queue.new} + let(:repository) { described_class.new(SplitIoClient::SplitConfig.new(cache_adapter: :redis), queue) } it 'removes keys' do repository.add_to_segment(name: 'foo', added: [1, 2, 3], removed: []) diff --git a/spec/cache/repositories/splits_repository_spec.rb b/spec/cache/repositories/splits_repository_spec.rb index b55bfd11..ab18b84d 100644 --- a/spec/cache/repositories/splits_repository_spec.rb +++ b/spec/cache/repositories/splits_repository_spec.rb @@ -8,7 +8,8 @@ let(:config) { SplitIoClient::SplitConfig.new(cache_adapter: cache_adapter) } let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::RedisFlagSetsRepository.new(config)} let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([])} - let(:repository) { described_class.new(config, flag_sets_repository, flag_set_filter) } + let(:queue) {Queue.new} + let(:repository) { described_class.new(config, flag_sets_repository, flag_set_filter, queue) } before :all do redis = Redis.new @@ -172,6 +173,39 @@ repository.update([split2], [], -1) expect(repository.get_split('corge2')[:conditions]).to eq SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE end + + it 'push to internal event queue' do + queue.clear() + + repository.update([{name: 'flag1', trafficTypeName: 'tt_name_1', conditions: []}, + {name: 'flag2', trafficTypeName: 'tt_name_1', conditions: []}], [], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE) + expect(event.metadata.names).to eq(['flag1', 'flag2']) + + repository.update([{name: 'flag1', trafficTypeName: 'tt_name_1', killed: false, default_treatment: 'on', changeNumber: 1, conditions: []}], + [{name: 'flag2', trafficTypeName: 'tt_name_1', conditions: []}], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE) + expect(event.metadata.names).to eq(['flag1', 'flag2']) + + repository.update([], [], 123) + expect(queue.empty?).to eq(true) + + repository.kill(123, 'flag1', 'off') + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::FLAG_KILLED_NOTIFICATION) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE) + expect(event.metadata.names).to eq(['flag1']) + + repository.update([], [{name: 'flag1', trafficTypeName: 'tt_name_1', killed: false, default_treatment: 'on', changeNumber: 1, conditions: []}], -1) + event = queue.pop + expect(event.internal_event).to be(SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED) + expect(event.metadata.type).to be(SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE) + expect(event.metadata.names).to eq(['flag1']) + end end describe 'with Memory Adapter' do