From 61e502f817c62e113dfc541380569819780d4dc8 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Wed, 14 May 2025 21:12:00 -0700 Subject: [PATCH 1/9] Added old spec support --- .../cache/fetchers/split_fetcher.rb | 4 +- lib/splitclient-rb/engine/api/client.rb | 3 + lib/splitclient-rb/engine/api/splits.rb | 59 +++++++++++++++-- .../helpers/repository_helper.rb | 7 +- lib/splitclient-rb/split_config.rb | 4 ++ .../sse/workers/splits_worker.rb | 4 +- spec/engine/api/splits_spec.rb | 51 ++++++++++++++- spec/integrations/old_spec_client_spec.rb | 42 ++++++++++++ .../rule_based_segments/split_old_spec.json | 64 ------------------- 9 files changed, 163 insertions(+), 75 deletions(-) create mode 100644 spec/integrations/old_spec_client_spec.rb diff --git a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb index c2772d62..cfa0b636 100644 --- a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +++ b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb @@ -25,8 +25,8 @@ def call def fetch_splits(fetch_options = { cache_control_headers: false, till: nil }) @semaphore.synchronize do data = splits_since(@splits_repository.get_change_number, @rule_based_segments_repository.get_change_number, fetch_options) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:ff][:d], data[:ff][:t], @config) - SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:ff][:d], data[:ff][:t], @config, @splits_api.clear_storage) + SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config, @splits_api.clear_storage) @splits_repository.set_segment_names(data[:segment_names]) @rule_based_segments_repository.set_segment_names(data[:segment_names]) @config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled diff --git a/lib/splitclient-rb/engine/api/client.rb b/lib/splitclient-rb/engine/api/client.rb index 65dcd027..d9d6e0df 100644 --- a/lib/splitclient-rb/engine/api/client.rb +++ b/lib/splitclient-rb/engine/api/client.rb @@ -50,6 +50,9 @@ def post_api(url, api_key, data, headers = {}, params = {}) raise e, 'Split SDK failed to connect to backend to post information', e.backtrace end + def sdk_url_overriden? + @config.sdk_url_overriden? + end private def api_client diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 0596c9de..45c1b30f 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -5,28 +5,68 @@ module Api # Retrieves split definitions from the Split Backend class Splits < Client + PROXY_CHECK_INTERVAL_SECONDS = 24 * 60 * 60 + SPEC_1_1 = "1.1" + def initialize(api_key, config, telemetry_runtime_producer) super(config) @api_key = api_key @telemetry_runtime_producer = telemetry_runtime_producer @flag_sets_filter = @config.flag_sets_filter + @spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION + @last_proxy_check_timestamp = 0 + @clear_storage = false end def since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, sets: nil}) start = Time.now + + if check_last_proxy_check_timestamp + puts "switching to new spec" + @spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION + @config.logger.debug("Switching to new Feature flag spec #{@spec_version} and fetching.") + since = -1 + since_rbs = -1 + fetch_options = { cache_control_headers: false, till: nil, sets: nil} + end + + if @spec_version == Splits::SPEC_1_1 + params = { s: @spec_version, since: since } + else + params = { s: @spec_version, since: since, rbSince: since_rbs } + end - params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since, rbSince: since_rbs } params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty? params[:till] = fetch_options[:till] unless fetch_options[:till].nil? @config.logger.debug("Fetching from splitChanges with #{params}: ") response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers]) + if response.status == 414 @config.logger.error("Error fetching feature flags; the amount of flag sets provided are too big, causing uri length error.") raise ApiException.new response.body, 414 end + + if response.status == 400 and sdk_url_overriden? and @spec_version == SplitIoClient::Spec::FeatureFlags::SPEC_VERSION + @config.logger.warn("Detected proxy response error, changing spec version from #{@spec_version} to #{Splits::SPEC_1_1} and re-fetching.") + @spec_version = Splits::SPEC_1_1 + @last_proxy_check_timestamp = Time.now + return since(since, 0, fetch_options = {cache_control_headers: fetch_options[:cache_control_headers], till: fetch_options[:till], + sets: fetch_options[:sets]}) + end + if response.success? - result = objects_with_segment_names(response.body) + result = JSON.parse(response.body, symbolize_names: true) + if @spec_version == Splits::SPEC_1_1 + result = convert_to_newSPEC(result) + end + + result = objects_with_segment_names(result) + if @spec_version == SplitIoClient::Spec::FeatureFlags::SPEC_VERSION + @clear_storage = @last_proxy_check_timestamp != 0 + @last_proxy_check_timestamp = 0 + end + unless result[:ff][:d].empty? @config.split_logger.log_if_debug("#{result[:ff][:d].length} feature flags retrieved. since=#{since}") end @@ -52,10 +92,13 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till end end + def clear_storage + @clear_storage + end + private - def objects_with_segment_names(objects_json) - parsed_objects = JSON.parse(objects_json, symbolize_names: true) + def objects_with_segment_names(parsed_objects) parsed_objects[:segment_names] = Set.new parsed_objects[:segment_names] = parsed_objects[:ff][:d].each_with_object(Set.new) do |split, splits| @@ -76,6 +119,14 @@ def objects_with_segment_names(objects_json) parsed_objects end + + def check_last_proxy_check_timestamp + @spec_version == Splits::SPEC_1_1 and ((Time.now - @last_proxy_check_timestamp) >= Splits::PROXY_CHECK_INTERVAL_SECONDS) + end + + def convert_to_newSPEC(body) + {:ff => {:d => body[:splits], :s => body[:since], :t => body[:till]}, :rbs => {:d => [], :s => -1, :t => -1}} + end end end end diff --git a/lib/splitclient-rb/helpers/repository_helper.rb b/lib/splitclient-rb/helpers/repository_helper.rb index 24fdd76b..be0e63c8 100644 --- a/lib/splitclient-rb/helpers/repository_helper.rb +++ b/lib/splitclient-rb/helpers/repository_helper.rb @@ -3,7 +3,7 @@ module SplitIoClient module Helpers class RepositoryHelper - def self.update_feature_flag_repository(feature_flag_repository, feature_flags, change_number, config) + def self.update_feature_flag_repository(feature_flag_repository, feature_flags, change_number, config, clear_storage) to_add = [] to_delete = [] feature_flags.each do |feature_flag| @@ -23,10 +23,11 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled to_add.push(feature_flag) end + feature_flag_repository.clear if clear_storage feature_flag_repository.update(to_add, to_delete, change_number) end - def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config) + def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config, clear_storage) to_add = [] to_delete = [] rule_based_segments.each do |rule_based_segment| @@ -39,6 +40,8 @@ def self.update_rule_based_segment_repository(rule_based_segment_repository, rul config.logger.debug("storing rule based segment (#{rule_based_segment[:name]})") if config.debug_enabled to_add.push(rule_based_segment) end + rule_based_segment_repository.clear if clear_storage + rule_based_segment_repository.update(to_add, to_delete, change_number) end end diff --git a/lib/splitclient-rb/split_config.rb b/lib/splitclient-rb/split_config.rb index da434c91..de7f3e4d 100644 --- a/lib/splitclient-rb/split_config.rb +++ b/lib/splitclient-rb/split_config.rb @@ -645,6 +645,10 @@ def consumer? @mode.equal?(:consumer) end + def sdk_url_overriden? + return @base_uri != SplitConfig.default_base_uri + end + # # gets the hostname where the sdk gem is running # diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 419a3814..88b06660 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -71,7 +71,7 @@ def update_feature_flag(notification) new_split = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, [new_split], - notification.data['changeNumber'], @config) + notification.data['changeNumber'], @config, false) fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_SEGMENT"), @feature_flags_repository) if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_RULE_BASED_SEGMENT"), notification.data['changeNumber']) return true @@ -93,7 +93,7 @@ def update_rule_based_segment(notification) new_rb_segment = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository, [new_rb_segment], - notification.data['changeNumber'], @config) + notification.data['changeNumber'], @config, false) fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, "IN_SEGMENT"), @rule_based_segment_repository) # TODO: enable when telemetry spec is added diff --git a/spec/engine/api/splits_spec.rb b/spec/engine/api/splits_spec.rb index af20bd9a..2d293498 100644 --- a/spec/engine/api/splits_spec.rb +++ b/spec/engine/api/splits_spec.rb @@ -21,7 +21,7 @@ stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1') .to_return(status: 200, body: splits) - parsed_splits = splits_api.send(:objects_with_segment_names, splits) + parsed_splits = splits_api.send(:objects_with_segment_names, JSON.parse(splits, symbolize_names: true)) expect(parsed_splits[:segment_names]).to eq(Set.new(%w[demo employees])) end @@ -183,4 +183,53 @@ ) end end + + context 'old spec tests' do + let(:old_spec_splits) { File.read(File.expand_path(File.join(File.dirname(__FILE__), '../../test_data/rule_based_segments/split_old_spec.json'))) } + let(:config) do + SplitIoClient::SplitConfig.new( + logger: Logger.new(log), + debug_enabled: true, + transport_debug_enabled: true, + base_uri: "https://proxy-server/api" + ) + end + let(:log) { StringIO.new } + let(:telemetry_runtime_producer) { SplitIoClient::Telemetry::RuntimeProducer.new(config) } + let(:splits_api) { described_class.new('', config, telemetry_runtime_producer) } + + it 'switch to old spec url whith proper conditions' do + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') + .to_return(status: 400, body: '') + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') + .to_return(status: 200, body: old_spec_splits) + + parsed_splits = splits_api.since(-1, -1) + + expect(parsed_splits[:ff][:d].length()).to eq(7) + expect(parsed_splits[:ff][:t]).to eq(1457726098069) + expect(parsed_splits[:ff][:s]).to eq(-1) + expect(parsed_splits[:rbs]).to eq({:d => [], :s => -1, :t => -1}) + expect(splits_api.clear_storage).to eq(false) + end + + it 'check new spec after last proxy timestamp expires' do + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') + .to_return({status: 400, body: ''}, {status: 200, body: splits}) + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') + .to_return(status: 200, body: old_spec_splits) + + parsed_splits = splits_api.since(-1, -1) + expect(parsed_splits[:ff][:d].length()).to eq(7) + expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Api::Splits::SPEC_1_1) + + SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 + sleep 1 + parsed_splits = splits_api.since(-1, -1) + expect(splits_api.clear_storage).to eq(true) + expect(parsed_splits[:ff][:d].length()).to eq(2) + expect(parsed_splits[:rbs][:d].length()).to eq(1) + expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Spec::FeatureFlags::SPEC_VERSION) + end + end end diff --git a/spec/integrations/old_spec_client_spec.rb b/spec/integrations/old_spec_client_spec.rb new file mode 100644 index 00000000..7ee2526c --- /dev/null +++ b/spec/integrations/old_spec_client_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe SplitIoClient do + context 'old spec tests' do + let(:old_spec_splits) { File.read(File.expand_path(File.join(File.dirname(__FILE__), '../test_data/rule_based_segments/split_old_spec.json'))) } + + it 'check new spec after last proxy timestamp expires' do + splits_rbs = File.read(File.join(SplitIoClient.root, 'spec/test_data/rule_based_segments/rule_base_segments.json')) + + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') + .to_return({status: 400, body: ''}, {status: 200, body: splits_rbs}) + stub_request(:get, "https://sdk.split.io/api/splitChanges?rbSince=1506703262916&s=1.3&since=1506703262916") + .to_return(status: 200, body: '') + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') + .to_return(status: 200, body: old_spec_splits) + stub_request(:get, "https://proxy-server/api/splitChanges?s=1.1&since=1457726098069") + .to_return(status: 200, body: '') + stub_request(:post, "https://telemetry.split.io/api/v1/metrics/config") + .to_return(status: 200, body: '') + + factory_old_spec = + SplitIoClient::SplitFactory.new('test_api_key', + {impressions_mode: :none, + features_refresh_rate: 2, + base_uri: "https://proxy-server/api", + streaming_enabled: false}) + + SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 + client_old_spec = factory_old_spec.client + client_old_spec.block_until_ready + expect(client_old_spec.get_treatment('whitelisted_user', 'whitelist_feature')).to eq('on') + + sleep 1 + split_fetcher = factory_old_spec.instance_variable_get(:@split_fetcher) + split_fetcher.fetch_splits + sleep 1 + expect(client_old_spec.get_treatment('bilal@split.io', 'rbs_feature_flag', {:email => 'bilal@split.io'})).to eq('on') + end + end +end diff --git a/spec/test_data/rule_based_segments/split_old_spec.json b/spec/test_data/rule_based_segments/split_old_spec.json index 0d7edf86..2d0aef1e 100644 --- a/spec/test_data/rule_based_segments/split_old_spec.json +++ b/spec/test_data/rule_based_segments/split_old_spec.json @@ -141,70 +141,6 @@ ], "sets": ["set3"] }, - { - "orgId": null, - "environment": null, - "trafficTypeId": null, - "trafficTypeName": null, - "name": "sample_feature", - "seed": 1548363147, - "status": "ACTIVE", - "killed": false, - "changeNumber": 123, - "defaultTreatment": "off", - "configurations": { - "on": "{\"size\":15,\"test\":20}" - }, - "conditions": [ - { - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "employees" - }, - "whitelistMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 100 - } - ] - }, - { - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "human_beigns" - }, - "whitelistMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 30 - }, - { - "treatment": "off", - "size": 70 - } - ] - } - ], - "sets": ["set1"] - }, { "orgId": null, "environment": null, From 2e54131fd0abcad871d1fc7fdf1e9e1f7663a6d9 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 15 May 2025 09:35:03 -0700 Subject: [PATCH 2/9] update tests --- .../cache/fetchers/split_fetcher.rb | 2 +- .../cache/repositories/splits_repository.rb | 4 ++ lib/splitclient-rb/engine/api/splits.rb | 1 - .../helpers/repository_helper.rb | 3 +- .../sse/workers/splits_worker.rb | 2 +- spec/integrations/in_memory_client_spec.rb | 38 +++++++++++++++++ spec/integrations/old_spec_client_spec.rb | 42 ------------------- 7 files changed, 45 insertions(+), 47 deletions(-) delete mode 100644 spec/integrations/old_spec_client_spec.rb diff --git a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb index cfa0b636..c1cba9dc 100644 --- a/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +++ b/lib/splitclient-rb/cache/fetchers/split_fetcher.rb @@ -26,7 +26,7 @@ def fetch_splits(fetch_options = { cache_control_headers: false, till: nil }) @semaphore.synchronize do data = splits_since(@splits_repository.get_change_number, @rule_based_segments_repository.get_change_number, fetch_options) SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@splits_repository, data[:ff][:d], data[:ff][:t], @config, @splits_api.clear_storage) - SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config, @splits_api.clear_storage) + SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segments_repository, data[:rbs][:d], data[:rbs][:t], @config) @splits_repository.set_segment_names(data[:segment_names]) @rule_based_segments_repository.set_segment_names(data[:segment_names]) @config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled diff --git a/lib/splitclient-rb/cache/repositories/splits_repository.rb b/lib/splitclient-rb/cache/repositories/splits_repository.rb index e98e0d84..bc763c36 100644 --- a/lib/splitclient-rb/cache/repositories/splits_repository.rb +++ b/lib/splitclient-rb/cache/repositories/splits_repository.rb @@ -127,6 +127,10 @@ def clear @tt_cache.clear @adapter.clear(namespace_key) + unless @config.mode.equal?(:consumer) + @adapter.set_string(namespace_key('.splits.till'), '-1') + @adapter.initialize_map(namespace_key('.segments.registered')) + end end def kill(change_number, split_name, default_treatment) diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 45c1b30f..6146d387 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -22,7 +22,6 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till start = Time.now if check_last_proxy_check_timestamp - puts "switching to new spec" @spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION @config.logger.debug("Switching to new Feature flag spec #{@spec_version} and fetching.") since = -1 diff --git a/lib/splitclient-rb/helpers/repository_helper.rb b/lib/splitclient-rb/helpers/repository_helper.rb index be0e63c8..d66bac33 100644 --- a/lib/splitclient-rb/helpers/repository_helper.rb +++ b/lib/splitclient-rb/helpers/repository_helper.rb @@ -27,7 +27,7 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, feature_flag_repository.update(to_add, to_delete, change_number) end - def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config, clear_storage) + def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config) to_add = [] to_delete = [] rule_based_segments.each do |rule_based_segment| @@ -40,7 +40,6 @@ def self.update_rule_based_segment_repository(rule_based_segment_repository, rul config.logger.debug("storing rule based segment (#{rule_based_segment[:name]})") if config.debug_enabled to_add.push(rule_based_segment) end - rule_based_segment_repository.clear if clear_storage rule_based_segment_repository.update(to_add, to_delete, change_number) end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 88b06660..a6ba1696 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -93,7 +93,7 @@ def update_rule_based_segment(notification) new_rb_segment = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository, [new_rb_segment], - notification.data['changeNumber'], @config, false) + notification.data['changeNumber'], @config) fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, "IN_SEGMENT"), @rule_based_segment_repository) # TODO: enable when telemetry spec is added diff --git a/spec/integrations/in_memory_client_spec.rb b/spec/integrations/in_memory_client_spec.rb index ab0538ae..2f2024b2 100644 --- a/spec/integrations/in_memory_client_spec.rb +++ b/spec/integrations/in_memory_client_spec.rb @@ -1381,6 +1381,44 @@ expect(client_rbs.get_treatment('mauro@split.io', 'rbs_feature_flag', {:email => 'mauro@split.io'})).to eq('off') end end + + context 'old spec tests' do + let(:old_spec_splits) { File.read(File.expand_path(File.join(File.dirname(__FILE__), '../test_data/rule_based_segments/split_old_spec.json'))) } + + it 'check new spec after last proxy timestamp expires' do + splits_rbs = File.read(File.join(SplitIoClient.root, 'spec/test_data/rule_based_segments/rule_base_segments.json')) + + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') + .to_return({status: 400, body: ''}, {status: 200, body: splits_rbs}) + stub_request(:get, "https://sdk.split.io/api/splitChanges?rbSince=1506703262916&s=1.3&since=1506703262916") + .to_return(status: 200, body: '') + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') + .to_return(status: 200, body: old_spec_splits) + stub_request(:get, "https://proxy-server/api/splitChanges?s=1.1&since=1457726098069") + .to_return(status: 200, body: '') + stub_request(:post, "https://telemetry.split.io/api/v1/metrics/config") + .to_return(status: 200, body: '') + + factory_old_spec = + SplitIoClient::SplitFactory.new('test_api_key', + {impressions_mode: :none, + features_refresh_rate: 2, + base_uri: "https://proxy-server/api", + streaming_enabled: false}) + + SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 + client_old_spec = factory_old_spec.client + client_old_spec.block_until_ready + expect(client_old_spec.get_treatment('whitelisted_user', 'whitelist_feature')).to eq('on') + + sleep 1 + split_fetcher = factory_old_spec.instance_variable_get(:@split_fetcher) + split_fetcher.fetch_splits + sleep 1 + expect(client_old_spec.get_treatment('bilal@split.io', 'rbs_feature_flag', {:email => 'bilal@split.io'})).to eq('on') + expect(client_old_spec.get_treatment('whitelisted_user', 'whitelist_feature')).to eq('control') + end + end end private diff --git a/spec/integrations/old_spec_client_spec.rb b/spec/integrations/old_spec_client_spec.rb deleted file mode 100644 index 7ee2526c..00000000 --- a/spec/integrations/old_spec_client_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe SplitIoClient do - context 'old spec tests' do - let(:old_spec_splits) { File.read(File.expand_path(File.join(File.dirname(__FILE__), '../test_data/rule_based_segments/split_old_spec.json'))) } - - it 'check new spec after last proxy timestamp expires' do - splits_rbs = File.read(File.join(SplitIoClient.root, 'spec/test_data/rule_based_segments/rule_base_segments.json')) - - stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') - .to_return({status: 400, body: ''}, {status: 200, body: splits_rbs}) - stub_request(:get, "https://sdk.split.io/api/splitChanges?rbSince=1506703262916&s=1.3&since=1506703262916") - .to_return(status: 200, body: '') - stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') - .to_return(status: 200, body: old_spec_splits) - stub_request(:get, "https://proxy-server/api/splitChanges?s=1.1&since=1457726098069") - .to_return(status: 200, body: '') - stub_request(:post, "https://telemetry.split.io/api/v1/metrics/config") - .to_return(status: 200, body: '') - - factory_old_spec = - SplitIoClient::SplitFactory.new('test_api_key', - {impressions_mode: :none, - features_refresh_rate: 2, - base_uri: "https://proxy-server/api", - streaming_enabled: false}) - - SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 - client_old_spec = factory_old_spec.client - client_old_spec.block_until_ready - expect(client_old_spec.get_treatment('whitelisted_user', 'whitelist_feature')).to eq('on') - - sleep 1 - split_fetcher = factory_old_spec.instance_variable_get(:@split_fetcher) - split_fetcher.fetch_splits - sleep 1 - expect(client_old_spec.get_treatment('bilal@split.io', 'rbs_feature_flag', {:email => 'bilal@split.io'})).to eq('on') - end - end -end From b7013d49ec2e8fc36f1adc6d8b48a421eca47751 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 15 May 2025 11:49:35 -0700 Subject: [PATCH 3/9] polish --- .../cache/repositories/splits_repository.rb | 17 +++---- lib/splitclient-rb/engine/api/splits.rb | 10 ++++ .../matchers/rule_based_segment_matcher.rb | 46 ++++++++++-------- .../helpers/evaluator_helper.rb | 4 +- .../helpers/repository_helper.rb | 17 ++++--- lib/splitclient-rb/helpers/util.rb | 3 +- .../sse/workers/splits_worker.rb | 48 ++++++++++--------- 7 files changed, 88 insertions(+), 57 deletions(-) diff --git a/lib/splitclient-rb/cache/repositories/splits_repository.rb b/lib/splitclient-rb/cache/repositories/splits_repository.rb index bc763c36..2fa7c396 100644 --- a/lib/splitclient-rb/cache/repositories/splits_repository.rb +++ b/lib/splitclient-rb/cache/repositories/splits_repository.rb @@ -43,10 +43,7 @@ def initialize(config, flag_sets_repository, flag_set_filter) end @flag_sets = flag_sets_repository @flag_set_filter = flag_set_filter - unless @config.mode.equal?(:consumer) - @adapter.set_string(namespace_key('.splits.till'), '-1') - @adapter.initialize_map(namespace_key('.segments.registered')) - end + initialize_keys end def update(to_add, to_delete, new_change_number) @@ -127,10 +124,7 @@ def clear @tt_cache.clear @adapter.clear(namespace_key) - unless @config.mode.equal?(:consumer) - @adapter.set_string(namespace_key('.splits.till'), '-1') - @adapter.initialize_map(namespace_key('.segments.registered')) - end + initialize_keys end def kill(change_number, split_name, default_treatment) @@ -171,6 +165,13 @@ def flag_set_filter private + def initialize_keys + unless @config.mode.equal?(:consumer) + @adapter.set_string(namespace_key('.splits.till'), '-1') + @adapter.initialize_map(namespace_key('.segments.registered')) + end + end + def add_feature_flag(split) return unless split[:name] existing_split = get_split(split[:name]) diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index 6146d387..b8e08974 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -59,6 +59,7 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till result = convert_to_newSPEC(result) end + result[:rbs][:d] = check_rbs_data(result[:rbs][:d]) result = objects_with_segment_names(result) if @spec_version == SplitIoClient::Spec::FeatureFlags::SPEC_VERSION @@ -97,6 +98,15 @@ def clear_storage private + def check_rbs_data(rbs_data) + rbs_data.each do |rb_segment| + rb_segment[:excluded] = {:keys => [], :segments => []} if rb_segment[:excluded].nil? + rb_segment[:excluded][:keys] = [] if rb_segment[:excluded][:keys].nil? + rb_segment[:excluded][:segments] = [] if rb_segment[:excluded][:segments].nil? + end + rbs_data + end + def objects_with_segment_names(parsed_objects) parsed_objects[:segment_names] = Set.new parsed_objects[:segment_names] = diff --git a/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb b/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb index 69c72272..081c657c 100644 --- a/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +++ b/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb @@ -25,20 +25,10 @@ def match?(args) rule_based_segment = @rule_based_segments_repository.get_rule_based_segment(@segment_name) return false if rule_based_segment.nil? - if args[:value].nil? or args[:value].empty? - key = args[:matching_key] - else - key = args[:value] - end + key = update_key(args) return false if rule_based_segment[:excluded][:keys].include?(key) - rule_based_segment[:excluded][:segments].each do |segment| - return false if segment[:type] == 'standard' and @segments_repository.in_segment?(segment[:name], key) - - if segment[:type] == 'rule-based' - return false if match_rbs(@rule_based_segments_repository.get_rule_based_segment(segment[:name]), args) - end - end + return false unless check_excluded_segments(rule_based_segment) matches = false rule_based_segment[:conditions].each do |c| @@ -54,13 +44,31 @@ def match?(args) private - def match_rbs(rule_based_segment, args) - rbs_matcher = RuleBasedSegmentMatcher.new(@segments_repository, @rule_based_segments_repository, rule_based_segment[:name], @config) - return rbs_matcher.match?( - matching_key: args[:matching_key], - bucketing_key: args[:value], - attributes: args[:attributes] - ) + def check_excluded_segments(rule_based_segment) + rule_based_segment[:excluded][:segments].each do |segment| + return false if segment[:type] == 'standard' && @segments_repository.in_segment?(segment[:name], key) + + return false if segment[:type] == 'rule-based' && match_rbs( + @rule_based_segments_repository.get_rule_based_segment(segment[:name]), args + ) + end + True + end + + def update_key(args) + if args[:value].nil? || args[:value].empty? + args[:matching_key] + else + args[:value] + end + end + + def match_rbs(rule_based_segment, args) + rbs_matcher = RuleBasedSegmentMatcher.new(@segments_repository, @rule_based_segments_repository, + rule_based_segment[:name], @config) + rbs_matcher.match?(matching_key: args[:matching_key], + bucketing_key: args[:value], + attributes: args[:attributes]) end end end diff --git a/lib/splitclient-rb/helpers/evaluator_helper.rb b/lib/splitclient-rb/helpers/evaluator_helper.rb index 331c7987..2b16e094 100644 --- a/lib/splitclient-rb/helpers/evaluator_helper.rb +++ b/lib/splitclient-rb/helpers/evaluator_helper.rb @@ -8,7 +8,9 @@ def self.matcher_type(condition, segments_repository, rb_segment_repository) segments_repository.adapter.pipelined do condition.matchers.each do |matcher| matchers << if matcher[:negate] - condition.negation_matcher(matcher_instance(matcher[:matcherType], condition, matcher, segments_repository, rb_segment_repository)) + condition.negation_matcher(matcher_instance(matcher[:matcherType], condition, + matcher, segments_repository, + rb_segment_repository)) else matcher_instance(matcher[:matcherType], condition, matcher, segments_repository, rb_segment_repository) end diff --git a/lib/splitclient-rb/helpers/repository_helper.rb b/lib/splitclient-rb/helpers/repository_helper.rb index d66bac33..eb790447 100644 --- a/lib/splitclient-rb/helpers/repository_helper.rb +++ b/lib/splitclient-rb/helpers/repository_helper.rb @@ -13,12 +13,7 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, next end - unless feature_flag.key?(:impressionsDisabled) - feature_flag[:impressionsDisabled] = false - if config.debug_enabled - config.logger.debug("feature flag (#{feature_flag[:name]}) does not have impressionsDisabled field, setting it to false") - end - end + feature_flag = self.check_impressions_disabled(feature_flag, config) config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled to_add.push(feature_flag) @@ -27,6 +22,16 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, feature_flag_repository.update(to_add, to_delete, change_number) end + def self.check_impressions_disabled(feature_flag, config) + unless feature_flag.key?(:impressionsDisabled) + feature_flag[:impressionsDisabled] = false + if config.debug_enabled + config.logger.debug("feature flag (#{feature_flag[:name]}) does not have impressionsDisabled field, setting it to false") + end + end + feature_flag + end + def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config) to_add = [] to_delete = [] diff --git a/lib/splitclient-rb/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb index c9b356c4..0f61d0ca 100644 --- a/lib/splitclient-rb/helpers/util.rb +++ b/lib/splitclient-rb/helpers/util.rb @@ -6,7 +6,8 @@ class Util def self.segment_names_by_object(object, matcher_type) object[:conditions].each_with_object(Set.new) do |condition, names| condition[:matcherGroup][:matchers].each do |matcher| - next if matcher[:userDefinedSegmentMatcherData].nil? or matcher[:matcherType] != matcher_type + next if matcher[:userDefinedSegmentMatcherData].nil? || matcher[:matcherType] != matcher_type + names << matcher[:userDefinedSegmentMatcherData][:segmentName] end end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index a6ba1696..27ea916e 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -4,7 +4,8 @@ module SplitIoClient module SSE module Workers class SplitsWorker - def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segment_repository) + def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, + segment_fetcher, rule_based_segment_repository) @synchronizer = synchronizer @config = config @feature_flags_repository = feature_flags_repository @@ -68,12 +69,11 @@ def perform def update_feature_flag(notification) return true if @feature_flags_repository.get_change_number.to_i >= notification.data['changeNumber'] return false unless !notification.data['d'].nil? && @feature_flags_repository.get_change_number == notification.data['pcn'] - new_split = return_object_from_json(notification) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, - [new_split], - notification.data['changeNumber'], @config, false) - fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_SEGMENT"), @feature_flags_repository) - if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, "IN_RULE_BASED_SEGMENT"), notification.data['changeNumber']) + + update_feature_flag_repository(notification) + fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_SEGMENT'), @feature_flags_repository) + if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_RULE_BASED_SEGMENT'), + notification.data['changeNumber']) return true end @@ -86,18 +86,26 @@ def update_feature_flag(notification) false end + def update_feature_flag_repository(notification) + new_split = return_object_from_json(notification) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, [new_split], + notification.data['changeNumber'], @config, false) + end + def update_rule_based_segment(notification) return true if @rule_based_segment_repository.get_change_number.to_i >= notification.data['changeNumber'] - return false unless !notification.data['d'].nil? && @rule_based_segment_repository.get_change_number == notification.data['pcn'] + return false unless !notification.data['d'].nil? && + @rule_based_segment_repository.get_change_number == notification.data['pcn'] new_rb_segment = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository, - [new_rb_segment], - notification.data['changeNumber'], @config) - fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, "IN_SEGMENT"), @rule_based_segment_repository) + [new_rb_segment], + notification.data['changeNumber'], @config) + fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, 'IN_SEGMENT'), + @rule_based_segment_repository) -# TODO: enable when telemetry spec is added -# @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS) + # TODO: enable when telemetry spec is added + # @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS) true rescue StandardError => e @@ -110,11 +118,9 @@ def kill_feature_flag(notification) return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber'] @config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}") - @feature_flags_repository.kill( - notification.data['changeNumber'], - notification.data['splitName'], - notification.data['defaultTreatment'] - ) + @feature_flags_repository.kill(notification.data['changeNumber'], + notification.data['splitName'], + notification.data['defaultTreatment']) @synchronizer.fetch_splits(notification.data['changeNumber'], 0) end @@ -124,7 +130,6 @@ def return_object_from_json(notification) end def fetch_segments_if_not_exists(segment_names, object_repository) - return if segment_names.nil? object_repository.set_segment_names(segment_names) @@ -132,9 +137,8 @@ def fetch_segments_if_not_exists(segment_names, object_repository) end def fetch_rule_based_segments_if_not_exists(segment_names, change_number) - if segment_names.nil? or segment_names.empty? or @rule_based_segment_repository.contains?(segment_names.to_a) - return false - end + return false if segment_names.nil? || segment_names.empty? || @rule_based_segment_repository.contains?(segment_names.to_a) + @synchronizer.fetch_splits(0, change_number) true From 1952d9d0da9e59e0f0bb9ddb13edb9e199709e26 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 16 May 2025 10:04:14 -0700 Subject: [PATCH 4/9] polish --- lib/splitclient-rb/helpers/repository_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/splitclient-rb/helpers/repository_helper.rb b/lib/splitclient-rb/helpers/repository_helper.rb index eb790447..da72ad22 100644 --- a/lib/splitclient-rb/helpers/repository_helper.rb +++ b/lib/splitclient-rb/helpers/repository_helper.rb @@ -13,7 +13,7 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, next end - feature_flag = self.check_impressions_disabled(feature_flag, config) + feature_flag = check_impressions_disabled(feature_flag, config) config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled to_add.push(feature_flag) From a2ce544eaa88905290d622953ae5fba2285690b6 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 16 May 2025 10:05:02 -0700 Subject: [PATCH 5/9] fix sse issue --- .../engine/matchers/rule_based_segment_matcher.rb | 6 +++--- lib/splitclient-rb/helpers/repository_helper.rb | 2 +- lib/splitclient-rb/sse/notification_processor.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb b/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb index 081c657c..74c5e2f4 100644 --- a/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +++ b/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb @@ -28,7 +28,7 @@ def match?(args) key = update_key(args) return false if rule_based_segment[:excluded][:keys].include?(key) - return false unless check_excluded_segments(rule_based_segment) + return false unless check_excluded_segments(rule_based_segment, key, args) matches = false rule_based_segment[:conditions].each do |c| @@ -44,7 +44,7 @@ def match?(args) private - def check_excluded_segments(rule_based_segment) + def check_excluded_segments(rule_based_segment, key, args) rule_based_segment[:excluded][:segments].each do |segment| return false if segment[:type] == 'standard' && @segments_repository.in_segment?(segment[:name], key) @@ -52,7 +52,7 @@ def check_excluded_segments(rule_based_segment) @rule_based_segments_repository.get_rule_based_segment(segment[:name]), args ) end - True + true end def update_key(args) diff --git a/lib/splitclient-rb/helpers/repository_helper.rb b/lib/splitclient-rb/helpers/repository_helper.rb index eb790447..da72ad22 100644 --- a/lib/splitclient-rb/helpers/repository_helper.rb +++ b/lib/splitclient-rb/helpers/repository_helper.rb @@ -13,7 +13,7 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags, next end - feature_flag = self.check_impressions_disabled(feature_flag, config) + feature_flag = check_impressions_disabled(feature_flag, config) config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled to_add.push(feature_flag) diff --git a/lib/splitclient-rb/sse/notification_processor.rb b/lib/splitclient-rb/sse/notification_processor.rb index d723cbdc..af5563c3 100644 --- a/lib/splitclient-rb/sse/notification_processor.rb +++ b/lib/splitclient-rb/sse/notification_processor.rb @@ -27,7 +27,7 @@ def process(incoming_notification) private def process_split_update(notification) - @config.logger.debug("#{notification.type} notification received: #{notification}") if @config.debug_enabled + @config.logger.debug("#{notification.event_type} notification received: #{notification}") if @config.debug_enabled @splits_worker.add_to_queue(notification) end From 1566bfbad6af04f38cc3173dcee81537d9d6e75e Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 16 May 2025 10:32:53 -0700 Subject: [PATCH 6/9] polish --- .../sse/workers/splits_worker.rb | 3 +- spec/engine/api/splits_spec.rb | 4 +- .../rule_based_segment_matcher_spec.rb | 4 +- spec/repository_helper.rb | 37 +++++++++++++------ 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index 27ea916e..f1e83775 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -70,7 +70,7 @@ def update_feature_flag(notification) return true if @feature_flags_repository.get_change_number.to_i >= notification.data['changeNumber'] return false unless !notification.data['d'].nil? && @feature_flags_repository.get_change_number == notification.data['pcn'] - update_feature_flag_repository(notification) + new_split = update_feature_flag_repository(notification) fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_SEGMENT'), @feature_flags_repository) if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_RULE_BASED_SEGMENT'), notification.data['changeNumber']) @@ -90,6 +90,7 @@ def update_feature_flag_repository(notification) new_split = return_object_from_json(notification) SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, [new_split], notification.data['changeNumber'], @config, false) + new_split end def update_rule_based_segment(notification) diff --git a/spec/engine/api/splits_spec.rb b/spec/engine/api/splits_spec.rb index 2d293498..9c384a32 100644 --- a/spec/engine/api/splits_spec.rb +++ b/spec/engine/api/splits_spec.rb @@ -206,7 +206,7 @@ parsed_splits = splits_api.since(-1, -1) - expect(parsed_splits[:ff][:d].length()).to eq(7) + expect(parsed_splits[:ff][:d].length()).to eq(6) expect(parsed_splits[:ff][:t]).to eq(1457726098069) expect(parsed_splits[:ff][:s]).to eq(-1) expect(parsed_splits[:rbs]).to eq({:d => [], :s => -1, :t => -1}) @@ -220,7 +220,7 @@ .to_return(status: 200, body: old_spec_splits) parsed_splits = splits_api.since(-1, -1) - expect(parsed_splits[:ff][:d].length()).to eq(7) + expect(parsed_splits[:ff][:d].length()).to eq(6) expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Api::Splits::SPEC_1_1) SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 diff --git a/spec/engine/matchers/rule_based_segment_matcher_spec.rb b/spec/engine/matchers/rule_based_segment_matcher_spec.rb index f09b5422..ce2f9aba 100644 --- a/spec/engine/matchers/rule_based_segment_matcher_spec.rb +++ b/spec/engine/matchers/rule_based_segment_matcher_spec.rb @@ -32,7 +32,7 @@ expect(matcher.match?(value: 'key2')).to be false end - it 'return true if excluded rb segment is matched' do + it 'return false if excluded rb segment is matched' do rbs_repositoy = SplitIoClient::Cache::Repositories::RuleBasedSegmentsRepository.new(config) rbs = {:name => 'sample_rule_based_segment', :trafficTypeName => 'tt_name_1', :conditions => [], :excluded => {:keys => [], :segments => [{:name => 'no_excludes', :type => 'rule-based'}]}} rbs2 = {:name => 'no_excludes', :trafficTypeName => 'tt_name_1', @@ -60,7 +60,7 @@ rbs_repositoy.update([rbs, rbs2], [], -1) matcher = described_class.new(segments_repository, rbs_repositoy, 'sample_rule_based_segment', config) - expect(matcher.match?(value: 'bilal@split.io', attributes: {'email': 'bilal@split.io'})).to be true + expect(matcher.match?(value: 'bilal@split.io', attributes: {'email': 'bilal@split.io'})).to be false expect(matcher.match?(value: 'bilal', attributes: {'email': 'bilal'})).to be false end diff --git a/spec/repository_helper.rb b/spec/repository_helper.rb index 0f091f78..d38dff96 100644 --- a/spec/repository_helper.rb +++ b/spec/repository_helper.rb @@ -13,16 +13,16 @@ flag_sets_repository, flag_set_filter) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(true) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => ['set_3']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => ['set_3']}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(true) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => ['set_1']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => ['set_1']}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ARCHIVED', conditions: [], :sets => ['set_1']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ARCHIVED', conditions: [], :sets => ['set_1']}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(true) end @@ -35,16 +35,16 @@ flag_sets_repository, flag_set_filter) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :sets => ['set_3']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :sets => ['set_3']}], -1, config, false) expect(feature_flag_repository.get_split('split2').nil?).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split3', :status => 'ACTIVE', conditions: [], :sets => ['set_1']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split3', :status => 'ACTIVE', conditions: [], :sets => ['set_1']}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ARCHIVED', conditions: [], :sets => ['set_1']}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ARCHIVED', conditions: [], :sets => ['set_1']}], -1, config, false) expect(feature_flag_repository.get_split('split1').nil?).to eq(true) end @@ -57,16 +57,31 @@ flag_sets_repository, flag_set_filter) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config, false) expect(feature_flag_repository.get_split('split1')[:impressionsDisabled]).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :impressionsDisabled => false, :sets => []}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :impressionsDisabled => false, :sets => []}], -1, config, false) expect(feature_flag_repository.get_split('split2')[:impressionsDisabled]).to eq(false) - SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :impressionsDisabled => true, :sets => []}], -1, config) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :impressionsDisabled => true, :sets => []}], -1, config, false) expect(feature_flag_repository.get_split('split2')[:impressionsDisabled]).to eq(true) + end + + it 'test clear cache flag' do + config = SplitIoClient::SplitConfig.new(cache_adapter: :memory) + flag_set_filter = SplitIoClient::Cache::Filter::FlagSetsFilter.new([]) + flag_sets_repository = SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([]) + feature_flag_repository = SplitIoClient::Cache::Repositories::SplitsRepository.new( + config, + flag_sets_repository, + flag_set_filter) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config, false) + expect(feature_flag_repository.get_split('split1').nil?).to eq(false) + SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split2', :status => 'ACTIVE', conditions: [], :sets => ['set_3']}], -1, config, true) + expect(feature_flag_repository.get_split('split2').nil?).to eq(false) + expect(feature_flag_repository.get_split('split1').nil?).to eq(true) end end end From ecd007b8f34868b5ddf975be9d1dd550fbb8617f Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 16 May 2025 12:15:51 -0700 Subject: [PATCH 7/9] updated split api --- lib/splitclient-rb/engine/api/splits.rb | 4 ++ spec/engine/api/splits_spec.rb | 29 +++++++- .../rule_based_segments/split_old_spec2.json | 66 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 spec/test_data/rule_based_segments/split_old_spec2.json diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index b8e08974..1b690e3b 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -16,6 +16,7 @@ def initialize(api_key, config, telemetry_runtime_producer) @spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION @last_proxy_check_timestamp = 0 @clear_storage = false + @old_spec_since = nil end def since(since, since_rbs, fetch_options = { cache_control_headers: false, till: nil, sets: nil}) @@ -24,13 +25,16 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till if check_last_proxy_check_timestamp @spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION @config.logger.debug("Switching to new Feature flag spec #{@spec_version} and fetching.") + @old_spec_since = since since = -1 since_rbs = -1 fetch_options = { cache_control_headers: false, till: nil, sets: nil} end if @spec_version == Splits::SPEC_1_1 + since = @old_spec_since unless @old_spec_since.nil? params = { s: @spec_version, since: since } + @old_spec_since = nil else params = { s: @spec_version, since: since, rbSince: since_rbs } end diff --git a/spec/engine/api/splits_spec.rb b/spec/engine/api/splits_spec.rb index 9c384a32..e5c4a47f 100644 --- a/spec/engine/api/splits_spec.rb +++ b/spec/engine/api/splits_spec.rb @@ -225,11 +225,38 @@ SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 sleep 1 - parsed_splits = splits_api.since(-1, -1) + parsed_splits = splits_api.since(1457726098069, -1) expect(splits_api.clear_storage).to eq(true) expect(parsed_splits[:ff][:d].length()).to eq(2) expect(parsed_splits[:rbs][:d].length()).to eq(1) expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Spec::FeatureFlags::SPEC_VERSION) + expect(splits_api.instance_variable_get(:@old_spec_since)).to eq(1457726098069) + end + + it 'check using old_spec_since variable' do + old_spec_splits2 = File.read(File.expand_path(File.join(File.dirname(__FILE__), '../../test_data/rule_based_segments/split_old_spec2.json'))) + + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.3&since=-1&rbSince=-1') + .to_return({status: 400, body: ''}, {status: 400, body: ''}) + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=-1') + .to_return(status: 200, body: old_spec_splits) + stub_request(:get, 'https://proxy-server/api/splitChanges?s=1.1&since=1457726098069') + .to_return(status: 200, body: old_spec_splits2) + + parsed_splits = splits_api.since(-1, -1) + expect(parsed_splits[:ff][:d].length()).to eq(6) + expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Api::Splits::SPEC_1_1) + + SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 1 + sleep 1 + parsed_splits = splits_api.since(1457726098069, -1) + SplitIoClient::Api::Splits::PROXY_CHECK_INTERVAL_SECONDS = 100000 + + sleep 1 + expect(splits_api.instance_variable_get(:@spec_version)).to eq(SplitIoClient::Api::Splits::SPEC_1_1) + expect(splits_api.instance_variable_get(:@old_spec_since)).to eq(nil) + expect(parsed_splits[:ff][:d].length()).to eq(1) + expect(log.string).to include 'Switching to new Feature flag spec 1.3 and fetching.' end end end diff --git a/spec/test_data/rule_based_segments/split_old_spec2.json b/spec/test_data/rule_based_segments/split_old_spec2.json new file mode 100644 index 00000000..74aff1ed --- /dev/null +++ b/spec/test_data/rule_based_segments/split_old_spec2.json @@ -0,0 +1,66 @@ +{ + "splits": [ + { + "orgId": null, + "environment": null, + "trafficTypeId": null, + "trafficTypeName": null, + "name": "new_feature", + "seed": -1222652054, + "status": "ACTIVE", + "killed": false, + "changeNumber": 123, + "defaultTreatment": "off", + "conditions": [ + { + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "matcherType": "WHITELIST", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": { + "whitelist": [ + "whitelisted_user" + ] + } + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + } + ] + }, + { + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 100 + } + ] + } + ], + "sets": ["set1", "set2"] + } ], + "since": -1, + "till": 1457726098069 +} \ No newline at end of file From 3a33ffcfabcf9f2d92b579e3f8cd5115a3a03e35 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 19 May 2025 15:45:46 -0700 Subject: [PATCH 8/9] updated util and test --- lib/splitclient-rb/engine/api/splits.rb | 10 +-------- lib/splitclient-rb/helpers/util.rb | 11 ++++++++++ .../sse/workers/splits_worker.rb | 2 +- spec/sse/workers/splits_worker_spec.rb | 21 ++++++++++++------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/splitclient-rb/engine/api/splits.rb b/lib/splitclient-rb/engine/api/splits.rb index b8e08974..a86397e1 100644 --- a/lib/splitclient-rb/engine/api/splits.rb +++ b/lib/splitclient-rb/engine/api/splits.rb @@ -115,15 +115,7 @@ def objects_with_segment_names(parsed_objects) end.flatten parsed_objects[:rbs][:d].each do |rule_based_segment| - parsed_objects[:segment_names].merge Helpers::Util.segment_names_by_object(rule_based_segment, "IN_SEGMENT") - end - - parsed_objects[:rbs][:d].each do |rule_based_segment| - rule_based_segment[:excluded][:segments].each do |segment| - if segment[:type] == "standard" - parsed_objects[:segment_names].add(segment[:name]) - end - end + parsed_objects[:segment_names].merge Helpers::Util.segment_names_in_rb_segment(rule_based_segment, "IN_SEGMENT") end parsed_objects diff --git a/lib/splitclient-rb/helpers/util.rb b/lib/splitclient-rb/helpers/util.rb index 0f61d0ca..3c6eff85 100644 --- a/lib/splitclient-rb/helpers/util.rb +++ b/lib/splitclient-rb/helpers/util.rb @@ -12,6 +12,17 @@ def self.segment_names_by_object(object, matcher_type) end end end + + def self.segment_names_in_rb_segment(object, matcher_type) + names = Set.new + names.merge segment_names_by_object(object, matcher_type) + object[:excluded][:segments].each do |segment| + if segment[:type] == 'standard' + names.add(segment[:name]) + end + end + names + end end end end diff --git a/lib/splitclient-rb/sse/workers/splits_worker.rb b/lib/splitclient-rb/sse/workers/splits_worker.rb index f1e83775..4fe7563e 100644 --- a/lib/splitclient-rb/sse/workers/splits_worker.rb +++ b/lib/splitclient-rb/sse/workers/splits_worker.rb @@ -102,7 +102,7 @@ def update_rule_based_segment(notification) SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository, [new_rb_segment], notification.data['changeNumber'], @config) - fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_rb_segment, 'IN_SEGMENT'), + fetch_segments_if_not_exists(Helpers::Util.segment_names_in_rb_segment(new_rb_segment, 'IN_SEGMENT'), @rule_based_segment_repository) # TODO: enable when telemetry spec is added diff --git a/spec/sse/workers/splits_worker_spec.rb b/spec/sse/workers/splits_worker_spec.rb index 0ef724f9..1bc41bf8 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -22,7 +22,7 @@ let(:event_split_update_no_definition) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c": 0, "d":null}'), 'test') } let(:event_split_update_segments) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":2,"d":"eJzcVFtr20wQ/SvhPK9AsnzTvpnPJp+po0DlppRgzFga2dusJLNapaRG/73Id7sOoU+FvmluZ3TOGXYDayhNVTx9W3NIGUOiKtlAQCWQSNq+FyeJ6yzcBTuex+T0qe86XrfrUkJBzH4AgXw3mVFlivl3eiWIA/BA6yImq4oc0nPdG/mIOYF0gpYfeO3AEyh3Ca/XDfxer+u2BUpLtiohMfhvOn4aQeBFad20paRLFkg4pUrbqWGyGecWEvbwPQ9cCMQrypccVtmCDaTX7feCnu+7nY7nCZBeFpAtgbjIU7WszPbPSshNvc0lah8/b05hoxkkvv4/no4m42gKgYxsvGJzb4pqDdn0ZguVNwsxCIenhh3SPriBk/OSLB/Z/Vgpy1qV9mE3MSRLDfwxD/kMSjKVb1dUpmgwVFxgVtezWmBNxp5RsDdlavkdCJTqJ2+tqmcCmhasIU+LOEEtftfg8+Nk8vjlzxV44beINce2ME3z2TEeDrEWVzKNw3k0un8YhTd0aiaGnKqck4iXDakrwcpdNjzdq9PChxIV+VEXt2F/UUvTC9Guyk/t90dfO+/Xro73w65z7y6cU/ndnvTdge7f9W8wmcw/jb5F1+79yybsX6c7U2lGPat/BQAA//9ygdKB"}'), 'test') } let(:event_split_update_rb_segments) { SplitIoClient::SSE::EventSource::StreamData.new("data", 123, JSON.parse('{"type":"SPLIT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":0,"d":"eyJjaGFuZ2VOdW1iZXIiOiAxMCwgInRyYWZmaWNUeXBlTmFtZSI6ICJ1c2VyIiwgIm5hbWUiOiAicmJzX2ZsYWciLCAidHJhZmZpY0FsbG9jYXRpb24iOiAxMDAsICJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOiAxODI4Mzc3MzgwLCAic2VlZCI6IC0yODY2MTc5MjEsICJzdGF0dXMiOiAiQUNUSVZFIiwgImtpbGxlZCI6IGZhbHNlLCAiZGVmYXVsdFRyZWF0bWVudCI6ICJvZmYiLCAiYWxnbyI6IDIsICJjb25kaXRpb25zIjogW3siY29uZGl0aW9uVHlwZSI6ICJST0xMT1VUIiwgIm1hdGNoZXJHcm91cCI6IHsiY29tYmluZXIiOiAiQU5EIiwgIm1hdGNoZXJzIjogW3sia2V5U2VsZWN0b3IiOiB7InRyYWZmaWNUeXBlIjogInVzZXIifSwgIm1hdGNoZXJUeXBlIjogIklOX1JVTEVfQkFTRURfU0VHTUVOVCIsICJuZWdhdGUiOiBmYWxzZSwgInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjogeyJzZWdtZW50TmFtZSI6ICJzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50In19XX0sICJwYXJ0aXRpb25zIjogW3sidHJlYXRtZW50IjogIm9uIiwgInNpemUiOiAxMDB9LCB7InRyZWF0bWVudCI6ICJvZmYiLCAic2l6ZSI6IDB9XSwgImxhYmVsIjogImluIHJ1bGUgYmFzZWQgc2VnbWVudCBzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50In0sIHsiY29uZGl0aW9uVHlwZSI6ICJST0xMT1VUIiwgIm1hdGNoZXJHcm91cCI6IHsiY29tYmluZXIiOiAiQU5EIiwgIm1hdGNoZXJzIjogW3sia2V5U2VsZWN0b3IiOiB7InRyYWZmaWNUeXBlIjogInVzZXIifSwgIm1hdGNoZXJUeXBlIjogIkFMTF9LRVlTIiwgIm5lZ2F0ZSI6IGZhbHNlfV19LCAicGFydGl0aW9ucyI6IFt7InRyZWF0bWVudCI6ICJvbiIsICJzaXplIjogMH0sIHsidHJlYXRtZW50IjogIm9mZiIsICJzaXplIjogMTAwfV0sICJsYWJlbCI6ICJkZWZhdWx0IHJ1bGUifV0sICJjb25maWd1cmF0aW9ucyI6IHt9LCAic2V0cyI6IFtdLCAiaW1wcmVzc2lvbnNEaXNhYmxlZCI6IGZhbHNlfQ=="}'), 'test') } - let(:event_rb_segment_update) { SplitIoClient::SSE::EventSource::StreamData.new("data", 12345, JSON.parse('{"type":"RB_SEGMENT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":0,"d":"eyJjaGFuZ2VOdW1iZXIiOiA1LCAibmFtZSI6ICJzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50IiwgInN0YXR1cyI6ICJBQ1RJVkUiLCAidHJhZmZpY1R5cGVOYW1lIjogInVzZXIiLCAiZXhjbHVkZWQiOiB7ImtleXMiOiBbIm1hdXJvQHNwbGl0LmlvIl0sICJzZWdtZW50cyI6IFtdfSwgImNvbmRpdGlvbnMiOiBbeyJtYXRjaGVyR3JvdXAiOiB7ImNvbWJpbmVyIjogIkFORCIsICJtYXRjaGVycyI6IFt7ImtleVNlbGVjdG9yIjogeyJ0cmFmZmljVHlwZSI6ICJ1c2VyIiwgImF0dHJpYnV0ZSI6ICJlbWFpbCJ9LCAibWF0Y2hlclR5cGUiOiAiRU5EU19XSVRIIiwgIm5lZ2F0ZSI6IGZhbHNlLCAid2hpdGVsaXN0TWF0Y2hlckRhdGEiOiB7IndoaXRlbGlzdCI6IFsiQHNwbGl0LmlvIl19fV19fV19"}'), 'test') } + let(:event_rb_segment_update) { SplitIoClient::SSE::EventSource::StreamData.new("data", 12345, JSON.parse('{"type":"RB_SEGMENT_UPDATE","changeNumber":5564531221,"pcn":1234,"c":0,"d":"eyJjaGFuZ2VOdW1iZXIiOiA1LCAibmFtZSI6ICJzYW1wbGVfcnVsZV9iYXNlZF9zZWdtZW50IiwgInN0YXR1cyI6ICJBQ1RJVkUiLCAidHJhZmZpY1R5cGVOYW1lIjogInVzZXIiLCAiZXhjbHVkZWQiOiB7ImtleXMiOiBbIm1hdXJvQHNwbGl0LmlvIl0sICJzZWdtZW50cyI6IFt7InR5cGUiOiAic3RhbmRhcmQiLCAibmFtZSI6ICJzZWdtZW50MSJ9XX0sICJjb25kaXRpb25zIjogW3sibWF0Y2hlckdyb3VwIjogeyJjb21iaW5lciI6ICJBTkQiLCAibWF0Y2hlcnMiOiBbeyJrZXlTZWxlY3RvciI6IHsidHJhZmZpY1R5cGUiOiAidXNlciIsICJhdHRyaWJ1dGUiOiAiZW1haWwifSwgIm1hdGNoZXJUeXBlIjogIklOX1NFR01FTlQiLCAibmVnYXRlIjogZmFsc2UsICJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6IHsic2VnbWVudE5hbWUiOiAiZGVtbyJ9fV19fV19"}'), 'test') } context 'add change number to queue' do let(:flag_sets_repository) {SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new([])} @@ -309,7 +309,7 @@ "trafficTypeName": "user", "excluded":{ "keys":["mauro@split.io","gaston@split.io"], - "segments":[] + "segments":["segment1"] }, "conditions": [ { @@ -321,13 +321,11 @@ "trafficType": "user", "attribute": "email" }, - "matcherType": "ENDS_WITH", + "matcherType": "IN_SEGMENT", "negate": false, - "whitelistMatcherData": { - "whitelist": [ - "@split.io" - ] - } + "userDefinedSegmentMatcherData":{ + "segmentName":"demo" + }, } ] } @@ -358,6 +356,8 @@ end it 'process rb segment update' do + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=-1').to_return(status: 200, body: '{"name":"maur-2","added":["admin"],"removed":[],"since":-1,"till":-1}}') + stub_request(:get, 'https://sdk.split.io/api/segmentChanges/demo?since=-1').to_return(status: 200, body: '{"name":"maur-2","added":["admin"],"removed":[],"since":-1,"till":-1}}') worker = subject.new(synchronizer, config, splits_repository, telemetry_runtime_producer, segment_fetcher, rule_based_segments_repository) worker.start @@ -366,6 +366,11 @@ sleep 2 rb_segment = rule_based_segments_repository.get_rule_based_segment("sample_rule_based_segment") expect(rb_segment[:name] == 'sample_rule_based_segment') + + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/demo?since=-1')).to have_been_made.once + expect(segments_repository.used_segment_names[0]).to eq('demo') + expect(a_request(:get, 'https://sdk.split.io/api/segmentChanges/segment1?since=-1')).to have_been_made.once + expect(segments_repository.used_segment_names[1]).to eq('segment1') end end From 3fe83c5f4be2ab98dc53154c4c2cad937311cf02 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 20 May 2025 10:34:24 -0700 Subject: [PATCH 9/9] fix test --- 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 1bc41bf8..74e00c51 100644 --- a/spec/sse/workers/splits_worker_spec.rb +++ b/spec/sse/workers/splits_worker_spec.rb @@ -309,7 +309,7 @@ "trafficTypeName": "user", "excluded":{ "keys":["mauro@split.io","gaston@split.io"], - "segments":["segment1"] + "segments":[{ "type": "standard", "name": "segment1"}] }, "conditions": [ {