prefab-cloud-ruby 0.8.0 → 0.9.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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +24 -0
- data/README.md +3 -0
- data/VERSION +1 -1
- data/lib/prefab/client.rb +12 -6
- data/lib/prefab/config_client.rb +48 -17
- data/lib/prefab/config_loader.rb +12 -10
- data/lib/prefab/config_resolver.rb +27 -35
- data/lib/prefab/feature_flag_client.rb +10 -9
- data/lib/prefab-cloud-ruby.rb +2 -0
- data/lib/prefab_pb.rb +20 -25
- data/lib/prefab_services_pb.rb +3 -3
- data/prefab-cloud-ruby.gemspec +5 -3
- data/run_test_harness_server.sh +1 -1
- data/test/harness_server.rb +6 -1
- data/test/test_config_loader.rb +20 -20
- data/test/test_config_resolver.rb +61 -49
- data/test/test_feature_flag_client.rb +50 -50
- data/test/test_helper.rb +5 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80a03ec9a75bc4c5d827c746354ff1353fe135a5ab6e31e9beaaf1ca1c27c931
|
4
|
+
data.tar.gz: d4c9f02e6bbb54d8d4884cc2d94179f39e859aafe3966188b1a00f7b7e5ccc48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67f8b5ed6f61f01943736f9abbb685c9d7f7fd4c029ff3e051356f6e65936595f18899160fd842c415d86c371b0f9d915d795c6b9adafbdebeadd5b6fc6cc75b
|
7
|
+
data.tar.gz: c56dd76208ad8bbfd9d7add1bbc317a951671c2590cecf93389fbb5170aa9da13898bb3501e396450df2eaa93a67d7041b24fbdc2ca77f2a414056d0cbf471f9
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -14,12 +14,18 @@ GEM
|
|
14
14
|
descendants_tracker (0.0.4)
|
15
15
|
thread_safe (~> 0.3, >= 0.3.1)
|
16
16
|
docile (1.3.5)
|
17
|
+
domain_name (0.5.20190701)
|
18
|
+
unf (>= 0.0.5, < 1.0.0)
|
17
19
|
eventmachine (1.2.7)
|
18
20
|
faraday (1.3.0)
|
19
21
|
faraday-net_http (~> 1.0)
|
20
22
|
multipart-post (>= 1.2, < 3)
|
21
23
|
ruby2_keywords
|
22
24
|
faraday-net_http (1.0.1)
|
25
|
+
ffi (1.15.5)
|
26
|
+
ffi-compiler (1.0.1)
|
27
|
+
ffi (>= 1.0.0)
|
28
|
+
rake
|
23
29
|
git (1.8.1)
|
24
30
|
rchardet (~> 1.8)
|
25
31
|
github_api (0.19.0)
|
@@ -37,6 +43,14 @@ GEM
|
|
37
43
|
grpc-tools (1.43.1)
|
38
44
|
hashie (3.6.0)
|
39
45
|
highline (2.0.3)
|
46
|
+
http (5.0.1)
|
47
|
+
addressable (~> 2.3)
|
48
|
+
http-cookie (~> 1.0)
|
49
|
+
http-form_data (~> 2.2)
|
50
|
+
llhttp-ffi (~> 0.3.0)
|
51
|
+
http-cookie (1.0.4)
|
52
|
+
domain_name (~> 0.5)
|
53
|
+
http-form_data (2.3.0)
|
40
54
|
i18n (1.8.9)
|
41
55
|
concurrent-ruby (~> 1.0)
|
42
56
|
json (1.8.6)
|
@@ -55,6 +69,12 @@ GEM
|
|
55
69
|
jwt (2.2.2)
|
56
70
|
kamelcase (0.0.2)
|
57
71
|
semver2 (~> 3)
|
72
|
+
ld-eventsource (2.2.0)
|
73
|
+
concurrent-ruby (~> 1.0)
|
74
|
+
http (>= 4.4.1, < 6.0.0)
|
75
|
+
llhttp-ffi (0.3.1)
|
76
|
+
ffi-compiler (~> 1.0)
|
77
|
+
rake (~> 13.0)
|
58
78
|
mini_portile2 (2.7.1)
|
59
79
|
minitest (5.14.4)
|
60
80
|
multi_json (1.15.0)
|
@@ -96,6 +116,9 @@ GEM
|
|
96
116
|
thread_safe (0.3.6)
|
97
117
|
tzinfo (1.2.9)
|
98
118
|
thread_safe (~> 0.1)
|
119
|
+
unf (0.1.4)
|
120
|
+
unf_ext
|
121
|
+
unf_ext (0.0.8)
|
99
122
|
|
100
123
|
PLATFORMS
|
101
124
|
ruby
|
@@ -109,6 +132,7 @@ DEPENDENCIES
|
|
109
132
|
grpc
|
110
133
|
grpc-tools
|
111
134
|
juwelier (~> 2.4.9)
|
135
|
+
ld-eventsource
|
112
136
|
rdoc (~> 3.12)
|
113
137
|
shoulda
|
114
138
|
simplecov
|
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.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, :environment
|
11
|
+
attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :environment, :prefab_api_url
|
12
12
|
|
13
13
|
def initialize(api_key: ENV['PREFAB_API_KEY'],
|
14
14
|
logdev: nil,
|
@@ -31,17 +31,19 @@ module Prefab
|
|
31
31
|
@namespace = namespace
|
32
32
|
@interceptor = Prefab::AuthInterceptor.new(api_key)
|
33
33
|
@stubs = {}
|
34
|
-
|
34
|
+
@prefab_api_url = ENV["PREFAB_API_URL"] || 'https://api.prefab.cloud'
|
35
|
+
@prefab_grpc_url = ENV["PREFAB_GRPC_URL"] || 'grpc.prefab.cloud:443'
|
36
|
+
log_internal Logger::INFO, "Prefab Initializing in environment: '#{@environment}' and namespace: '#{@namespace}'"
|
37
|
+
log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
|
35
38
|
at_exit do
|
36
39
|
channel.destroy
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
40
43
|
def channel
|
41
|
-
credentials =
|
42
|
-
|
43
|
-
|
44
|
-
@_channel ||= GRPC::Core::Channel.new(url, nil, credentials)
|
44
|
+
credentials = http_secure? ? creds : :this_channel_is_insecure
|
45
|
+
log_internal Logger::DEBUG, "GRPC Channel #{@prefab_grpc_url} #{credentials}"
|
46
|
+
@_channel ||= GRPC::Core::Channel.new(@prefab_grpc_url, nil, credentials)
|
45
47
|
end
|
46
48
|
|
47
49
|
def config_client(timeout: 5.0)
|
@@ -101,6 +103,10 @@ module Prefab
|
|
101
103
|
|
102
104
|
private
|
103
105
|
|
106
|
+
def http_secure?
|
107
|
+
ENV["PREFAB_CLOUD_HTTP"] != "true"
|
108
|
+
end
|
109
|
+
|
104
110
|
def stub_for(service, timeout)
|
105
111
|
@stubs["#{service}_#{timeout}"] ||= service::Stub.new(nil,
|
106
112
|
nil,
|
data/lib/prefab/config_client.rb
CHANGED
@@ -29,7 +29,8 @@ module Prefab
|
|
29
29
|
|
30
30
|
def start_streaming
|
31
31
|
@streaming = true
|
32
|
-
|
32
|
+
# start_grpc_streaming_connection_thread(@config_loader.highwater_mark)
|
33
|
+
start_sse_streaming_connection_thread(@config_loader.highwater_mark)
|
33
34
|
end
|
34
35
|
|
35
36
|
def get(key)
|
@@ -62,8 +63,14 @@ module Prefab
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def self.value_to_delta(key, config_value, namespace = nil)
|
65
|
-
Prefab::
|
66
|
-
|
66
|
+
Prefab::Config.new(key: [namespace, key].compact.join(":"),
|
67
|
+
rows: [Prefab::ConfigRow.new(value: config_value)])
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_config_obj(key)
|
71
|
+
@initialization_lock.with_read_lock do
|
72
|
+
@config_resolver.get_config(key)
|
73
|
+
end
|
67
74
|
end
|
68
75
|
|
69
76
|
private
|
@@ -92,12 +99,12 @@ module Prefab
|
|
92
99
|
def load_checkpoint_from_config
|
93
100
|
@base_client.log_internal Logger::DEBUG, "Load Checkpoint From Config"
|
94
101
|
|
95
|
-
config_req = Prefab::ConfigServicePointer.new(
|
96
|
-
|
102
|
+
config_req = Prefab::ConfigServicePointer.new(start_at_id: @config_loader.highwater_mark)
|
103
|
+
|
97
104
|
resp = stub.get_all_config(config_req)
|
98
105
|
@base_client.log_internal Logger::DEBUG, "Got Response #{resp}"
|
99
|
-
|
100
|
-
resp.
|
106
|
+
load_configs(resp, :api)
|
107
|
+
resp.configs.each do |delta|
|
101
108
|
@config_loader.set(delta)
|
102
109
|
end
|
103
110
|
@config_resolver.update
|
@@ -112,16 +119,16 @@ module Prefab
|
|
112
119
|
url = "#{@s3_cloud_front}/#{@base_client.api_key.gsub("|", "/")}"
|
113
120
|
resp = Faraday.get url
|
114
121
|
if resp.status == 200
|
115
|
-
|
116
|
-
|
122
|
+
configs = Prefab::Configs.decode(resp.body)
|
123
|
+
load_configs(configs, :s3)
|
117
124
|
else
|
118
125
|
@base_client.log_internal Logger::INFO, "No S3 checkpoint. Response #{resp.status} Plan may not support this."
|
119
126
|
end
|
120
127
|
end
|
121
128
|
|
122
|
-
def
|
123
|
-
|
124
|
-
@config_loader.set(
|
129
|
+
def load_configs(configs, source)
|
130
|
+
configs.configs.each do |config|
|
131
|
+
@config_loader.set(config)
|
125
132
|
end
|
126
133
|
@base_client.log_internal Logger::INFO, "Found checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}"
|
127
134
|
@base_client.stats.increment("prefab.config.checkpoint.load")
|
@@ -156,11 +163,35 @@ module Prefab
|
|
156
163
|
end
|
157
164
|
end
|
158
165
|
|
166
|
+
|
167
|
+
def start_sse_streaming_connection_thread(start_at_id)
|
168
|
+
auth = "#{@base_client.project_id}:#{@base_client.api_key}"
|
169
|
+
|
170
|
+
auth_string = Base64.strict_encode64(auth)
|
171
|
+
headers = {
|
172
|
+
"x-prefab-start-at-id": start_at_id,
|
173
|
+
"Authorization": "Basic #{auth_string}",
|
174
|
+
}
|
175
|
+
url = "#{@base_client.prefab_api_url}/api/v1/sse/config"
|
176
|
+
@base_client.log_internal Logger::INFO, "SSE Streaming Connect to #{url}"
|
177
|
+
SSE::Client.new(url, headers: headers) do |client|
|
178
|
+
client.on_event do |event|
|
179
|
+
configs = Prefab::Configs.decode(Base64.decode64(event.data))
|
180
|
+
@base_client.log_internal Logger::INFO, "SSE received configs."
|
181
|
+
@base_client.log_internal Logger::DEBUG, "SSE received configs: #{configs}"
|
182
|
+
configs.configs.each do |config|
|
183
|
+
@config_loader.set(config)
|
184
|
+
end
|
185
|
+
@config_resolver.update
|
186
|
+
finish_init!(:streaming)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
159
191
|
# Setup a streaming connection to the API
|
160
192
|
# Save new config values into the loader
|
161
|
-
def
|
162
|
-
config_req = Prefab::ConfigServicePointer.new(
|
163
|
-
start_at_id: start_at_id)
|
193
|
+
def start_grpc_streaming_connection_thread(start_at_id)
|
194
|
+
config_req = Prefab::ConfigServicePointer.new(start_at_id: start_at_id)
|
164
195
|
@base_client.log_internal Logger::DEBUG, "start api connection thread #{start_at_id}"
|
165
196
|
@base_client.stats.increment("prefab.config.api.start")
|
166
197
|
|
@@ -174,8 +205,8 @@ module Prefab
|
|
174
205
|
begin
|
175
206
|
resp = stub.get_config(config_req)
|
176
207
|
resp.each do |r|
|
177
|
-
r.
|
178
|
-
@config_loader.set(
|
208
|
+
r.configs.each do |config|
|
209
|
+
@config_loader.set(config)
|
179
210
|
end
|
180
211
|
@config_resolver.update
|
181
212
|
finish_init!(:streaming)
|
data/lib/prefab/config_loader.rb
CHANGED
@@ -20,18 +20,18 @@ module Prefab
|
|
20
20
|
rtn
|
21
21
|
end
|
22
22
|
|
23
|
-
def set(
|
23
|
+
def set(config)
|
24
24
|
# don't overwrite newer values
|
25
|
-
if @api_config[
|
25
|
+
if @api_config[config.key] && @api_config[config.key].id > config.id
|
26
26
|
return
|
27
27
|
end
|
28
28
|
|
29
|
-
if
|
30
|
-
@api_config.delete(
|
29
|
+
if config.rows.empty?
|
30
|
+
@api_config.delete(config.key)
|
31
31
|
else
|
32
|
-
@api_config[
|
32
|
+
@api_config[config.key] = config
|
33
33
|
end
|
34
|
-
@highwater_mark = [
|
34
|
+
@highwater_mark = [config.id, @highwater_mark].max
|
35
35
|
end
|
36
36
|
|
37
37
|
def rm(key)
|
@@ -39,11 +39,11 @@ module Prefab
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def get_api_deltas
|
42
|
-
|
42
|
+
configs = Prefab::Configs.new
|
43
43
|
@api_config.each_value do |config_value|
|
44
|
-
|
44
|
+
configs.configs << config_value
|
45
45
|
end
|
46
|
-
|
46
|
+
configs
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
@@ -63,7 +63,9 @@ module Prefab
|
|
63
63
|
Dir.glob(glob).each do |file|
|
64
64
|
yaml = load(file)
|
65
65
|
yaml.each do |k, v|
|
66
|
-
rtn[k] = Prefab::
|
66
|
+
rtn[k] = Prefab::Config.new(key: k, rows: [
|
67
|
+
Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(v)))
|
68
|
+
])
|
67
69
|
end
|
68
70
|
end
|
69
71
|
rtn
|
@@ -24,12 +24,15 @@ module Prefab
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def get(property)
|
27
|
-
config =
|
28
|
-
@local_store[property]
|
29
|
-
end
|
27
|
+
config = _get(property)
|
30
28
|
config ? value_of(config[:value]) : nil
|
31
29
|
end
|
32
30
|
|
31
|
+
def get_config(property)
|
32
|
+
config = _get(property)
|
33
|
+
config ? config[:config] : nil
|
34
|
+
end
|
35
|
+
|
33
36
|
def update
|
34
37
|
make_local
|
35
38
|
end
|
@@ -55,46 +58,35 @@ module Prefab
|
|
55
58
|
|
56
59
|
def make_local
|
57
60
|
store = {}
|
58
|
-
@config_loader.calc_config.each do |key,
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
# override the top level default with env default
|
69
|
-
to_store = { match: "env_default", env: env_value.environment, value: env_value.default }
|
70
|
-
|
71
|
-
if env_value.namespace_values.any?
|
72
|
-
# check all namespace_values for match
|
73
|
-
env_value.namespace_values.each do |namespace_value|
|
74
|
-
(starts_with, count) = starts_with_ns?(namespace_value.namespace, @namespace)
|
75
|
-
if starts_with
|
76
|
-
# is this match the best match?
|
77
|
-
if count > (to_store[:match_depth_count] || 0)
|
78
|
-
to_store = { match: namespace_value.namespace, count: count, value: namespace_value.config_value }
|
79
|
-
end
|
80
|
-
end
|
61
|
+
@config_loader.calc_config.each do |key, config|
|
62
|
+
sortable = config.rows.map do |row|
|
63
|
+
if !row.env_key.empty?
|
64
|
+
if row.env_key == @environment
|
65
|
+
if !row.namespace.empty?
|
66
|
+
(starts_with, count) = starts_with_ns?(row.namespace, @namespace)
|
67
|
+
# rubocop:disable BlockNesting
|
68
|
+
{ sortable: 2 + count, match: row.namespace, value: row.value, config: config} if starts_with
|
69
|
+
else
|
70
|
+
{ sortable: 1, match: row.env_key, value: row.value, config: config}
|
81
71
|
end
|
82
72
|
end
|
73
|
+
else
|
74
|
+
{ sortable: 0, match: "default", value: row.value, config: config}
|
83
75
|
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# feature flags are a funny case
|
87
|
-
# we only define the variants in the default in order to be DRY
|
88
|
-
# but we want to access them in environments, clone them over
|
89
|
-
if to_store[:value].type == :feature_flag
|
90
|
-
to_store[:value].feature_flag.variants = delta.default.feature_flag.variants
|
91
|
-
end
|
92
|
-
|
76
|
+
end.compact
|
77
|
+
to_store = sortable.sort_by { |h| h[:sortable] }.last
|
93
78
|
store[key] = to_store
|
94
79
|
end
|
80
|
+
|
95
81
|
@lock.with_write_lock do
|
96
82
|
@local_store = store
|
97
83
|
end
|
98
84
|
end
|
85
|
+
|
86
|
+
def _get(property)
|
87
|
+
@lock.with_read_lock do
|
88
|
+
@local_store[property]
|
89
|
+
end
|
90
|
+
end
|
99
91
|
end
|
100
92
|
end
|
@@ -24,11 +24,12 @@ module Prefab
|
|
24
24
|
|
25
25
|
def get(feature_name, lookup_key, attributes)
|
26
26
|
feature_obj = @base_client.config_client.get(feature_name)
|
27
|
-
|
27
|
+
variants = @base_client.config_client.get_config_obj(feature_name).variants
|
28
|
+
evaluate(feature_name, lookup_key, attributes, feature_obj, variants)
|
28
29
|
end
|
29
30
|
|
30
|
-
def evaluate(feature_name, lookup_key, attributes, feature_obj)
|
31
|
-
value_of(get_variant(feature_name, lookup_key, attributes, feature_obj))
|
31
|
+
def evaluate(feature_name, lookup_key, attributes, feature_obj, variants)
|
32
|
+
value_of(get_variant(feature_name, lookup_key, attributes, feature_obj, variants))
|
32
33
|
end
|
33
34
|
|
34
35
|
private
|
@@ -40,9 +41,9 @@ module Prefab
|
|
40
41
|
variant.bool
|
41
42
|
end
|
42
43
|
|
43
|
-
def get_variant(feature_name, lookup_key, attributes, feature_obj)
|
44
|
+
def get_variant(feature_name, lookup_key, attributes, feature_obj, variants)
|
44
45
|
if !feature_obj.active
|
45
|
-
return get_variant_obj(
|
46
|
+
return get_variant_obj(variants, feature_obj.inactive_variant_idx)
|
46
47
|
end
|
47
48
|
|
48
49
|
variant_distribution = feature_obj.default
|
@@ -50,7 +51,7 @@ module Prefab
|
|
50
51
|
# if user_targets.match
|
51
52
|
feature_obj.user_targets.each do |target|
|
52
53
|
if (target.identifiers.include? lookup_key)
|
53
|
-
return get_variant_obj(
|
54
|
+
return get_variant_obj(variants, target.variant_idx)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -73,11 +74,11 @@ module Prefab
|
|
73
74
|
variant_idx = get_variant_idx_from_weights(variant_distribution.variant_weights.weights, distribution_bucket, feature_name)
|
74
75
|
end
|
75
76
|
|
76
|
-
return get_variant_obj(
|
77
|
+
return get_variant_obj(variants, variant_idx)
|
77
78
|
end
|
78
79
|
|
79
|
-
def get_variant_obj(
|
80
|
-
return
|
80
|
+
def get_variant_obj(variants, idx)
|
81
|
+
return variants[idx] if variants.length >= idx
|
81
82
|
nil
|
82
83
|
end
|
83
84
|
|
data/lib/prefab-cloud-ruby.rb
CHANGED
data/lib/prefab_pb.rb
CHANGED
@@ -22,28 +22,21 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
22
22
|
optional :segment, :message, 8, "prefab.Segment"
|
23
23
|
end
|
24
24
|
end
|
25
|
-
add_message "prefab.
|
26
|
-
|
27
|
-
optional :config_value, :message, 2, "prefab.ConfigValue"
|
25
|
+
add_message "prefab.Configs" do
|
26
|
+
repeated :configs, :message, 1, "prefab.Config"
|
28
27
|
end
|
29
|
-
add_message "prefab.
|
30
|
-
optional :environment, :string, 1
|
31
|
-
repeated :namespace_values, :message, 2, "prefab.NamespaceValue"
|
32
|
-
optional :default, :message, 3, "prefab.ConfigValue"
|
33
|
-
end
|
34
|
-
add_message "prefab.ConfigDelta" do
|
28
|
+
add_message "prefab.Config" do
|
35
29
|
optional :id, :int64, 1
|
36
|
-
optional :
|
37
|
-
optional :
|
38
|
-
repeated :envs, :message, 4, "prefab.EnvironmentValues"
|
39
|
-
end
|
40
|
-
add_message "prefab.ConfigDeltas" do
|
41
|
-
repeated :deltas, :message, 1, "prefab.ConfigDelta"
|
42
|
-
end
|
43
|
-
add_message "prefab.UpsertRequest" do
|
44
|
-
optional :project_id, :int64, 1
|
45
|
-
optional :config_delta, :message, 2, "prefab.ConfigDelta"
|
30
|
+
optional :project_id, :int64, 2
|
31
|
+
optional :key, :string, 3
|
46
32
|
optional :changed_by, :string, 4
|
33
|
+
repeated :rows, :message, 5, "prefab.ConfigRow"
|
34
|
+
repeated :variants, :message, 6, "prefab.FeatureFlagVariant"
|
35
|
+
end
|
36
|
+
add_message "prefab.ConfigRow" do
|
37
|
+
optional :env_key, :string, 1
|
38
|
+
optional :namespace, :string, 2
|
39
|
+
optional :value, :message, 3, "prefab.ConfigValue"
|
47
40
|
end
|
48
41
|
add_message "prefab.LimitResponse" do
|
49
42
|
optional :passed, :bool, 1
|
@@ -137,7 +130,6 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
137
130
|
optional :default, :message, 3, "prefab.VariantDistribution"
|
138
131
|
repeated :user_targets, :message, 4, "prefab.UserTarget"
|
139
132
|
repeated :rules, :message, 5, "prefab.Rule"
|
140
|
-
repeated :variants, :message, 6, "prefab.FeatureFlagVariant"
|
141
133
|
end
|
142
134
|
add_message "prefab.LimitDefinition" do
|
143
135
|
optional :policy_name, :enum, 2, "prefab.LimitResponse.LimitPolicyNames"
|
@@ -177,6 +169,10 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
177
169
|
add_message "prefab.BasicResponse" do
|
178
170
|
optional :message, :string, 1
|
179
171
|
end
|
172
|
+
add_message "prefab.CreationResponse" do
|
173
|
+
optional :message, :string, 1
|
174
|
+
optional :new_id, :int64, 2
|
175
|
+
end
|
180
176
|
add_enum "prefab.OnFailure" do
|
181
177
|
value :NOT_SET, 0
|
182
178
|
value :LOG_AND_PASS, 1
|
@@ -189,11 +185,9 @@ end
|
|
189
185
|
module Prefab
|
190
186
|
ConfigServicePointer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigServicePointer").msgclass
|
191
187
|
ConfigValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigValue").msgclass
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
ConfigDeltas = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigDeltas").msgclass
|
196
|
-
UpsertRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.UpsertRequest").msgclass
|
188
|
+
Configs = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Configs").msgclass
|
189
|
+
Config = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Config").msgclass
|
190
|
+
ConfigRow = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigRow").msgclass
|
197
191
|
LimitResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitResponse").msgclass
|
198
192
|
LimitResponse::LimitPolicyNames = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitResponse.LimitPolicyNames").enummodule
|
199
193
|
LimitRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitRequest").msgclass
|
@@ -214,5 +208,6 @@ module Prefab
|
|
214
208
|
BufferedRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.BufferedRequest").msgclass
|
215
209
|
BatchRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.BatchRequest").msgclass
|
216
210
|
BasicResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.BasicResponse").msgclass
|
211
|
+
CreationResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.CreationResponse").msgclass
|
217
212
|
OnFailure = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.OnFailure").enummodule
|
218
213
|
end
|
data/lib/prefab_services_pb.rb
CHANGED
@@ -28,9 +28,9 @@ module Prefab
|
|
28
28
|
self.unmarshal_class_method = :decode
|
29
29
|
self.service_name = 'prefab.ConfigService'
|
30
30
|
|
31
|
-
rpc :GetConfig, ::Prefab::ConfigServicePointer, stream(::Prefab::
|
32
|
-
rpc :GetAllConfig, ::Prefab::ConfigServicePointer, ::Prefab::
|
33
|
-
rpc :Upsert, ::Prefab::
|
31
|
+
rpc :GetConfig, ::Prefab::ConfigServicePointer, stream(::Prefab::Configs)
|
32
|
+
rpc :GetAllConfig, ::Prefab::ConfigServicePointer, ::Prefab::Configs
|
33
|
+
rpc :Upsert, ::Prefab::Config, ::Prefab::CreationResponse
|
34
34
|
end
|
35
35
|
|
36
36
|
Stub = Service.rpc_stub_class
|
data/prefab-cloud-ruby.gemspec
CHANGED
@@ -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.
|
5
|
+
# stub: prefab-cloud-ruby 0.9.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.9.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-
|
14
|
+
s.date = "2022-03-18"
|
15
15
|
s.description = "RateLimits & Config as a service".freeze
|
16
16
|
s.email = "jdwyer@prefab.cloud".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -67,6 +67,7 @@ Gem::Specification.new do |s|
|
|
67
67
|
if s.respond_to? :add_runtime_dependency then
|
68
68
|
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, ["~> 1.0", ">= 1.0.5"])
|
69
69
|
s.add_runtime_dependency(%q<faraday>.freeze, [">= 0"])
|
70
|
+
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
70
71
|
s.add_runtime_dependency(%q<grpc>.freeze, [">= 0"])
|
71
72
|
s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
72
73
|
s.add_runtime_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
|
@@ -80,6 +81,7 @@ Gem::Specification.new do |s|
|
|
80
81
|
else
|
81
82
|
s.add_dependency(%q<concurrent-ruby>.freeze, ["~> 1.0", ">= 1.0.5"])
|
82
83
|
s.add_dependency(%q<faraday>.freeze, [">= 0"])
|
84
|
+
s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
83
85
|
s.add_dependency(%q<grpc>.freeze, [">= 0"])
|
84
86
|
s.add_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
85
87
|
s.add_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
|
data/run_test_harness_server.sh
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL=debug PREFAB_CLOUD_HTTP=true
|
1
|
+
PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL=debug PREFAB_CLOUD_HTTP=true PREFAB_GRPC_URL="localhost:50051" ruby -Ilib test/harness_server.rb
|
2
2
|
#GRPC_TRACE=all GRPC_VERBOSITY=DEBUG PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL=debug PREFAB_CLOUD_HTTP=true PREFAB_API_KEY="1|local_development_api_key" PREFAB_API_URL="localhost:50051" ruby -Ilib test/harness_server.rb
|
data/test/harness_server.rb
CHANGED
@@ -20,7 +20,7 @@ class RackApp
|
|
20
20
|
is_feature_flag = !props["feature_flag"].nil?
|
21
21
|
|
22
22
|
client = Prefab::Client.new(
|
23
|
-
api_key: "1-#{environment}-local_development_api_key", #sets environment
|
23
|
+
api_key: "1-#{environment}-local_development_api_key-SDK", #sets environment
|
24
24
|
namespace: namespace,
|
25
25
|
)
|
26
26
|
|
@@ -40,6 +40,11 @@ class RackApp
|
|
40
40
|
puts "return #{rtn}"
|
41
41
|
|
42
42
|
[200, { "Content-Type" => "text/plain" }, rtn]
|
43
|
+
|
44
|
+
rescue Exception => e
|
45
|
+
puts "ERROR #{e.message}"
|
46
|
+
puts e.backtrace
|
47
|
+
[500, { "Content-Type" => "text/plain" }, e.message]
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
data/test/test_config_loader.rb
CHANGED
@@ -16,26 +16,26 @@ class TestConfigLoader < Minitest::Test
|
|
16
16
|
|
17
17
|
def test_highwater
|
18
18
|
assert_equal 0, @loader.highwater_mark
|
19
|
-
@loader.set(Prefab::
|
19
|
+
@loader.set(Prefab::Config.new(id: 1, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 456))]))
|
20
20
|
assert_equal 1, @loader.highwater_mark
|
21
21
|
|
22
|
-
@loader.set(Prefab::
|
22
|
+
@loader.set(Prefab::Config.new(id: 5, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 456))]))
|
23
23
|
assert_equal 5, @loader.highwater_mark
|
24
|
-
@loader.set(Prefab::
|
24
|
+
@loader.set(Prefab::Config.new(id: 2, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 456))]))
|
25
25
|
assert_equal 5, @loader.highwater_mark
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_keeps_most_recent
|
29
29
|
assert_equal 0, @loader.highwater_mark
|
30
|
-
@loader.set(Prefab::
|
30
|
+
@loader.set(Prefab::Config.new(id: 1, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 1))]))
|
31
31
|
assert_equal 1, @loader.highwater_mark
|
32
32
|
should_be :int, 1, "sample_int"
|
33
33
|
|
34
|
-
@loader.set(Prefab::
|
34
|
+
@loader.set(Prefab::Config.new(id: 4, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 4))]))
|
35
35
|
assert_equal 4, @loader.highwater_mark
|
36
36
|
should_be :int, 4, "sample_int"
|
37
37
|
|
38
|
-
@loader.set(Prefab::
|
38
|
+
@loader.set(Prefab::Config.new(id: 2, key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 2))]))
|
39
39
|
assert_equal 4, @loader.highwater_mark
|
40
40
|
should_be :int, 4, "sample_int"
|
41
41
|
end
|
@@ -43,37 +43,37 @@ class TestConfigLoader < Minitest::Test
|
|
43
43
|
def test_api_precedence
|
44
44
|
should_be :int, 123, "sample_int"
|
45
45
|
|
46
|
-
@loader.set(Prefab::
|
46
|
+
@loader.set(Prefab::Config.new(key: "sample_int", rows: [Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(int: 456))]))
|
47
47
|
should_be :int, 456, "sample_int"
|
48
48
|
end
|
49
49
|
|
50
50
|
def test_api_deltas
|
51
51
|
val = Prefab::ConfigValue.new(int: 456)
|
52
|
-
|
53
|
-
@loader.set(
|
52
|
+
config = Prefab::Config.new(key: "sample_int", rows: [Prefab::ConfigRow.new(value: val)])
|
53
|
+
@loader.set(config)
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
assert_equal
|
55
|
+
configs = Prefab::Configs.new
|
56
|
+
configs.configs << config
|
57
|
+
assert_equal configs, @loader.get_api_deltas
|
58
58
|
end
|
59
59
|
|
60
60
|
def test_loading_tombstones_removes_entries
|
61
61
|
val = Prefab::ConfigValue.new(int: 456)
|
62
|
-
|
63
|
-
@loader.set(
|
62
|
+
config = Prefab::Config.new(key: "sample_int", rows: [Prefab::ConfigRow.new(value: val)])
|
63
|
+
@loader.set(config)
|
64
64
|
|
65
|
-
|
66
|
-
@loader.set(
|
65
|
+
config = Prefab::Config.new(key: "sample_int", rows: [])
|
66
|
+
@loader.set(config)
|
67
67
|
|
68
|
-
|
69
|
-
assert_equal
|
68
|
+
configs = Prefab::Configs.new
|
69
|
+
assert_equal configs, @loader.get_api_deltas
|
70
70
|
end
|
71
71
|
|
72
72
|
private
|
73
73
|
|
74
74
|
def should_be(type, value, key)
|
75
|
-
assert_equal type, @loader.calc_config[key].
|
76
|
-
assert_equal value, @loader.calc_config[key].
|
75
|
+
assert_equal type, @loader.calc_config[key].rows[0].value.type
|
76
|
+
assert_equal value, @loader.calc_config[key].rows[0].value.send(type)
|
77
77
|
end
|
78
78
|
|
79
79
|
end
|
@@ -6,35 +6,44 @@ class TestConfigResolver < Minitest::Test
|
|
6
6
|
@loader = MockConfigLoader.new
|
7
7
|
|
8
8
|
loaded_values = {
|
9
|
-
"key" => Prefab::
|
9
|
+
"key" => Prefab::Config.new(
|
10
10
|
key: "key",
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
11
|
+
rows: [
|
12
|
+
Prefab::ConfigRow.new(
|
13
|
+
value: Prefab::ConfigValue.new(string: "value_no_env_default"),
|
14
|
+
),
|
15
|
+
Prefab::ConfigRow.new(
|
16
|
+
env_key: "test",
|
17
|
+
value: Prefab::ConfigValue.new(string: "value_none"),
|
18
|
+
),
|
19
|
+
Prefab::ConfigRow.new(
|
20
|
+
env_key: "test",
|
21
|
+
namespace: "projectA",
|
22
|
+
value: Prefab::ConfigValue.new(string: "valueA"),
|
23
|
+
),
|
24
|
+
Prefab::ConfigRow.new(
|
25
|
+
env_key: "test",
|
26
|
+
namespace: "projectB",
|
27
|
+
value: Prefab::ConfigValue.new(string: "valueB"),
|
28
|
+
),
|
29
|
+
Prefab::ConfigRow.new(
|
30
|
+
env_key: "test",
|
31
|
+
namespace: "projectB.subprojectX",
|
32
|
+
value: Prefab::ConfigValue.new(string: "projectB.subprojectX"),
|
33
|
+
),
|
34
|
+
Prefab::ConfigRow.new(
|
35
|
+
env_key: "test",
|
36
|
+
namespace: "projectB.subprojectY",
|
37
|
+
value: Prefab::ConfigValue.new(string: "projectB.subprojectY"),
|
38
|
+
),
|
39
|
+
|
40
|
+
]
|
34
41
|
),
|
35
|
-
"key2" => Prefab::
|
42
|
+
"key2" => Prefab::Config.new(
|
36
43
|
key: "key2",
|
37
|
-
|
44
|
+
rows: [
|
45
|
+
value: Prefab::ConfigValue.new(string: "valueB2"),
|
46
|
+
]
|
38
47
|
)
|
39
48
|
}
|
40
49
|
|
@@ -93,32 +102,31 @@ class TestConfigResolver < Minitest::Test
|
|
93
102
|
def test_special_ff_variant_copying
|
94
103
|
@loader = MockConfigLoader.new
|
95
104
|
loaded_values = {
|
96
|
-
"ff" => Prefab::
|
105
|
+
"ff" => Prefab::Config.new(
|
97
106
|
key: "ff",
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
default: Prefab::ConfigValue.new(feature_flag: Prefab::FeatureFlag.new(
|
107
|
+
variants: [
|
108
|
+
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
109
|
+
Prefab::FeatureFlagVariant.new(string: "default"),
|
110
|
+
Prefab::FeatureFlagVariant.new(string: "env"),
|
111
|
+
],
|
112
|
+
rows: [
|
113
|
+
{ value: Prefab::ConfigValue.new(feature_flag: Prefab::FeatureFlag.new(
|
114
|
+
inactive_variant_idx: 0,
|
115
|
+
default: Prefab::VariantDistribution.new(variant_idx: 1)
|
116
|
+
)) },
|
117
|
+
{ env_key: "test",
|
118
|
+
value: Prefab::ConfigValue.new(feature_flag: Prefab::FeatureFlag.new(
|
111
119
|
inactive_variant_idx: 0,
|
112
|
-
default: Prefab::VariantDistribution.new(variant_idx: 2)
|
113
|
-
|
120
|
+
default: Prefab::VariantDistribution.new(variant_idx: 2)
|
121
|
+
)) }
|
114
122
|
]
|
115
123
|
)
|
116
124
|
}
|
117
125
|
@loader.stub :calc_config, loaded_values do
|
118
126
|
resolver = Prefab::ConfigResolver.new(MockBaseClient.new, @loader)
|
119
|
-
|
120
|
-
assert_equal 3,
|
121
|
-
assert_equal %w(inactive default env),
|
127
|
+
config = resolver.get_config("ff")
|
128
|
+
assert_equal 3, config.variants.size
|
129
|
+
assert_equal %w(inactive default env), config.variants.map(&:string)
|
122
130
|
end
|
123
131
|
end
|
124
132
|
|
@@ -127,13 +135,17 @@ class TestConfigResolver < Minitest::Test
|
|
127
135
|
@loader = MockConfigLoader.new
|
128
136
|
|
129
137
|
loaded_values = {
|
130
|
-
"Key:With:Colons" => Prefab::
|
138
|
+
"Key:With:Colons" => Prefab::Config.new(
|
131
139
|
key: "Key:With:Colons",
|
132
|
-
|
140
|
+
rows: [Prefab::ConfigRow.new(
|
141
|
+
value: Prefab::ConfigValue.new(string: "value")
|
142
|
+
)]
|
133
143
|
),
|
134
|
-
"proj:apikey" => Prefab::
|
144
|
+
"proj:apikey" => Prefab::Config.new(
|
135
145
|
key: "proj:apikey",
|
136
|
-
|
146
|
+
rows: [Prefab::ConfigRow.new(
|
147
|
+
value: Prefab::ConfigValue.new(string: "v2")
|
148
|
+
)]
|
137
149
|
)
|
138
150
|
}
|
139
151
|
|
@@ -13,12 +13,12 @@ class TestFeatureFlagClient < Minitest::Test
|
|
13
13
|
def test_pct
|
14
14
|
feature = "FlagName"
|
15
15
|
|
16
|
+
variants = [
|
17
|
+
Prefab::FeatureFlagVariant.new(bool: false),
|
18
|
+
Prefab::FeatureFlagVariant.new(bool: true)
|
19
|
+
]
|
16
20
|
flag = Prefab::FeatureFlag.new(
|
17
21
|
active: true,
|
18
|
-
variants: [
|
19
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
20
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
21
|
-
],
|
22
22
|
inactive_variant_idx: 0,
|
23
23
|
default: Prefab::VariantDistribution.new(variant_weights:
|
24
24
|
Prefab::VariantWeights.new(weights: [
|
@@ -32,52 +32,52 @@ class TestFeatureFlagClient < Minitest::Test
|
|
32
32
|
)
|
33
33
|
|
34
34
|
assert_equal false,
|
35
|
-
@client.evaluate(feature, "hashes high", [], flag)
|
35
|
+
@client.evaluate(feature, "hashes high", [], flag, variants)
|
36
36
|
assert_equal true,
|
37
|
-
@client.evaluate(feature, "hashes low", [], flag)
|
37
|
+
@client.evaluate(feature, "hashes low", [], flag, variants)
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_basic_active_inactive
|
41
41
|
feature = "FlagName"
|
42
|
+
variants = [
|
43
|
+
Prefab::FeatureFlagVariant.new(bool: false),
|
44
|
+
Prefab::FeatureFlagVariant.new(bool: true)
|
45
|
+
]
|
42
46
|
flag = Prefab::FeatureFlag.new(
|
43
47
|
active: true,
|
44
|
-
variants: [
|
45
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
46
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
47
|
-
],
|
48
48
|
inactive_variant_idx: 0,
|
49
49
|
default: Prefab::VariantDistribution.new(variant_idx: 1)
|
50
50
|
)
|
51
51
|
assert_equal true,
|
52
|
-
@client.evaluate(feature, "hashes high", [], flag)
|
52
|
+
@client.evaluate(feature, "hashes high", [], flag, variants)
|
53
53
|
assert_equal true,
|
54
|
-
@client.evaluate(feature, "hashes low", [], flag)
|
54
|
+
@client.evaluate(feature, "hashes low", [], flag, variants)
|
55
55
|
|
56
|
+
variants = [
|
57
|
+
Prefab::FeatureFlagVariant.new(bool: false),
|
58
|
+
Prefab::FeatureFlagVariant.new(bool: true)
|
59
|
+
]
|
56
60
|
flag = Prefab::FeatureFlag.new(
|
57
61
|
active: false,
|
58
|
-
variants: [
|
59
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
60
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
61
|
-
],
|
62
62
|
inactive_variant_idx: 0,
|
63
63
|
default: Prefab::VariantDistribution.new(variant_idx: 1)
|
64
64
|
)
|
65
65
|
assert_equal false,
|
66
|
-
@client.evaluate(feature, "hashes high", [], flag)
|
66
|
+
@client.evaluate(feature, "hashes high", [], flag, variants)
|
67
67
|
assert_equal false,
|
68
|
-
@client.evaluate(feature, "hashes low", [], flag)
|
68
|
+
@client.evaluate(feature, "hashes low", [], flag, variants)
|
69
69
|
end
|
70
70
|
|
71
71
|
def test_user_targets
|
72
72
|
|
73
73
|
feature = "FlagName"
|
74
|
+
variants = [
|
75
|
+
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
76
|
+
Prefab::FeatureFlagVariant.new(string: "user target"),
|
77
|
+
Prefab::FeatureFlagVariant.new(string: "default"),
|
78
|
+
]
|
74
79
|
flag = Prefab::FeatureFlag.new(
|
75
80
|
active: true,
|
76
|
-
variants: [
|
77
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
78
|
-
Prefab::FeatureFlagVariant.new(string: "user target"),
|
79
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
80
|
-
],
|
81
81
|
inactive_variant_idx: 0,
|
82
82
|
user_targets: [
|
83
83
|
variant_idx: 1,
|
@@ -87,22 +87,22 @@ class TestFeatureFlagClient < Minitest::Test
|
|
87
87
|
)
|
88
88
|
|
89
89
|
assert_equal "user target",
|
90
|
-
@client.evaluate(feature, "user:1", [], flag)
|
90
|
+
@client.evaluate(feature, "user:1", [], flag, variants)
|
91
91
|
assert_equal "default",
|
92
|
-
@client.evaluate(feature, "user:2", [], flag)
|
92
|
+
@client.evaluate(feature, "user:2", [], flag, variants)
|
93
93
|
assert_equal "user target",
|
94
|
-
@client.evaluate(feature, "user:3", [], flag)
|
94
|
+
@client.evaluate(feature, "user:3", [], flag, variants)
|
95
95
|
end
|
96
96
|
|
97
97
|
def test_inclusion_rule
|
98
98
|
feature = "FlagName"
|
99
|
+
variants = [
|
100
|
+
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
101
|
+
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
102
|
+
Prefab::FeatureFlagVariant.new(string: "default"),
|
103
|
+
]
|
99
104
|
flag = Prefab::FeatureFlag.new(
|
100
105
|
active: true,
|
101
|
-
variants: [
|
102
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
103
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
104
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
105
|
-
],
|
106
106
|
inactive_variant_idx: 0,
|
107
107
|
rules: [Prefab::Rule.new(
|
108
108
|
distribution: Prefab::VariantDistribution.new(variant_idx: 1),
|
@@ -115,9 +115,9 @@ class TestFeatureFlagClient < Minitest::Test
|
|
115
115
|
)
|
116
116
|
|
117
117
|
assert_equal "rule target",
|
118
|
-
@client.evaluate(feature, "user:1", [], flag)
|
118
|
+
@client.evaluate(feature, "user:1", [], flag, variants)
|
119
119
|
assert_equal "default",
|
120
|
-
@client.evaluate(feature, "user:2", [], flag)
|
120
|
+
@client.evaluate(feature, "user:2", [], flag, variants)
|
121
121
|
|
122
122
|
end
|
123
123
|
|
@@ -143,13 +143,13 @@ class TestFeatureFlagClient < Minitest::Test
|
|
143
143
|
)
|
144
144
|
|
145
145
|
feature = "FlagName"
|
146
|
+
variants = [
|
147
|
+
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
148
|
+
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
149
|
+
Prefab::FeatureFlagVariant.new(string: "default"),
|
150
|
+
]
|
146
151
|
flag = Prefab::FeatureFlag.new(
|
147
152
|
active: true,
|
148
|
-
variants: [
|
149
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
150
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
151
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
152
|
-
],
|
153
153
|
inactive_variant_idx: 0,
|
154
154
|
rules: [Prefab::Rule.new(
|
155
155
|
distribution: Prefab::VariantDistribution.new(variant_idx: 1),
|
@@ -162,9 +162,9 @@ class TestFeatureFlagClient < Minitest::Test
|
|
162
162
|
)
|
163
163
|
|
164
164
|
assert_equal "rule target",
|
165
|
-
@client.evaluate(feature, "user:1", [], flag)
|
165
|
+
@client.evaluate(feature, "user:1", [], flag, variants)
|
166
166
|
assert_equal "default",
|
167
|
-
@client.evaluate(feature, "user:2", [], flag)
|
167
|
+
@client.evaluate(feature, "user:2", [], flag, variants)
|
168
168
|
|
169
169
|
end
|
170
170
|
|
@@ -187,13 +187,13 @@ class TestFeatureFlagClient < Minitest::Test
|
|
187
187
|
)
|
188
188
|
|
189
189
|
feature = "FlagName"
|
190
|
+
variants = [
|
191
|
+
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
192
|
+
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
193
|
+
Prefab::FeatureFlagVariant.new(string: "default"),
|
194
|
+
]
|
190
195
|
flag = Prefab::FeatureFlag.new(
|
191
196
|
active: true,
|
192
|
-
variants: [
|
193
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
194
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
195
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
196
|
-
],
|
197
197
|
inactive_variant_idx: 0,
|
198
198
|
rules: [Prefab::Rule.new(
|
199
199
|
distribution: Prefab::VariantDistribution.new(variant_idx: 1),
|
@@ -206,15 +206,15 @@ class TestFeatureFlagClient < Minitest::Test
|
|
206
206
|
)
|
207
207
|
|
208
208
|
assert_equal "rule target",
|
209
|
-
@client.evaluate(feature, "user:1", [], flag)
|
209
|
+
@client.evaluate(feature, "user:1", [], flag, variants)
|
210
210
|
assert_equal "rule target",
|
211
|
-
@client.evaluate(feature, "user:2", [], flag), "matches segment 1"
|
211
|
+
@client.evaluate(feature, "user:2", [], flag, variants), "matches segment 1"
|
212
212
|
assert_equal "rule target",
|
213
|
-
@client.evaluate(feature, "user:3", [], flag)
|
213
|
+
@client.evaluate(feature, "user:3", [], flag, variants)
|
214
214
|
assert_equal "rule target",
|
215
|
-
@client.evaluate(feature, "user:4", [], flag)
|
215
|
+
@client.evaluate(feature, "user:4", [], flag, variants)
|
216
216
|
assert_equal "default",
|
217
|
-
@client.evaluate(feature, "user:5", [], flag)
|
217
|
+
@client.evaluate(feature, "user:5", [], flag, variants)
|
218
218
|
|
219
219
|
end
|
220
220
|
end
|
data/test/test_helper.rb
CHANGED
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.
|
4
|
+
version: 0.9.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-
|
11
|
+
date: 2022-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -44,6 +44,20 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ld-eventsource
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: grpc
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|