prefab-cloud-ruby 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c18d5a31a2f535269b3faf262b82a57e67b75ceee5581c5ef6f8cea7bbdb416b
4
- data.tar.gz: d7125da40abab76dc25e37459cdde3a891801dc4f630c3f3f2f22f7f65ef2f5d
3
+ metadata.gz: 22d564bcc76424b3308623b4d2e27a4acaf4217c285bcca02542291d8cc15827
4
+ data.tar.gz: c097169d379d9f477a66d20fc378f693173de044baecad08059263fd239257e5
5
5
  SHA512:
6
- metadata.gz: 38e1ad427078327f05b01b869d5f0879819271b372d8373996d5d592e3d4efa92bed6b59d061d92dc2a21eb49c6c529140ae9f9b5d8825fc2b828840d1b23a7f
7
- data.tar.gz: 88cf63bf9dfdc9c103660240a5d2b35f27103eda55c28a96cb16943da41adf4ffa85928533fd739a868b3b5f5bb5ef565b80073f75712f3bb62305921694d1b2
6
+ metadata.gz: cdf6ca3b1b28bf83caa629193b21e2d26e4d22d64ee4cd30b7a88fdce623adc7f3feb3605df7107cdca00e7823709f9eeac2a68176db1d10b6616196d2bcb580
7
+ data.tar.gz: c61b171a2be217c016fad1cc0a1ce9faed159c6f894065db4202ec200ec1f8ac22caabb880fae0f358fcced0930ce49d4e273f800a0fb72c39c6d6f19cc59d07
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.11.0
data/lib/prefab/client.rb CHANGED
@@ -8,7 +8,7 @@ module Prefab
8
8
  }
9
9
 
10
10
 
11
- attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :project_env_id, :prefab_api_url
11
+ attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :prefab_api_url
12
12
 
13
13
  def initialize(api_key: ENV['PREFAB_API_KEY'],
14
14
  logdev: nil,
@@ -26,14 +26,12 @@ module Prefab
26
26
  @stats = (stats || NoopStats.new)
27
27
  @shared_cache = (shared_cache || NoopCache.new)
28
28
  @api_key = api_key
29
- @project_id = api_key.split("-")[0].to_i
30
- @project_env_id = api_key.split("-")[1].to_i
29
+ @project_id = api_key.split("-")[0].to_i # unvalidated, but that's ok. APIs only listen to the actual passwd
31
30
  @namespace = namespace
32
31
  @interceptor = Prefab::AuthInterceptor.new(api_key)
33
32
  @stubs = {}
34
33
  @prefab_api_url = ENV["PREFAB_API_URL"] || 'https://api.prefab.cloud'
35
34
  @prefab_grpc_url = ENV["PREFAB_GRPC_URL"] || 'grpc.prefab.cloud:443'
36
- log_internal Logger::INFO, "Prefab Initializing in environment: '#{@project_env_id}' and namespace: '#{@namespace}'"
37
35
  log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
38
36
  at_exit do
39
37
  channel.destroy
@@ -104,9 +104,6 @@ module Prefab
104
104
  resp = stub.get_all_config(config_req)
105
105
  @base_client.log_internal Logger::DEBUG, "Got Response #{resp}"
106
106
  load_configs(resp, :api)
107
- resp.configs.each do |delta|
108
- @config_loader.set(delta)
109
- end
110
107
  @config_resolver.update
111
108
  finish_init!(:api)
112
109
  true
@@ -127,6 +124,10 @@ module Prefab
127
124
  end
128
125
 
129
126
  def load_configs(configs, source)
127
+ project_env_id = configs.config_service_pointer.project_env_id
128
+ @config_resolver.project_env_id = project_env_id
129
+
130
+ @base_client.log_internal Logger::INFO, "Prefab Initializing in project: #{@base_client.project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
130
131
  configs.configs.each do |config|
131
132
  @config_loader.set(config)
132
133
  end
@@ -3,12 +3,14 @@ module Prefab
3
3
  include Prefab::ConfigHelper
4
4
  NAMESPACE_DELIMITER = ".".freeze
5
5
 
6
+ attr_accessor :project_env_id # this will be set by the config_client when it gets an API response
7
+
6
8
  def initialize(base_client, config_loader)
7
9
  @lock = Concurrent::ReadWriteLock.new
8
10
  @local_store = {}
9
- @project_env_id = base_client.project_env_id
10
11
  @namespace = base_client.namespace
11
12
  @config_loader = config_loader
13
+ @project_env_id = 0
12
14
  make_local
13
15
  end
14
16
 
@@ -2,7 +2,6 @@ module Prefab
2
2
  class FeatureFlagClient
3
3
  include Prefab::ConfigHelper
4
4
  MAX_32_FLOAT = 4294967294.0
5
- DISTRIBUTION_SPACE = 1000
6
5
 
7
6
  def initialize(base_client)
8
7
  @base_client = base_client
@@ -22,9 +21,11 @@ module Prefab
22
21
  return is_on?(get(feature_name, lookup_key, attributes))
23
22
  end
24
23
 
25
- def get(feature_name, lookup_key, attributes)
24
+ def get(feature_name, lookup_key=nil, attributes={})
26
25
  feature_obj = @base_client.config_client.get(feature_name)
27
- variants = @base_client.config_client.get_config_obj(feature_name).variants
26
+ config_obj = @base_client.config_client.get_config_obj(feature_name)
27
+ return nil if feature_obj.nil? || config_obj.nil?
28
+ variants = config_obj.variants
28
29
  evaluate(feature_name, lookup_key, attributes, feature_obj, variants)
29
30
  end
30
31
 
@@ -39,6 +40,9 @@ module Prefab
39
40
  return false
40
41
  end
41
42
  variant.bool
43
+ rescue
44
+ @base_client.log.info("is_on? methods only work for boolean feature flags variants. This feature flags variant is '#{variant}'. Returning false")
45
+ false
42
46
  end
43
47
 
44
48
  def get_variant(feature_name, lookup_key, attributes, feature_obj, variants)
@@ -46,8 +50,6 @@ module Prefab
46
50
  return get_variant_obj(variants, feature_obj.inactive_variant_idx)
47
51
  end
48
52
 
49
- variant_distribution = feature_obj.default
50
-
51
53
  # if user_targets.match
52
54
  feature_obj.user_targets.each do |target|
53
55
  if (target.identifiers.include? lookup_key)
@@ -55,34 +57,37 @@ module Prefab
55
57
  end
56
58
  end
57
59
 
60
+ #default to inactive
61
+ variant_weights = [Prefab::VariantWeight.new(variant_idx: feature_obj.inactive_variant_idx, weight: 1)]
62
+
58
63
  # if rules.match
59
64
  feature_obj.rules.each do |rule|
60
65
  if criteria_match?(rule, lookup_key, attributes)
61
- variant_distribution = rule.distribution
66
+ variant_weights = rule.variant_weights
67
+ break
62
68
  end
63
69
  end
64
70
 
65
- if variant_distribution.type == :variant_idx
66
- variant_idx = variant_distribution.variant_idx
67
- else
68
- percent_through_distribution = rand()
69
- if lookup_key
70
- percent_through_distribution = get_user_pct(feature_name, lookup_key)
71
- end
72
- distribution_bucket = DISTRIBUTION_SPACE * percent_through_distribution
73
71
 
74
- variant_idx = get_variant_idx_from_weights(variant_distribution.variant_weights.weights, distribution_bucket, feature_name)
72
+ percent_through_distribution = rand()
73
+ if lookup_key
74
+ percent_through_distribution = get_user_pct(feature_name, lookup_key)
75
75
  end
76
76
 
77
+ variant_idx = get_variant_idx_from_weights(variant_weights, percent_through_distribution, feature_name)
78
+
77
79
  return get_variant_obj(variants, variant_idx)
78
80
  end
79
81
 
80
82
  def get_variant_obj(variants, idx)
81
- return variants[idx] if variants.length >= idx
83
+ # our array is 0 based, but the idx are 1 based so the protos are clearly set
84
+ return variants[idx - 1] if variants.length >= idx
82
85
  nil
83
86
  end
84
87
 
85
- def get_variant_idx_from_weights(variant_weights, bucket, feature_name)
88
+ def get_variant_idx_from_weights(variant_weights, percent_through_distribution, feature_name)
89
+ distrubution_space = variant_weights.inject(0) { |sum, v| sum + v.weight }
90
+ bucket = distrubution_space * percent_through_distribution
86
91
  sum = 0
87
92
  variant_weights.each do |variant_weight|
88
93
  if bucket < sum + variant_weight.weight
@@ -93,7 +98,7 @@ module Prefab
93
98
  end
94
99
  # variants didn't add up to 100%
95
100
  @base_client.log.info("Variants of #{feature_name} did not add to 100%")
96
- return variant_weights.last.variant
101
+ return variant_weights.last.variant_idx
97
102
  end
98
103
 
99
104
  def get_user_pct(feature, lookup_key)
@@ -103,14 +108,21 @@ module Prefab
103
108
  end
104
109
 
105
110
  def criteria_match?(rule, lookup_key, attributes)
106
- if rule.criteria.operator == :IN
111
+
112
+ if rule.criteria.operator == :ALWAYS_TRUE
113
+ return true
114
+ elsif rule.criteria.operator == :LOOKUP_KEY_IN
107
115
  return rule.criteria.values.include?(lookup_key)
108
- elsif rule.criteria.operator == :NOT_IN
116
+ elsif rule.criteria.operator == :LOOKUP_KEY_NOT_IN
109
117
  return !rule.criteria.values.include?(lookup_key)
110
118
  elsif rule.criteria.operator == :IN_SEG
111
119
  return segment_matches(rule.criteria.values, lookup_key, attributes).any?
112
120
  elsif rule.criteria.operator == :NOT_IN_SEG
113
121
  return segment_matches(rule.criteria.values, lookup_key, attributes).none?
122
+ elsif rule.criteria.operator == :PROP_IS_ONE_OF
123
+ return rule.criteria.values.include?(attributes[rule.criteria.property]) || rule.criteria.values.include?(attributes[rule.criteria.property.to_sym])
124
+ elsif rule.criteria.operator == :PROP_IS_NOT_ONE_OF
125
+ return !(rule.criteria.values.include?(attributes[rule.criteria.property]) || rule.criteria.values.include?(attributes[rule.criteria.property.to_sym]))
114
126
  end
115
127
  @base_client.log.info("Unknown Operator")
116
128
  false
data/lib/prefab_pb.rb CHANGED
@@ -24,6 +24,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
24
24
  end
25
25
  add_message "prefab.Configs" do
26
26
  repeated :configs, :message, 1, "prefab.Config"
27
+ optional :config_service_pointer, :message, 2, "prefab.ConfigServicePointer"
27
28
  end
28
29
  add_message "prefab.Config" do
29
30
  optional :id, :int64, 1
@@ -90,15 +91,19 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
90
91
  end
91
92
  add_enum "prefab.Criteria.CriteriaOperator" do
92
93
  value :NOT_SET, 0
93
- value :IN, 1
94
- value :NOT_IN, 2
95
- value :EQ, 3
96
- value :IN_SEG, 4
97
- value :NOT_IN_SEG, 5
94
+ value :LOOKUP_KEY_IN, 1
95
+ value :LOOKUP_KEY_NOT_IN, 2
96
+ value :IN_SEG, 3
97
+ value :NOT_IN_SEG, 4
98
+ value :ALWAYS_TRUE, 5
99
+ value :PROP_IS_ONE_OF, 6
100
+ value :PROP_IS_NOT_ONE_OF, 7
101
+ value :PROP_ENDS_WITH_ONE_OF, 8
102
+ value :PROP_DOES_NOT_END_WITH_ONE_OF, 9
98
103
  end
99
104
  add_message "prefab.Rule" do
100
105
  optional :criteria, :message, 1, "prefab.Criteria"
101
- optional :distribution, :message, 2, "prefab.VariantDistribution"
106
+ repeated :variant_weights, :message, 2, "prefab.VariantWeight"
102
107
  end
103
108
  add_message "prefab.Segment" do
104
109
  optional :name, :string, 1
@@ -115,19 +120,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
115
120
  optional :weight, :int32, 1
116
121
  optional :variant_idx, :int32, 2
117
122
  end
118
- add_message "prefab.VariantWeights" do
119
- repeated :weights, :message, 1, "prefab.VariantWeight"
120
- end
121
- add_message "prefab.VariantDistribution" do
122
- oneof :type do
123
- optional :variant_idx, :int32, 1
124
- optional :variant_weights, :message, 2, "prefab.VariantWeights"
125
- end
126
- end
127
123
  add_message "prefab.FeatureFlag" do
128
124
  optional :active, :bool, 1
129
125
  optional :inactive_variant_idx, :int32, 2
130
- optional :default, :message, 3, "prefab.VariantDistribution"
131
126
  repeated :user_targets, :message, 4, "prefab.UserTarget"
132
127
  repeated :rules, :message, 5, "prefab.Rule"
133
128
  end
@@ -212,8 +207,6 @@ module Prefab
212
207
  Segment = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Segment").msgclass
213
208
  UserTarget = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.UserTarget").msgclass
214
209
  VariantWeight = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.VariantWeight").msgclass
215
- VariantWeights = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.VariantWeights").msgclass
216
- VariantDistribution = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.VariantDistribution").msgclass
217
210
  FeatureFlag = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.FeatureFlag").msgclass
218
211
  LimitDefinition = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitDefinition").msgclass
219
212
  LimitDefinition::SafetyLevel = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitDefinition.SafetyLevel").enummodule
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: prefab-cloud-ruby 0.10.0 ruby lib
5
+ # stub: prefab-cloud-ruby 0.11.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "0.10.0"
9
+ s.version = "0.11.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Jeff Dwyer".freeze]
14
- s.date = "2022-03-23"
14
+ s.date = "2022-05-05"
15
15
  s.description = "RateLimits & Config as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -15,18 +15,18 @@ class RackApp
15
15
 
16
16
  key = props["key"]
17
17
  namespace = props["namespace"]
18
- project_env_id = props["project_env_id"]
18
+ api_key = props["api_key"]
19
19
  user_key = props["user_key"]
20
20
  is_feature_flag = !props["feature_flag"].nil?
21
-
21
+ puts props
22
22
  client = Prefab::Client.new(
23
- api_key: "1-#{project_env_id}-local_development_api_key-SDK", #sets environment
23
+ api_key: api_key,
24
24
  namespace: namespace,
25
25
  )
26
26
 
27
27
  puts "Key #{key}"
28
28
  puts "User #{user_key}"
29
- puts "project_env_id #{project_env_id}"
29
+ puts "api_key #{api_key}"
30
30
  puts "Namespace #{namespace}"
31
31
  puts "Props! #{props}"
32
32
  puts "is_feature_flag! #{is_feature_flag}"
@@ -117,12 +117,12 @@ class TestConfigResolver < Minitest::Test
117
117
  rows: [
118
118
  { value: Prefab::ConfigValue.new(feature_flag: Prefab::FeatureFlag.new(
119
119
  inactive_variant_idx: 0,
120
- default: Prefab::VariantDistribution.new(variant_idx: 1)
120
+ rules: default_ff_rule(1),
121
121
  )) },
122
122
  { project_env_id: TEST_ENV_ID,
123
123
  value: Prefab::ConfigValue.new(feature_flag: Prefab::FeatureFlag.new(
124
124
  inactive_variant_idx: 0,
125
- default: Prefab::VariantDistribution.new(variant_idx: 2)
125
+ rules: default_ff_rule(2),
126
126
  )) }
127
127
  ]
128
128
  )
@@ -189,7 +189,10 @@ class TestConfigResolver < Minitest::Test
189
189
  end
190
190
 
191
191
  def resolver_for_namespace(namespace, loader, project_env_id: TEST_ENV_ID)
192
- Prefab::ConfigResolver.new(MockBaseClient.new(namespace: namespace, project_env_id: project_env_id), loader)
192
+ resolver = Prefab::ConfigResolver.new(MockBaseClient.new(namespace: namespace), loader)
193
+ resolver.project_env_id = project_env_id
194
+ resolver.update
195
+ resolver
193
196
  end
194
197
 
195
198
  end
@@ -19,22 +19,29 @@ class TestFeatureFlagClient < Minitest::Test
19
19
  ]
20
20
  flag = Prefab::FeatureFlag.new(
21
21
  active: true,
22
- inactive_variant_idx: 0,
23
- default: Prefab::VariantDistribution.new(variant_weights:
24
- Prefab::VariantWeights.new(weights: [
25
- Prefab::VariantWeight.new(weight: 500,
26
- variant_idx: 1),
27
- Prefab::VariantWeight.new(weight: 500,
28
- variant_idx: 0),
29
- ]
30
- )
31
- )
22
+ inactive_variant_idx: 1,
23
+ rules: [
24
+ Prefab::Rule.new(
25
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
26
+ variant_weights: [
27
+ Prefab::VariantWeight.new(weight: 86,
28
+ variant_idx: 2), #true
29
+ Prefab::VariantWeight.new(weight: 14,
30
+ variant_idx: 1), #false
31
+ ]
32
+ )
33
+ ]
32
34
  )
35
+ # weights above chosen to be 86% in variant_idx 2. and 14% in variant_idx 1.
36
+ # since hashes high is 86.32 > 86 it just falls outside the 86% range and gets false
33
37
 
38
+ # "1FlagNamehashes high" hashes to 86.322% through dist
34
39
  assert_equal false,
35
40
  @client.evaluate(feature, "hashes high", [], flag, variants)
41
+ # "1FlagNamehashes low" hashes to 44.547% through dist
36
42
  assert_equal true,
37
43
  @client.evaluate(feature, "hashes low", [], flag, variants)
44
+
38
45
  end
39
46
 
40
47
  def test_basic_active_inactive
@@ -45,8 +52,8 @@ class TestFeatureFlagClient < Minitest::Test
45
52
  ]
46
53
  flag = Prefab::FeatureFlag.new(
47
54
  active: true,
48
- inactive_variant_idx: 0,
49
- default: Prefab::VariantDistribution.new(variant_idx: 1)
55
+ inactive_variant_idx: 1,
56
+ rules: default_ff_rule(2)
50
57
  )
51
58
  assert_equal true,
52
59
  @client.evaluate(feature, "hashes high", [], flag, variants)
@@ -59,8 +66,8 @@ class TestFeatureFlagClient < Minitest::Test
59
66
  ]
60
67
  flag = Prefab::FeatureFlag.new(
61
68
  active: false,
62
- inactive_variant_idx: 0,
63
- default: Prefab::VariantDistribution.new(variant_idx: 1)
69
+ inactive_variant_idx: 1,
70
+ rules: default_ff_rule(2)
64
71
  )
65
72
  assert_equal false,
66
73
  @client.evaluate(feature, "hashes high", [], flag, variants)
@@ -78,12 +85,12 @@ class TestFeatureFlagClient < Minitest::Test
78
85
  ]
79
86
  flag = Prefab::FeatureFlag.new(
80
87
  active: true,
81
- inactive_variant_idx: 0,
88
+ inactive_variant_idx: 1,
82
89
  user_targets: [
83
- variant_idx: 1,
90
+ variant_idx: 2,
84
91
  identifiers: ["user:1", "user:3"]
85
92
  ],
86
- default: Prefab::VariantDistribution.new(variant_idx: 2)
93
+ rules: default_ff_rule(3)
87
94
  )
88
95
 
89
96
  assert_equal "user target",
@@ -103,15 +110,27 @@ class TestFeatureFlagClient < Minitest::Test
103
110
  ]
104
111
  flag = Prefab::FeatureFlag.new(
105
112
  active: true,
106
- inactive_variant_idx: 0,
107
- rules: [Prefab::Rule.new(
108
- distribution: Prefab::VariantDistribution.new(variant_idx: 1),
109
- criteria: Prefab::Criteria.new(
110
- operator: "IN",
111
- values: ["user:1"]
113
+ inactive_variant_idx: 1,
114
+ rules: [
115
+ Prefab::Rule.new(
116
+ variant_weights: [
117
+ Prefab::VariantWeight.new(weight: 1000,
118
+ variant_idx: 2)
119
+ ],
120
+ criteria: Prefab::Criteria.new(
121
+ operator: "LOOKUP_KEY_IN",
122
+ values: ["user:1"]
123
+ )
124
+ ),
125
+ Prefab::Rule.new(
126
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
127
+ variant_weights: [
128
+ Prefab::VariantWeight.new(weight: 1000,
129
+ variant_idx: 3)
130
+ ]
112
131
  )
113
- )],
114
- default: Prefab::VariantDistribution.new(variant_idx: 2)
132
+
133
+ ],
115
134
  )
116
135
 
117
136
  assert_equal "rule target",
@@ -121,6 +140,50 @@ class TestFeatureFlagClient < Minitest::Test
121
140
 
122
141
  end
123
142
 
143
+ def test_property_is_one_of
144
+ feature = "FlagName"
145
+ variants = [
146
+ Prefab::FeatureFlagVariant.new(string: "inactive"),
147
+ Prefab::FeatureFlagVariant.new(string: "rule target"),
148
+ Prefab::FeatureFlagVariant.new(string: "default"),
149
+ ]
150
+ flag = Prefab::FeatureFlag.new(
151
+ active: true,
152
+ inactive_variant_idx: 1,
153
+ rules: [
154
+ Prefab::Rule.new(
155
+ variant_weights: [
156
+ Prefab::VariantWeight.new(weight: 1000,
157
+ variant_idx: 2)
158
+ ],
159
+ criteria: Prefab::Criteria.new(
160
+ operator: "PROP_IS_ONE_OF",
161
+ values: ["a@example.com", "b@example.com"],
162
+ property: "email"
163
+ )
164
+ ),
165
+ Prefab::Rule.new(
166
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
167
+ variant_weights: [
168
+ Prefab::VariantWeight.new(weight: 1000,
169
+ variant_idx: 3)
170
+ ]
171
+ )
172
+
173
+ ],
174
+ )
175
+
176
+ assert_equal "default",
177
+ @client.evaluate(feature, "user:1", {email: "not@example.com"}, flag, variants)
178
+ assert_equal "default",
179
+ @client.evaluate(feature, "user:2", {}, flag, variants)
180
+ assert_equal "rule target",
181
+ @client.evaluate(feature, "user:2", {email: "b@example.com"}, flag, variants)
182
+ assert_equal "rule target",
183
+ @client.evaluate(feature, "user:2", {"email" => "b@example.com"}, flag, variants)
184
+
185
+ end
186
+
124
187
  def test_segment_match?
125
188
  segment = Prefab::Segment.new(
126
189
  name: "Beta Group",
@@ -136,10 +199,10 @@ class TestFeatureFlagClient < Minitest::Test
136
199
  def test_segments
137
200
  segment_key = "prefab-segment-beta-group"
138
201
  @mock_base_client.config_client.mock_this_config(segment_key,
139
- Prefab::Segment.new(
140
- name: "Beta Group",
141
- includes: ["user:1"]
142
- )
202
+ Prefab::Segment.new(
203
+ name: "Beta Group",
204
+ includes: ["user:1"]
205
+ )
143
206
  )
144
207
 
145
208
  feature = "FlagName"
@@ -150,15 +213,27 @@ class TestFeatureFlagClient < Minitest::Test
150
213
  ]
151
214
  flag = Prefab::FeatureFlag.new(
152
215
  active: true,
153
- inactive_variant_idx: 0,
154
- rules: [Prefab::Rule.new(
155
- distribution: Prefab::VariantDistribution.new(variant_idx: 1),
156
- criteria: Prefab::Criteria.new(
157
- operator: "IN_SEG",
158
- values: [segment_key]
216
+ inactive_variant_idx: 1,
217
+ rules: [
218
+ Prefab::Rule.new(
219
+ variant_weights: [
220
+ Prefab::VariantWeight.new(weight: 1000,
221
+ variant_idx: 2)
222
+ ],
223
+ criteria: Prefab::Criteria.new(
224
+ operator: "IN_SEG",
225
+ values: [segment_key]
226
+ )
227
+ ),
228
+ Prefab::Rule.new(
229
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
230
+ variant_weights: [
231
+ Prefab::VariantWeight.new(weight: 1000,
232
+ variant_idx: 3)
233
+ ]
159
234
  )
160
- )],
161
- default: Prefab::VariantDistribution.new(variant_idx: 2)
235
+
236
+ ],
162
237
  )
163
238
 
164
239
  assert_equal "rule target",
@@ -171,19 +246,19 @@ class TestFeatureFlagClient < Minitest::Test
171
246
  def test_in_multiple_segments_has_or_behavior
172
247
  segment_key_one = "prefab-segment-segment-1"
173
248
  @mock_base_client.config_client.mock_this_config(segment_key_one,
174
- Prefab::Segment.new(
175
- name: "Segment-1",
176
- includes: ["user:1", "user:2"],
177
- excludes: ["user:3"]
178
- )
249
+ Prefab::Segment.new(
250
+ name: "Segment-1",
251
+ includes: ["user:1", "user:2"],
252
+ excludes: ["user:3"]
253
+ )
179
254
  )
180
255
  segment_key_two = "prefab-segment-segment-2"
181
256
  @mock_base_client.config_client.mock_this_config(segment_key_two,
182
- Prefab::Segment.new(
183
- name: "Segment-2",
184
- includes: ["user:3", "user:4"],
185
- excludes: ["user:2"]
186
- )
257
+ Prefab::Segment.new(
258
+ name: "Segment-2",
259
+ includes: ["user:3", "user:4"],
260
+ excludes: ["user:2"]
261
+ )
187
262
  )
188
263
 
189
264
  feature = "FlagName"
@@ -194,15 +269,26 @@ class TestFeatureFlagClient < Minitest::Test
194
269
  ]
195
270
  flag = Prefab::FeatureFlag.new(
196
271
  active: true,
197
- inactive_variant_idx: 0,
198
- rules: [Prefab::Rule.new(
199
- distribution: Prefab::VariantDistribution.new(variant_idx: 1),
200
- criteria: Prefab::Criteria.new(
201
- operator: "IN_SEG",
202
- values: [segment_key_one, segment_key_two]
272
+ inactive_variant_idx: 1,
273
+ rules: [
274
+ Prefab::Rule.new(
275
+ variant_weights: [
276
+ Prefab::VariantWeight.new(weight: 1000,
277
+ variant_idx: 2)
278
+ ],
279
+ criteria: Prefab::Criteria.new(
280
+ operator: "IN_SEG",
281
+ values: [segment_key_one, segment_key_two]
282
+ )
283
+ ),
284
+ Prefab::Rule.new(
285
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
286
+ variant_weights: [
287
+ Prefab::VariantWeight.new(weight: 1000,
288
+ variant_idx: 3)
289
+ ]
203
290
  )
204
- )],
205
- default: Prefab::VariantDistribution.new(variant_idx: 2)
291
+ ]
206
292
  )
207
293
 
208
294
  assert_equal "rule target",
@@ -217,4 +303,5 @@ class TestFeatureFlagClient < Minitest::Test
217
303
  @client.evaluate(feature, "user:5", [], flag, variants)
218
304
 
219
305
  end
306
+
220
307
  end
data/test/test_helper.rb CHANGED
@@ -5,10 +5,10 @@ class MockBaseClient
5
5
  STAGING_ENV_ID = 1
6
6
  PRODUCTION_ENV_ID = 2
7
7
  TEST_ENV_ID = 3
8
- attr_reader :namespace, :logger, :project_env_id, :config_client
8
+ attr_reader :namespace, :logger, :config_client
9
+
10
+ def initialize(namespace: "")
9
11
 
10
- def initialize(project_env_id: TEST_ENV_ID, namespace: "")
11
- @project_env_id = project_env_id
12
12
  @namespace = namespace
13
13
  @logger = Logger.new($stdout)
14
14
  @config_client = MockConfigClient.new
@@ -18,8 +18,8 @@ class MockBaseClient
18
18
  1
19
19
  end
20
20
 
21
- def project_env_id
22
- @project_env_id
21
+ def log
22
+ @logger
23
23
  end
24
24
 
25
25
  def log_internal level, message
@@ -52,3 +52,18 @@ class MockConfigLoader
52
52
  def calc_config
53
53
  end
54
54
  end
55
+
56
+
57
+ private
58
+
59
+ def default_ff_rule(variant_idx)
60
+ [
61
+ Prefab::Rule.new(
62
+ criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
63
+ variant_weights: [
64
+ Prefab::VariantWeight.new(weight: 1000,
65
+ variant_idx: variant_idx)
66
+ ]
67
+ )
68
+ ]
69
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefab-cloud-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-23 00:00:00.000000000 Z
11
+ date: 2022-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby