From 207532c6fa73e6ecee34860910a55ae36a31ee87 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 8 May 2025 20:39:18 -0700 Subject: [PATCH] Updated SSE and synchronizer classes --- .../cache/fetchers/split_fetcher.rb | 5 +- .../rule_based_segments_repository.rb | 1 + lib/splitclient-rb/engine/api/splits.rb | 8 +- lib/splitclient-rb/engine/synchronizer.rb | 30 +++- lib/splitclient-rb/helpers/util.rb | 5 +- lib/splitclient-rb/split_factory.rb | 6 +- .../sse/event_source/event_types.rb | 1 + .../sse/notification_processor.rb | 4 +- .../sse/workers/splits_worker.rb | 59 +++++-- spec/engine/api/splits_spec.rb | 8 +- spec/engine/synchronizer_spec.rb | 64 ++++---- spec/sse/event_source/client_spec.rb | 31 ++-- spec/sse/sse_handler_spec.rb | 7 +- spec/sse/workers/segments_worker_spec.rb | 5 +- spec/sse/workers/splits_worker_spec.rb | 146 +++++++++++++----- spec/test_data/integrations/splits.json | 11 +- spec/test_data/integrations/splits_push.json | 11 +- spec/test_data/integrations/splits_push2.json | 9 +- spec/test_data/integrations/splits_push3.json | 11 +- 19 files changed, 276 insertions(+), 146 deletions(-) diff --git a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb index 204e0e8e..8353d51d 100644 --- a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +++ b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb @@ -22,10 +22,9 @@ def call splits_thread end - def fetch_splits(fetch_options = { cache_control_headers: false, till: nil, till_rbs: nil }) + def fetch_splits(fetch_options = { cache_control_headers: false, till: nil }) @semaphore.synchronize do data = splits_since(@splits_repository.get_change_number, @rule_based_segments_repository.get_change_number, fetch_options) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:ff][:d], data[:ff][:t], @config) SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config) @splits_repository.set_segment_names(data[:segment_names]) @@ -57,7 +56,7 @@ def splits_thread end end - def splits_since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, till_rbs: nil }) + def splits_since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil }) splits_api.since(since, since_rbs, fetch_options) end 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 5ea0e333..e7e383fb 100644 --- a/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +++ b/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb @@ -85,6 +85,7 @@ def clear end def contains?(segment_names) + return false if rule_based_segment_names.empty? return set(segment_names).subset?(rule_based_segment_names) end diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 32d4ad8e..62e3d4a6 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -12,13 +12,12 @@ def initialize(api_key, config, telemetry_runtime_producer) @flag_sets_filter = @config.flag_sets_filter end - def since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, till_rbs: nil, sets: nil}) + def since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, sets: nil}) start = Time.now params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since, rbSince: since_rbs } params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty? params[:till] = fetch_options[:till] unless fetch_options[:till].nil? - params[:till_rbs] = fetch_options[:till_rbs] unless fetch_options[:till_rbs].nil? @config.logger.debug("Fetching from splitChanges with #{params}: ") response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers]) if response.status == 414 @@ -57,14 +56,13 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till def objects_with_segment_names(objects_json) parsed_objects = JSON.parse(objects_json, symbolize_names: true) - parsed_objects[:segment_names] = parsed_objects[:ff][:d].each_with_object(Set.new) do |split, splits| - splits << Helpers::Util.segment_names_by_object(split) + splits << Helpers::Util.segment_names_by_object(split, "IN_SEGMENT") end.flatten if not parsed_objects[:ff][:rbs].nil? parsed_objects[:segment_names].merge parsed_objects[:ff][:rbs].each_with_object(Set.new) do |rule_based_segment, rule_based_segments| - rule_based_segments << Helpers::Util.segment_names_by_object(rule_based_segment) + rule_based_segments << Helpers::Util.segment_names_by_object(rule_based_segment, "IN_SEGMENT") end.flatten end parsed_objects diff --git a/lib/splitclient-rb/engine/synchronizer.rb b/lib/splitclient-rb/engine/synchronizer.rb index d2e0b319..99461670 100644 --- a/lib/splitclient-rb/engine/synchronizer.rb +++ b/lib/splitclient-rb/engine/synchronizer.rb @@ -15,6 +15,7 @@ def initialize( ) @splits_repository = repositories[:splits] @segments_repository = repositories[:segments] + @rule_based_segments_repository = repositories[:rule_based_segments] @impressions_repository = repositories[:impressions] @events_repository = repositories[:events] @config = config @@ -63,12 +64,12 @@ def stop_periodic_fetch @segment_fetcher.stop_segments_thread end - def fetch_splits(target_change_number) - return if target_change_number <= @splits_repository.get_change_number.to_i + def fetch_splits(target_change_number, rbs_target_change_number) + return if check_exit_conditions(target_change_number, rbs_target_change_number) fetch_options = { cache_control_headers: true, till: nil } - result = attempt_splits_sync(target_change_number, + result = attempt_splits_sync(target_change_number, rbs_target_change_number, fetch_options, @config.on_demand_fetch_max_retries, @config.on_demand_fetch_retry_delay_seconds, @@ -82,8 +83,13 @@ def fetch_splits(target_change_number) return end - fetch_options[:till] = target_change_number - result = attempt_splits_sync(target_change_number, + if target_change_number != 0 + fetch_options[:till] = target_change_number + else + fetch_options[:till] = rbs_target_change_number + end + + result = attempt_splits_sync(target_change_number, rbs_target_change_number, fetch_options, ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES, nil, @@ -156,7 +162,7 @@ def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_dela end end - def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) + def attempt_splits_sync(target_cn, rbs_target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff) remaining_attempts = max_retries @splits_sync_backoff.reset @@ -165,7 +171,7 @@ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_secon result = @split_fetcher.fetch_splits(fetch_options) - return sync_result(true, remaining_attempts, result[:segment_names]) if target_cn <= @splits_repository.get_change_number + return sync_result(true, remaining_attempts, result[:segment_names]) if check_exit_conditions(target_cn, rbs_target_cn) return sync_result(false, remaining_attempts, result[:segment_names]) if remaining_attempts <= 0 delay = with_backoff ? @splits_sync_backoff.interval : retry_delay_seconds @@ -206,6 +212,16 @@ def sync_splits_and_segments splits_result[:success] && @segment_fetcher.fetch_segments end + + def check_exit_conditions(target_change_number, rbs_target_change_number) + return true if rbs_target_change_number == 0 and target_change_number == 0 + + return target_change_number <= @splits_repository.get_change_number.to_i if rbs_target_change_number == 0 + + return rbs_target_change_number <= @rule_based_segments_repository.get_change_number.to_i if target_change_number == 0 + + return (target_change_number <= @splits_repository.get_change_number.to_i and rbs_target_change_number <= @rule_based_segments_repository.get_change_number.to_i) + end end end end diff --git a/lib/splitclient-rb/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb index 93747d50..c9b356c4 100644 --- a/lib/splitclient-rb/helpers/util.rb +++ b/lib/splitclient-rb/helpers/util.rb @@ -3,11 +3,10 @@ module SplitIoClient module Helpers class Util - def self.segment_names_by_object(object) + def self.segment_names_by_object(object, matcher_type) object[:conditions].each_with_object(Set.new) do |condition, names| condition[:matcherGroup][:matchers].each do |matcher| - next if matcher[:userDefinedSegmentMatcherData].nil? - + next if matcher[:userDefinedSegmentMatcherData].nil? or matcher[:matcherType] != matcher_type names << matcher[:userDefinedSegmentMatcherData][:segmentName] end end diff --git a/lib/splitclient-rb/split_factory.rb b/lib/splitclient-rb/split_factory.rb index 442298e7..22be6ca7 100644 --- a/lib/splitclient-rb/split_factory.rb +++ b/lib/splitclient-rb/split_factory.rb @@ -154,6 +154,7 @@ def repositories segments: @segments_repository, impressions: @impressions_repository, events: @events_repository, + rule_based_segments: @rule_based_segment_repository } end @@ -178,7 +179,7 @@ def build_telemetry_components end def build_fetchers - @split_fetcher = SplitFetcher.new(@splits_repository, @api_key, @config, @runtime_producer) + @split_fetcher = SplitFetcher.new(@splits_repository, @rule_based_segments_repository, @api_key, @config, @runtime_producer) @segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @config, @runtime_producer) end @@ -198,7 +199,7 @@ def build_synchronizer def build_streaming_components @push_status_queue = Queue.new - splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher) + splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher, @rule_based_segment_repository) segments_worker = SSE::Workers::SegmentsWorker.new(@synchronizer, @config, @segments_repository) notification_manager_keeper = SSE::NotificationManagerKeeper.new(@config, @runtime_producer, @push_status_queue) notification_processor = SSE::NotificationProcessor.new(@config, splits_worker, segments_worker) @@ -220,6 +221,7 @@ def build_repositories end @splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter) @segments_repository = SegmentsRepository.new(@config) + @rule_based_segment_repository = RuleBasedSegmentRepository.new(@config) @impressions_repository = ImpressionsRepository.new(@config) @events_repository = EventsRepository.new(@config, @api_key, @runtime_producer) end diff --git a/lib/splitclient-rb/sse/event_source/event_types.rb b/lib/splitclient-rb/sse/event_source/event_types.rb index dbe5361d..5396417d 100644 --- a/lib/splitclient-rb/sse/event_source/event_types.rb +++ b/lib/splitclient-rb/sse/event_source/event_types.rb @@ -8,6 +8,7 @@ class EventTypes SPLIT_KILL = 'SPLIT_KILL' SEGMENT_UPDATE = 'SEGMENT_UPDATE' CONTROL = 'CONTROL' + RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE' end end end diff --git a/lib/splitclient-rb/sse/notification_processor.rb b/lib/splitclient-rb/sse/notification_processor.rb index 0c137f59..d723cbdc 100644 --- a/lib/splitclient-rb/sse/notification_processor.rb +++ b/lib/splitclient-rb/sse/notification_processor.rb @@ -13,6 +13,8 @@ def process(incoming_notification) case incoming_notification.data['type'] when SSE::EventSource::EventTypes::SPLIT_UPDATE process_split_update(incoming_notification) + when SSE::EventSource::EventTypes::RB_SEGMENT_UPDATE + process_split_update(incoming_notification) when SSE::EventSource::EventTypes::SPLIT_KILL process_split_kill(incoming_notification) when SSE::EventSource::EventTypes::SEGMENT_UPDATE @@ -25,7 +27,7 @@ def process(incoming_notification) private def process_split_update(notification) - @config.logger.debug("SPLIT UPDATE notification received: #{notification}") if @config.debug_enabled + @config.logger.debug("#{notification.type} notification received: #{notification}") if @config.debug_enabled @splits_worker.add_to_queue(notification) end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 7971bce8..419a3814 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,7 +4,7 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher) + def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segment_repository) @synchronizer = synchronizer @config = config @feature_flags_repository = feature_flags_repository @@ -12,6 +12,7 @@ def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime @running = Concurrent::AtomicBoolean.new(false) @telemetry_runtime_producer = telemetry_runtime_producer @segment_fetcher = segment_fetcher + @rule_based_segment_repository = rule_based_segment_repository end def start @@ -54,7 +55,10 @@ def perform case notification.data['type'] when SSE::EventSource::EventTypes::SPLIT_UPDATE success = update_feature_flag(notification) - @synchronizer.fetch_splits(notification.data['changeNumber']) unless success + @synchronizer.fetch_splits(notification.data['changeNumber'], 0) unless success + when SSE::EventSource::EventTypes::RB_SEGMENT_UPDATE + success = update_rule_based_segment(notification) + @synchronizer.fetch_splits(0, notification.data['changeNumber']) unless success when SSE::EventSource::EventTypes::SPLIT_KILL kill_feature_flag(notification) end @@ -64,12 +68,14 @@ def perform def update_feature_flag(notification) return true if @feature_flags_repository.get_change_number.to_i >= notification.data['changeNumber'] return false unless !notification.data['d'].nil? && @feature_flags_repository.get_change_number == notification.data['pcn'] - - new_split = return_split_from_json(notification) + new_split = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, [new_split], notification.data['changeNumber'], @config) - fetch_segments_if_not_exists(new_split) + fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_SEGMENT"), @feature_flags_repository) + if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_RULE_BASED_SEGMENT"), notification.data['changeNumber']) + return true + end @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS) @@ -80,6 +86,26 @@ def update_feature_flag(notification) false end + def update_rule_based_segment(notification) + return true if @rule_based_segment_repository.get_change_number.to_i >= notification.data['changeNumber'] + return false unless !notification.data['d'].nil? && @rule_based_segment_repository.get_change_number == notification.data['pcn'] + + new_rb_segment = return_object_from_json(notification) + SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository, + [new_rb_segment], + notification.data['changeNumber'], @config) + fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, "IN_SEGMENT"), @rule_based_segment_repository) + +# TODO: enable when telemetry spec is added +# @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS) + + true + rescue StandardError => e + @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled + + false + end + def kill_feature_flag(notification) return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] @@ -89,21 +115,30 @@ def kill_feature_flag(notification) notification.data['splitName'], notification.data['defaultTreatment'] ) - @synchronizer.fetch_splits(notification.data['changeNumber']) + @synchronizer.fetch_splits(notification.data['changeNumber'], 0) end - def return_split_from_json(notification) - split_json = Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']) - JSON.parse(split_json, symbolize_names: true) + def return_object_from_json(notification) + object_json = Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']) + JSON.parse(object_json, symbolize_names: true) end - def fetch_segments_if_not_exists(feature_flag) - segment_names = Helpers::Util.segment_names_by_feature_flag(feature_flag) + def fetch_segments_if_not_exists(segment_names, object_repository) + return if segment_names.nil? - @feature_flags_repository.set_segment_names(segment_names) + object_repository.set_segment_names(segment_names) @segment_fetcher.fetch_segments_if_not_exists(segment_names) end + + def fetch_rule_based_segments_if_not_exists(segment_names, change_number) + if segment_names.nil? or segment_names.empty? or @rule_based_segment_repository.contains?(segment_names.to_a) + return false + end + @synchronizer.fetch_splits(0, change_number) + + true + end end end end diff --git a/spec/engine/api/splits_spec.rb b/spec/engine/api/splits_spec.rb index dffb68c5..af20bd9a 100644 --- a/spec/engine/api/splits_spec.rb +++ b/spec/engine/api/splits_spec.rb @@ -52,7 +52,7 @@ }) .to_return(status: 200, body: splits) - fetch_options = { cache_control_headers: false, till: nil, till_rbs: nil, sets: ['set_1','set_2'] } + fetch_options = { cache_control_headers: false, till: nil, sets: ['set_1','set_2'] } returned_splits = splits_api.since(-1, -1, fetch_options) expect(returned_splits[:segment_names]).to eq(Set.new(%w[demo employees])) @@ -72,7 +72,7 @@ }) .to_return(status: 414, body: splits) - fetch_options = { cache_control_headers: false, till: nil, till_rbs: nil, sets: ['set_1','set_2'] } + fetch_options = { cache_control_headers: false, till: nil, sets: ['set_1','set_2'] } captured = 0 begin returned_splits = splits_api.since(-1, -1, fetch_options) @@ -126,7 +126,7 @@ }) .to_return(status: 200, body: splits) - fetch_options = { cache_control_headers: false, till: 123_123, till_rbs: nil, sets: nil } + fetch_options = { cache_control_headers: false, till: 123_123, sets: nil } returned_splits = splits_api.since(-1, -1, fetch_options) expect(returned_splits[:segment_names]).to eq(Set.new(%w[demo employees])) @@ -147,7 +147,7 @@ }) .to_return(status: 200, body: splits) - fetch_options = { cache_control_headers: true, till: nil, till_rbs: nil, sets: nil } + fetch_options = { cache_control_headers: true, till: nil, sets: nil } returned_splits = splits_api.since(-1, -1, fetch_options) expect(returned_splits[:segment_names]).to eq(Set.new(%w[demo employees])) diff --git a/spec/engine/synchronizer_spec.rb b/spec/engine/synchronizer_spec.rb index 4a920b55..cef2020d 100644 --- a/spec/engine/synchronizer_spec.rb +++ b/spec/engine/synchronizer_spec.rb @@ -18,16 +18,18 @@ flag_set_filter = SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) splits_repository = SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) + rule_based_segments_repository = SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) repositories = { splits: splits_repository, segments: segments_repository, impressions: SplitIoClient::Cache::Repositories::ImpressionsRepository.new(config), - events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, runtime_producer) + events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, runtime_producer), + rule_based_segments: rule_based_segments_repository } parameters = { - split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, runtime_producer), + split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, runtime_producer), segment_fetcher: SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, runtime_producer), telemetry_runtime_producer: runtime_producer, unique_keys_tracker: SplitIoClient::Engine::Impressions::NoopUniqueKeysTracker.new @@ -59,7 +61,7 @@ sleep(2) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment2?since=-1')).to have_been_made.once @@ -73,7 +75,7 @@ sleep(2) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment2?since=-1')).to have_been_made.once @@ -91,7 +93,7 @@ it 'start_periodic_fetch' do synchronizer.start_periodic_fetch - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=-1')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=1470947453877')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment2?since=-1')).to have_been_made.once @@ -101,7 +103,7 @@ end it 'sync_all synchronous - should return false' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').to_return(status: 500) + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').to_return(status: 500) result = synchronizer.sync_all(false) @@ -118,40 +120,40 @@ mock_segment_changes('segment1', segment1, '-1') mock_segment_changes('segment1', segment1, '1470947453877') - synchronizer.fetch_splits(0) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.once + synchronizer.fetch_splits(1506703262916, 0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.once end it 'fetch_splits - with CDN bypassed' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .to_return(status: 200, body: - '{ - "splits": [], - "since": -1, - "till": 1506703262918 - }') + '{"ff":{ + "d": [], + "s": -1, + "t": 1506703262918 + }, "rbs":{"d":[],"s":-1,"t":-1}}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1') .to_return(status: 200, body: - '{ - "splits": [], - "since": 1506703262918, - "till": 1506703262918 - }') + '{"ff":{ + "d": [], + "s": 1506703262918, + "t": 1506703262918 + }, "rbs":{"d":[],"s":-1,"t":-1}}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918&till=1506703262920') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1&till=1506703262920') .to_return(status: 200, body: - '{ - "splits": [], - "since": 1506703262918, - "till": 1506703262921 - }') + '{"ff":{ + "d": [], + "s": 1506703262918, + "t": 1506703262921 + }, "rbs":{"d":[],"s":-1,"t":-1}}') - synchronizer.fetch_splits(1_506_703_262_920) + synchronizer.fetch_splits(1_506_703_262_920, 0) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.once - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918')).to have_been_made.times(9) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918&till=1506703262920')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1')).to have_been_made.times(9) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1&till=1506703262920')).to have_been_made.once end it 'fetch_segment' do @@ -234,7 +236,7 @@ private def mock_split_changes(splits_json) - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').to_return(status: 200, body: splits_json) + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').to_return(status: 200, body: splits_json) end def mock_segment_changes(segment_name, segment_json, since) diff --git a/spec/sse/event_source/client_spec.rb b/spec/sse/event_source/client_spec.rb index 3547f6a1..1c199b09 100644 --- a/spec/sse/event_source/client_spec.rb +++ b/spec/sse/event_source/client_spec.rb @@ -20,19 +20,20 @@ splits: SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter), segments: SplitIoClient::Cache::Repositories::SegmentsRepository.new(config), impressions: SplitIoClient::Cache::Repositories::ImpressionsRepository.new(config), - events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, telemetry_runtime_producer) + events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, telemetry_runtime_producer), + rule_based_segments: SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } end let(:parameters) do { - split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(repositories[:splits], api_key, config, telemetry_runtime_producer), + split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(repositories[:splits], repositories[:rule_based_segments], api_key, config, telemetry_runtime_producer), segment_fetcher: SplitIoClient::Cache::Fetchers::SegmentFetcher.new(repositories[:segments], api_key, config, telemetry_runtime_producer), imp_counter: SplitIoClient::Engine::Common::ImpressionCounter.new, telemetry_runtime_producer: telemetry_runtime_producer } end let(:synchronizer) { SplitIoClient::Engine::Synchronizer.new(repositories, config, parameters) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, repositories[:splits], telemetry_runtime_producer, parameters[:segment_fetcher]) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, repositories[:splits], telemetry_runtime_producer, parameters[:segment_fetcher], repositories[:rule_based_segments]) } let(:segments_worker) { SplitIoClient::SSE::Workers::SegmentsWorker.new(synchronizer, config, repositories[:segments]) } let(:push_status_queue) { Queue.new } let(:notification_manager_keeper) { SplitIoClient::SSE::NotificationManagerKeeper.new(config, telemetry_runtime_producer, push_status_queue) } @@ -48,12 +49,12 @@ context 'tests' do it 'receive split update event' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .with(headers: { 'Authorization' => 'Bearer client-spec-key' }) - .to_return(status: 200, body: '{"splits":[],"since":-1,"till":5564531221}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=5564531221') + .to_return(status: 200, body: '{"ff":{"d":[],"s":-1,"t":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=5564531221&rbSince=-1') .with(headers: { 'Authorization' => 'Bearer client-spec-key' }) - .to_return(status: 200, body: '{"splits":[],"since":5564531221,"till":5564531221}') + .to_return(status: 200, body: '{"ff":{"d":[],"s":5564531221,"t":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}') mock_server do |server| server.setup_response('/') do |_, res| @@ -68,7 +69,7 @@ expect(sse_client.connected?).to eq(true) expect(push_status_queue.pop(true)).to eq(SplitIoClient::Constants::PUSH_CONNECTED) sleep 1 - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(1) sse_client.close @@ -79,12 +80,12 @@ end it 'receive split kill event' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .with(headers: { 'Authorization' => 'Bearer client-spec-key' }) - .to_return(status: 200, body: '{"splits":[],"since":-1,"till":5564531221}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=5564531221') + .to_return(status: 200, body: '{"ff":{"d":[],"since":-1,"till":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=5564531221&rbSince=-1') .with(headers: { 'Authorization' => 'Bearer client-spec-key' }) - .to_return(status: 200, body: '{"splits":[],"since":5564531221,"till":5564531221}') + .to_return(status: 200, body: '{"ff":{"d":[],"since":5564531221,"till":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}') mock_server do |server| server.setup_response('/') do |_, res| @@ -99,7 +100,7 @@ expect(sse_client.connected?).to eq(true) expect(push_status_queue.pop(true)).to eq(SplitIoClient::Constants::PUSH_CONNECTED) sleep 1 - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(1) sse_client.close @@ -150,7 +151,7 @@ expect(connected).to eq(true) expect(sse_client.connected?).to eq(true) expect(push_status_queue.pop(true)).to eq(SplitIoClient::Constants::PUSH_CONNECTED) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment-test?since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) sse_client.close @@ -172,7 +173,7 @@ expect(connected).to eq(true) expect(sse_client.connected?).to eq(true) expect(push_status_queue.pop(true)).to eq(SplitIoClient::Constants::PUSH_CONNECTED) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment-test?since=-1').with(headers: { 'Authorization' => 'Bearer client-spec-key' })).to have_been_made.times(0) sse_client.close diff --git a/spec/sse/sse_handler_spec.rb b/spec/sse/sse_handler_spec.rb index e6a314dc..099f7932 100644 --- a/spec/sse/sse_handler_spec.rb +++ b/spec/sse/sse_handler_spec.rb @@ -21,19 +21,20 @@ splits: splits_repository, segments: segments_repository, impressions: SplitIoClient::Cache::Repositories::ImpressionsRepository.new(config), - events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, telemetry_runtime_producer) + events: SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, telemetry_runtime_producer), + rule_based_segments: SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } end let(:parameters) do { - split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer), + split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, repositories[:rule_based_segments], api_key, config, telemetry_runtime_producer), segment_fetcher: SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer), imp_counter: SplitIoClient::Engine::Common::ImpressionCounter.new, telemetry_runtime_producer: telemetry_runtime_producer } end let(:synchronizer) { SplitIoClient::Engine::Synchronizer.new(repositories, config, parameters) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository, telemetry_runtime_producer, parameters[:segment_fetcher]) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository, telemetry_runtime_producer, parameters[:segment_fetcher], repositories[:rule_based_segments]) } let(:segments_worker) { SplitIoClient::SSE::Workers::SegmentsWorker.new(synchronizer, config, segments_repository) } let(:notification_processor) { SplitIoClient::SSE::NotificationProcessor.new(config, splits_worker, segments_worker) } let(:event_parser) { SplitIoClient::SSE::EventSource::EventParser.new(config) } diff --git a/spec/sse/workers/segments_worker_spec.rb b/spec/sse/workers/segments_worker_spec.rb index aad5db85..8e3405bc 100644 --- a/spec/sse/workers/segments_worker_spec.rb +++ b/spec/sse/workers/segments_worker_spec.rb @@ -17,10 +17,11 @@ let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([])} let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) } let(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } + let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } let(:impressions_repository) { SplitIoClient::Cache::Repositories::ImpressionsRepository.new(config) } let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } let(:events_repository) { SplitIoClient::Cache::Repositories::EventsRepository.new(config, api_key, telemetry_runtime_producer) } - let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer) } + let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } let(:repositories) { { splits: splits_repository, segments: segments_repository } } let(:impression_counter) { SplitIoClient::Engine::Common::ImpressionCounter.new } @@ -101,7 +102,7 @@ private def mock_split_changes(splits_json) - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .to_return(status: 200, body: splits_json) end diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index b45aef73..0ef724f9 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -21,13 +21,16 @@ let(:event_split_archived_no_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 0,"d":"eyJ0cmFmZmljVHlwZU5hbWUiOiAidXNlciIsICJpZCI6ICIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCAibmFtZSI6ICJiaWxhbF9zcGxpdCIsICJ0cmFmZmljQWxsb2NhdGlvbiI6IDEwMCwgInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6IC0xMzY0MTE5MjgyLCAic2VlZCI6IC02MDU5Mzg4NDMsICJzdGF0dXMiOiAiQVJDSElWRUQiLCAia2lsbGVkIjogZmFsc2UsICJkZWZhdWx0VHJlYXRtZW50IjogIm9mZiIsICJjaGFuZ2VOdW1iZXIiOiAxNjg0Mjc1ODM5OTUyLCAiYWxnbyI6IDIsICJjb25maWd1cmF0aW9ucyI6IHt9LCAiY29uZGl0aW9ucyI6IFt7ImNvbmRpdGlvblR5cGUiOiAiUk9MTE9VVCIsICJtYXRjaGVyR3JvdXAiOiB7ImNvbWJpbmVyIjogIkFORCIsICJtYXRjaGVycyI6IFt7ImtleVNlbGVjdG9yIjogeyJ0cmFmZmljVHlwZSI6ICJ1c2VyIn0sICJtYXRjaGVyVHlwZSI6ICJJTl9TRUdNRU5UIiwgIm5lZ2F0ZSI6IGZhbHNlLCAidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOiB7InNlZ21lbnROYW1lIjogImJpbGFsX3NlZ21lbnQifX1dfSwgInBhcnRpdGlvbnMiOiBbeyJ0cmVhdG1lbnQiOiAib24iLCAic2l6ZSI6IDB9LCB7InRyZWF0bWVudCI6ICJvZmYiLCAic2l6ZSI6IDEwMH1dLCAibGFiZWwiOiAiaW4gc2VnbWVudCBiaWxhbF9zZWdtZW50In0sIHsiY29uZGl0aW9uVHlwZSI6ICJST0xMT1VUIiwgIm1hdGNoZXJHcm91cCI6IHsiY29tYmluZXIiOiAiQU5EIiwgIm1hdGNoZXJzIjogW3sia2V5U2VsZWN0b3IiOiB7InRyYWZmaWNUeXBlIjogInVzZXIifSwgIm1hdGNoZXJUeXBlIjogIkFMTF9LRVlTIiwgIm5lZ2F0ZSI6IGZhbHNlfV19LCAicGFydGl0aW9ucyI6IFt7InRyZWF0bWVudCI6ICJvbiIsICJzaXplIjogMH0sIHsidHJlYXRtZW50IjogIm9mZiIsICJzaXplIjogMTAwfV0sICJsYWJlbCI6ICJkZWZhdWx0IHJ1bGUifV19"}'), 'test') } let(:event_split_update_no_definition) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 0, "d":null}'), 'test') } let(:event_split_update_segments) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":2,"d":"eJzcVFtr20wQ/SvhPK9AsnzTvpnPJp+po0DlppRgzFga2dusJLNapaRG/73Id7sOoU+FvmluZ3TOGXYDayhNVTx9W3NIGUOiKtlAQCWQSNq+FyeJ6yzcBTuex+T0qe86XrfrUkJBzH4AgXw3mVFlivl3eiWIA/BA6yImq4oc0nPdG/mIOYF0gpYfeO3AEyh3Ca/XDfxer+u2BUpLtiohMfhvOn4aQeBFad20paRLFkg4pUrbqWGyGecWEvbwPQ9cCMQrypccVtmCDaTX7feCnu+7nY7nCZBeFpAtgbjIU7WszPbPSshNvc0lah8/b05hoxkkvv4/no4m42gKgYxsvGJzb4pqDdn0ZguVNwsxCIenhh3SPriBk/OSLB/Z/Vgpy1qV9mE3MSRLDfwxD/kMSjKVb1dUpmgwVFxgVtezWmBNxp5RsDdlavkdCJTqJ2+tqmcCmhasIU+LOEEtftfg8+Nk8vjlzxV44beINce2ME3z2TEeDrEWVzKNw3k0un8YhTd0aiaGnKqck4iXDakrwcpdNjzdq9PChxIV+VEXt2F/UUvTC9Guyk/t90dfO+/Xro73w65z7y6cU/ndnvTdge7f9W8wmcw/jb5F1+79yybsX6c7U2lGPat/BQAA//9ygdKB"}'), 'test') } + let(:event_split_update_rb_segments) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":0,"d":"eyJjaGFuZ2VOdW1iZXIiOiAxMCwgInRyYWZmaWNUeXBlTmFtZSI6ICJ1c2VyIiwgIm5hbWUiOiAicmJzX2ZsYWciLCAidHJhZmZpY0FsbG9jYXRpb24iOiAxMDAsICJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOiAxODI4Mzc3MzgwLCAic2VlZCI6IC0yODY2MTc5MjEsICJzdGF0dXMiOiAiQUNUSVZFIiwgImtpbGxlZCI6IGZhbHNlLCAiZGVmYXVsdFRyZWF0bWVudCI6ICJvZmYiLCAiYWxnbyI6IDIsICJjb25kaXRpb25zIjogW3siY29uZGl0aW9uVHlwZSI6ICJST0xMT1VUIiwgIm1hdGNoZXJHcm91cCI6IHsiY29tYmluZXIiOiAiQU5EIiwgIm1hdGNoZXJzIjogW3sia2V5U2VsZWN0b3IiOiB7InRyYWZmaWNUeXBlIjogInVzZXIifSwgIm1hdGNoZXJUeXBlIjogIklOX1JVTEVfQkFTRURfU0VHTUVOVCIsICJuZWdhdGUiOiBmYWxzZSwgInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjogeyJzZWdtZW50TmFtZSI6ICJzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50In19XX0sICJwYXJ0aXRpb25zIjogW3sidHJlYXRtZW50IjogIm9uIiwgInNpemUiOiAxMDB9LCB7InRyZWF0bWVudCI6ICJvZmYiLCAic2l6ZSI6IDB9XSwgImxhYmVsIjogImluIHJ1bGUgYmFzZWQgc2VnbWVudCBzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50In0sIHsiY29uZGl0aW9uVHlwZSI6ICJST0xMT1VUIiwgIm1hdGNoZXJHcm91cCI6IHsiY29tYmluZXIiOiAiQU5EIiwgIm1hdGNoZXJzIjogW3sia2V5U2VsZWN0b3IiOiB7InRyYWZmaWNUeXBlIjogInVzZXIifSwgIm1hdGNoZXJUeXBlIjogIkFMTF9LRVlTIiwgIm5lZ2F0ZSI6IGZhbHNlfV19LCAicGFydGl0aW9ucyI6IFt7InRyZWF0bWVudCI6ICJvbiIsICJzaXplIjogMH0sIHsidHJlYXRtZW50IjogIm9mZiIsICJzaXplIjogMTAwfV0sICJsYWJlbCI6ICJkZWZhdWx0IHJ1bGUifV0sICJjb25maWd1cmF0aW9ucyI6IHt9LCAic2V0cyI6IFtdLCAiaW1wcmVzc2lvbnNEaXNhYmxlZCI6IGZhbHNlfQ=="}'), 'test') } + let(:event_rb_segment_update) { SplitIoClient::SSE::EventSource::StreamData.new("data", 12345, JSON.parse('{"type":"RB_SEGMENT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":0,"d":"eyJjaGFuZ2VOdW1iZXIiOiA1LCAibmFtZSI6ICJzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50IiwgInN0YXR1cyI6ICJBQ1RJVkUiLCAidHJhZmZpY1R5cGVOYW1lIjogInVzZXIiLCAiZXhjbHVkZWQiOiB7ImtleXMiOiBbIm1hdXJvQHNwbGl0LmlvIl0sICJzZWdtZW50cyI6IFtdfSwgImNvbmRpdGlvbnMiOiBbeyJtYXRjaGVyR3JvdXAiOiB7ImNvbWJpbmVyIjogIkFORCIsICJtYXRjaGVycyI6IFt7ImtleVNlbGVjdG9yIjogeyJ0cmFmZmljVHlwZSI6ICJ1c2VyIiwgImF0dHJpYnV0ZSI6ICJlbWFpbCJ9LCAibWF0Y2hlclR5cGUiOiAiRU5EU19XSVRIIiwgIm5lZ2F0ZSI6IGZhbHNlLCAid2hpdGVsaXN0TWF0Y2hlckRhdGEiOiB7IndoaXRlbGlzdCI6IFsiQHNwbGl0LmlvIl19fV19fV19"}'), 'test') } context 'add change number to queue' do let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([])} let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([])} let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) } let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } - let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer) } + let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } + let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } let(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } let(:synchronizer) do @@ -36,7 +39,8 @@ repositories = { splits: splits_repository, - segments: segments_repository + segments: segments_repository, + rule_based_segments: rule_based_segments_repository } params = { @@ -51,49 +55,49 @@ end it 'add change number - must tigger fetch - with retries' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262918}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918').to_return(status: 200, body: '{"splits": [],"since": 1506703262918,"till": 1506703262918}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918&till=1506703262919').to_return(status: 200, body: '{"splits": [],"since": 1506703262919,"till": 1506703262919}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": -1,"t": 1506703262918}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1506703262918,"t": 1506703262918}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1&till=1506703262919').to_return(status: 200, body: '{"ff":{"d": [],"s": 1506703262919,"t": 1506703262919}, "rbs":{"d":[],"s":-1,"t":-1}}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262919}'), 'test')) sleep 1 - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')).to have_been_made.times(1) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918')).to have_been_made.at_least_times(2) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262918&till=1506703262919')).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1')).to have_been_made.at_least_times(2) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262918&rbSince=-1&till=1506703262919')).to have_been_made.times(1) end it 'must trigger fetch' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262916}') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916').to_return(status: 200, body: '{"splits": [],"since": 1506703262916,"till": 1506703262918}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": -1,"t": 1506703262916}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1506703262916,"t": 1506703262918}, "rbs":{"d":[],"s":-1,"t":-1}}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262918}'), 'test')) sleep 1 - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1')).to have_been_made.once end it 'must not trigger fetch' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262916}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": -1,"t": 1506703262916}, "rbs":{"d":[],"s":-1,"t":-1}}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262916}'), 'test')) sleep 1 - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916')).to have_been_made.times(0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1')).to have_been_made.times(0) end it 'without start, must not fetch' do - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262918}'), 'test')) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916')).to have_been_made.times(0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1')).to have_been_made.times(0) end end @@ -102,16 +106,18 @@ let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([])} let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) } let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } - let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer) } + let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } let(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } + let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } let(:synchronizer) do telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) impressions_api = SplitIoClient::Api::Impressions.new(api_key, config, telemetry_runtime_producer) repositories = { splits: splits_repository, - segments: segments_repository + segments: segments_repository, + rule_based_segments: rule_based_segments_repository } params = { @@ -136,9 +142,9 @@ end it 'must kill split and trigger fetch' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916').to_return(status: 200, body: '{"splits": [],"since": 1506703262916,"till": 1506703262918}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1506703262916,"t": 1506703262918}, "rbs":{"d":[],"s":-1,"t":-1}}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262918}'), 'test') @@ -148,11 +154,11 @@ expect(split[:killed]).to be_truthy expect(split[:defaultTreatment]).to eq('on') expect(split[:changeNumber]).to eq(1_506_703_262_918) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916')).to have_been_made.once + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1')).to have_been_made.once end it 'must kill split and must not trigger fetch' do - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262916}'), 'test') @@ -163,7 +169,7 @@ expect(split[:killed]).to be_truthy expect(split[:defaultTreatment]).to eq('on') expect(split[:changeNumber]).to eq(1_506_703_262_916) - expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1506703262916')).to have_been_made.times(0) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1506703262916&rbSince=-1')).to have_been_made.times(0) end end @@ -172,16 +178,18 @@ let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new(["set_1"])} let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) } let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } - let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer) } + let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } let(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } + let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } let(:synchronizer) do telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) impressions_api = SplitIoClient::Api::Impressions.new(api_key, config, telemetry_runtime_producer) repositories = { splits: splits_repository, - segments: segments_repository + segments: segments_repository, + rule_based_segments: rule_based_segments_repository } params = { @@ -195,10 +203,10 @@ SplitIoClient::Engine::Synchronizer.new(repositories, config, params) end it 'update split with and without flagset' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1234').to_return(status: 200, body: '{"splits": [],"since": 1234,"till": 1234}') - stub_request(:get, "https://sdk.split.io/api/splitChanges?s=1.1&since=1234&till=5564531221").to_return(status: 200, body: '{"splits": [],"since": 1234,"till": 5564531221}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1234&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1234,"t": 1234}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, "https://sdk.split.io/api/splitChanges?s=1.3&since=1234&rbSince=-1&till=5564531221").to_return(status: 200, body: '{"ff":{"d": [],"s": 1234,"t": 5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}') stub_request(:get, "https://sdk.split.io/api/segmentChanges/bilal_segment?since=-1").to_return(status: 200, body: "") - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start splits_repository.set_change_number(1234) @@ -224,16 +232,18 @@ let(:flag_set_filter) {SplitIoClient::Cache::Filter::FlagSetsFilter.new([])} let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config, flag_sets_repository, flag_set_filter) } let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } - let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer) } + let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, rule_based_segments_repository, api_key, config, telemetry_runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } let(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } + let(:rule_based_segments_repository) { SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) } let(:synchronizer) do telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) impressions_api = SplitIoClient::Api::Impressions.new(api_key, config, telemetry_runtime_producer) repositories = { splits: splits_repository, - segments: segments_repository + segments: segments_repository, + rule_based_segments: rule_based_segments_repository } params = { @@ -246,9 +256,10 @@ SplitIoClient::Engine::Synchronizer.new(repositories, config, params) end + it 'decode and decompress split update data' do stub_request(:get, "https://sdk.split.io/api/segmentChanges/bilal_segment?since=-1").to_return(status: 200, body: "") - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start splits_repository.set_change_number(1234) @@ -276,9 +287,9 @@ end it 'instant ff update split notification with segment matcher.' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1234').to_return(status: 200, body: '{"splits": [],"since": 1234,"till": 1234}') - stub_request(:get, 'https://sdk.split.io/api/segmentChanges/maur-2?since=-1').to_return(status: 200, body: '{"name":"maur-2","added":["admin"],"removed":[],"since":-1,"till":-1}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1234&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1234,"t": 1234}, "rbs":{"d":[],"s":-1,"t":-1}}') + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/maur-2?since=-1').to_return(status: 200, body: '{"name":"maur-2","added":["admin"],"removed":[],"since":-1,"till":-1}}') + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start splits_repository.set_change_number(1234) @@ -289,9 +300,55 @@ expect(segments_repository.used_segment_names[0]).to eq('maur-2') end + it 'instant ff update split notification with rule based segment matcher.' do + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1234&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 1234,"t": 1234}, "rbs":{"d":[],"s":-1,"t":5564531221}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=5564531221&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": 5564531221,"t": 5564531221}, "rbs":{"d":[{"{ + "changeNumber": 123, + "name": "sample_rule_based_segment", + "status": "ACTIVE", + "trafficTypeName": "user", + "excluded":{ + "keys":["mauro@split.io","gaston@split.io"], + "segments":[] + }, + "conditions": [ + { + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "user", + "attribute": "email" + }, + "matcherType": "ENDS_WITH", + "negate": false, + "whitelistMatcherData": { + "whitelist": [ + "@split.io" + ] + } + } + ] + } + } + ] + }"}],"s":-1,"t":5564531221}}') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=5564531221&rbSince=5564531221').to_return(status: 200, body: '{"ff":{"d": [],"s": 5564531221,"t": 5564531221}, "rbs":{"d":[],"s":5564531221,"t":5564531221}}') + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) + worker.start + + splits_repository.set_change_number(1234) + expect(rule_based_segments_repository.get_rule_based_segment("sample_rule_based_segment") == nil) + + worker.add_to_queue(event_split_update_rb_segments) + sleep 1 + expect(rule_based_segments_repository.get_rule_based_segment("sample_rule_based_segment") != nil) + end + it 'should not update if definition is nil' do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1234').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262918}') - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=1234&rbSince=-1').to_return(status: 200, body: '{"ff":{"d": [],"s": -1,"t": 1506703262918}, "rbs":{"d":[],"s":-1,"t":-1}}') + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start splits_repository.set_change_number(1234) @@ -299,12 +356,23 @@ sleep 1 expect(splits_repository.exists?('bilal_split') == false) end + + it 'process rb segment update' do + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) + worker.start + + rule_based_segments_repository.set_change_number(1234) + worker.add_to_queue(event_rb_segment_update) + sleep 2 + rb_segment = rule_based_segments_repository.get_rule_based_segment("sample_rule_based_segment") + expect(rb_segment[:name] == 'sample_rule_based_segment') + end end private def mock_split_changes(splits_json) - stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .to_return(status: 200, body: splits_json) end diff --git a/spec/test_data/integrations/splits.json b/spec/test_data/integrations/splits.json index 4361b6bb..9881fda2 100644 --- a/spec/test_data/integrations/splits.json +++ b/spec/test_data/integrations/splits.json @@ -1,5 +1,5 @@ -{ - "splits": [ +{"ff": { + "d": [ { "impressionsDisabled": false, "trafficTypeName": "account", @@ -2523,6 +2523,7 @@ ] } ], - "since": -1, - "till": 1506703262916 - } \ No newline at end of file + "s": -1, + "t": 1506703262916 + }, "rbs": {"d":[], "t":-1, "s":-1} +} \ No newline at end of file diff --git a/spec/test_data/integrations/splits_push.json b/spec/test_data/integrations/splits_push.json index 833a41a9..72962e8b 100644 --- a/spec/test_data/integrations/splits_push.json +++ b/spec/test_data/integrations/splits_push.json @@ -1,6 +1,6 @@ -{ - "splits": [ - { +{"ff": { + "d": [ + { "impressionsDisabled": false, "trafficTypeName": "user", "name": "push_test", @@ -225,6 +225,7 @@ ] } ], - "since": -1, - "till": 1585948850109 + "s": -1, + "t": 1585948850109 + }, "rbs": {"d":[], "t":-1, "s":-1} } \ No newline at end of file diff --git a/spec/test_data/integrations/splits_push2.json b/spec/test_data/integrations/splits_push2.json index c4f7d93d..701b7880 100644 --- a/spec/test_data/integrations/splits_push2.json +++ b/spec/test_data/integrations/splits_push2.json @@ -1,5 +1,6 @@ -{ - "splits": [], - "since": 1585948850109, - "till": 1585948850110 +{"ff": { + "d": [], + "s": 1585948850109, + "t": 1585948850110 + }, "rbs": {"d":[], "t":-1, "s":-1} } \ No newline at end of file diff --git a/spec/test_data/integrations/splits_push3.json b/spec/test_data/integrations/splits_push3.json index 8984c5ff..bfade789 100644 --- a/spec/test_data/integrations/splits_push3.json +++ b/spec/test_data/integrations/splits_push3.json @@ -1,6 +1,6 @@ -{ - "splits": [ - { +{"ff": { + "d": [ + { "impressionsDisabled": false, "trafficTypeName": "user", "name": "push_test", @@ -87,6 +87,7 @@ ] } ], - "since": 1585948850110, - "till": 1585948850111 + "s": 1585948850110, + "t": 1585948850111 + }, "rbs": {"d":[], "t":-1, "s":-1} } \ No newline at end of file