diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..9e319810 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @splitio/sdk diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38dab547..1da52c42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: matrix: version: - '2.5.0' - - '3.1.1' + - '3.2.2' steps: - name: Checkout code @@ -56,7 +56,7 @@ jobs: run: echo "VERSION=$(cat lib/splitclient-rb/version.rb | grep VERSION | awk -F "'" '{print $2}')" >> $GITHUB_ENV - name: SonarQube Scan (Push) - if: matrix.version == '3.1.1' && github.event_name == 'push' + if: matrix.version == '3.2.2' && github.event_name == 'push' uses: SonarSource/sonarcloud-github-action@v1.9 env: SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }} @@ -68,7 +68,7 @@ jobs: -Dsonar.projectVersion=${{ env.VERSION }} - name: SonarQube Scan (Pull Request) - if: matrix.version == '3.1.1' && github.event_name == 'pull_request' + if: matrix.version == '3.2.2' && github.event_name == 'pull_request' uses: SonarSource/sonarcloud-github-action@v1.9 env: SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }} diff --git a/CHANGES.txt b/CHANGES.txt index 1f7497b9..6e1339d1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,8 @@ CHANGES +8.2.0 (Jul 18, 2023) +- Improved streaming architecture implementation to apply feature flag updates from the notification received which is now enhanced, improving efficiency and reliability of the whole update system. + 8.1.2 (May 15, 2023) - Updated terminology on the SDKs codebase to be more aligned with current standard without causing a breaking change. The core change is the term split for feature flag on things like logs and IntelliSense comments. diff --git a/lib/splitclient-rb.rb b/lib/splitclient-rb.rb index 57ea263e..bba7eb84 100644 --- a/lib/splitclient-rb.rb +++ b/lib/splitclient-rb.rb @@ -41,6 +41,8 @@ require 'splitclient-rb/clients/split_client' require 'splitclient-rb/managers/split_manager' require 'splitclient-rb/helpers/thread_helper' +require 'splitclient-rb/helpers/decryption_helper' +require 'splitclient-rb/helpers/util' require 'splitclient-rb/split_factory' require 'splitclient-rb/split_factory_builder' require 'splitclient-rb/split_config' diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 8fea9141..10d4544c 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -46,21 +46,11 @@ def splits_with_segment_names(splits_json) parsed_splits[:segment_names] = parsed_splits[:splits].each_with_object(Set.new) do |split, splits| - splits << segment_names(split) + splits << Helpers::Util.segment_names_by_feature_flag(split) end.flatten parsed_splits end - - def segment_names(split) - split[:conditions].each_with_object(Set.new) do |condition, names| - condition[:matcherGroup][:matchers].each do |matcher| - next if matcher[:userDefinedSegmentMatcherData].nil? - - names << matcher[:userDefinedSegmentMatcherData][:segmentName] - end - end - end end end end diff --git a/lib/splitclient-rb/engine/push_manager.rb b/lib/splitclient-rb/engine/push_manager.rb index 9eba5e85..e36a9588 100644 --- a/lib/splitclient-rb/engine/push_manager.rb +++ b/lib/splitclient-rb/engine/push_manager.rb @@ -33,6 +33,7 @@ def start_sse def stop_sse @sse_handler.stop + SplitIoClient::Helpers::ThreadHelper.stop(:schedule_next_token_refresh, @config) rescue StandardError => e @config.logger.error(e.inspect) end diff --git a/lib/splitclient-rb/helpers/decryption_helper.rb b/lib/splitclient-rb/helpers/decryption_helper.rb new file mode 100644 index 00000000..5dc63128 --- /dev/null +++ b/lib/splitclient-rb/helpers/decryption_helper.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module SplitIoClient + NO_COMPRESSION = 0 + GZIP_COMPRESSION = 1 + ZLIB_COMPRESSION = 2 + + module Helpers + class DecryptionHelper + def self.get_encoded_definition(compression, data) + case compression + when NO_COMPRESSION + Base64.decode64(data) + when GZIP_COMPRESSION + gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(data))) + gz.read + when ZLIB_COMPRESSION + Zlib::Inflate.inflate(Base64.decode64(data)) + else + raise StandardError, 'Compression flag value is incorrect' + end + end + end + end +end diff --git a/lib/splitclient-rb/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb new file mode 100644 index 00000000..0cf9aad2 --- /dev/null +++ b/lib/splitclient-rb/helpers/util.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module SplitIoClient + module Helpers + class Util + def self.segment_names_by_feature_flag(feature_flag) + feature_flag[:conditions].each_with_object(Set.new) do |condition, names| + condition[:matcherGroup][:matchers].each do |matcher| + next if matcher[:userDefinedSegmentMatcherData].nil? + + names << matcher[:userDefinedSegmentMatcherData][:segmentName] + end + end + end + end + end +end diff --git a/lib/splitclient-rb/split_config.rb b/lib/splitclient-rb/split_config.rb index 1f42a3f8..ba42db6f 100644 --- a/lib/splitclient-rb/split_config.rb +++ b/lib/splitclient-rb/split_config.rb @@ -320,7 +320,7 @@ def init_impressions_mode(impressions_mode, adapter) return :debug else default = adapter == :redis ? :debug : :optimized - @logger.error("You passed an invalid impressions_mode, impressions_mode should be one of the following values: :debug, :optimized or :none. Defaulting to #{default} mode") + @logger.error("You passed an invalid impressions_mode, impressions_mode should be one of the following values: :debug, :optimized or :none. Defaulting to #{default} mode") unless impressions_mode.nil? return default end end diff --git a/lib/splitclient-rb/split_factory.rb b/lib/splitclient-rb/split_factory.rb index 334d79db..4a18f4fa 100644 --- a/lib/splitclient-rb/split_factory.rb +++ b/lib/splitclient-rb/split_factory.rb @@ -184,7 +184,7 @@ def build_synchronizer def build_streaming_components @push_status_queue = Queue.new - splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository) + splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher) 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) diff --git a/lib/splitclient-rb/sse/event_source/client.rb b/lib/splitclient-rb/sse/event_source/client.rb index 5c44c576..022894d6 100644 --- a/lib/splitclient-rb/sse/event_source/client.rb +++ b/lib/splitclient-rb/sse/event_source/client.rb @@ -92,7 +92,7 @@ def connect_stream(latch) raise 'eof exception' if partial_data == :eof rescue Errno::EBADF, IOError => e - @config.logger.error(e.inspect) + @config.logger.error(e.inspect) if @config.debug_enabled return nil rescue StandardError => e return nil if ENV['SPLITCLIENT_ENV'] == 'test' diff --git a/lib/splitclient-rb/sse/notification_processor.rb b/lib/splitclient-rb/sse/notification_processor.rb index 6bde38a3..0c137f59 100644 --- a/lib/splitclient-rb/sse/notification_processor.rb +++ b/lib/splitclient-rb/sse/notification_processor.rb @@ -26,16 +26,12 @@ def process(incoming_notification) def process_split_update(notification) @config.logger.debug("SPLIT UPDATE notification received: #{notification}") if @config.debug_enabled - @splits_worker.add_to_queue(notification.data['changeNumber']) + @splits_worker.add_to_queue(notification) end def process_split_kill(notification) @config.logger.debug("SPLIT KILL notification received: #{notification}") if @config.debug_enabled - change_number = notification.data['changeNumber'] - default_treatment = notification.data['defaultTreatment'] - split_name = notification.data['splitName'] - - @splits_worker.kill_split(change_number, split_name, default_treatment) + @splits_worker.add_to_queue(notification) end def process_segment_update(notification) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 48bccfa2..cb8b5d67 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,12 +4,14 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, splits_repository) + def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher) @synchronizer = synchronizer @config = config - @splits_repository = splits_repository + @feature_flags_repository = feature_flags_repository @queue = Queue.new @running = Concurrent::AtomicBoolean.new(false) + @telemetry_runtime_producer = telemetry_runtime_producer + @segment_fetcher = segment_fetcher end def start @@ -29,36 +31,83 @@ def stop end @running.make_false - SplitIoClient::Helpers::ThreadHelper.stop(:split_update_worker, @config) + Helpers::ThreadHelper.stop(:split_update_worker, @config) end - def add_to_queue(change_number) - @config.logger.debug("feature_flags_worker add to queue #{change_number}") - @queue.push(change_number) + def add_to_queue(notification) + @config.logger.debug("feature_flags_worker add to queue #{notification.data['changeNumber']}") + @queue.push(notification) end - def kill_split(change_number, split_name, default_treatment) - return if @splits_repository.get_change_number.to_i > change_number + private - @config.logger.debug("feature_flags_worker kill #{split_name}, #{change_number}") - @splits_repository.kill(change_number, split_name, default_treatment) - add_to_queue(change_number) + def perform_thread + @config.threads[:split_update_worker] = Thread.new do + @config.logger.debug('starting feature_flags_worker ...') if @config.debug_enabled + perform + end end - private - def perform - while (change_number = @queue.pop) - @config.logger.debug("feature_flags_worker change_number dequeue #{change_number}") - @synchronizer.fetch_splits(change_number) + while (notification = @queue.pop) + @config.logger.debug("feature_flags_worker change_number dequeue #{notification.data['changeNumber']}") + case notification.data['type'] + when SSE::EventSource::EventTypes::SPLIT_UPDATE + success = update_feature_flag(notification) + @synchronizer.fetch_splits(notification.data['changeNumber']) unless success + when SSE::EventSource::EventTypes::SPLIT_KILL + kill_feature_flag(notification) + end end end - def perform_thread - @config.threads[:split_update_worker] = Thread.new do - @config.logger.debug('starting feature_flags_worker ...') if @config.debug_enabled - 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) + if Engine::Models::Split.archived?(new_split) + @feature_flags_repository.remove_split(new_split) + else + @feature_flags_repository.add_split(new_split) + + fetch_segments_if_not_exists(new_split) end + + @feature_flags_repository.set_change_number(notification.data['changeNumber']) + @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'] + + @config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}") + @feature_flags_repository.kill( + notification.data['changeNumber'], + notification.data['splitName'], + notification.data['defaultTreatment'] + ) + @synchronizer.fetch_splits(notification.data['changeNumber']) + 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) + end + + def fetch_segments_if_not_exists(feature_flag) + segment_names = Helpers::Util.segment_names_by_feature_flag(feature_flag) + return if segment_names.nil? + + @feature_flags_repository.set_segment_names(segment_names) + @segment_fetcher.fetch_segments_if_not_exists(segment_names) end end end diff --git a/lib/splitclient-rb/telemetry/domain/constants.rb b/lib/splitclient-rb/telemetry/domain/constants.rb index ed3f743c..c3ad34eb 100644 --- a/lib/splitclient-rb/telemetry/domain/constants.rb +++ b/lib/splitclient-rb/telemetry/domain/constants.rb @@ -36,6 +36,8 @@ class Constants TREATMENT_WITH_CONFIG = 'treatmentWithConfig' TREATMENTS_WITH_CONFIG = 'treatmentsWithConfig' TRACK = 'track' + + SPLITS = 'splits' end end end diff --git a/lib/splitclient-rb/telemetry/domain/structs.rb b/lib/splitclient-rb/telemetry/domain/structs.rb index 8d60abc0..c2d8b9d9 100644 --- a/lib/splitclient-rb/telemetry/domain/structs.rb +++ b/lib/splitclient-rb/telemetry/domain/structs.rb @@ -22,11 +22,14 @@ module Telemetry # ls: lastSynchronization, ml: clientMethodLatencies, me: clientMethodExceptions, he: httpErros, hl: httpLatencies, # tr: tokenRefreshes, ar: authRejections, iq: impressionsQueued, ide: impressionsDeduped, idr: impressionsDropped, # spc: splitsCount, sec: segmentCount, skc: segmentKeyCount, sl: sessionLengthMs, eq: eventsQueued, ed: eventsDropped, - # se: streamingEvents, t: tags - Usage = Struct.new(:ls, :ml, :me, :he, :hl, :tr, :ar, :iq, :ide, :idr, :spc, :sec, :skc, :sl, :eq, :ed, :se, :t) + # se: streamingEvents, t: tags, ufs: updates from sse + Usage = Struct.new(:ls, :ml, :me, :he, :hl, :tr, :ar, :iq, :ide, :idr, :spc, :sec, :skc, :sl, :eq, :ed, :se, :t, :ufs) # t: treatment, ts: treatments, tc: treatmentWithConfig, tcs: treatmentsWithConfig, tr: track ClientMethodLatencies = Struct.new(:t, :ts, :tc, :tcs, :tr) ClientMethodExceptions = Struct.new(:t, :ts, :tc, :tcs, :tr) + + # sp: splits + UpdatesFromSSE = Struct.new(:sp) end end diff --git a/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb b/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb index 37daf160..6787d904 100644 --- a/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +++ b/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb @@ -94,6 +94,13 @@ def session_length @adapter.session_length.value end + def pop_updates_from_sse + splits = @adapter.updates_from_sse[Domain::Constants::SPLITS] + @adapter.updates_from_sse[Domain::Constants::SPLITS] = 0 + + UpdatesFromSSE.new(splits) + end + private def find_last_synchronization(type) diff --git a/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb b/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb index 80884ad5..602fa1b6 100644 --- a/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +++ b/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb @@ -76,6 +76,12 @@ def record_session_length(session) rescue StandardError => e @config.log_found_exception(__method__.to_s, e) end + + def record_updates_from_sse(event) + @adapter.updates_from_sse[event] += 1 + rescue StandardError => e + @config.log_found_exception(__method__.to_s, e) + end end end end diff --git a/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb b/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb index 6d4ac313..45df5c59 100644 --- a/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +++ b/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb @@ -34,7 +34,8 @@ def synchronize_stats @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_QUEUED), @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_DROPPED), @telemetry_runtime_consumer.pop_streaming_events, - @telemetry_runtime_consumer.pop_tags) + @telemetry_runtime_consumer.pop_tags, + @telemetry_runtime_consumer.pop_updates_from_sse) @telemetry_api.record_stats(format_stats(usage)) rescue StandardError => e @@ -163,7 +164,8 @@ def format_stats(usage) eQ: usage.eq, eD: usage.ed, sE: usage.se, - t: usage.t + t: usage.t, + ufs: usage.ufs.to_h } end diff --git a/lib/splitclient-rb/telemetry/runtime_consumer.rb b/lib/splitclient-rb/telemetry/runtime_consumer.rb index f4c29792..7d044b74 100644 --- a/lib/splitclient-rb/telemetry/runtime_consumer.rb +++ b/lib/splitclient-rb/telemetry/runtime_consumer.rb @@ -14,7 +14,8 @@ class RuntimeConsumer :pop_auth_rejections, :pop_token_refreshes, :pop_streaming_events, - :session_length + :session_length, + :pop_updates_from_sse def initialize(config) @runtime = SplitIoClient::Telemetry::MemoryRuntimeConsumer.new(config) diff --git a/lib/splitclient-rb/telemetry/runtime_producer.rb b/lib/splitclient-rb/telemetry/runtime_producer.rb index a18f5f32..79dffac9 100644 --- a/lib/splitclient-rb/telemetry/runtime_producer.rb +++ b/lib/splitclient-rb/telemetry/runtime_producer.rb @@ -14,7 +14,8 @@ class RuntimeProducer :record_auth_rejections, :record_token_refreshes, :record_streaming_event, - :record_session_length + :record_session_length, + :record_updates_from_sse def initialize(config) @runtime = SplitIoClient::Telemetry::MemoryRuntimeProducer.new(config) diff --git a/lib/splitclient-rb/telemetry/storages/memory.rb b/lib/splitclient-rb/telemetry/storages/memory.rb index 8b111db3..bbe243db 100644 --- a/lib/splitclient-rb/telemetry/storages/memory.rb +++ b/lib/splitclient-rb/telemetry/storages/memory.rb @@ -16,7 +16,8 @@ class Memory :auth_rejections, :token_refreshes, :streaming_events, - :session_length + :session_length, + :updates_from_sse def initialize init_latencies @@ -32,6 +33,7 @@ def initialize init_streaming_events init_session_length init_tags + init_updates_from_sse end def init_latencies @@ -133,6 +135,12 @@ def init_streaming_events def init_session_length @session_length = Concurrent::AtomicFixnum.new(0) end + + def init_updates_from_sse + @updates_from_sse = Concurrent::Hash.new + + @updates_from_sse[Domain::Constants::SPLITS] = 0 + end end end end diff --git a/lib/splitclient-rb/version.rb b/lib/splitclient-rb/version.rb index 01b81d03..116ff706 100644 --- a/lib/splitclient-rb/version.rb +++ b/lib/splitclient-rb/version.rb @@ -1,3 +1,3 @@ module SplitIoClient - VERSION = '8.1.2' + VERSION = '8.2.0' end diff --git a/spec/engine/matchers/between_matcher_spec.rb b/spec/engine/matchers/between_matcher_spec.rb index 4e58871a..7f84cd3e 100644 --- a/spec/engine/matchers/between_matcher_spec.rb +++ b/spec/engine/matchers/between_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::BetweenMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:datetime_matcher_splits) do @@ -27,19 +27,21 @@ let(:missing_key_attributes) { {} } let(:nil_attributes) { nil } + before do + stub_request(:any, /https:\/\/telemetry.*/).to_return(status: 200, body: 'ok') + stub_request(:any, /https:\/\/events.*/).to_return(status: 200, body: "", headers: {}) + end + context 'between positive numbers' do let(:matching_inclusive_low_attributes) { { income: 100 } } let(:matching_inclusive_high_attributes) { { income: 120 } } let(:non_matching_low_value_attributes) { { income: 99 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: number_matcher_splits) - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: 'ok') - subject.block_until_ready + sleep 1 end it 'validates the treatment is ON for correct number attribute value' do @@ -62,13 +64,10 @@ let(:non_matching_low_value_negative_attributes) { { income: -999 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since.*/) .to_return(status: 200, body: negative_number_matcher_splits) - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: 'ok') - subject.block_until_ready + sleep 1 end it 'validates the treatment is ON for correct negative numbers attribute value' do @@ -93,13 +92,10 @@ let(:non_matching_high_value_attributes) { { created: 1_459_775_460 } } # "2016/04/04T13:11Z" before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: datetime_matcher_splits) - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: 'ok') - subject.block_until_ready + sleep 1 end it 'validates the treatment is ON for correct number attribute value' do @@ -117,10 +113,18 @@ end context '#string_type' do + before do + stub_request(:get, /https:\/\/sdk.*/) + .to_return(status: 200, body: 'ok') + sleep 1 + end + it 'is not string type matcher' do expect(described_class.new({ attribute: 'foo', data_type: 'NUMBER', start_value: 0, end_value: 10 }, @split_logger, @split_validator).string_type?) .to be false + sleep 1 + subject.destroy() end end end diff --git a/spec/engine/matchers/combining_matcher_spec.rb b/spec/engine/matchers/combining_matcher_spec.rb index c5277eb5..a602ebbd 100644 --- a/spec/engine/matchers/combining_matcher_spec.rb +++ b/spec/engine/matchers/combining_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::CombiningMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:splits_json) do @@ -19,8 +19,13 @@ before do stub_request(:get, 'https://sdk.split.io/api/segmentChanges/employees?since=-1') .to_return(status: 200, body: segments_json) - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: splits_json) + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: 'ok') + sleep 1 end describe 'anding' do @@ -33,6 +38,8 @@ 'join' => 1_461_283_200, 'custom_attribute' => 'usa' )).to eq('V-YZKS') + sleep 1 + subject.destroy() end end end diff --git a/spec/engine/matchers/equal_to_matcher_spec.rb b/spec/engine/matchers/equal_to_matcher_spec.rb index 8c19e9c3..a9daf292 100644 --- a/spec/engine/matchers/equal_to_matcher_spec.rb +++ b/spec/engine/matchers/equal_to_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::EqualToMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:date_splits_json) do @@ -35,8 +35,13 @@ let(:matching_attributes) { { age: 30 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: 'ok') + sleep 1 end it 'validates the treatment is ON for correct attribute value' do @@ -57,8 +62,13 @@ let(:matching_negative_zero_attributes) { { age: -0 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: zero_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: 'ok') + sleep 1 end it 'validates the treatment is ON for 0 and -0 attribute values' do @@ -78,8 +88,13 @@ let(:non_matching_negative_attributes) { { age: -10 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: negative_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: 'ok') + sleep 1 end it 'validates the treatment is on for negative attribute value' do @@ -100,8 +115,13 @@ let(:non_matching_low_value_attributes) { { created: Time.parse('2016/03/31T23:59Z').to_i } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: date_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: 'ok') + sleep 1 end it 'validates the treatment is ON for correct number attribute value' do @@ -116,6 +136,8 @@ expect(subject.get_treatment(user, feature, non_matching_high_value_attributes)).to eq 'default' expect(subject.get_treatment(user, feature, missing_key_attributes)).to eq 'default' expect(subject.get_treatment(user, feature, nil_attributes)).to eq 'default' + sleep 1 + subject.destroy() end end end diff --git a/spec/engine/matchers/greater_than_or_equal_to_matcher_spec.rb b/spec/engine/matchers/greater_than_or_equal_to_matcher_spec.rb index 4a0b5b01..0307dae7 100644 --- a/spec/engine/matchers/greater_than_or_equal_to_matcher_spec.rb +++ b/spec/engine/matchers/greater_than_or_equal_to_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::GreaterThanOrEqualToMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:date_splits_json) do @@ -33,8 +33,12 @@ let(:non_matching_value_attributes) { { age: 29 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) end it 'validates the treatment is ON for correct attribute value' do @@ -55,8 +59,12 @@ let(:non_matching_negative_attributes) { { age: -91 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: negative_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) end it 'validates the treatment is ON for correct negative attribute value' do @@ -82,8 +90,12 @@ let(:non_matching_attributes_2) { { created: Time.parse('2015/04/01T00:01Z').to_i } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: date_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) end it 'validates the treatment is ON for correct attribute value' do @@ -98,6 +110,8 @@ expect(subject.get_treatment(user, feature, non_matching_attributes_2)).to eq 'default' expect(subject.get_treatment(user, feature, missing_key_attributes)).to eq 'default' expect(subject.get_treatment(user, feature, nil_attributes)).to eq 'default' + sleep 1 + subject.destroy() end end end diff --git a/spec/engine/matchers/less_than_or_equal_to_matcher_spec.rb b/spec/engine/matchers/less_than_or_equal_to_matcher_spec.rb index 858034ca..bd53166c 100644 --- a/spec/engine/matchers/less_than_or_equal_to_matcher_spec.rb +++ b/spec/engine/matchers/less_than_or_equal_to_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::LessThanOrEqualToMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:date_splits_json) do @@ -35,8 +35,13 @@ let(:non_matching_value_attributes) { { age: 31 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) + sleep 1 end it 'validates the treatment is ON for correct attribute value' do @@ -57,8 +62,13 @@ let(:non_matching_negative_attributes) { { age: -1 } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: negative_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) + sleep 1 end it 'validates the treatment is ON for correct negative attribute value' do @@ -81,8 +91,13 @@ let(:non_matching_attributes_2) { { created: Time.parse('2017/04/01T00:01Z').to_i } } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: date_splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) + sleep 1 end it 'validates the treatment is ON for correct attribute value' do @@ -102,14 +117,21 @@ context 'wrongly formed date' do before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: date_splits2_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) + sleep 1 end it 'validates the treatment is the default for wrongly formed date attribute' do subject.block_until_ready expect(subject.get_treatment(user, 'RUBY_isOnOrBeforeDateTimeWithAttributeValueThatDoesNotMatch', join: 'fer')) .to eq 'V1' + sleep 1 + subject.destroy() end end end diff --git a/spec/engine/matchers/whitelist_matcher_spec.rb b/spec/engine/matchers/whitelist_matcher_spec.rb index 7937dcee..e2472867 100644 --- a/spec/engine/matchers/whitelist_matcher_spec.rb +++ b/spec/engine/matchers/whitelist_matcher_spec.rb @@ -4,7 +4,7 @@ describe SplitIoClient::WhitelistMatcher do subject do - SplitIoClient::SplitFactory.new('test_api_key', logger: Logger.new('/dev/null'), streaming_enabled: false).client + SplitIoClient::SplitFactory.new('test_api_key', {logger: Logger.new('/dev/null'), streaming_enabled: false, impressions_refresh_rate: 9999, impressions_mode: :none, features_refresh_rate: 9999, telemetry_refresh_rate: 99999}).client end let(:splits_json) do @@ -20,8 +20,12 @@ let(:nil_attributes) { nil } before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:any, /https:\/\/telemetry.*/) + .to_return(status: 200, body: 'ok') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: splits_json) + stub_request(:any, /https:\/\/events.*/) + .to_return(status: 200, body: "", headers: {}) end it 'validates the treatment is ON for correct attribute value' do @@ -34,5 +38,7 @@ expect(subject.get_treatment(user, feature, non_matching_value_attributes)).to eq 'default' expect(subject.get_treatment(user, feature, missing_key_attributes)).to eq 'default' expect(subject.get_treatment(user, feature, nil_attributes)).to eq 'default' + sleep 1 + subject.destroy() end end diff --git a/spec/engine/push_manager_spec.rb b/spec/engine/push_manager_spec.rb index 4904408c..215535bf 100644 --- a/spec/engine/push_manager_spec.rb +++ b/spec/engine/push_manager_spec.rb @@ -15,7 +15,7 @@ let(:runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } let(:split_fetcher) { SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, runtime_producer) } let(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, runtime_producer) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(split_fetcher, config, splits_repository) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(split_fetcher, config, splits_repository, runtime_producer, segment_fetcher) } let(:segments_worker) { SplitIoClient::SSE::Workers::SegmentsWorker.new(segment_fetcher, config, segments_repository) } let(:push_status_queue) { Queue.new } let(:notification_manager_keeper) { SplitIoClient::SSE::NotificationManagerKeeper.new(config, runtime_producer, push_status_queue) } diff --git a/spec/engine/sync_manager_spec.rb b/spec/engine/sync_manager_spec.rb index 217fe77f..a8a5ee7a 100644 --- a/spec/engine/sync_manager_spec.rb +++ b/spec/engine/sync_manager_spec.rb @@ -48,7 +48,7 @@ let(:telemetry_api) { SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) } let(:telemetry_synchronizer) { SplitIoClient::Telemetry::Synchronizer.new(config, telemetry_consumers, init_producer, repositories, telemetry_api) } let(:status_manager) { SplitIoClient::Engine::StatusManager.new(config) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository, telemetry_runtime_producer, sync_params[:segment_fetcher]) } 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) } @@ -85,6 +85,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once expect(config.threads.size).to eq(11) + config.threads.values.each { |thread| Thread.kill(thread) } end end @@ -104,6 +105,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.once expect(config.threads.size).to eq(8) + config.threads.values.each { |thread| Thread.kill(thread) } end end @@ -125,6 +127,7 @@ sse_handler = sync_manager.instance_variable_get(:@sse_handler) expect(sse_handler.connected?).to eq(false) + config.threads.values.each { |thread| Thread.kill(thread) } end end diff --git a/spec/engine/synchronizer_spec.rb b/spec/engine/synchronizer_spec.rb index ea5327fa..86ae7882 100644 --- a/spec/engine/synchronizer_spec.rb +++ b/spec/engine/synchronizer_spec.rb @@ -217,6 +217,8 @@ expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333')).to have_been_made.times(10) expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111333&till=111555')).to have_been_made.once expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=111555&till=111555')).to have_been_made.once + synchronizer.stop_periodic_fetch + config.threads.values.each { |thread| Thread.kill(thread) } end end diff --git a/spec/engine_spec.rb b/spec/engine_spec.rb index 4107bd8f..63057aae 100644 --- a/spec/engine_spec.rb +++ b/spec/engine_spec.rb @@ -12,6 +12,8 @@ cache_adapter: cache_adapter, redis_namespace: 'test', mode: @mode, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, impressions_refresh_rate: 1, impression_listener: customer_impression_listener, streaming_enabled: false, @@ -69,12 +71,10 @@ before do @mode = cache_adapter.equal?(:memory) ? :standalone : :consumer - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/usage') - .to_return(status: 200, body: 'ok') - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: 'ok') + stub_request(:any, /https:\/\/telemetry.*/).to_return(status: 200, body: 'ok') + stub_request(:any, /https:\/\/events.*/).to_return(status: 200, body: '') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) + .to_return(status: 200, body: '') end before :each do @@ -83,15 +83,7 @@ context '#equal_to_set_matcher and get_treatment validation attributes' do before do - stub_request(:post, 'https://events.split.io/api/testImpressions/bulk') - .to_return(status: 200, body: '') - - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since') - .to_return(status: 200, body: '') - - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: '') - + sleep 1 load_splits(equal_to_set_matcher_json) subject.block_until_ready end @@ -132,9 +124,7 @@ context '#get_treatment' do before do - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since').to_return(status: 200, body: '') - stub_request(:post, 'https://events.split.io/api/testImpressions/bulk').to_return(status: 200, body: '') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/).to_return(status: 200, body: '') load_splits(all_keys_matcher_json) subject.block_until_ready @@ -312,6 +302,7 @@ before do load_splits(configurations_json) subject.block_until_ready + sleep 1 end it 'returns the config' do @@ -649,6 +640,7 @@ describe 'impressions' do before do load_splits(impressions_test_json) + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/).to_return(status: 200, body: '') end it 'returns correct impressions for get_treatments checking ' do @@ -732,8 +724,8 @@ end it 'returns control' do - stub_request(:post, 'https://events.split.io/api/testImpressions/bulk').to_return(status: 200, body: '') - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since').to_return(status: 200, body: '') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) + .to_return(status: 200, body: all_keys_matcher_json) subject.block_until_ready expect(subject.get_treatment('fake_user_id_1', 'test_feature')).to eq 'on' @@ -745,7 +737,7 @@ describe 'redis outage' do before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: all_keys_matcher_json) end @@ -757,7 +749,7 @@ describe 'events' do before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: all_keys_matcher_json) end @@ -785,9 +777,9 @@ context '#track' do before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/) .to_return(status: 200, body: all_keys_matcher_json) - end + end it 'event is not added when nil key' do expect(subject.instance_variable_get(:@events_repository)).not_to receive(:add) @@ -955,6 +947,7 @@ expect(log.string).to include "track: Traffic Type #{traffic_type_name} " \ "does not have any corresponding feature flags in this environment, make sure you're tracking " \ 'your events to a valid traffic type defined in the Split user interface' + subject.destroy end end end @@ -965,8 +958,8 @@ end before do - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') - .to_return(status: 200, body: all_keys_matcher_json) + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since.*/) + .to_return(status: 200, body: all_keys_matcher_json) end context 'standalone mode' do @@ -975,13 +968,13 @@ logger: Logger.new('/dev/null'), cache_adapter: :memory, mode: :standalone, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false).client end it 'fetch splits' do - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config') - .to_return(status: 200, body: 'ok') - subject.block_until_ready expect(subject.instance_variable_get(:@splits_repository).splits.size).to eq(1) end @@ -1003,6 +996,9 @@ redis_namespace: 'test', max_cache_size: 1, mode: :consumer, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false).client end @@ -1037,8 +1033,8 @@ def load_splits(splits_json) if @mode.equal?(:standalone) - stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1') - .to_return(status: 200, body: splits_json) + stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since.*/) + .to_return(status: 200, body: splits_json) else add_splits_to_repository(splits_json) end diff --git a/spec/integrations/in_memory_client_spec.rb b/spec/integrations/in_memory_client_spec.rb index f8a6f4d6..7a45cd74 100644 --- a/spec/integrations/in_memory_client_spec.rb +++ b/spec/integrations/in_memory_client_spec.rb @@ -40,13 +40,14 @@ mock_segment_changes('segment2', segment2, '-1') mock_segment_changes('segment2', segment2, '1470947453878') mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://events.split.io/api/testImpressions/bulk').to_return(status: 200, body: 'ok') - stub_request(:post, 'https://events.split.io/api/testImpressions/count').to_return(status: 200, body: 'ok') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: 'ok') + stub_request(:any, /https:\/\/events.*/).to_return(status: 200, body: '') + stub_request(:any, /https:\/\/telemetry.*/).to_return(status: 200, body: 'ok') +# sleep 1 end context '#get_treatment' do it 'returns treatments with FACUNDO_TEST feature and check impressions' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment('nico_test', 'FACUNDO_TEST')).to eq 'on' expect(client.get_treatment('mauro_test', 'FACUNDO_TEST')).to eq 'off' @@ -70,6 +71,7 @@ end it 'returns treatments with Test_Save_1 feature and check impressions' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment('1', 'Test_Save_1')).to eq 'on' expect(client.get_treatment('24', 'Test_Save_1')).to eq 'off' @@ -93,6 +95,7 @@ end it 'returns treatments with input validations' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment('nico_test', 'FACUNDO_TEST')).to eq 'on' expect(client.get_treatment('', 'FACUNDO_TEST')).to eq 'control' @@ -120,6 +123,7 @@ end it 'returns CONTROL with treatment doesnt exist' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') expect(client.get_treatment('nico_test', 'random_treatment')).to eq 'control' impressions = custom_impression_listener.queue @@ -127,6 +131,7 @@ end it 'returns CONTROL when server return 500' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') mock_split_changes_error expect(client.get_treatment('nico_test', 'FACUNDO_TEST')).to eq 'control' @@ -143,6 +148,7 @@ end it 'with multiple factories returns on' do +# stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') local_log = StringIO.new logger = Logger.new(local_log) @@ -161,18 +167,30 @@ factory1 = SplitIoClient::SplitFactory.new('api_key', logger: logger, impression_listener: impression_listener1, - streaming_enabled: false) + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, + streaming_enabled: false) factory2 = SplitIoClient::SplitFactory.new('another_key', logger: logger, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, impression_listener: impression_listener2, streaming_enabled: false) factory3 = SplitIoClient::SplitFactory.new('random_key', logger: logger, impression_listener: impression_listener3, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false) factory4 = SplitIoClient::SplitFactory.new('api_key', logger: logger, impression_listener: impression_listener4, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false) client1 = factory1.client @@ -200,11 +218,17 @@ expect(impressions2.size).to eq 1 expect(impressions3.size).to eq 1 expect(impressions4.size).to eq 1 + + client1.destroy() + client2.destroy() + client3.destroy() + client4.destroy() end end context '#get_treatment_with_config' do it 'returns treatments and configs with FACUNDO_TEST treatment and check impressions' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment_with_config('nico_test', 'FACUNDO_TEST')).to eq( treatment: 'on', @@ -234,6 +258,7 @@ end it 'returns treatments and configs with MAURO_TEST treatment and check impressions' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment_with_config('mauro', 'MAURO_TEST')).to eq( @@ -264,6 +289,7 @@ end it 'returns treatments with input validations' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment_with_config('nico_test', 'FACUNDO_TEST')).to eq( @@ -310,6 +336,7 @@ end it 'returns CONTROL with treatment doesnt exist' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready expect(client.get_treatment_with_config('nico_test', 'random_treatment')).to eq( @@ -323,6 +350,7 @@ end it 'returns CONTROL when server return 500' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') mock_split_changes_error expect(client.get_treatment_with_config('nico_test', 'FACUNDO_TEST')).to eq( @@ -343,6 +371,10 @@ end context '#get_treatments' do + before do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') + end + it 'returns treatments and check impressions' do client.block_until_ready result = client.get_treatments('nico_test', %w[FACUNDO_TEST MAURO_TEST Test_Save_1]) @@ -444,6 +476,7 @@ context '#get_treatments_with_config' do it 'returns treatments and check impressions' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready result = client.get_treatments_with_config('nico_test', %w[FACUNDO_TEST MAURO_TEST Test_Save_1]) expect(result[:FACUNDO_TEST]).to eq( @@ -483,6 +516,7 @@ end it 'returns treatments with input validation' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready result1 = client.get_treatments_with_config('nico_test', %w[FACUNDO_TEST "" nil]) result2 = client.get_treatments_with_config('', %w["" MAURO_TEST Test_Save_1]) @@ -521,6 +555,7 @@ end it 'returns CONTROL with treatment doesnt exist' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') client.block_until_ready result = client.get_treatments_with_config('nico_test', %w[FACUNDO_TEST random_treatment]) @@ -545,6 +580,7 @@ end it 'returns CONTROL when server return 500' do + stub_request(:get, "https://sdk.split.io/api/splitChanges?since=1506703262916").to_return(status: 200, body: 'ok') mock_split_changes_error result = client.get_treatments_with_config('nico_test', %w[FACUNDO_TEST MAURO_TEST Test_Save_1]) @@ -602,14 +638,23 @@ factory1 = SplitIoClient::SplitFactory.new('api_key_other', logger: logger, impression_listener: impression_listener1, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false) factory2 = SplitIoClient::SplitFactory.new('another_key_second', logger: logger, impression_listener: impression_listener2, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false) factory3 = SplitIoClient::SplitFactory.new('api_key_other', logger: logger, impression_listener: impression_listener3, + features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999, streaming_enabled: false) client1 = factory1.client @@ -645,6 +690,10 @@ expect(impressions1.size).to eq 1 expect(impressions2.size).to eq 1 expect(impressions3.size).to eq 1 + + client1.destroy() + client2.destroy() + client3.destroy() end end @@ -696,6 +745,7 @@ events = client.instance_variable_get(:@events_repository).batch expect(events.size).to eq 0 + client.destroy() end end end diff --git a/spec/integrations/push_client_spec.rb b/spec/integrations/push_client_spec.rb index 13f657a1..7bd17fb3 100644 --- a/spec/integrations/push_client_spec.rb +++ b/spec/integrations/push_client_spec.rb @@ -4,6 +4,11 @@ require 'http_server_mock' describe SplitIoClient do + let(:event_split_iff_update_no_compression) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850111, \\\"pcn\\\":1585948850110,\\\"c\\\": 0,\\\"d\\\":\\\"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ==\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } + let(:event_split_iff_update_incorrect_pcn) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850111, \\\"pcn\\\":1234,\\\"c\\\": 0,\\\"d\\\":\\\"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ==\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } + let(:event_split_iff_update_missing_definition) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850111, \\\"pcn\\\":1585948850110,\\\"c\\\": 0,\\\"d\\\":\\\"\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } + let(:event_split_iff_update_incorrect_compression) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850111, \\\"pcn\\\":1585948850110,\\\"c\\\": 4,\\\"d\\\":\\\"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ==\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } + let(:event_split_update_missing_change_number) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } let(:event_split_update_must_fetch) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850111}\",\"name\":\"asdasd\"}\n\n\r\n" } let(:event_split_update_must_not_fetch) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\": 1585948850100}\",\"name\":\"asdasd\"}\n\n\r\n" } let(:event_split_kill_must_fetch) { "fb\r\nid: 123\nevent: message\ndata: {\"id\":\"1\",\"clientId\":\"emptyClientId\",\"connectionId\":\"1\",\"timestamp\":1582045421733,\"channel\":\"mauroc\",\"data\":\"{\\\"type\\\" : \\\"SPLIT_KILL\\\",\\\"changeNumber\\\": 1585948850111, \\\"defaultTreatment\\\" : \\\"off_kill\\\", \\\"splitName\\\" : \\\"push_test\\\"}\",\"name\":\"asdasd\"}\n\n\r\n" } @@ -36,9 +41,13 @@ File.read(File.join(SplitIoClient.root, 'spec/test_data/integrations/auth_body_response.json')) end + before do + stub_request(:any, /https:\/\/events.*/).to_return(status: 200, body: '') + stub_request(:any, /https:\/\/telemetry.*/).to_return(status: 200, body: 'ok') + end + context 'SPLIT_UPDATE' do it 'processing split update event' do - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_splits_request(splits, '-1') mock_splits_request(splits2, '1585948850109') mock_splits_request(splits3, '1585948850110') @@ -56,7 +65,10 @@ factory = SplitIoClient::SplitFactory.new( 'test_api_key', streaming_service_url: streaming_service_url, - auth_service_url: auth_service_url + auth_service_url: auth_service_url, +# features_refresh_rate: 9999, + telemetry_refresh_rate: 99999, + impressions_refresh_rate: 99999 ) client = factory.client @@ -66,6 +78,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.at_least_times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850109')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.times(1) + client.destroy end end @@ -73,7 +86,6 @@ mock_splits_request(splits, -1) mock_splits_request(splits2, 1_585_948_850_109) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_server do |server| server.setup_response('/') do |_, res| @@ -97,6 +109,152 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850109')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.times(0) + client.destroy + end + end + + it 'processing split update missing change number' do + mock_splits_request(splits, -1) + mock_splits_request(splits2, 1_585_948_850_109) + mock_segment_changes('segment3', segment3, '-1') + stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') + + mock_server do |server| + server.setup_response('/') do |_, res| + send_content(res, event_split_update_missing_change_number) + end + + stub_request(:get, auth_service_url).to_return(status: 200, body: auth_body_response) + + streaming_service_url = server.base_uri + factory = SplitIoClient::SplitFactory.new( + 'test_api_key', + streaming_enabled: true, + streaming_service_url: streaming_service_url, + auth_service_url: auth_service_url + ) + + client = factory.client + client.block_until_ready(1) + sleep(1) + expect(client.get_treatment('admin', 'push_test')).to eq('on') + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850109')).to have_been_made.times(1) + expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.times(0) + end + end + + it 'processing split iff update event' do + mock_splits_request(splits, -1) + mock_splits_request(splits2, '1585948850109') + mock_splits_request(splits3, '1585948850110') + mock_segment_changes('segment3', segment3, '-1') + stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') + mock_server do |server| + server.setup_response('/') do |_, res| + send_content(res, event_split_iff_update_no_compression) + end + + stub_request(:get, auth_service_url).to_return(status: 200, body: auth_body_response) + + streaming_service_url = server.base_uri + factory = SplitIoClient::SplitFactory.new( + 'test_api_key', + streaming_service_url: streaming_service_url, + auth_service_url: auth_service_url + ) + + client = factory.client + client.block_until_ready + sleep(2) + expect(client.get_treatment('admin', 'bilal_split')).to eq('off') + end + end + + it 'processing incorrect split iff update event' do + mock_splits_request(splits, -1) + mock_splits_request(splits2, '1585948850109') + mock_splits_request(splits3, '1585948850110') + mock_segment_changes('segment3', segment3, '-1') + stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850111').to_return(status: 200, body: '') + mock_server do |server| + server.setup_response('/') do |_, res| + send_content(res, event_split_iff_update_incorrect_pcn) + end + + stub_request(:get, auth_service_url).to_return(status: 200, body: auth_body_response) + + streaming_service_url = server.base_uri + factory = SplitIoClient::SplitFactory.new( + 'test_api_key', + streaming_service_url: streaming_service_url, + auth_service_url: auth_service_url + ) + + client = factory.client + client.block_until_ready + sleep(2) + expect(client.get_treatment('admin', 'bilal_split')).to eq('control') + expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + end + end + + it 'processing split iff update event missing definition' do + mock_splits_request(splits, -1) + mock_splits_request(splits2, '1585948850109') + mock_splits_request(splits3, '1585948850110') + mock_segment_changes('segment3', segment3, '-1') + stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850111').to_return(status: 200, body: '') + mock_server do |server| + server.setup_response('/') do |_, res| + send_content(res, event_split_iff_update_missing_definition) + end + + stub_request(:get, auth_service_url).to_return(status: 200, body: auth_body_response) + + streaming_service_url = server.base_uri + factory = SplitIoClient::SplitFactory.new( + 'test_api_key', + streaming_service_url: streaming_service_url, + auth_service_url: auth_service_url + ) + + client = factory.client + client.block_until_ready + sleep(2) + expect(client.get_treatment('admin', 'bilal_split')).to eq('control') + expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + end + end + + it 'processing split iff update event incorrect compression' do + mock_splits_request(splits, -1) + mock_splits_request(splits2, '1585948850109') + mock_splits_request(splits3, '1585948850110') + mock_segment_changes('segment3', segment3, '-1') + stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850111').to_return(status: 200, body: '') + mock_server do |server| + server.setup_response('/') do |_, res| + send_content(res, event_split_iff_update_incorrect_compression) + end + + stub_request(:get, auth_service_url).to_return(status: 200, body: auth_body_response) + + streaming_service_url = server.base_uri + factory = SplitIoClient::SplitFactory.new( + 'test_api_key', + streaming_service_url: streaming_service_url, + auth_service_url: auth_service_url + ) + + client = factory.client + client.block_until_ready + sleep(2) + expect(client.get_treatment('admin', 'bilal_split')).to eq('control') + expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') end end end @@ -107,7 +265,6 @@ mock_splits_request(splits2, '1585948850109') mock_splits_request(splits3, '1585948850110') mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_server do |server| server.setup_response('/') do |_, res| @@ -130,6 +287,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850109')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.at_least_times(1) + client.destroy end end @@ -137,7 +295,6 @@ mock_splits_request(splits, -1) mock_splits_request(splits2, 1_585_948_850_109) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110').to_return(status: 200, body: '') mock_server do |server| @@ -162,6 +319,7 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850109')).to have_been_made.times(1) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.times(0) + client.destroy end end end @@ -170,7 +328,6 @@ it 'processing segment update event with fetch' do mock_splits_request(splits, -1) mock_splits_request(splits2, 1_585_948_850_109) - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1&till=1470947453879').to_return(status: 200, body: '') stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1') .to_return({ status: 200, body: segment3 }, { status: 200, body: segment3 }, { status: 200, body: segment3_updated }) @@ -194,13 +351,13 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('test_in_segment', 'feature_segment')).to eq('def_test') + client.destroy end end it 'processing segment update event without fetch' do mock_splits_request(splits, -1) mock_splits_request(splits2, 1_585_948_850_109) - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment3?since=-1') .to_return(status: 200, body: segment3) @@ -223,13 +380,13 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('test_in_segment', 'feature_segment')).to eq('on') + client.destroy end end end context 'OCCUPANCY' do it 'occupancy event with publishers available' do - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_splits_request(splits, -1) mock_splits_request(splits2, 1_585_948_850_109) mock_splits_request(splits3, 1_585_948_850_110) @@ -255,6 +412,7 @@ client.block_until_ready(1) sleep(3) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end @@ -263,7 +421,6 @@ mock_splits_request(splits2, 1_585_948_850_109) mock_splits_request(splits3, 1_585_948_850_110) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_server do |server| server.setup_response('/') do |_, res| @@ -284,6 +441,7 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end end @@ -294,7 +452,6 @@ mock_splits_request(splits2, 1_585_948_850_109) mock_splits_request(splits3, 1_585_948_850_110) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_server do |server| server.setup_response('/') do |_, res| @@ -315,6 +472,7 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end @@ -323,7 +481,6 @@ mock_splits_request(splits2, 1_585_948_850_109) mock_splits_request(splits3, 1_585_948_850_110) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') mock_server do |server| server.setup_response('/') do |_, res| @@ -344,6 +501,7 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end @@ -352,7 +510,6 @@ mock_splits_request(splits2, 1_585_948_850_109) mock_splits_request(splits3, 1_585_948_850_110) mock_segment_changes('segment3', segment3, '-1') - stub_request(:post, 'https://telemetry.split.io/api/v1/metrics/config').to_return(status: 200, body: '') stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850111').to_return(status: 200, body: '') mock_server do |server| @@ -374,6 +531,7 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end end diff --git a/spec/sse/event_source/client_spec.rb b/spec/sse/event_source/client_spec.rb index ae65f5a4..ffae8516 100644 --- a/spec/sse/event_source/client_spec.rb +++ b/spec/sse/event_source/client_spec.rb @@ -30,7 +30,7 @@ } end let(:synchronizer) { SplitIoClient::Engine::Synchronizer.new(repositories, config, parameters) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, repositories[:splits]) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, repositories[:splits], telemetry_runtime_producer, parameters[:segment_fetcher]) } 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) } diff --git a/spec/sse/sse_handler_spec.rb b/spec/sse/sse_handler_spec.rb index 231fb0be..28fcb1ed 100644 --- a/spec/sse/sse_handler_spec.rb +++ b/spec/sse/sse_handler_spec.rb @@ -31,7 +31,7 @@ } end let(:synchronizer) { SplitIoClient::Engine::Synchronizer.new(repositories, config, parameters) } - let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository) } + let(:splits_worker) { SplitIoClient::SSE::Workers::SplitsWorker.new(synchronizer, config, splits_repository, telemetry_runtime_producer, parameters[:segment_fetcher]) } 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/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 0bfc7845..9ac38740 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' require 'http_server_mock' +require 'byebug' describe SplitIoClient::SSE::Workers::SplitsWorker do subject { SplitIoClient::SSE::Workers::SplitsWorker } @@ -16,8 +17,15 @@ let(:splits_repository) { SplitIoClient::Cache::Repositories::SplitsRepository.new(config) } 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(:segment_fetcher) { SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer) } + let(:event_split_update_no_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 0,"d":"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ=="}'), 'test') } + let(:event_split_update_gzip_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 1,"d":"H4sIAAkVZWQC/8WST0+DQBDFv0qzZ0ig/BF6a2xjGismUk2MaZopzOKmy9Isy0EbvrtDwbY2Xo233Tdv5se85cCMBs5FtvrYYwIlsglratTMYiKns+chcAgc24UwsF0Xczt2cm5z8Jw8DmPH9wPyqr5zKyTITb2XwpA4TJ5KWWVgRKXYxHWcX/QUkVi264W+68bjaGyxupdCJ4i9KPI9UgyYpibI9Ha1eJnT/J2QsnNxkDVaLEcOjTQrjWBKVIasFefky95BFZg05Zb2mrhh5I9vgsiL44BAIIuKTeiQVYqLotHHLyLOoT1quRjub4fztQuLxj89LpePzytClGCyd9R3umr21ErOcitUh2PTZHY29HN2+JGixMxUujNfvMB3+u2pY1AXySad3z3Mk46msACDp8W7jhly4uUpFt3qD33vDAx0gLpXkx+P1GusbdcE24M2F4uaywwVEWvxSa1Oa13Vjvn2RXradm0xCVuUVBJqNCBGV0DrX4OcLpeb+/lreh3jH8Uw/JQj3UhkxPgCCurdEnADAAA="}'), 'test') } + let(:event_split_update_zlib_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 2,"d":"eJzEUtFq20AQ/JUwz2c4WZZr3ZupTQh1FKjcQinGrKU95cjpZE6nh9To34ssJ3FNX0sfd3Zm53b2TgietDbF9vXIGdUMha5lDwFTQiGOmTQlchLRPJlEEZeTVJZ6oimWZTpP5WyWQMCNyoOxZPft0ZoA8TZ5aW1TUDCNg4qk/AueM5dQkyiez6IonS6mAu0IzWWSxovFLBZoA4WuhcLy8/bh+xoCL8bagaXJtixQsqbOhq1nCjW7AIVGawgUz+Qqzrr6wB4qmi9m00/JIk7TZCpAtmqgpgJF47SpOn9+UQt16s9YaS71z9NHOYQFha9Pm83Tty0EagrFM/t733RHqIFZH4wb7LDMVh+Ecc4Lv+ZsuQiNH8hXF3hLv39XXNCHbJ+v7x/X2eDmuKLA74sPihVr47jMuRpWfxy1Kwo0GLQjmv1xpBFD3+96gSP5cLVouM7QQaA1vxhK9uKmd853bEZS9jsBSwe2UDDu7mJxd2Mo/muQy81m/2X9I7+N8R/FcPmUd76zjH7X/w4AAP//90glTw=="}'), 'test') } + 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(:segments_repository) { SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) } let(:synchronizer) do - segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) impressions_api = SplitIoClient::Api::Impressions.new(api_key, config, telemetry_runtime_producer) @@ -27,8 +35,8 @@ } params = { - split_fetcher: SplitIoClient::Cache::Fetchers::SplitFetcher.new(splits_repository, api_key, config, telemetry_runtime_producer), - segment_fetcher: SplitIoClient::Cache::Fetchers::SegmentFetcher.new(segments_repository, api_key, config, telemetry_runtime_producer), + split_fetcher: split_fetcher, + segment_fetcher: segment_fetcher, imp_counter: SplitIoClient::Engine::Common::ImpressionCounter.new, impressions_sender_adapter: SplitIoClient::Cache::Senders::ImpressionsSenderAdapter.new(config, telemetry_api, impressions_api), impressions_api: SplitIoClient::Api::Impressions.new(api_key, config, telemetry_runtime_producer) @@ -43,9 +51,9 @@ stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918').to_return(status: 200, body: '{"splits": [],"since": 1506703262918,"till": 1506703262918}') stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262918&till=1506703262919').to_return(status: 200, body: '{"splits": [],"since": 1506703262919,"till": 1506703262919}') - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start - worker.add_to_queue(1_506_703_262_919) + worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262919}'), 'test')) sleep 1 @@ -58,9 +66,9 @@ stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262916}') stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262916').to_return(status: 200, body: '{"splits": [],"since": 1506703262916,"till": 1506703262918}') - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start - worker.add_to_queue(1_506_703_262_918) + 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?since=1506703262916')).to have_been_made.once @@ -69,17 +77,17 @@ it 'must not trigger fetch' do stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262916}') - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start - worker.add_to_queue(1_506_703_262_916) + 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?since=1506703262916')).to have_been_made.times(0) end it 'without start, must not fetch' do - worker = subject.new(synchronizer, config, splits_repository) - worker.add_to_queue(1_506_703_262_918) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + 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?since=1506703262916')).to have_been_made.times(0) end @@ -100,9 +108,9 @@ it 'must kill split and trigger fetch' do stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262916').to_return(status: 200, body: '{"splits": [],"since": 1506703262916,"till": 1506703262918}') - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start - worker.kill_split(1_506_703_262_918, 'FACUNDO_TEST', 'on') + 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') sleep(1) @@ -114,10 +122,10 @@ end it 'must kill split and must not trigger fetch' do - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start - worker.kill_split(1_506_703_262_916, 'FACUNDO_TEST', 'on') + 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') sleep(1) @@ -129,6 +137,61 @@ end end + context 'instant ff update split notification' do + it 'decode and decompress split update data' do + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker.start + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_no_compression) + sleep 1 + split = splits_repository.get_split('bilal_split') + expect(split[:name] == 'bilal_split') + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_gzip_compression) + sleep 1 + split = splits_repository.get_split('bilal_split') + expect(split[:name] == 'bilal_split') + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_zlib_compression) + sleep 1 + split = splits_repository.get_split('bilal_split') + expect(split[:name] == 'bilal_split') + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_archived_no_compression) + sleep 1 + expect(splits_repository.exists?('bilal_split') == false) + end + + it 'instant ff update split notification with segment matcher.' do + stub_request(:get, 'https://sdk.split.io/api/splitChanges?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) + worker.start + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_segments) + sleep 1 + + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/maur-2?since=-1')).to have_been_made.once + expect(segments_repository.used_segment_names[0]).to eq('maur-2') + end + + it 'should not update if definition is nil' do + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1234').to_return(status: 200, body: '{"splits": [],"since": -1,"till": 1506703262918}') + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) + worker.start + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_no_definition) + sleep 1 + expect(splits_repository.exists?('bilal_split') == false) + end + end + private def mock_split_changes(splits_json) diff --git a/spec/telemetry/synchronizer_spec.rb b/spec/telemetry/synchronizer_spec.rb index 48c5acfb..94b4e716 100644 --- a/spec/telemetry/synchronizer_spec.rb +++ b/spec/telemetry/synchronizer_spec.rb @@ -42,8 +42,8 @@ let(:init_producer) { SplitIoClient::Telemetry::InitProducer.new(config) } let(:telemetry_api) { SplitIoClient::Api::TelemetryApi.new(config, api_key, runtime_producer) } let(:telemetry_consumers) { { init: init_consumer, runtime: runtime_consumer, evaluation: evaluation_consumer } } - let(:body_usage) { "{\"lS\":{\"sp\":111111222,\"se\":111111222,\"im\":111111222,\"ic\":111111222,\"ev\":111111222,\"te\":111111222,\"to\":111111222},\"mL\":{\"t\":[0,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ts\":[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tc\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tcs\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tr\":[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"mE\":{\"t\":2,\"ts\":1,\"tc\":1,\"tcs\":0,\"tr\":1},\"hE\":{\"sp\":{},\"se\":{\"400\":1},\"im\":{},\"ic\":{},\"ev\":{\"500\":2,\"501\":1},\"te\":{},\"to\":{}},\"hL\":{\"sp\":[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"se\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"im\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ic\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ev\":[0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"te\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"to\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"tR\":1,\"aR\":1,\"iQ\":3,\"iDe\":1,\"iDr\":2,\"spC\":3,\"seC\":3,\"skC\":7,\"sL\":444555,\"eQ\":4,\"eD\":1,\"sE\":[{\"e\":50,\"d\":222222333,\"t\":222222333},{\"e\":70,\"d\":0,\"t\":222222333},{\"e\":70,\"d\":1,\"t\":222222333}],\"t\":[\"tag-1\",\"tag-2\"]}" } - let(:empty_body_usage) { "{\"lS\":{\"sp\":0,\"se\":0,\"im\":0,\"ic\":0,\"ev\":0,\"te\":0,\"to\":0},\"mL\":{\"t\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ts\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tc\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tcs\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tr\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"mE\":{\"t\":0,\"ts\":0,\"tc\":0,\"tcs\":0,\"tr\":0},\"hE\":{\"sp\":{},\"se\":{},\"im\":{},\"ic\":{},\"ev\":{},\"te\":{},\"to\":{}},\"hL\":{\"sp\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"se\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"im\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ic\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ev\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"te\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"to\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"tR\":0,\"aR\":0,\"iQ\":0,\"iDe\":0,\"iDr\":0,\"spC\":0,\"seC\":0,\"skC\":0,\"sL\":0,\"eQ\":0,\"eD\":0,\"sE\":[],\"t\":[]}" } + let(:body_usage) { "{\"lS\":{\"sp\":111111222,\"se\":111111222,\"im\":111111222,\"ic\":111111222,\"ev\":111111222,\"te\":111111222,\"to\":111111222},\"mL\":{\"t\":[0,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ts\":[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tc\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tcs\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tr\":[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"mE\":{\"t\":2,\"ts\":1,\"tc\":1,\"tcs\":0,\"tr\":1},\"hE\":{\"sp\":{},\"se\":{\"400\":1},\"im\":{},\"ic\":{},\"ev\":{\"500\":2,\"501\":1},\"te\":{},\"to\":{}},\"hL\":{\"sp\":[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"se\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"im\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ic\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ev\":[0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"te\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"to\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"tR\":1,\"aR\":1,\"iQ\":3,\"iDe\":1,\"iDr\":2,\"spC\":3,\"seC\":3,\"skC\":7,\"sL\":444555,\"eQ\":4,\"eD\":1,\"sE\":[{\"e\":50,\"d\":222222333,\"t\":222222333},{\"e\":70,\"d\":0,\"t\":222222333},{\"e\":70,\"d\":1,\"t\":222222333}],\"t\":[\"tag-1\",\"tag-2\"],\"ufs\":{\"sp\":5}}" } + let(:empty_body_usage) { "{\"lS\":{\"sp\":0,\"se\":0,\"im\":0,\"ic\":0,\"ev\":0,\"te\":0,\"to\":0},\"mL\":{\"t\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ts\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tc\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tcs\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"tr\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"mE\":{\"t\":0,\"ts\":0,\"tc\":0,\"tcs\":0,\"tr\":0},\"hE\":{\"sp\":{},\"se\":{},\"im\":{},\"ic\":{},\"ev\":{},\"te\":{},\"to\":{}},\"hL\":{\"sp\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"se\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"im\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ic\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"ev\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"te\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"to\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"tR\":0,\"aR\":0,\"iQ\":0,\"iDe\":0,\"iDr\":0,\"spC\":0,\"seC\":0,\"skC\":0,\"sL\":0,\"eQ\":0,\"eD\":0,\"sE\":[],\"t\":[],\"ufs\":{\"sp\":0}}" } let(:body_custom_config) { "{\"oM\":0,\"sE\":true,\"st\":\"memory\",\"rR\":{\"sp\":100,\"se\":110,\"im\":120,\"ev\":130,\"te\":140},\"iQ\":5000,\"eQ\":500,\"iM\":0,\"uO\":{\"s\":true,\"e\":true,\"a\":true,\"st\":false,\"t\":false},\"iL\":false,\"hP\":false,\"aF\":1,\"rF\":1,\"tR\":100,\"bT\":2,\"nR\":1,\"t\":[],\"i\":null}" } let(:body_default_config) { "{\"oM\":0,\"sE\":true,\"st\":\"memory\",\"rR\":{\"sp\":60,\"se\":60,\"im\":300,\"ev\":60,\"te\":3600},\"iQ\":5000,\"eQ\":500,\"iM\":0,\"uO\":{\"s\":false,\"e\":false,\"a\":false,\"st\":false,\"t\":false},\"iL\":false,\"hP\":false,\"aF\":1,\"rF\":1,\"tR\":500,\"bT\":0,\"nR\":0,\"t\":[],\"i\":null}" } let(:body_proxy_config) { "{\"oM\":0,\"sE\":true,\"st\":\"memory\",\"rR\":{\"sp\":60,\"se\":60,\"im\":300,\"ev\":60,\"te\":3600},\"iQ\":5000,\"eQ\":500,\"iM\":0,\"uO\":{\"s\":false,\"e\":false,\"a\":false,\"st\":false,\"t\":false},\"iL\":false,\"hP\":true,\"aF\":1,\"rF\":1,\"tR\":500,\"bT\":0,\"nR\":0,\"t\":[],\"i\":null}" } @@ -100,6 +100,11 @@ runtime_producer.record_streaming_event(SplitIoClient::Telemetry::Domain::Constants::SYNC_MODE, 0, 222_222_333) runtime_producer.record_streaming_event(SplitIoClient::Telemetry::Domain::Constants::SYNC_MODE, 1, 222_222_333) runtime_producer.record_session_length(444_555) + runtime_producer.record_updates_from_sse(SplitIoClient::Telemetry::Domain::Constants::SPLITS) + runtime_producer.record_updates_from_sse(SplitIoClient::Telemetry::Domain::Constants::SPLITS) + runtime_producer.record_updates_from_sse(SplitIoClient::Telemetry::Domain::Constants::SPLITS) + runtime_producer.record_updates_from_sse(SplitIoClient::Telemetry::Domain::Constants::SPLITS) + runtime_producer.record_updates_from_sse(SplitIoClient::Telemetry::Domain::Constants::SPLITS) evaluation_producer.record_latency(SplitIoClient::Telemetry::Domain::Constants::TREATMENT, 1) evaluation_producer.record_latency(SplitIoClient::Telemetry::Domain::Constants::TREATMENT, 3) evaluation_producer.record_latency(SplitIoClient::Telemetry::Domain::Constants::TREATMENT, 2) diff --git a/spec/test_data/regexp/data.txt b/spec/test_data/regexp/data.txt index d776a132..973570c9 100644 --- a/spec/test_data/regexp/data.txt +++ b/spec/test_data/regexp/data.txt @@ -115,8 +115,6 @@ perl\B#perl stuff#false ^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$#john@doe.com#true ^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$#john@doe.something#false ^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$#johndoe.sg#false -^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$#http://split.io/about#true -^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$#http://google.com/some/file!.html#false ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$#73.60.124.136#true ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$#256.60.124.136#false ^\d+$#123#true diff --git a/splitclient-rb.gemspec b/splitclient-rb.gemspec index fb6a32c8..a8adca6a 100644 --- a/splitclient-rb.gemspec +++ b/splitclient-rb.gemspec @@ -37,6 +37,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'allocation_stats', '~> 0.1' spec.add_development_dependency 'bundler', '~> 2.2' + spec.add_development_dependency 'byebug', '~> 11.1' spec.add_development_dependency 'pry', '~> 0.14' spec.add_development_dependency 'pry-nav', '~> 1.0' spec.add_development_dependency 'rake', '~> 13.0'