Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion lib/splitclient-rb/cache/repositories/splits_repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,32 @@ module Cache
module Repositories
class SplitsRepository < Repository
attr_reader :adapter

DEFAULT_CONDITIONS_TEMPLATE = {
conditionType: "ROLLOUT",
matcherGroup: {
combiner: "AND",
matchers: [
{
keySelector: nil,
matcherType: "ALL_KEYS",
negate: false,
userDefinedSegmentMatcherData: nil,
whitelistMatcherData: nil,
unaryNumericMatcherData: nil,
betweenMatcherData: nil,
dependencyMatcherData: nil,
booleanMatcherData: nil,
stringMatcherData: nil
}]
},
partitions: [
{
treatment: "control",
size: 100
}
],
label: "unsupported matcher type"
}
def initialize(config, flag_sets_repository, flag_set_filter)
super(config)
@tt_cache = {}
Expand Down Expand Up @@ -155,6 +180,10 @@ def add_feature_flag(split)
remove_from_flag_sets(existing_split)
end

if check_undefined_matcher(split)
@config.logger.warn("Feature Flag #{split[:name]} has undefined matcher, setting conditions to default template.")
split[:conditions] = [SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]
end
if !split[:sets].nil?
for flag_set in split[:sets]
if !@flag_sets.flag_set_exist?(flag_set)
Expand All @@ -170,6 +199,18 @@ def add_feature_flag(split)
@adapter.set_string(namespace_key(".split.#{split[:name]}"), split.to_json)
end

def check_undefined_matcher(split)
for condition in split[:conditions]
for matcher in condition[:matcherGroup][:matchers]
if !SplitIoClient::Condition.instance_methods(false).map(&:to_s).include?("matcher_#{matcher[:matcherType].downcase}")
@config.logger.error("Detected undefined matcher #{matcher[:matcherType].downcase} in feature flag #{split[:name]}")
return true
end
end
end
return false
end

def remove_feature_flag(split)
decrease_tt_name_count(split[:trafficTypeName])
remove_from_flag_sets(split)
Expand Down
82 changes: 65 additions & 17 deletions spec/cache/repositories/splits_repository_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

before do
# in memory setup
repository.update([{name: 'foo', trafficTypeName: 'tt_name_1'},
{name: 'bar', trafficTypeName: 'tt_name_2'},
{name: 'baz', trafficTypeName: 'tt_name_1'}], [], -1)
repository.update([{name: 'foo', trafficTypeName: 'tt_name_1', conditions: []},
{name: 'bar', trafficTypeName: 'tt_name_2', conditions: []},
{name: 'baz', trafficTypeName: 'tt_name_1', conditions: []}], [], -1)

# redis setup
repository.instance_variable_get(:@adapter).set_string(
Expand All @@ -31,13 +31,13 @@
end

after do
repository.update([], [{name: 'foo', trafficTypeName: 'tt_name_1'},
{name: 'bar', trafficTypeName: 'tt_name_2'},
{name: 'bar', trafficTypeName: 'tt_name_2'},
{name: 'qux', trafficTypeName: 'tt_name_3'},
{name: 'quux', trafficTypeName: 'tt_name_4'},
{name: 'corge', trafficTypeName: 'tt_name_5'},
{name: 'corge', trafficTypeName: 'tt_name_6'}], -1)
repository.update([], [{name: 'foo', trafficTypeName: 'tt_name_1', conditions: []},
{name: 'bar', trafficTypeName: 'tt_name_2', conditions: []},
{name: 'bar', trafficTypeName: 'tt_name_2', conditions: []},
{name: 'qux', trafficTypeName: 'tt_name_3', conditions: []},
{name: 'quux', trafficTypeName: 'tt_name_4', conditions: []},
{name: 'corge', trafficTypeName: 'tt_name_5', conditions: []},
{name: 'corge', trafficTypeName: 'tt_name_6', conditions: []}], -1)
end

it 'returns splits names' do
Expand All @@ -52,7 +52,7 @@
expect(repository.traffic_type_exists('tt_name_1')).to be true
expect(repository.traffic_type_exists('tt_name_2')).to be true

split = { name: 'qux', trafficTypeName: 'tt_name_3' }
split = { name: 'qux', trafficTypeName: 'tt_name_3', conditions: [] }

repository.update([split], [], -1)
repository.update([], [split], -1)
Expand All @@ -61,7 +61,7 @@
end

it 'does not increment traffic type count when adding same split twice' do
split = { name: 'quux', trafficTypeName: 'tt_name_4' }
split = { name: 'quux', trafficTypeName: 'tt_name_4', conditions: [] }

repository.update([split, split], [], -1)
repository.update([], [split], -1)
Expand All @@ -70,7 +70,7 @@
end

it 'updates traffic type count accordingly when split changes traffic type' do
split = { name: 'corge', trafficTypeName: 'tt_name_5' }
split = { name: 'corge', trafficTypeName: 'tt_name_5', conditions: [] }

repository.update([split], [], -1)
repository.instance_variable_get(:@adapter).set_string(
Expand All @@ -79,7 +79,7 @@

expect(repository.traffic_type_exists('tt_name_5')).to be true

split = { name: 'corge', trafficTypeName: 'tt_name_6' }
split = { name: 'corge', trafficTypeName: 'tt_name_6', conditions: [] }

repository.update([split], [], -1)

Expand All @@ -97,11 +97,59 @@

it 'returns splits data' do
expect(repository.splits).to eq(
'foo' => { name: 'foo', trafficTypeName: 'tt_name_1' },
'bar' => { name: 'bar', trafficTypeName: 'tt_name_2' },
'baz' => { name: 'baz', trafficTypeName: 'tt_name_1' }
'foo' => { name: 'foo', trafficTypeName: 'tt_name_1', conditions: [] },
'bar' => { name: 'bar', trafficTypeName: 'tt_name_2', conditions: [] },
'baz' => { name: 'baz', trafficTypeName: 'tt_name_1', conditions: [] }
)
end

it 'remove undefined matcher with template condition' do
split = { name: 'corge', trafficTypeName: 'tt_name_5', conditions: [
{
partitions: [
{treatment: 'on', size: 50},
{treatment: 'off', size: 50}
],
contitionType: 'WHITELIST',
label: 'some_label',
matcherGroup: {
matchers: [
{
matcherType: 'UNDEFINED',
whitelistMatcherData: {
whitelist: ['k1', 'k2', 'k3']
},
negate: false,
}
],
combiner: 'AND'
}
}]
}
repository.update([split], [], -1)
expect(repository.get_split('corge')[:conditions]).to eq [SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]

# test with multiple conditions
split[:conditions] .append({
partitions: [
{treatment: 'on', size: 25},
{treatment: 'off', size: 75}
],
contitionType: 'WHITELIST',
label: 'some_other_label',
matcherGroup: {
matchers: [
{
matcherType: 'ALL_KEYS',
negate: false,
}
],
combiner: 'AND'
}
})
repository.update([split], [], -1)
expect(repository.get_split('corge')[:conditions]).to eq [SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]
end
end

describe 'with Memory Adapter' do
Expand Down
16 changes: 8 additions & 8 deletions spec/repository_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
flag_sets_repository,
flag_set_filter)

SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', :sets => []}], -1, config)
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config)
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', :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)
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', :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)
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', :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)
expect(feature_flag_repository.get_split('split1').nil?).to eq(true)
end

Expand All @@ -35,16 +35,16 @@
flag_sets_repository,
flag_set_filter)

SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', :sets => []}], -1, config)
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(feature_flag_repository, [{:name => 'split1', :status => 'ACTIVE', conditions: [], :sets => []}], -1, config)
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', :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)
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', :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)
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', :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)
expect(feature_flag_repository.get_split('split1').nil?).to eq(true)
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/telemetry/synchronizer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@
end

it 'with data' do
splits_repository.update([{name: 'foo', trafficTypeName: 'tt_name_1'},
{name: 'bar', trafficTypeName: 'tt_name_2'},
{name: 'baz', trafficTypeName: 'tt_name_1'}], [], -1)
splits_repository.update([{name: 'foo', trafficTypeName: 'tt_name_1', conditions: []},
{name: 'bar', trafficTypeName: 'tt_name_2', conditions: []},
{name: 'baz', trafficTypeName: 'tt_name_1', conditions: []}], [], -1)

segments_repository.add_to_segment(name: 'foo-1', added: [1, 2, 3], removed: [])
segments_repository.add_to_segment(name: 'foo-2', added: [1, 2, 3, 4], removed: [])
Expand Down