prefab-cloud-ruby 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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