devcycle-ruby-server-sdk 3.7.0 → 3.8.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: c3acf8324fc7606185240c3ea421048f87c8618a3944951ed71ed729ed4cde7a
4
- data.tar.gz: 763e2632030ffbc90bd365614f158bc960c767e15bcf0d88afd2a2407ff56f24
3
+ metadata.gz: 5b3044307e6ee4e30c1a53aeac3d62eceaaac8ea86fc380b1a41bbf15294ce98
4
+ data.tar.gz: 3fdb48a7217e4390bfe4f53f2e438324803cd9bc8b32a2f91c31a7e7783a32bf
5
5
  SHA512:
6
- metadata.gz: 7830aef854188cded6ed20a3667d4fe6dbf2bcd4482e605b823c95023b7d9fb3f30a52d01543346adae4ed260290f25b71cd516a3172679e4209d54d342eac6b
7
- data.tar.gz: be2f2cb6349a64b95216dd3868642284d917ea4c8db7d2991f550f9beb9e0ddb3f8dae91dc6aa5c817fbf0f2b5f562da1f95fcccee0bddceea67323b96ec783c
6
+ metadata.gz: af96f97ff9a13800b415f59777446ea075535e24959939e737b845599201c6b1d8ddce1d170b099837ee2d2b91dee7039b8354298f009df0e2e0eeb0d731c071
7
+ data.tar.gz: 021bfd22df2c904f03e4e089387a8914b078e9b70d237f12551cfd036665120cba7df2ba3f09b1df62177b6fd9e1b576f7e75c23415880da4c54c8705445eee8
data/Gemfile CHANGED
@@ -15,4 +15,5 @@ group :development, :test do
15
15
  gem 'rake', '~> 13.0.1'
16
16
  gem 'pry-byebug'
17
17
  gem 'rubocop', '~> 1.57.1'
18
+ gem 'webmock'
18
19
  end
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Taplytics Inc.
3
+ Copyright (c) 2025 Taplytics Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -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', '20.0.2'
27
+ s.add_runtime_dependency 'wasmtime', '39.0.1'
28
28
  s.add_runtime_dependency 'concurrent-ruby', '~> 1.2.0'
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.0'
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)
@@ -9,5 +9,8 @@ module DevCycle
9
9
  module DEFAULT_REASON_DETAILS
10
10
  MISSING_CONFIG = 'Missing Config'
11
11
  USER_NOT_TARGETED = 'User Not Targeted'
12
+ TYPE_MISMATCH = 'Variable Type Mismatch'
13
+ MISSING_VARIABLE = 'Missing Variable'
14
+ ERROR = 'Error'
12
15
  end
13
16
  end
@@ -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
- @@wasi_ctx = Wasmtime::WasiCtxBuilder.new
31
- .inherit_stdout
32
- .inherit_stderr
33
- .set_argv(ARGV)
34
- .set_env(ENV)
35
- .build
36
- @@store = Wasmtime::Store.new(@@engine, wasi_ctx: @@wasi_ctx)
37
- @@linker = Wasmtime::Linker.new(@@engine, wasi: true)
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
@@ -78,7 +78,8 @@ module DevCycle
78
78
  :'type' => :'String',
79
79
  :'value' => :'Object',
80
80
  :'defaultValue' => :'Object',
81
- :'isDefaulted' => :'Boolean'
81
+ :'isDefaulted' => :'Boolean',
82
+ :'eval' => :'Object'
82
83
  }
83
84
  end
84
85
 
@@ -1,3 +1,3 @@
1
1
  module DevCycle
2
- VERSION = '3.7.0'
2
+ VERSION = '3.8.0'
3
3
  end
@@ -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.7.0
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DevCycleHQ
@@ -35,14 +35,14 @@ dependencies:
35
35
  requirements:
36
36
  - - '='
37
37
  - !ruby/object:Gem::Version
38
- version: 20.0.2
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: 20.0.2
45
+ version: 39.0.1
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: concurrent-ruby
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -119,14 +119,14 @@ dependencies:
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: 0.4.0
122
+ version: 0.4.1
123
123
  type: :runtime
124
124
  prerelease: false
125
125
  version_requirements: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: 0.4.0
129
+ version: 0.4.1
130
130
  - !ruby/object:Gem::Dependency
131
131
  name: rspec
132
132
  requirement: !ruby/object:Gem::Requirement