devcycle-ruby-server-sdk 3.7.0 → 3.8.1
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/LICENSE +1 -1
- data/devcycle-ruby-server-sdk.gemspec +3 -3
- data/lib/devcycle-ruby-server-sdk/api/client.rb +15 -2
- data/lib/devcycle-ruby-server-sdk/api/dev_cycle_provider.rb +10 -1
- data/lib/devcycle-ruby-server-sdk/eval_reasons.rb +3 -0
- data/lib/devcycle-ruby-server-sdk/localbucketing/local_bucketing.rb +8 -8
- data/lib/devcycle-ruby-server-sdk/models/variable.rb +2 -1
- data/lib/devcycle-ruby-server-sdk/version.rb +1 -1
- data/spec/api/devcycle_api_spec.rb +83 -0
- data/spec/spec_helper.rb +4 -0
- metadata +16 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04ba19c1b3a21f3f12f891099851c154cf1b6e994b1ddf733c9d5140e731f2e3
|
|
4
|
+
data.tar.gz: 833df647e1fdb7337dfefbb8969cf3c9458aa119596a2b79a67d84b7a530b0eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5def331e282c250dc916cb89f297f87e2a23d85c951b452aa007365c76e0738a8a7b224cd55264f4109d3fb260a7bdd93c0527fdd45fe228cc3637e7eeb8949f
|
|
7
|
+
data.tar.gz: 307c208e98faa99b3295be532681bf28313cf2e7422652c173c9b43d21dd08e3b6da728ce8dd255ad668e8b2147ffe502cb51256a8c4d71b4020cb26222155ee
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
|
@@ -24,13 +24,13 @@ Gem::Specification.new do |s|
|
|
|
24
24
|
s.required_ruby_version = ">= 3.2"
|
|
25
25
|
|
|
26
26
|
s.add_runtime_dependency 'typhoeus', '~> 1.0', '>= 1.0.1'
|
|
27
|
-
s.add_runtime_dependency 'wasmtime', '
|
|
28
|
-
s.add_runtime_dependency 'concurrent-ruby', '
|
|
27
|
+
s.add_runtime_dependency 'wasmtime', '39.0.1'
|
|
28
|
+
s.add_runtime_dependency 'concurrent-ruby', '>= 1.2', '< 1.4'
|
|
29
29
|
s.add_runtime_dependency 'sorbet-runtime', '>= 0.5.11481'
|
|
30
30
|
s.add_runtime_dependency 'oj', '~> 3.0'
|
|
31
31
|
s.add_runtime_dependency 'google-protobuf', '~> 3.22'
|
|
32
32
|
s.add_runtime_dependency 'ld-eventsource', '~> 2.2.3'
|
|
33
|
-
s.add_runtime_dependency 'openfeature-sdk', '~> 0.4.
|
|
33
|
+
s.add_runtime_dependency 'openfeature-sdk', '~> 0.4.1'
|
|
34
34
|
|
|
35
35
|
s.add_development_dependency 'rspec', '~> 3.6', '>= 3.6.0'
|
|
36
36
|
|
|
@@ -325,14 +325,27 @@ module DevCycle
|
|
|
325
325
|
if @api_client.config.debugging
|
|
326
326
|
@api_client.config.logger.debug "API called: DevCycle::Client#variable\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
327
327
|
end
|
|
328
|
+
if default && data.type
|
|
329
|
+
api_type_to_ruby_class = {
|
|
330
|
+
'Boolean' => [TrueClass, FalseClass],
|
|
331
|
+
'Number' => [Integer, Float],
|
|
332
|
+
'String' => [String],
|
|
333
|
+
'JSON' => [Hash]
|
|
334
|
+
}
|
|
335
|
+
ruby_classes = api_type_to_ruby_class[data.type.to_s]
|
|
336
|
+
unless ruby_classes && ruby_classes.any? { |klass| default.is_a?(klass) }
|
|
337
|
+
eval = { reason: DevCycle::EVAL_REASONS::DEFAULT, details: DevCycle::DEFAULT_REASON_DETAILS::TYPE_MISMATCH }
|
|
338
|
+
return Variable.new(key: key, value: default, isDefaulted: true, eval: eval)
|
|
339
|
+
end
|
|
340
|
+
end
|
|
328
341
|
return data
|
|
329
342
|
rescue ApiError => error
|
|
330
343
|
if error.code != 404
|
|
331
344
|
@api_client.config.logger.error("Failed to retrieve variable value: #{error.message}")
|
|
332
345
|
end
|
|
333
346
|
|
|
334
|
-
return Variable.new(key: key, value: default, isDefaulted: true)
|
|
335
|
-
end
|
|
347
|
+
return Variable.new(key: key, value: default, isDefaulted: true, eval: { reason: DevCycle::EVAL_REASONS::DEFAULT, details: DevCycle::DEFAULT_REASON_DETAILS::ERROR })
|
|
348
|
+
end
|
|
336
349
|
end
|
|
337
350
|
|
|
338
351
|
# Get all variables by key for user data
|
|
@@ -32,7 +32,16 @@ module DevCycle
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
|
|
35
|
-
@client.variable(Provider.user_from_openfeature_context(evaluation_context), flag_key, default_value)
|
|
35
|
+
variable = @client.variable(Provider.user_from_openfeature_context(evaluation_context), flag_key, default_value)
|
|
36
|
+
|
|
37
|
+
Variable.new(
|
|
38
|
+
key: variable.key,
|
|
39
|
+
type: variable.type,
|
|
40
|
+
value: variable.value.to_i,
|
|
41
|
+
defaultValue: variable.defaultValue,
|
|
42
|
+
isDefaulted: variable.isDefaulted,
|
|
43
|
+
eval: variable.eval
|
|
44
|
+
)
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
|
|
@@ -27,14 +27,14 @@ module DevCycle
|
|
|
27
27
|
# added to ensure that there is no processes deadlock when compiling wasm before forking
|
|
28
28
|
|
|
29
29
|
@@wasmmodule = Wasmtime::Module.from_file(@@engine, "#{__dir__}/bucketing-lib.release.wasm")
|
|
30
|
-
@@
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@@
|
|
37
|
-
|
|
30
|
+
@@wasi_config = Wasmtime::WasiConfig.new
|
|
31
|
+
.inherit_stdout
|
|
32
|
+
.inherit_stderr
|
|
33
|
+
.set_argv(ARGV)
|
|
34
|
+
.set_env(ENV)
|
|
35
|
+
@@store = Wasmtime::Store.new(@@engine, wasi_p1_config: @@wasi_config)
|
|
36
|
+
@@linker = Wasmtime::Linker.new(@@engine)
|
|
37
|
+
Wasmtime::WASI::P1.add_to_linker_sync(@@linker)
|
|
38
38
|
|
|
39
39
|
@@linker.func_new("env", "Date.now", [], [:f64]) do |_caller|
|
|
40
40
|
DateTime.now.strftime("%Q").to_i
|
|
@@ -12,6 +12,9 @@ OpenAPI Generator version: 5.3.0
|
|
|
12
12
|
|
|
13
13
|
require 'spec_helper'
|
|
14
14
|
require 'json'
|
|
15
|
+
require 'webmock'
|
|
16
|
+
|
|
17
|
+
include WebMock::API
|
|
15
18
|
|
|
16
19
|
# Unit tests for DevCycle::Client
|
|
17
20
|
# Automatically generated by openapi-generator (https://openapi-generator.tech)
|
|
@@ -68,6 +71,8 @@ describe 'DevCycle::Client' do
|
|
|
68
71
|
it 'should work' do
|
|
69
72
|
result = @api_instance.variable(@user, "ruby-example-tests-default", false)
|
|
70
73
|
expect(result.isDefaulted).to eq true
|
|
74
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
75
|
+
expect(result.eval[:details]).to eq "Error"
|
|
71
76
|
|
|
72
77
|
result = @api_instance.variable_value(@user, "ruby-example-tests-default", true)
|
|
73
78
|
expect(result).to eq true
|
|
@@ -88,6 +93,51 @@ describe 'DevCycle::Client' do
|
|
|
88
93
|
|
|
89
94
|
result = @api_instance.variable_value(@user, "test", true)
|
|
90
95
|
expect(result).to eq true
|
|
96
|
+
|
|
97
|
+
result = @api_instance.variable(@user, "test-number-variable", 0)
|
|
98
|
+
expect(result.isDefaulted).to eq false
|
|
99
|
+
expect(result.value).to eq 123
|
|
100
|
+
|
|
101
|
+
result = @api_instance.variable(@user, "test-number-variable", 0)
|
|
102
|
+
expect(result.isDefaulted).to eq false
|
|
103
|
+
expect(result.value).to eq 123
|
|
104
|
+
|
|
105
|
+
result = @api_instance.variable(@user, "test-float-variable", 0.0)
|
|
106
|
+
expect(result.isDefaulted).to eq false
|
|
107
|
+
expect(result.value).to eq 4.56
|
|
108
|
+
|
|
109
|
+
result = @api_instance.variable(@user, "test-string-variable", "")
|
|
110
|
+
expect(result.isDefaulted).to eq false
|
|
111
|
+
expect(result.value).to eq "on"
|
|
112
|
+
|
|
113
|
+
result = @api_instance.variable(@user, "test-json-variable", {})
|
|
114
|
+
expect(result.isDefaulted).to eq false
|
|
115
|
+
expect(result.value).to eq({:message => "a"})
|
|
116
|
+
|
|
117
|
+
result = @api_instance.variable(@user, "test", "false")
|
|
118
|
+
expect(result.isDefaulted).to eq true
|
|
119
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
120
|
+
expect(result.eval[:details]).to eq "Variable Type Mismatch"
|
|
121
|
+
|
|
122
|
+
result = @api_instance.variable(@user, "test-number-variable", "123")
|
|
123
|
+
expect(result.isDefaulted).to eq true
|
|
124
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
125
|
+
expect(result.eval[:details]).to eq "Variable Type Mismatch"
|
|
126
|
+
|
|
127
|
+
result = @api_instance.variable(@user, "test-number-variable", true)
|
|
128
|
+
expect(result.isDefaulted).to eq true
|
|
129
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
130
|
+
expect(result.eval[:details]).to eq "Variable Type Mismatch"
|
|
131
|
+
|
|
132
|
+
result = @api_instance.variable(@user, "test-string-variable", true)
|
|
133
|
+
expect(result.isDefaulted).to eq true
|
|
134
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
135
|
+
expect(result.eval[:details]).to eq "Variable Type Mismatch"
|
|
136
|
+
|
|
137
|
+
result = @api_instance.variable(@user, "test-json-variable", "on")
|
|
138
|
+
expect(result.isDefaulted).to eq true
|
|
139
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
140
|
+
expect(result.eval[:details]).to eq "Variable Type Mismatch"
|
|
91
141
|
end
|
|
92
142
|
end
|
|
93
143
|
|
|
@@ -104,4 +154,37 @@ describe 'DevCycle::Client' do
|
|
|
104
154
|
end
|
|
105
155
|
end
|
|
106
156
|
|
|
157
|
+
describe 'get_variable_by_key test' do
|
|
158
|
+
before do
|
|
159
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
after do
|
|
163
|
+
WebMock.allow_net_connect!
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'should work with mocked response' do
|
|
167
|
+
stub_request(:post, "https://bucketing-api.devcycle.com/v1/variables/mocked_variable").
|
|
168
|
+
to_return(status: 200, body: "{\"isDefaulted\": false, \"value\": true, \"eval\": {\"reason\": \"SPLIT\", \"details\": \"Random Distribution | All Users\", \"target_id\": \"621642332ea68943c8833c4d\"}}", headers: {})
|
|
169
|
+
|
|
170
|
+
result = @api_instance.variable(@user, "mocked_variable", false)
|
|
171
|
+
expect(result.isDefaulted).to eq false
|
|
172
|
+
expect(result.value).to eq true
|
|
173
|
+
# Use Hash syntax since eval is deserialized as a Hash
|
|
174
|
+
expect(result.eval[:reason]).to eq "SPLIT"
|
|
175
|
+
expect(result.eval[:details]).to eq "Random Distribution | All Users"
|
|
176
|
+
expect(result.eval[:target_id]).to eq "621642332ea68943c8833c4d"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'should return error details' do
|
|
180
|
+
stub_request(:post, "https://bucketing-api.devcycle.com/v1/variables/test").
|
|
181
|
+
to_return(status: 500, body: "{\"isDefaulted\": true, \"value\": false, \"eval\": {\"reason\": \"DEFAULT\", \"details\": \"Error\"}}", headers: {})
|
|
182
|
+
|
|
183
|
+
result = @api_instance.variable(@user, "test", false)
|
|
184
|
+
expect(result.isDefaulted).to eq true
|
|
185
|
+
expect(result.eval[:reason]).to eq "DEFAULT"
|
|
186
|
+
expect(result.eval[:details]).to eq "Error"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
107
190
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -12,6 +12,10 @@ OpenAPI Generator version: 5.3.0
|
|
|
12
12
|
|
|
13
13
|
# load the gem
|
|
14
14
|
require 'devcycle-ruby-server-sdk'
|
|
15
|
+
require 'webmock/rspec'
|
|
16
|
+
|
|
17
|
+
# Configure WebMock to allow real HTTP requests by default, but enable it for specific tests
|
|
18
|
+
WebMock.allow_net_connect!
|
|
15
19
|
|
|
16
20
|
# The following was generated by the `rspec --init` command. Conventionally, all
|
|
17
21
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devcycle-ruby-server-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DevCycleHQ
|
|
@@ -35,28 +35,34 @@ dependencies:
|
|
|
35
35
|
requirements:
|
|
36
36
|
- - '='
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version:
|
|
38
|
+
version: 39.0.1
|
|
39
39
|
type: :runtime
|
|
40
40
|
prerelease: false
|
|
41
41
|
version_requirements: !ruby/object:Gem::Requirement
|
|
42
42
|
requirements:
|
|
43
43
|
- - '='
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
|
-
version:
|
|
45
|
+
version: 39.0.1
|
|
46
46
|
- !ruby/object:Gem::Dependency
|
|
47
47
|
name: concurrent-ruby
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
|
49
49
|
requirements:
|
|
50
|
-
- - "
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '1.2'
|
|
53
|
+
- - "<"
|
|
51
54
|
- !ruby/object:Gem::Version
|
|
52
|
-
version: 1.
|
|
55
|
+
version: '1.4'
|
|
53
56
|
type: :runtime
|
|
54
57
|
prerelease: false
|
|
55
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
56
59
|
requirements:
|
|
57
|
-
- - "
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '1.2'
|
|
63
|
+
- - "<"
|
|
58
64
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: 1.
|
|
65
|
+
version: '1.4'
|
|
60
66
|
- !ruby/object:Gem::Dependency
|
|
61
67
|
name: sorbet-runtime
|
|
62
68
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,14 +125,14 @@ dependencies:
|
|
|
119
125
|
requirements:
|
|
120
126
|
- - "~>"
|
|
121
127
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: 0.4.
|
|
128
|
+
version: 0.4.1
|
|
123
129
|
type: :runtime
|
|
124
130
|
prerelease: false
|
|
125
131
|
version_requirements: !ruby/object:Gem::Requirement
|
|
126
132
|
requirements:
|
|
127
133
|
- - "~>"
|
|
128
134
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: 0.4.
|
|
135
|
+
version: 0.4.1
|
|
130
136
|
- !ruby/object:Gem::Dependency
|
|
131
137
|
name: rspec
|
|
132
138
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -215,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
215
221
|
- !ruby/object:Gem::Version
|
|
216
222
|
version: '0'
|
|
217
223
|
requirements: []
|
|
218
|
-
rubygems_version:
|
|
224
|
+
rubygems_version: 4.0.3
|
|
219
225
|
specification_version: 4
|
|
220
226
|
summary: DevCycle Bucketing API Ruby Gem
|
|
221
227
|
test_files:
|