Skip to content

Commit

Permalink
Merge pull request #521 from splitio/semver-integration-spec
Browse files Browse the repository at this point in the history
semver matchers integrations spec
  • Loading branch information
chillaq authored Apr 10, 2024
2 parents 89826a3 + 9f1b7d9 commit f76b944
Show file tree
Hide file tree
Showing 10 changed files with 666 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/splitclient-rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
require 'splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher'
require 'splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher'
require 'splitclient-rb/engine/matchers/between_semver_matcher'
require 'splitclient-rb/engine/matchers/in_list_semver_matcher'
require 'splitclient-rb/engine/evaluator/splitter'
require 'splitclient-rb/engine/impressions/noop_unique_keys_tracker'
require 'splitclient-rb/engine/impressions/unique_keys_tracker'
Expand Down
31 changes: 31 additions & 0 deletions lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module SplitIoClient
class InListSemverMatcher < Matcher
MATCHER_TYPE = 'IN_LIST_SEMVER'

attr_reader :attribute

def initialize(attribute, list_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver_list = list_value.map { |item| SplitIoClient::Semver.new(item) }
@logger = logger
end

def match?(args)
@logger.log_if_debug('[InListSemverMatcher] evaluating value and attributes.')
return false unless @validator.valid_matcher_arguments(args)

value_to_match = args[:attributes][@attribute.to_sym]
unless value_to_match.is_a?(String)
@logger.log_if_debug('whitelistMatcherData is required for IN_LIST_SEMVER matcher type')
return false
end
matches = (@semver_list.map { |item| item.compare(SplitIoClient::Semver.new(value_to_match)) }).any?(&:zero?)
@logger.log_if_debug("[InListSemverMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
8 changes: 8 additions & 0 deletions lib/splitclient-rb/engine/parser/condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ def matcher_between_semver(params)
)
end

def matcher_in_list_semver(params)
InListSemverMatcher.new(
params[:matcher][:keySelector][:attribute],
params[:matcher][:whitelistMatcherData][:whitelist],
@config.split_logger, @config.split_validator
)
end

#
# @return [object] the negate value for this condition
def negate
Expand Down
40 changes: 40 additions & 0 deletions spec/engine/matchers/matches_in_list_semver_matcher_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

require 'spec_helper'

describe SplitIoClient::InListSemverMatcher do
let(:raw) { {
'negate': false,
'matcherType': 'INLIST_SEMVER',
'whitelistMatcherData': {"whitelist": ["2.1.8", "2.1.11"]}
} }
let(:config) { SplitIoClient::SplitConfig.new }

it 'initilized params' do
matcher = described_class.new("version", raw[:whitelistMatcherData][:whitelist], config.split_logger, config.split_validator)
expect(matcher.attribute).to eq("version")
semver_list = matcher.instance_variable_get(:@semver_list)
expect(semver_list[0].instance_variable_get(:@old_version)).to eq("2.1.8")
expect(semver_list[1].instance_variable_get(:@old_version)).to eq("2.1.11")
end

it 'matches' do
matcher = described_class.new("version", raw[:whitelistMatcherData][:whitelist], config.split_logger, config.split_validator)
expect(matcher.match?(:attributes=>{"version": "2.1.8+rc"})).to eq(true)
expect(matcher.match?(:attributes=>{"version": "2.1.11"})).to eq(true)
end

it 'does not match' do
matcher = described_class.new("version", raw[:whitelistMatcherData][:whitelist], config.split_logger, config.split_validator)
expect(matcher.match?(:attributes=>{"version": "2.1.7"})).to eq(false)
expect(matcher.match?(:attributes=>{"version": "2.1.11-rc12"})).to eq(false)
expect(matcher.match?(:attributes=>{"version": "2.1.8-rc1"})).to eq(false)
end

it 'invalid attribute' do
matcher = described_class.new("version", raw[:whitelistMatcherData][:whitelist], config.split_logger, config.split_validator)
expect(matcher.match?(:attributes=>{"version": 2.1})).to eq(false)
expect(matcher.match?(:attributes=>{"version": nil})).to eq(false)
end

end
159 changes: 159 additions & 0 deletions spec/engine/matchers/semver_matchers_integration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'Semver matchers integration' do
subject do
SplitIoClient::SplitFactory.new('test_api_key', {
logger: Logger.new(log),
streaming_enabled: false,
impressions_refresh_rate: 9999,
impressions_mode: :none,
features_refresh_rate: 9999,
telemetry_refresh_rate: 99999}).client
end

let(:log) { StringIO.new }

let(:semver_between_matcher_splits) do
File.read(File.expand_path(File.join(File.dirname(__FILE__),
'../../test_data/splits/semver_matchers/semver_between.json')))
end

let(:semver_equalto_matcher_splits) do
File.read(File.expand_path(File.join(File.dirname(__FILE__),
'../../test_data/splits/semver_matchers/semver_equalto.json')))
end

let(:semver_greater_or_equalto_matcher_splits) do
File.read(File.expand_path(File.join(File.dirname(__FILE__),
'../../test_data/splits/semver_matchers/semver_greater_or_equalto.json')))
end

let(:semver_less_or_equalto_matcher_splits) do
File.read(File.expand_path(File.join(File.dirname(__FILE__),
'../../test_data/splits/semver_matchers/semver_less_or_equalto.json')))
end

let(:semver_inlist_matcher_splits) do
File.read(File.expand_path(File.join(File.dirname(__FILE__),
'../../test_data/splits/semver_matchers/semver_inlist.json')))
end

let(:user) { 'fake_user_id_1' }

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 'equal to matcher' do
before do
stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/)
.to_return(status: 200, body: semver_equalto_matcher_splits)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
.to_return(status: 200, body: semver_equalto_matcher_splits)
sleep 1
subject.block_until_ready
end

it 'validates the treatment is ON for correct attribute value' do
expect(subject.get_treatment(user, 'semver_equalto', {:version => "1.22.9"})).to eq 'on'
end

it 'validates the treatment is the default treatment for incorrect attributes hash and nil' do
expect(subject.get_treatment(user, 'semver_equalto')).to eq 'off'
expect(subject.get_treatment(user, 'semver_equalto', {:version => "1.22.10"})).to eq 'off'
subject.destroy()
end
end

context 'greater than or equal to matcher' do
before do
stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/)
.to_return(status: 200, body: semver_greater_or_equalto_matcher_splits)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
.to_return(status: 200, body: semver_greater_or_equalto_matcher_splits)
sleep 1
subject.block_until_ready
end

it 'validates the treatment is ON for correct attribute value' do
expect(subject.get_treatment(user, 'semver_greater_or_equalto', {:version => "1.22.9"})).to eq 'on'
expect(subject.get_treatment(user, 'semver_greater_or_equalto', {:version => "1.22.10"})).to eq 'on'
end

it 'validates the treatment is the default treatment for incorrect attributes hash and nil' do
expect(subject.get_treatment(user, 'semver_greater_or_equalto')).to eq 'off'
expect(subject.get_treatment(user, 'semver_greater_or_equalto', {:version => "1.22.8"})).to eq 'off'
subject.destroy()
end
end

context 'less than or equal to matcher' do
before do
stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/)
.to_return(status: 200, body: semver_less_or_equalto_matcher_splits)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
.to_return(status: 200, body: semver_less_or_equalto_matcher_splits)
sleep 1
subject.block_until_ready
end

it 'validates the treatment is ON for correct attribute value' do
expect(subject.get_treatment(user, 'semver_less_or_equalto', {:version => "1.22.9"})).to eq 'on'
expect(subject.get_treatment(user, 'semver_less_or_equalto', {:version => "1.22.8"})).to eq 'on'
end

it 'validates the treatment is the default treatment for incorrect attributes hash and nil' do
expect(subject.get_treatment(user, 'semver_less_or_equalto')).to eq 'off'
expect(subject.get_treatment(user, 'semver_less_or_equalto', {:version => "1.22.10"})).to eq 'off'
subject.destroy()
end
end

context 'in list matcher' do
before do
stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/)
.to_return(status: 200, body: semver_inlist_matcher_splits)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
.to_return(status: 200, body: semver_inlist_matcher_splits)
sleep 1
subject.block_until_ready
end

it 'validates the treatment is ON for correct attribute value' do
expect(subject.get_treatment(user, 'semver_inlist', {:version => "1.22.9"})).to eq 'on'
expect(subject.get_treatment(user, 'semver_inlist', {:version => "2.1.0"})).to eq 'on'
end

it 'validates the treatment is the default treatment for incorrect attributes hash and nil' do
expect(subject.get_treatment(user, 'semver_inlist')).to eq 'off'
expect(subject.get_treatment(user, 'semver_inlist', {:version => "1.22.10"})).to eq 'off'
subject.destroy()
end
end

context 'between matcher' do
before do
stub_request(:get, /https:\/\/sdk\.split\.io\/api\/splitChanges\?since/)
.to_return(status: 200, body: semver_between_matcher_splits)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
.to_return(status: 200, body: semver_between_matcher_splits)
sleep 1
subject.block_until_ready
end

it 'validates the treatment is ON for correct attribute value' do
expect(subject.get_treatment(user, 'semver_between', {:version => "1.22.9"})).to eq 'on'
expect(subject.get_treatment(user, 'semver_between', {:version => "2.0.10"})).to eq 'on'
end

it 'validates the treatment is the default treatment for incorrect attributes hash and nil' do
expect(subject.get_treatment(user, 'semver_between')).to eq 'off'
expect(subject.get_treatment(user, 'semver_between', {:version => "1.22.9-rc1"})).to eq 'off'
expect(subject.get_treatment(user, 'semver_between', {:version => "2.1.1"})).to eq 'off'
subject.destroy()
end
end
end
86 changes: 86 additions & 0 deletions spec/test_data/splits/semver_matchers/semver_between.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"splits": [
{
"trafficTypeName": "user",
"name": "semver_between",
"trafficAllocation": 100,
"trafficAllocationSeed": 1068038034,
"seed": -1053389887,
"status": "ACTIVE",
"killed": false,
"defaultTreatment": "off",
"changeNumber": 1675259356568,
"algo": 2,
"configurations": {},
"conditions": [
{
"conditionType": "ROLLOUT",
"matcherGroup": {
"combiner": "AND",
"matchers":
[
{"keySelector": {"trafficType": "user", "attribute": "version"},
"matcherType": "BETWEEN_SEMVER",
"negate": false,
"userDefinedSegmentMatcherData": null,
"whitelistMatcherData": null,
"unaryNumericMatcherData": null,
"betweenMatcherData": null,
"dependencyMatcherData": null,
"booleanMatcherData": null,
"stringMatcherData": null,
"betweenStringMatcherData": {"start": "1.22.9", "end": "2.1.0"}}
]
},
"partitions": [
{
"treatment": "on",
"size": 100
},
{
"treatment": "off",
"size": 0
}
],
"label": "between semver"
},
{
"conditionType": "ROLLOUT",
"matcherGroup": {
"combiner": "AND",
"matchers": [
{
"keySelector": {
"trafficType": "user",
"attribute": null
},
"matcherType": "ALL_KEYS",
"negate": false,
"userDefinedSegmentMatcherData": null,
"whitelistMatcherData": null,
"unaryNumericMatcherData": null,
"betweenMatcherData": null,
"booleanMatcherData": null,
"dependencyMatcherData": null,
"stringMatcherData": null
}
]
},
"partitions": [
{
"treatment": "on",
"size": 0
},
{
"treatment": "off",
"size": 100
}
],
"label": "default rule"
}
]
}
],
"since": -1,
"till": 1675259356568
}
Loading

0 comments on commit f76b944

Please sign in to comment.