From d1157c40bc4b4fcf66058655f3d8e90ffff08e3b Mon Sep 17 00:00:00 2001 From: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> Date: Thu, 18 May 2023 13:34:57 -0300 Subject: [PATCH 01/25] Create CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS 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 From 1a3cd09c04cc61f95bc52f6823f988ad99b983b9 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 31 May 2023 08:25:20 -0700 Subject: [PATCH 02/25] added iff compression and decoding message --- .../sse/notification_processor.rb | 2 +- .../sse/workers/splits_worker.rb | 26 +++++++++++++++++++ spec/sse/workers/splits_worker_spec.rb | 20 ++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/splitclient-rb/sse/notification_processor.rb b/lib/splitclient-rb/sse/notification_processor.rb index 6bde38a3..51c8616a 100644 --- a/lib/splitclient-rb/sse/notification_processor.rb +++ b/lib/splitclient-rb/sse/notification_processor.rb @@ -26,7 +26,7 @@ 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.split_update(notification) end def process_split_kill(notification) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 48bccfa2..27b9c71f 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -32,6 +32,20 @@ def stop SplitIoClient::Helpers::ThreadHelper.stop(:split_update_worker, @config) end + def split_update(notification) + if @splits_repository.get_change_number() == notification.data['pcn'] + begin + @new_split = JSON.parse(get_encoded_definition(notification), symbolize_names: true) + @splits_repository.add_split(@new_split) + @splits_repository.set_change_number(notification.data['changeNumber']) + return + rescue Exception => e + @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled + end + end + add_to_queue(notification.data['changeNumber']) + end + def add_to_queue(change_number) @config.logger.debug("feature_flags_worker add to queue #{change_number}") @queue.push(change_number) @@ -45,6 +59,18 @@ def kill_split(change_number, split_name, default_treatment) add_to_queue(change_number) end + def get_encoded_definition(notification) + case notification.data[:c] + when 0 + return Base64.decode64(notification.data[:d]) + when 1 + gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(notification.data[:d]))) + return gz.read + when 2 + return Zlib::Inflate.inflate(Base64.decode64(notification.data[:d])) + end + end + private def perform diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 0bfc7845..8d5fb88f 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,6 +17,9 @@ 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(:event_split_update_no_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, {"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, {"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, {"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(:synchronizer) do segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) @@ -129,6 +133,22 @@ end end + context 'update split notification' do + it 'decode and decompress split update data' do + worker = subject.new(synchronizer, config, splits_repository) + worker.start + split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_no_compression)) + expect(split_definition['name'] == 'bilal_split') + + split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_gzip_compression)) + expect(split_definition['name'] == 'bilal_split') + + split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_zlib_compression)) + expect(split_definition['name'] == 'bilal_split') + + end + end + private def mock_split_changes(splits_json) From ba9989e9556113ba4fce9bfe94c26fceb82e7611 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 31 May 2023 08:30:50 -0700 Subject: [PATCH 03/25] moved decode function to private --- lib/splitclient-rb/sse/workers/splits_worker.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 27b9c71f..1e603ca3 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -59,6 +59,8 @@ def kill_split(change_number, split_name, default_treatment) add_to_queue(change_number) end + private + def get_encoded_definition(notification) case notification.data[:c] when 0 @@ -71,8 +73,6 @@ def get_encoded_definition(notification) end end - private - def perform while (change_number = @queue.pop) @config.logger.debug("feature_flags_worker change_number dequeue #{change_number}") From 1cca90e6f822ee32d8fc5405a0f0e70fb5a74c80 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 31 May 2023 13:03:19 -0700 Subject: [PATCH 04/25] polish and refactor --- lib/splitclient-rb.rb | 1 + .../helpers/decryption_helper.rb | 19 ++++++++ .../sse/notification_processor.rb | 8 +--- .../sse/workers/splits_worker.rb | 45 +++++++++---------- spec/sse/workers/splits_worker_spec.rb | 41 ++++++++++------- 5 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 lib/splitclient-rb/helpers/decryption_helper.rb diff --git a/lib/splitclient-rb.rb b/lib/splitclient-rb.rb index 57ea263e..a69aa23f 100644 --- a/lib/splitclient-rb.rb +++ b/lib/splitclient-rb.rb @@ -41,6 +41,7 @@ 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/split_factory' require 'splitclient-rb/split_factory_builder' require 'splitclient-rb/split_config' diff --git a/lib/splitclient-rb/helpers/decryption_helper.rb b/lib/splitclient-rb/helpers/decryption_helper.rb new file mode 100644 index 00000000..c7c2af18 --- /dev/null +++ b/lib/splitclient-rb/helpers/decryption_helper.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module SplitIoClient + module Helpers + class DecryptionHelper + def self.get_encoded_definition(compression, data) + case compression + when 0 + return Base64.decode64(data) + when 1 + gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(data))) + return gz.read + when 2 + return Zlib::Inflate.inflate(Base64.decode64(data)) + end + end + end + end +end diff --git a/lib/splitclient-rb/sse/notification_processor.rb b/lib/splitclient-rb/sse/notification_processor.rb index 51c8616a..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.split_update(notification) + @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 1e603ca3..e781f460 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true +require 'byebug' module SplitIoClient module SSE @@ -33,9 +34,10 @@ def stop end def split_update(notification) +# byebug if @splits_repository.get_change_number() == notification.data['pcn'] begin - @new_split = JSON.parse(get_encoded_definition(notification), symbolize_names: true) + @new_split = JSON.parse(SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']), symbolize_names: true) @splits_repository.add_split(@new_split) @splits_repository.set_change_number(notification.data['changeNumber']) return @@ -43,40 +45,33 @@ def split_update(notification) @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled end end - add_to_queue(notification.data['changeNumber']) + @synchronizer.fetch_splits(notification.data['changeNumber']) 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 + def kill_split(notification) + return if @splits_repository.get_change_number.to_i > notification.data['changeNumber'] - @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) + @config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}") + @splits_repository.kill(notification.data['changeNumber'], notification.data['splitName'], notification.data['defaultTreatment']) + @synchronizer.fetch_splits(notification.data['changeNumber']) end private - def get_encoded_definition(notification) - case notification.data[:c] - when 0 - return Base64.decode64(notification.data[:d]) - when 1 - gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(notification.data[:d]))) - return gz.read - when 2 - return Zlib::Inflate.inflate(Base64.decode64(notification.data[:d])) - end - end - 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 + split_update(notification) + when SSE::EventSource::EventTypes::SPLIT_KILL + kill_split(notification) + end end end diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 8d5fb88f..82a79fb2 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -17,9 +17,9 @@ 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(:event_split_update_no_compression) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, {"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, {"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, {"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_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(:synchronizer) do segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) @@ -49,7 +49,7 @@ worker = subject.new(synchronizer, config, splits_repository) 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 @@ -64,7 +64,7 @@ worker = subject.new(synchronizer, config, splits_repository) 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 @@ -75,7 +75,7 @@ worker = subject.new(synchronizer, config, splits_repository) 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) @@ -83,7 +83,7 @@ it 'without start, must not fetch' do worker = subject.new(synchronizer, config, splits_repository) - 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')) expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1506703262916')).to have_been_made.times(0) end @@ -106,7 +106,7 @@ worker = subject.new(synchronizer, config, splits_repository) worker.start - worker.kill_split(1_506_703_262_918, 'FACUNDO_TEST', 'on') + worker.kill_split(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262918}'), 'test')) sleep(1) @@ -121,7 +121,7 @@ worker = subject.new(synchronizer, config, splits_repository) worker.start - worker.kill_split(1_506_703_262_916, 'FACUNDO_TEST', 'on') + worker.kill_split(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262916}'), 'test')) sleep(1) @@ -133,18 +133,27 @@ end end - context 'update split notification' do + context 'instant ff update split notification' do it 'decode and decompress split update data' do worker = subject.new(synchronizer, config, splits_repository) worker.start - split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_no_compression)) - expect(split_definition['name'] == 'bilal_split') + 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') - split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_gzip_compression)) - expect(split_definition['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') - split_definition = JSON.parse(worker.send(:get_encoded_definition, event_split_update_zlib_compression)) - expect(split_definition['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') end end From a75db9c1224eddc4d9a0a5b2fab9a9b016dc0168 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 31 May 2023 13:05:48 -0700 Subject: [PATCH 05/25] polish --- lib/splitclient-rb/sse/workers/splits_worker.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index e781f460..35137d52 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require 'byebug' module SplitIoClient module SSE @@ -34,7 +33,6 @@ def stop end def split_update(notification) -# byebug if @splits_repository.get_change_number() == notification.data['pcn'] begin @new_split = JSON.parse(SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']), symbolize_names: true) From 5a8491780fa34bc2b52f7363d77da64cc9f36dd6 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 1 Jun 2023 09:01:48 -0700 Subject: [PATCH 06/25] used constants for compression level --- lib/splitclient-rb/helpers/decryption_helper.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/splitclient-rb/helpers/decryption_helper.rb b/lib/splitclient-rb/helpers/decryption_helper.rb index c7c2af18..b8e3dc22 100644 --- a/lib/splitclient-rb/helpers/decryption_helper.rb +++ b/lib/splitclient-rb/helpers/decryption_helper.rb @@ -1,16 +1,20 @@ # 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 0 + when NO_COMPRESSION return Base64.decode64(data) - when 1 + when GZIP_COMPRESSION gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(data))) return gz.read - when 2 + when ZLIB_COMPRESSION return Zlib::Inflate.inflate(Base64.decode64(data)) end end From c1c7b3baaf570779f60d65b84aaaded83a7e49c8 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 1 Jun 2023 10:50:53 -0700 Subject: [PATCH 07/25] iff e2e and edge cases --- spec/integrations/push_client_spec.rb | 150 ++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/spec/integrations/push_client_spec.rb b/spec/integrations/push_client_spec.rb index 13f657a1..a44452aa 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" } @@ -99,6 +104,151 @@ expect(a_request(:get, 'https://sdk.split.io/api/splitChanges?since=1585948850110')).to have_been_made.times(0) 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 context 'SPLIT_KILL' do From 8e9d1b52ceab3d11ca4cde7a5629f0ef83a86833 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 5 Jun 2023 08:17:45 -0700 Subject: [PATCH 08/25] polish and fixes --- .../sse/workers/splits_worker.rb | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 35137d52..1a258765 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -33,13 +33,22 @@ def stop end def split_update(notification) - if @splits_repository.get_change_number() == notification.data['pcn'] + return if @splits_repository.get_change_number.to_i > notification.data['changeNumber'] + + if @splits_repository.get_change_number == notification.data['pcn'] begin - @new_split = JSON.parse(SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']), symbolize_names: true) - @splits_repository.add_split(@new_split) + @splits_repository.add_split( + JSON.parse( + SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( + notification.data['c'], + notification.data['d'] + ), + symbolize_names: true + ) + ) @splits_repository.set_change_number(notification.data['changeNumber']) return - rescue Exception => e + rescue StandardError => e @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled end end @@ -55,7 +64,11 @@ def kill_split(notification) return if @splits_repository.get_change_number.to_i > notification.data['changeNumber'] @config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}") - @splits_repository.kill(notification.data['changeNumber'], notification.data['splitName'], notification.data['defaultTreatment']) + @splits_repository.kill( + notification.data['changeNumber'], + notification.data['splitName'], + notification.data['defaultTreatment'] + ) @synchronizer.fetch_splits(notification.data['changeNumber']) end From 6164afd832c9e255bfb9e6181cd1f843b8c60fa0 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 5 Jun 2023 08:19:20 -0700 Subject: [PATCH 09/25] added byebug --- splitclient-rb.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/splitclient-rb.gemspec b/splitclient-rb.gemspec index fb6a32c8..659a967a 100644 --- a/splitclient-rb.gemspec +++ b/splitclient-rb.gemspec @@ -48,6 +48,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'timecop', '~> 0.9' spec.add_development_dependency 'webmock', '~> 3.14' spec.add_development_dependency 'webrick', '~> 1.7' + spec.add_development_dependency 'byebug', '~> 11.1' spec.add_runtime_dependency 'bitarray', '~> 1.3' spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0' From d2a6b31a80122214607c96d7be54520428eec16e Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 5 Jun 2023 08:48:38 -0700 Subject: [PATCH 10/25] renaming split to feature flag --- .../sse/workers/splits_worker.rb | 38 +++++++++---------- spec/sse/workers/splits_worker_spec.rb | 4 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 1a258765..87e8d968 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,10 +4,10 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, splits_repository) + def initialize(synchronizer, config, feature_flags_repository) @synchronizer = synchronizer @config = config - @splits_repository = splits_repository + @feature_flags_repository = feature_flags_repository @queue = Queue.new @running = Concurrent::AtomicBoolean.new(false) end @@ -32,12 +32,19 @@ def stop SplitIoClient::Helpers::ThreadHelper.stop(:split_update_worker, @config) end - def split_update(notification) - return if @splits_repository.get_change_number.to_i > notification.data['changeNumber'] + def add_to_queue(notification) + @config.logger.debug("feature_flags_worker add to queue #{notification.data['changeNumber']}") + @queue.push(notification) + end + + private + + def update_feature_flag(notification) + return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] - if @splits_repository.get_change_number == notification.data['pcn'] + if @feature_flags_repository.get_change_number == notification.data['pcn'] begin - @splits_repository.add_split( + @feature_flags_repository.add_split( JSON.parse( SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( notification.data['c'], @@ -46,7 +53,7 @@ def split_update(notification) symbolize_names: true ) ) - @splits_repository.set_change_number(notification.data['changeNumber']) + @feature_flags_repository.set_change_number(notification.data['changeNumber']) return rescue StandardError => e @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled @@ -55,16 +62,11 @@ def split_update(notification) @synchronizer.fetch_splits(notification.data['changeNumber']) end - def add_to_queue(notification) - @config.logger.debug("feature_flags_worker add to queue #{notification.data['changeNumber']}") - @queue.push(notification) - end - - def kill_split(notification) - return if @splits_repository.get_change_number.to_i > notification.data['changeNumber'] + 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']}") - @splits_repository.kill( + @feature_flags_repository.kill( notification.data['changeNumber'], notification.data['splitName'], notification.data['defaultTreatment'] @@ -72,16 +74,14 @@ def kill_split(notification) @synchronizer.fetch_splits(notification.data['changeNumber']) end - private - def perform 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 - split_update(notification) + update_feature_flag(notification) when SSE::EventSource::EventTypes::SPLIT_KILL - kill_split(notification) + kill_feature_flag(notification) end end end diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 82a79fb2..5f67a120 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -106,7 +106,7 @@ worker = subject.new(synchronizer, config, splits_repository) worker.start - worker.kill_split(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262918}'), 'test')) + 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) @@ -121,7 +121,7 @@ worker = subject.new(synchronizer, config, splits_repository) worker.start - worker.kill_split(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262916}'), 'test')) + 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) From 3eecb05c0db10433edb1180defbd50915caea1b3 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 5 Jun 2023 11:24:05 -0700 Subject: [PATCH 11/25] polishing --- lib/splitclient-rb/helpers/decryption_helper.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/splitclient-rb/helpers/decryption_helper.rb b/lib/splitclient-rb/helpers/decryption_helper.rb index b8e3dc22..5dc63128 100644 --- a/lib/splitclient-rb/helpers/decryption_helper.rb +++ b/lib/splitclient-rb/helpers/decryption_helper.rb @@ -10,12 +10,14 @@ class DecryptionHelper def self.get_encoded_definition(compression, data) case compression when NO_COMPRESSION - return Base64.decode64(data) + Base64.decode64(data) when GZIP_COMPRESSION gz = Zlib::GzipReader.new(StringIO.new(Base64.decode64(data))) - return gz.read + gz.read when ZLIB_COMPRESSION - return Zlib::Inflate.inflate(Base64.decode64(data)) + Zlib::Inflate.inflate(Base64.decode64(data)) + else + raise StandardError, 'Compression flag value is incorrect' end end end From 6b6968bd64a58dbb693815c5e02fe2d24e5efce6 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 6 Jun 2023 11:16:31 -0700 Subject: [PATCH 12/25] Added client.destroy and stub telemetry and event urls --- spec/engine/matchers/between_matcher_spec.rb | 36 +++++++----- .../engine/matchers/combining_matcher_spec.rb | 11 +++- spec/engine/matchers/equal_to_matcher_spec.rb | 32 ++++++++-- .../greater_than_or_equal_to_matcher_spec.rb | 22 +++++-- .../less_than_or_equal_to_matcher_spec.rb | 32 ++++++++-- .../engine/matchers/whitelist_matcher_spec.rb | 10 +++- spec/engine/sync_manager_spec.rb | 3 + spec/engine/synchronizer_spec.rb | 2 + spec/engine_spec.rb | 58 +++++++++---------- spec/integrations/in_memory_client_spec.rb | 58 +++++++++++++++++-- spec/integrations/push_client_spec.rb | 32 ++++++---- 11 files changed, 215 insertions(+), 81 deletions(-) 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/sync_manager_spec.rb b/spec/engine/sync_manager_spec.rb index 217fe77f..b6891862 100644 --- a/spec/engine/sync_manager_spec.rb +++ b/spec/engine/sync_manager_spec.rb @@ -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..f24ddf47 100644 --- a/spec/integrations/push_client_spec.rb +++ b/spec/integrations/push_client_spec.rb @@ -36,9 +36,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 +60,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 +73,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 +81,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 +104,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 @@ -107,7 +115,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 +137,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 +145,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 +169,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 +178,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 +201,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 +230,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 +262,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 +271,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 +291,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 +302,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 +322,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 +331,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 +351,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 +360,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 +381,7 @@ client.block_until_ready(1) sleep(2) expect(client.get_treatment('admin', 'push_test')).to eq('after_fetch') + client.destroy end end end From 544bc33b2fda77cfcfa17f17221701abb6127197 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 7 Jun 2023 16:51:30 -0700 Subject: [PATCH 13/25] Added iif archived process --- .../sse/workers/splits_worker.rb | 19 +++++++++++-------- spec/sse/workers/splits_worker_spec.rb | 5 +++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 87e8d968..3887d538 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -44,15 +44,18 @@ def update_feature_flag(notification) if @feature_flags_repository.get_change_number == notification.data['pcn'] begin - @feature_flags_repository.add_split( - JSON.parse( - SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( - notification.data['c'], - notification.data['d'] - ), - symbolize_names: true - ) + new_split = JSON.parse( + SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( + notification.data['c'], + notification.data['d'] + ), + symbolize_names: true ) + if SplitIoClient::Engine::Models::Split.matchable?(new_split) + @feature_flags_repository.add_split(new_split) + else + @feature_flags_repository.remove_split(new_split) + end @feature_flags_repository.set_change_number(notification.data['changeNumber']) return rescue StandardError => e diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 5f67a120..379d76b3 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -20,6 +20,7 @@ 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":"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ=="}'), 'test') } let(:synchronizer) do segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) @@ -155,6 +156,10 @@ 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 end From 65d4eb97f979ae9def8447944e6e5a23a9026a11 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 8 Jun 2023 09:21:56 -0700 Subject: [PATCH 14/25] polishing --- .../sse/workers/splits_worker.rb | 26 +++++++++++-------- spec/sse/workers/splits_worker_spec.rb | 16 +++++++++++- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 3887d538..d28528bd 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -39,22 +39,26 @@ def add_to_queue(notification) private + def return_split_from_json(notification) + JSON.parse( + SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( + notification.data['c'], + notification.data['d'] + ), + symbolize_names: true + ) + end + def update_feature_flag(notification) return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] - if @feature_flags_repository.get_change_number == notification.data['pcn'] + if @feature_flags_repository.get_change_number == notification.data['pcn'] && !notification.data['d'].nil? begin - new_split = JSON.parse( - SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( - notification.data['c'], - notification.data['d'] - ), - symbolize_names: true - ) - if SplitIoClient::Engine::Models::Split.matchable?(new_split) - @feature_flags_repository.add_split(new_split) - else + new_split = return_split_from_json(notification) + if SplitIoClient::Engine::Models::Split.archived?(new_split) @feature_flags_repository.remove_split(new_split) + else + @feature_flags_repository.add_split(new_split) end @feature_flags_repository.set_change_number(notification.data['changeNumber']) return diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 379d76b3..94650e11 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -20,7 +20,8 @@ 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":"eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiIzM2VhZmE1MC0xYTY1LTExZWQtOTBkZi1mYTMwZDk2OTA0NDUiLCJuYW1lIjoiYmlsYWxfc3BsaXQiLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOi0xMzY0MTE5MjgyLCJzZWVkIjotNjA1OTM4ODQzLCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib2ZmIiwiY2hhbmdlTnVtYmVyIjoxNjg0MzQwOTA4NDc1LCJhbGdvIjoyLCJjb25maWd1cmF0aW9ucyI6e30sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6ImJpbGFsX3NlZ21lbnQifX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjEwMH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgYmlsYWxfc2VnbWVudCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoiZGVmYXVsdCBydWxlIn1dfQ=="}'), '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(:synchronizer) do segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(config) telemetry_api = SplitIoClient::Api::TelemetryApi.new(config, api_key, telemetry_runtime_producer) @@ -135,9 +136,11 @@ end context 'instant ff update split notification' do + it 'decode and decompress split update data' do worker = subject.new(synchronizer, config, splits_repository) worker.start + splits_repository.set_change_number(1234) worker.add_to_queue(event_split_update_no_compression) sleep 1 @@ -161,6 +164,17 @@ sleep 1 expect(splits_repository.exists?('bilal_split') == false) 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) + 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 From 93e6bddc05df922c2b0d44be24c0078ef6fa015b Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 9 Jun 2023 08:19:19 -0700 Subject: [PATCH 15/25] fixes for rubocop --- lib/splitclient-rb/sse/workers/splits_worker.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index d28528bd..4f5407cd 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -49,10 +49,14 @@ def return_split_from_json(notification) ) end + def check_update(notification) + @feature_flags_repository.get_change_number == notification.data['pcn'] && !notification.data['d'].nil? + end + def update_feature_flag(notification) return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] - if @feature_flags_repository.get_change_number == notification.data['pcn'] && !notification.data['d'].nil? + if check_update(notification) begin new_split = return_split_from_json(notification) if SplitIoClient::Engine::Models::Split.archived?(new_split) From 8b709aeaaffa707c1bd7ed7fc0a0e2a08226ee63 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 9 Jun 2023 08:22:34 -0700 Subject: [PATCH 16/25] polish --- splitclient-rb.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitclient-rb.gemspec b/splitclient-rb.gemspec index 659a967a..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' @@ -48,7 +49,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'timecop', '~> 0.9' spec.add_development_dependency 'webmock', '~> 3.14' spec.add_development_dependency 'webrick', '~> 1.7' - spec.add_development_dependency 'byebug', '~> 11.1' spec.add_runtime_dependency 'bitarray', '~> 1.3' spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0' From 25336164b249547185b97efd2d71f861f47b908d Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 28 Jun 2023 10:34:16 -0300 Subject: [PATCH 17/25] killing resfresh token thread --- lib/splitclient-rb/engine/push_manager.rb | 1 + lib/splitclient-rb/split_config.rb | 2 +- lib/splitclient-rb/sse/event_source/client.rb | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) 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/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/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' From abb63816fba1c660e2d016835db4443b1483e528 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 28 Jun 2023 13:51:30 -0300 Subject: [PATCH 18/25] added telemetry and segments fetch --- lib/splitclient-rb.rb | 1 + lib/splitclient-rb/engine/api/splits.rb | 12 +-- lib/splitclient-rb/helpers/util.rb | 17 ++++ lib/splitclient-rb/split_factory.rb | 2 +- .../sse/workers/splits_worker.rb | 84 +++++++++---------- .../telemetry/domain/constants.rb | 2 + .../telemetry/domain/structs.rb | 7 +- .../memory/memory_runtime_consumer.rb | 7 ++ .../memory/memory_runtime_producer.rb | 6 ++ .../telemetry/memory/memory_synchronizer.rb | 6 +- .../telemetry/runtime_consumer.rb | 3 +- .../telemetry/runtime_producer.rb | 3 +- .../telemetry/storages/memory.rb | 10 ++- spec/engine/push_manager_spec.rb | 2 +- spec/engine/sync_manager_spec.rb | 2 +- spec/sse/event_source/client_spec.rb | 2 +- spec/sse/sse_handler_spec.rb | 2 +- spec/sse/workers/splits_worker_spec.rb | 16 ++-- spec/telemetry/synchronizer_spec.rb | 9 +- 19 files changed, 117 insertions(+), 76 deletions(-) create mode 100644 lib/splitclient-rb/helpers/util.rb diff --git a/lib/splitclient-rb.rb b/lib/splitclient-rb.rb index a69aa23f..bba7eb84 100644 --- a/lib/splitclient-rb.rb +++ b/lib/splitclient-rb.rb @@ -42,6 +42,7 @@ 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..0ce158e5 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_split(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/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb new file mode 100644 index 00000000..f736fbf5 --- /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_split(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/split_factory.rb b/lib/splitclient-rb/split_factory.rb index 334d79db..6e0c6b86 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) 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/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 4f5407cd..6b83ac6f 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,12 +4,13 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, feature_flags_repository) + def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer) @synchronizer = synchronizer @config = config @feature_flags_repository = feature_flags_repository @queue = Queue.new @running = Concurrent::AtomicBoolean.new(false) + @telemetry_runtime_producer = telemetry_runtime_producer end def start @@ -29,7 +30,7 @@ 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(notification) @@ -39,38 +40,48 @@ def add_to_queue(notification) private - def return_split_from_json(notification) - JSON.parse( - SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition( - notification.data['c'], - notification.data['d'] - ), - symbolize_names: true - ) + 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 - def check_update(notification) - @feature_flags_repository.get_change_number == notification.data['pcn'] && !notification.data['d'].nil? + def perform + 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 update_feature_flag(notification) - return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] + 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'] - if check_update(notification) - begin - new_split = return_split_from_json(notification) - if SplitIoClient::Engine::Models::Split.archived?(new_split) - @feature_flags_repository.remove_split(new_split) - else - @feature_flags_repository.add_split(new_split) - end - @feature_flags_repository.set_change_number(notification.data['changeNumber']) - return - rescue StandardError => e - @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled - end + 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) + segment_names = Helpers::Util.segment_names_by_split(new_split) + + @feature_flags_repository.set_segment_names(segment_names) unless segment_names.nil? end - @synchronizer.fetch_splits(notification.data['changeNumber']) + + @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) @@ -85,23 +96,10 @@ def kill_feature_flag(notification) @synchronizer.fetch_splits(notification.data['changeNumber']) end - def perform - 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 - update_feature_flag(notification) - when SSE::EventSource::EventTypes::SPLIT_KILL - kill_feature_flag(notification) - end - end - end + def return_split_from_json(notification) + split_json = Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d']) - def perform_thread - @config.threads[:split_update_worker] = Thread.new do - @config.logger.debug('starting feature_flags_worker ...') if @config.debug_enabled - perform - end + JSON.parse(split_json, symbolize_names: true) end end end diff --git a/lib/splitclient-rb/telemetry/domain/constants.rb b/lib/splitclient-rb/telemetry/domain/constants.rb index ed3f743c..23da9afc 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..7f45ad5b 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/spec/engine/push_manager_spec.rb b/spec/engine/push_manager_spec.rb index 4904408c..05619cf3 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) } 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..1090cd1e 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) } 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/event_source/client_spec.rb b/spec/sse/event_source/client_spec.rb index ae65f5a4..db59901d 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) } 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..3c958808 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) } 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 94650e11..4366f053 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -49,7 +49,7 @@ 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) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262919}'), 'test')) @@ -64,7 +64,7 @@ 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) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262918}'), 'test')) sleep 1 @@ -75,7 +75,7 @@ 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) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262916}'), 'test')) sleep 1 @@ -84,7 +84,7 @@ end it 'without start, must not fetch' do - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) 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) @@ -106,7 +106,7 @@ 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) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262918}'), 'test') @@ -120,7 +120,7 @@ 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) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262916}'), 'test') @@ -138,7 +138,7 @@ context 'instant ff update split notification' do it 'decode and decompress split update data' do - worker = subject.new(synchronizer, config, splits_repository) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) worker.start splits_repository.set_change_number(1234) @@ -167,7 +167,7 @@ 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) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) worker.start splits_repository.set_change_number(1234) 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) From 714ba44a715d24e7664a5561be1e74db0cac2f3c Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 28 Jun 2023 14:50:10 -0300 Subject: [PATCH 19/25] added segments tests --- spec/sse/workers/splits_worker_spec.rb | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 4366f053..196598f7 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -22,8 +22,9 @@ 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) @@ -136,7 +137,6 @@ 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) worker.start @@ -165,6 +165,19 @@ expect(splits_repository.exists?('bilal_split') == false) end + it 'test' do + stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1234').to_return(status: 200, body: '{"splits": [],"since": 1234,"till": 1234}') + + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) + worker.start + + splits_repository.set_change_number(1234) + worker.add_to_queue(event_split_update_segments) + sleep 1 + + 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) From ecb46353354a4d21fa1b63f6ccfe9bcbae017a9c Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 28 Jun 2023 15:55:58 -0300 Subject: [PATCH 20/25] pr feedback --- lib/splitclient-rb/engine/api/splits.rb | 2 +- lib/splitclient-rb/helpers/util.rb | 4 +-- lib/splitclient-rb/split_factory.rb | 2 +- .../sse/workers/splits_worker.rb | 14 +++++++--- .../telemetry/domain/constants.rb | 2 +- .../memory/memory_runtime_consumer.rb | 2 +- spec/engine/push_manager_spec.rb | 2 +- spec/engine/sync_manager_spec.rb | 2 +- spec/sse/event_source/client_spec.rb | 2 +- spec/sse/sse_handler_spec.rb | 2 +- spec/sse/workers/splits_worker_spec.rb | 26 ++++++++++--------- 11 files changed, 35 insertions(+), 25 deletions(-) diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 0ce158e5..10d4544c 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -46,7 +46,7 @@ def splits_with_segment_names(splits_json) parsed_splits[:segment_names] = parsed_splits[:splits].each_with_object(Set.new) do |split, splits| - splits << Helpers::Util.segment_names_by_split(split) + splits << Helpers::Util.segment_names_by_feature_flag(split) end.flatten parsed_splits diff --git a/lib/splitclient-rb/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb index f736fbf5..0cf9aad2 100644 --- a/lib/splitclient-rb/helpers/util.rb +++ b/lib/splitclient-rb/helpers/util.rb @@ -3,8 +3,8 @@ module SplitIoClient module Helpers class Util - def self.segment_names_by_split(split) - split[:conditions].each_with_object(Set.new) do |condition, names| + 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? diff --git a/lib/splitclient-rb/split_factory.rb b/lib/splitclient-rb/split_factory.rb index 6e0c6b86..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, @runtime_producer) + 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/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 6b83ac6f..cb8b5d67 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,13 +4,14 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer) + def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher) @synchronizer = synchronizer @config = config @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 @@ -69,9 +70,8 @@ def update_feature_flag(notification) @feature_flags_repository.remove_split(new_split) else @feature_flags_repository.add_split(new_split) - segment_names = Helpers::Util.segment_names_by_split(new_split) - @feature_flags_repository.set_segment_names(segment_names) unless segment_names.nil? + fetch_segments_if_not_exists(new_split) end @feature_flags_repository.set_change_number(notification.data['changeNumber']) @@ -101,6 +101,14 @@ def return_split_from_json(notification) 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 end diff --git a/lib/splitclient-rb/telemetry/domain/constants.rb b/lib/splitclient-rb/telemetry/domain/constants.rb index 23da9afc..c3ad34eb 100644 --- a/lib/splitclient-rb/telemetry/domain/constants.rb +++ b/lib/splitclient-rb/telemetry/domain/constants.rb @@ -37,7 +37,7 @@ class Constants TREATMENTS_WITH_CONFIG = 'treatmentsWithConfig' TRACK = 'track' - SPLITS = "splits" + SPLITS = 'splits' end 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 7f45ad5b..6787d904 100644 --- a/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +++ b/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb @@ -97,7 +97,7 @@ def session_length 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 diff --git a/spec/engine/push_manager_spec.rb b/spec/engine/push_manager_spec.rb index 05619cf3..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, runtime_producer) } + 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 1090cd1e..fc04a1ea 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, telemetry_runtime_producer) } + 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) } diff --git a/spec/sse/event_source/client_spec.rb b/spec/sse/event_source/client_spec.rb index db59901d..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], telemetry_runtime_producer) } + 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 3c958808..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, telemetry_runtime_producer) } + 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 196598f7..22afd34a 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -17,6 +17,7 @@ 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') } @@ -34,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) @@ -50,7 +51,7 @@ 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, telemetry_runtime_producer) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262919}'), 'test')) @@ -65,7 +66,7 @@ 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, telemetry_runtime_producer) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262918}'), 'test')) sleep 1 @@ -76,7 +77,7 @@ 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, telemetry_runtime_producer) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start worker.add_to_queue(SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_UPDATE", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":1506703262916}'), 'test')) sleep 1 @@ -85,7 +86,7 @@ end it 'without start, must not fetch' do - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) + 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) @@ -107,7 +108,7 @@ 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, telemetry_runtime_producer) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262918}'), 'test') @@ -121,7 +122,7 @@ end it 'must kill split and must not trigger fetch' do - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start worker.send :kill_feature_flag, SplitIoClient::SSE::EventSource::StreamData.new("SPLIT_KILL", 123, JSON.parse('{"splitName":"FACUNDO_TEST", "defaultTreatment":"on", "type":"SPLIT_KILL","changeNumber":1506703262916}'), 'test') @@ -138,7 +139,7 @@ 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) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start splits_repository.set_change_number(1234) @@ -167,20 +168,21 @@ it 'test' do stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1234').to_return(status: 200, body: '{"splits": [],"since": 1234,"till": 1234}') - - worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer) + 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) + worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher) worker.start splits_repository.set_change_number(1234) From 7a1f92072d9bb7dfc84fa49f764a0f048e8d5a49 Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Wed, 28 Jun 2023 16:15:57 -0300 Subject: [PATCH 21/25] updated test name --- spec/sse/workers/splits_worker_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 22afd34a..9ac38740 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -166,7 +166,7 @@ expect(splits_repository.exists?('bilal_split') == false) end - it 'test' do + 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) From 777330743790aa93d57859bb02170083ef475c3d Mon Sep 17 00:00:00 2001 From: Mauro Antonio Sanz Date: Thu, 29 Jun 2023 10:07:00 -0300 Subject: [PATCH 22/25] merged SDKS-6587 --- .github/workflows/ci.yml | 6 +++--- spec/test_data/regexp/data.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) 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/spec/test_data/regexp/data.txt b/spec/test_data/regexp/data.txt index d776a132..266e8912 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 @@ -143,3 +141,5 @@ perl\B#perl stuff#false ^(19|20)\d{2}$#1810#false ^([1-9]|0[1-9]|[12][0-9]|3[01])\D([1-9]|0[1-9]|1[012])\D(19[0-9][0-9]|20[0-9][0-9])$#11/11/2011#true ^([1-9]|0[1-9]|[12][0-9]|3[01])\D([1-9]|0[1-9]|1[012])\D(19[0-9][0-9]|20[0-9][0-9])$#13/13/2011#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 \ No newline at end of file From ac99802ea2cfecd82e191d7337da79776364186c Mon Sep 17 00:00:00 2001 From: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:03:07 -0300 Subject: [PATCH 23/25] Update CHANGES.txt --- CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) 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. From 302f748c17f5a25ef9eb54cc30ae74a62bc11a43 Mon Sep 17 00:00:00 2001 From: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:03:39 -0300 Subject: [PATCH 24/25] Update version.rb --- lib/splitclient-rb/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 84d18aa9546a37ddc98c0ba61ba1fc5b4014476b Mon Sep 17 00:00:00 2001 From: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:21:02 -0300 Subject: [PATCH 25/25] Update data.txt --- spec/test_data/regexp/data.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/test_data/regexp/data.txt b/spec/test_data/regexp/data.txt index 266e8912..973570c9 100644 --- a/spec/test_data/regexp/data.txt +++ b/spec/test_data/regexp/data.txt @@ -141,5 +141,3 @@ perl\B#perl stuff#false ^(19|20)\d{2}$#1810#false ^([1-9]|0[1-9]|[12][0-9]|3[01])\D([1-9]|0[1-9]|1[012])\D(19[0-9][0-9]|20[0-9][0-9])$#11/11/2011#true ^([1-9]|0[1-9]|[12][0-9]|3[01])\D([1-9]|0[1-9]|1[012])\D(19[0-9][0-9]|20[0-9][0-9])$#13/13/2011#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 \ No newline at end of file