sdk-reforge 1.9.0 → 1.9.2
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/.github/workflows/push_gem.yml +46 -0
- data/CHANGELOG.md +9 -0
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/dev/script_setup.rb +1 -1
- data/lib/reforge/config_client.rb +19 -2
- data/lib/reforge/criteria_evaluator.rb +13 -1
- data/lib/reforge/{prefab.rb → reforge.rb} +1 -1
- data/lib/reforge/sse_config_client.rb +14 -1
- data/lib/{reforge-sdk.rb → sdk-reforge.rb} +1 -1
- data/sdk-reforge.gemspec +149 -0
- data/test/support/common_helpers.rb +15 -1
- data/test/test_client.rb +7 -7
- data/test/test_config_client.rb +67 -0
- data/test/test_helper.rb +1 -1
- data/test/test_sse_config_client.rb +39 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46d6f6afa160400b4319eb454fd5271462d1dc8264570c549327652a4debb1c3
|
4
|
+
data.tar.gz: 4a88ea9de1cdfef5dc0e8eff6f8d7b210808ffed6236efb8ec150d138d6923cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 569a9c836b3c0d85f06387235f3909343233ee2d5c8ab9c5d888d5f7780a16cac6c70b78fafa89e9cf3653890c16c1eb86a5461afedce5d96edcf904c1d8a42a
|
7
|
+
data.tar.gz: 1dd174148278acbc0625ee85081c39ca3d975d710ee837813c4ab3587f117796a341c27d63fd548e16a423d040421efb9096e62809d9922818d9a5ed6de508b2
|
@@ -0,0 +1,46 @@
|
|
1
|
+
---
|
2
|
+
name: Push gem
|
3
|
+
|
4
|
+
"on":
|
5
|
+
workflow_run:
|
6
|
+
workflows: ["Ruby"]
|
7
|
+
branches: [main]
|
8
|
+
types:
|
9
|
+
- completed
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
push:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
15
|
+
|
16
|
+
permissions:
|
17
|
+
contents: write
|
18
|
+
id-token: write
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v4
|
22
|
+
with:
|
23
|
+
persist-credentials: false
|
24
|
+
submodules: recursive
|
25
|
+
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
bundler-cache: true
|
30
|
+
ruby-version: ruby
|
31
|
+
|
32
|
+
- name: Check if version already exists
|
33
|
+
id: version-check
|
34
|
+
run: |
|
35
|
+
VERSION=$(cat VERSION)
|
36
|
+
if gem list -r sdk-reforge | grep -q "sdk-reforge ($VERSION)"; then
|
37
|
+
echo "version-exists=true" >> $GITHUB_OUTPUT
|
38
|
+
echo "Version $VERSION already exists on RubyGems, skipping publish"
|
39
|
+
else
|
40
|
+
echo "version-exists=false" >> $GITHUB_OUTPUT
|
41
|
+
echo "Version $VERSION not found, proceeding with publish"
|
42
|
+
fi
|
43
|
+
|
44
|
+
- name: Release gem
|
45
|
+
if: steps.version-check.outputs.version-exists == 'false'
|
46
|
+
uses: rubygems/release-gem@v1
|
data/CHANGELOG.md
CHANGED
data/Rakefile
CHANGED
@@ -56,8 +56,9 @@ end
|
|
56
56
|
|
57
57
|
# Add release task for CI
|
58
58
|
task :release do
|
59
|
-
sh '
|
59
|
+
sh 'mkdir -p pkg'
|
60
60
|
version = File.read('VERSION').strip
|
61
|
-
gem_file = "sdk-reforge-#{version}.gem"
|
61
|
+
gem_file = "pkg/sdk-reforge-#{version}.gem"
|
62
|
+
sh "gem build sdk-reforge.gemspec --output #{gem_file}"
|
62
63
|
sh "gem push #{gem_file}"
|
63
64
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.9.
|
1
|
+
1.9.2
|
data/dev/script_setup.rb
CHANGED
@@ -140,6 +140,11 @@ module Reforge
|
|
140
140
|
def load_url(conn, source)
|
141
141
|
resp = conn.get('')
|
142
142
|
if resp.status == 200
|
143
|
+
if resp.body.nil? || resp.body.empty?
|
144
|
+
LOG.warn "Checkpoint #{source} [#{conn.uri}] failed to load. Response body is empty"
|
145
|
+
return false
|
146
|
+
end
|
147
|
+
|
143
148
|
configs = PrefabProto::Configs.decode(resp.body)
|
144
149
|
load_configs(configs, source)
|
145
150
|
cache_configs(configs)
|
@@ -218,7 +223,13 @@ module Reforge
|
|
218
223
|
return false unless @options.use_local_cache
|
219
224
|
File.open(cache_path) do |f|
|
220
225
|
f.flock(File::LOCK_SH)
|
221
|
-
|
226
|
+
content = f.read
|
227
|
+
if content.nil? || content.empty?
|
228
|
+
LOG.warn "Failed to read cached configs at #{cache_path}. File is empty"
|
229
|
+
return false
|
230
|
+
end
|
231
|
+
|
232
|
+
configs = PrefabProto::Configs.decode_json(content)
|
222
233
|
load_configs(configs, :cache)
|
223
234
|
|
224
235
|
hours_old = ((Time.now - File.mtime(f)) / 60 / 60).round(2)
|
@@ -235,7 +246,13 @@ module Reforge
|
|
235
246
|
def load_json_file(file)
|
236
247
|
File.open(file) do |f|
|
237
248
|
f.flock(File::LOCK_SH)
|
238
|
-
|
249
|
+
content = f.read
|
250
|
+
if content.nil? || content.empty?
|
251
|
+
LOG.warn "Failed to read datafile at #{file}. File is empty"
|
252
|
+
return false
|
253
|
+
end
|
254
|
+
|
255
|
+
configs = PrefabProto::Configs.decode_json(content)
|
239
256
|
load_configs(configs, :datafile)
|
240
257
|
end
|
241
258
|
end
|
@@ -227,11 +227,23 @@ module Reforge
|
|
227
227
|
row.values.each_with_index do |conditional_value, value_index|
|
228
228
|
next unless all_criteria_match?(conditional_value, properties)
|
229
229
|
|
230
|
+
# we compute the row index here as if the @config.rows were sorted with the default environment (id=0) last. the client would only ever see one or two rows
|
231
|
+
# 2 rows if there's a default env rule and a targed env rule
|
232
|
+
# 1 row if there's only a default env rule or only a target env rule
|
233
|
+
config_row_index = if @config.rows.length == 1
|
234
|
+
0
|
235
|
+
elsif row.project_env_id != 0
|
236
|
+
0
|
237
|
+
else
|
238
|
+
1
|
239
|
+
end
|
240
|
+
|
241
|
+
|
230
242
|
return Reforge::Evaluation.new(
|
231
243
|
config: @config,
|
232
244
|
value: conditional_value.value,
|
233
245
|
value_index: value_index,
|
234
|
-
config_row_index:
|
246
|
+
config_row_index: config_row_index,
|
235
247
|
context: properties,
|
236
248
|
resolver: @resolver
|
237
249
|
)
|
@@ -73,7 +73,20 @@ module Reforge
|
|
73
73
|
reconnect_time: @options.sse_default_reconnect_time,
|
74
74
|
logger: Reforge::InternalLogger.new(SSE::Client)) do |client|
|
75
75
|
client.on_event do |event|
|
76
|
-
|
76
|
+
if event.data.nil? || event.data.empty?
|
77
|
+
@logger.error "SSE Streaming Error: Received empty data for url #{url}"
|
78
|
+
client.close
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
decoded_data = Base64.decode64(event.data)
|
83
|
+
if decoded_data.nil? || decoded_data.empty?
|
84
|
+
@logger.error "SSE Streaming Error: Decoded data is empty for url #{url}"
|
85
|
+
client.close
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
configs = PrefabProto::Configs.decode(decoded_data)
|
77
90
|
load_configs.call(configs, event, :sse)
|
78
91
|
end
|
79
92
|
|
@@ -49,7 +49,7 @@ require 'reforge/client'
|
|
49
49
|
require 'reforge/config_client_presenter'
|
50
50
|
require 'reforge/config_client'
|
51
51
|
require 'reforge/feature_flag_client'
|
52
|
-
require 'reforge/
|
52
|
+
require 'reforge/reforge'
|
53
53
|
require 'reforge/murmer3'
|
54
54
|
require 'reforge/javascript_stub'
|
55
55
|
require 'reforge/semver'
|
data/sdk-reforge.gemspec
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Generated by juwelier
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: sdk-reforge 1.9.2 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "sdk-reforge".freeze
|
9
|
+
s.version = "1.9.2"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["Jeff Dwyer".freeze]
|
14
|
+
s.date = "2025-10-02"
|
15
|
+
s.description = "Feature Flags, Live Config as a service".freeze
|
16
|
+
s.email = "jeff.dwyer@reforge.com.cloud".freeze
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"CHANGELOG.md",
|
19
|
+
"LICENSE.txt",
|
20
|
+
"README.md"
|
21
|
+
]
|
22
|
+
s.files = [
|
23
|
+
".envrc.sample",
|
24
|
+
".github/CODEOWNERS",
|
25
|
+
".github/pull_request_template.md",
|
26
|
+
".github/workflows/push_gem.yml",
|
27
|
+
".github/workflows/ruby.yml",
|
28
|
+
".gitmodules",
|
29
|
+
".rubocop.yml",
|
30
|
+
".tool-versions",
|
31
|
+
"CHANGELOG.md",
|
32
|
+
"CODEOWNERS",
|
33
|
+
"Gemfile",
|
34
|
+
"Gemfile.lock",
|
35
|
+
"LICENSE.txt",
|
36
|
+
"README.md",
|
37
|
+
"Rakefile",
|
38
|
+
"VERSION",
|
39
|
+
"compile_protos.sh",
|
40
|
+
"dev/allocation_stats",
|
41
|
+
"dev/benchmark",
|
42
|
+
"dev/console",
|
43
|
+
"dev/script_setup.rb",
|
44
|
+
"lib/prefab_pb.rb",
|
45
|
+
"lib/reforge/caching_http_connection.rb",
|
46
|
+
"lib/reforge/client.rb",
|
47
|
+
"lib/reforge/config_client.rb",
|
48
|
+
"lib/reforge/config_client_presenter.rb",
|
49
|
+
"lib/reforge/config_loader.rb",
|
50
|
+
"lib/reforge/config_resolver.rb",
|
51
|
+
"lib/reforge/config_value_unwrapper.rb",
|
52
|
+
"lib/reforge/config_value_wrapper.rb",
|
53
|
+
"lib/reforge/context.rb",
|
54
|
+
"lib/reforge/context_shape.rb",
|
55
|
+
"lib/reforge/context_shape_aggregator.rb",
|
56
|
+
"lib/reforge/criteria_evaluator.rb",
|
57
|
+
"lib/reforge/duration.rb",
|
58
|
+
"lib/reforge/encryption.rb",
|
59
|
+
"lib/reforge/error.rb",
|
60
|
+
"lib/reforge/errors/env_var_parse_error.rb",
|
61
|
+
"lib/reforge/errors/initialization_timeout_error.rb",
|
62
|
+
"lib/reforge/errors/invalid_sdk_key_error.rb",
|
63
|
+
"lib/reforge/errors/missing_default_error.rb",
|
64
|
+
"lib/reforge/errors/missing_env_var_error.rb",
|
65
|
+
"lib/reforge/errors/uninitialized_error.rb",
|
66
|
+
"lib/reforge/evaluation.rb",
|
67
|
+
"lib/reforge/evaluation_summary_aggregator.rb",
|
68
|
+
"lib/reforge/example_contexts_aggregator.rb",
|
69
|
+
"lib/reforge/exponential_backoff.rb",
|
70
|
+
"lib/reforge/feature_flag_client.rb",
|
71
|
+
"lib/reforge/fixed_size_hash.rb",
|
72
|
+
"lib/reforge/http_connection.rb",
|
73
|
+
"lib/reforge/internal_logger.rb",
|
74
|
+
"lib/reforge/javascript_stub.rb",
|
75
|
+
"lib/reforge/local_config_parser.rb",
|
76
|
+
"lib/reforge/murmer3.rb",
|
77
|
+
"lib/reforge/options.rb",
|
78
|
+
"lib/reforge/periodic_sync.rb",
|
79
|
+
"lib/reforge/rate_limit_cache.rb",
|
80
|
+
"lib/reforge/reforge.rb",
|
81
|
+
"lib/reforge/resolved_config_presenter.rb",
|
82
|
+
"lib/reforge/semver.rb",
|
83
|
+
"lib/reforge/sse_config_client.rb",
|
84
|
+
"lib/reforge/time_helpers.rb",
|
85
|
+
"lib/reforge/weighted_value_resolver.rb",
|
86
|
+
"lib/reforge/yaml_config_parser.rb",
|
87
|
+
"lib/sdk-reforge.rb",
|
88
|
+
"sdk-reforge.gemspec",
|
89
|
+
"test/fixtures/datafile.json",
|
90
|
+
"test/integration_test.rb",
|
91
|
+
"test/integration_test_helpers.rb",
|
92
|
+
"test/support/common_helpers.rb",
|
93
|
+
"test/support/mock_base_client.rb",
|
94
|
+
"test/support/mock_config_client.rb",
|
95
|
+
"test/support/mock_config_loader.rb",
|
96
|
+
"test/test_caching_http_connection.rb",
|
97
|
+
"test/test_client.rb",
|
98
|
+
"test/test_config_client.rb",
|
99
|
+
"test/test_config_loader.rb",
|
100
|
+
"test/test_config_resolver.rb",
|
101
|
+
"test/test_config_value_unwrapper.rb",
|
102
|
+
"test/test_config_value_wrapper.rb",
|
103
|
+
"test/test_context.rb",
|
104
|
+
"test/test_context_shape.rb",
|
105
|
+
"test/test_context_shape_aggregator.rb",
|
106
|
+
"test/test_criteria_evaluator.rb",
|
107
|
+
"test/test_duration.rb",
|
108
|
+
"test/test_encryption.rb",
|
109
|
+
"test/test_evaluation_summary_aggregator.rb",
|
110
|
+
"test/test_example_contexts_aggregator.rb",
|
111
|
+
"test/test_exponential_backoff.rb",
|
112
|
+
"test/test_feature_flag_client.rb",
|
113
|
+
"test/test_fixed_size_hash.rb",
|
114
|
+
"test/test_helper.rb",
|
115
|
+
"test/test_integration.rb",
|
116
|
+
"test/test_internal_logger.rb",
|
117
|
+
"test/test_javascript_stub.rb",
|
118
|
+
"test/test_local_config_parser.rb",
|
119
|
+
"test/test_logger_initialization.rb",
|
120
|
+
"test/test_options.rb",
|
121
|
+
"test/test_prefab.rb",
|
122
|
+
"test/test_rate_limit_cache.rb",
|
123
|
+
"test/test_semver.rb",
|
124
|
+
"test/test_sse_config_client.rb",
|
125
|
+
"test/test_weighted_value_resolver.rb"
|
126
|
+
]
|
127
|
+
s.homepage = "http://github.com/ReforgeHQ/sdk-ruby".freeze
|
128
|
+
s.licenses = ["MIT".freeze]
|
129
|
+
s.rubygems_version = "3.4.19".freeze
|
130
|
+
s.summary = "Reforge Launch Ruby Infrastructure".freeze
|
131
|
+
|
132
|
+
s.specification_version = 4
|
133
|
+
|
134
|
+
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, ["~> 1.0", ">= 1.0.5"])
|
135
|
+
s.add_runtime_dependency(%q<faraday>.freeze, [">= 0"])
|
136
|
+
s.add_runtime_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
|
137
|
+
s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
138
|
+
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
139
|
+
s.add_runtime_dependency(%q<uuid>.freeze, [">= 0"])
|
140
|
+
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4"])
|
141
|
+
s.add_runtime_dependency(%q<semantic_logger>.freeze, ["!= 4.16.0"])
|
142
|
+
s.add_development_dependency(%q<allocation_stats>.freeze, [">= 0"])
|
143
|
+
s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
144
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
145
|
+
s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
|
146
|
+
s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
|
147
|
+
s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
|
148
|
+
end
|
149
|
+
|
@@ -137,7 +137,21 @@ module CommonHelpers
|
|
137
137
|
def assert_summary(client, data)
|
138
138
|
raise 'Evaluation summary aggregator not enabled' unless client.evaluation_summary_aggregator
|
139
139
|
|
140
|
-
|
140
|
+
actual = client.evaluation_summary_aggregator.data
|
141
|
+
|
142
|
+
# Compare keys first (order independent)
|
143
|
+
assert_equal data.keys.sort_by(&:to_s), actual.keys.sort_by(&:to_s), "Summary keys mismatch"
|
144
|
+
|
145
|
+
# Then compare each nested hash (order independent)
|
146
|
+
data.each do |key, expected_counters|
|
147
|
+
actual_counters = actual[key]
|
148
|
+
|
149
|
+
# Convert to sets for order-independent comparison
|
150
|
+
expected_set = expected_counters.to_a.to_set
|
151
|
+
actual_set = actual_counters.to_a.to_set
|
152
|
+
|
153
|
+
assert_equal expected_set, actual_set, "Counter mismatch for #{key}"
|
154
|
+
end
|
141
155
|
end
|
142
156
|
|
143
157
|
def assert_example_contexts(client, data)
|
data/test/test_client.rb
CHANGED
@@ -106,7 +106,7 @@ class TestClient < Minitest::Test
|
|
106
106
|
[KEY, :CONFIG] => {
|
107
107
|
{
|
108
108
|
config_id: config.id,
|
109
|
-
config_row_index:
|
109
|
+
config_row_index: 0,
|
110
110
|
selected_value: DESIRED_VALUE_CONFIG,
|
111
111
|
conditional_value_index: 0,
|
112
112
|
weighted_value_index: nil,
|
@@ -131,7 +131,7 @@ class TestClient < Minitest::Test
|
|
131
131
|
[KEY, :CONFIG] => {
|
132
132
|
{
|
133
133
|
config_id: config.id,
|
134
|
-
config_row_index:
|
134
|
+
config_row_index: 0,
|
135
135
|
selected_value: DESIRED_VALUE_CONFIG,
|
136
136
|
conditional_value_index: 0,
|
137
137
|
weighted_value_index: nil,
|
@@ -181,7 +181,7 @@ class TestClient < Minitest::Test
|
|
181
181
|
[KEY, :CONFIG] => {
|
182
182
|
{
|
183
183
|
config_id: config.id,
|
184
|
-
config_row_index:
|
184
|
+
config_row_index: 0,
|
185
185
|
selected_value: PrefabProto::ConfigValue.new(string: 'abc'),
|
186
186
|
conditional_value_index: 0,
|
187
187
|
weighted_value_index: 0,
|
@@ -190,7 +190,7 @@ class TestClient < Minitest::Test
|
|
190
190
|
|
191
191
|
{
|
192
192
|
config_id: config.id,
|
193
|
-
config_row_index:
|
193
|
+
config_row_index: 0,
|
194
194
|
selected_value: PrefabProto::ConfigValue.new(string: 'def'),
|
195
195
|
conditional_value_index: 0,
|
196
196
|
weighted_value_index: 1,
|
@@ -199,7 +199,7 @@ class TestClient < Minitest::Test
|
|
199
199
|
|
200
200
|
{
|
201
201
|
config_id: config.id,
|
202
|
-
config_row_index:
|
202
|
+
config_row_index: 0,
|
203
203
|
selected_value: PrefabProto::ConfigValue.new(string: 'ghi'),
|
204
204
|
conditional_value_index: 0,
|
205
205
|
weighted_value_index: 2,
|
@@ -278,9 +278,9 @@ class TestClient < Minitest::Test
|
|
278
278
|
weighted_value_index: nil, selected_index: nil } => 1
|
279
279
|
},
|
280
280
|
[KEY, :NOT_SET_CONFIG_TYPE] => {
|
281
|
-
{ config_id: 0, config_row_index:
|
281
|
+
{ config_id: 0, config_row_index: 1, conditional_value_index: 0, selected_value: DEFAULT_VALUE_CONFIG,
|
282
282
|
weighted_value_index: nil, selected_index: nil } => 2,
|
283
|
-
{ config_id: 0, config_row_index:
|
283
|
+
{ config_id: 0, config_row_index: 0, conditional_value_index: 0, selected_value: DESIRED_VALUE_CONFIG,
|
284
284
|
weighted_value_index: nil, selected_index: nil } => 1
|
285
285
|
}
|
286
286
|
}
|
data/test/test_config_client.rb
CHANGED
@@ -81,4 +81,71 @@ class TestConfigClient < Minitest::Test
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
def test_load_url_with_empty_body
|
85
|
+
options = Reforge::Options.new(
|
86
|
+
prefab_datasources: Reforge::Options::DATASOURCES::LOCAL_ONLY,
|
87
|
+
x_use_local_cache: true,
|
88
|
+
sdk_key: "123-ENV-KEY-SDK",)
|
89
|
+
|
90
|
+
config_client = Reforge::ConfigClient.new(MockBaseClient.new(options), 10)
|
91
|
+
|
92
|
+
# Mock connection with empty response body
|
93
|
+
mock_conn = Minitest::Mock.new
|
94
|
+
mock_resp = Minitest::Mock.new
|
95
|
+
mock_resp.expect(:status, 200)
|
96
|
+
mock_resp.expect(:body, '')
|
97
|
+
mock_resp.expect(:body, '')
|
98
|
+
mock_conn.expect(:get, mock_resp, [''])
|
99
|
+
mock_conn.expect(:uri, 'http://test.example.com')
|
100
|
+
|
101
|
+
result = config_client.send(:load_url, mock_conn, :test_source)
|
102
|
+
|
103
|
+
assert_equal false, result, 'Expected load_url to return false for empty body'
|
104
|
+
mock_conn.verify
|
105
|
+
mock_resp.verify
|
106
|
+
|
107
|
+
assert_logged [/Response body is empty/]
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_load_cache_with_empty_file
|
111
|
+
options = Reforge::Options.new(
|
112
|
+
prefab_datasources: Reforge::Options::DATASOURCES::LOCAL_ONLY,
|
113
|
+
x_use_local_cache: true,
|
114
|
+
sdk_key: "123-ENV-KEY-SDK",)
|
115
|
+
|
116
|
+
config_client = Reforge::ConfigClient.new(MockBaseClient.new(options), 10)
|
117
|
+
cache_path = config_client.send(:cache_path)
|
118
|
+
|
119
|
+
# Create an empty cache file
|
120
|
+
FileUtils.mkdir_p(File.dirname(cache_path))
|
121
|
+
File.write(cache_path, '')
|
122
|
+
|
123
|
+
result = config_client.send(:load_cache)
|
124
|
+
|
125
|
+
assert_equal false, result, 'Expected load_cache to return false for empty file'
|
126
|
+
assert_logged [/File is empty/]
|
127
|
+
ensure
|
128
|
+
File.delete(cache_path) if File.exist?(cache_path)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_load_json_file_with_empty_file
|
132
|
+
options = Reforge::Options.new(
|
133
|
+
prefab_datasources: Reforge::Options::DATASOURCES::LOCAL_ONLY,
|
134
|
+
x_use_local_cache: true,
|
135
|
+
sdk_key: "123-ENV-KEY-SDK",)
|
136
|
+
|
137
|
+
config_client = Reforge::ConfigClient.new(MockBaseClient.new(options), 10)
|
138
|
+
|
139
|
+
# Create a temporary empty datafile
|
140
|
+
temp_file = File.join(Dir.tmpdir, 'test_empty_datafile.json')
|
141
|
+
File.write(temp_file, '')
|
142
|
+
|
143
|
+
result = config_client.send(:load_json_file, temp_file)
|
144
|
+
|
145
|
+
assert_equal false, result, 'Expected load_json_file to return false for empty file'
|
146
|
+
assert_logged [/File is empty/]
|
147
|
+
ensure
|
148
|
+
File.delete(temp_file) if File.exist?(temp_file)
|
149
|
+
end
|
150
|
+
|
84
151
|
end
|
data/test/test_helper.rb
CHANGED
@@ -208,4 +208,43 @@ class TestSSEConfigClient < Minitest::Test
|
|
208
208
|
output << "data: CmYIu8fh4YaO0x4QZBo0bG9nLWxldmVsLmNsb3VkLnByZWZhYi5zZXJ2ZXIubG9nZ2luZy5FdmVudFByb2Nlc3NvciIfCAESG2phbWVzLmtlYmluZ2VyQHByZWZhYi5jbG91ZDgGSAkSDQhkELvH4eGGjtMeGGU=\n\n"
|
209
209
|
end
|
210
210
|
end
|
211
|
+
|
212
|
+
def test_empty_data_validation
|
213
|
+
# Unit test to verify that empty data is properly detected and handled
|
214
|
+
log_output = StringIO.new
|
215
|
+
logger = Logger.new(log_output)
|
216
|
+
|
217
|
+
# Test that empty event.data is detected
|
218
|
+
mock_event = OpenStruct.new(data: '')
|
219
|
+
mock_client = Minitest::Mock.new
|
220
|
+
mock_client.expect(:close, nil)
|
221
|
+
|
222
|
+
# Simulate the on_event handler logic
|
223
|
+
if mock_event.data.nil? || mock_event.data.empty?
|
224
|
+
logger.error "SSE Streaming Error: Received empty data for url http://test"
|
225
|
+
mock_client.close
|
226
|
+
end
|
227
|
+
|
228
|
+
log_lines = log_output.string.split("\n")
|
229
|
+
assert log_lines.any? { |line| line.include?('SSE Streaming Error') && line.include?('empty data') },
|
230
|
+
'Expected to have logged an error about empty data'
|
231
|
+
mock_client.verify
|
232
|
+
|
233
|
+
# Test that nil event.data is detected
|
234
|
+
log_output = StringIO.new
|
235
|
+
logger = Logger.new(log_output)
|
236
|
+
mock_event = OpenStruct.new(data: nil)
|
237
|
+
mock_client = Minitest::Mock.new
|
238
|
+
mock_client.expect(:close, nil)
|
239
|
+
|
240
|
+
if mock_event.data.nil? || mock_event.data.empty?
|
241
|
+
logger.error "SSE Streaming Error: Received empty data for url http://test"
|
242
|
+
mock_client.close
|
243
|
+
end
|
244
|
+
|
245
|
+
log_lines = log_output.string.split("\n")
|
246
|
+
assert log_lines.any? { |line| line.include?('SSE Streaming Error') && line.include?('empty data') },
|
247
|
+
'Expected to have logged an error about empty data for nil'
|
248
|
+
mock_client.verify
|
249
|
+
end
|
211
250
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sdk-reforge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.
|
4
|
+
version: 1.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Dwyer
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-10-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: concurrent-ruby
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- ".envrc.sample"
|
224
224
|
- ".github/CODEOWNERS"
|
225
225
|
- ".github/pull_request_template.md"
|
226
|
+
- ".github/workflows/push_gem.yml"
|
226
227
|
- ".github/workflows/ruby.yml"
|
227
228
|
- ".gitmodules"
|
228
229
|
- ".rubocop.yml"
|
@@ -241,7 +242,6 @@ files:
|
|
241
242
|
- dev/console
|
242
243
|
- dev/script_setup.rb
|
243
244
|
- lib/prefab_pb.rb
|
244
|
-
- lib/reforge-sdk.rb
|
245
245
|
- lib/reforge/caching_http_connection.rb
|
246
246
|
- lib/reforge/client.rb
|
247
247
|
- lib/reforge/config_client.rb
|
@@ -276,14 +276,16 @@ files:
|
|
276
276
|
- lib/reforge/murmer3.rb
|
277
277
|
- lib/reforge/options.rb
|
278
278
|
- lib/reforge/periodic_sync.rb
|
279
|
-
- lib/reforge/prefab.rb
|
280
279
|
- lib/reforge/rate_limit_cache.rb
|
280
|
+
- lib/reforge/reforge.rb
|
281
281
|
- lib/reforge/resolved_config_presenter.rb
|
282
282
|
- lib/reforge/semver.rb
|
283
283
|
- lib/reforge/sse_config_client.rb
|
284
284
|
- lib/reforge/time_helpers.rb
|
285
285
|
- lib/reforge/weighted_value_resolver.rb
|
286
286
|
- lib/reforge/yaml_config_parser.rb
|
287
|
+
- lib/sdk-reforge.rb
|
288
|
+
- sdk-reforge.gemspec
|
287
289
|
- test/fixtures/datafile.json
|
288
290
|
- test/integration_test.rb
|
289
291
|
- test/integration_test_helpers.rb
|