prefab-cloud-ruby 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc.sample +3 -0
  3. data/.github/workflows/ruby.yml +4 -0
  4. data/.gitmodules +3 -0
  5. data/Gemfile +12 -12
  6. data/Gemfile.lock +16 -14
  7. data/README.md +1 -1
  8. data/Rakefile +13 -14
  9. data/VERSION +1 -1
  10. data/lib/prefab/auth_interceptor.rb +2 -1
  11. data/lib/prefab/cancellable_interceptor.rb +8 -7
  12. data/lib/prefab/client.rb +33 -24
  13. data/lib/prefab/config_client.rb +55 -66
  14. data/lib/prefab/config_loader.rb +7 -114
  15. data/lib/prefab/config_resolver.rb +27 -57
  16. data/lib/prefab/config_value_unwrapper.rb +23 -0
  17. data/lib/prefab/criteria_evaluator.rb +96 -0
  18. data/lib/prefab/errors/invalid_api_key_error.rb +1 -1
  19. data/lib/prefab/feature_flag_client.rb +13 -145
  20. data/lib/prefab/internal_logger.rb +6 -5
  21. data/lib/prefab/local_config_parser.rb +110 -0
  22. data/lib/prefab/logger_client.rb +26 -31
  23. data/lib/prefab/murmer3.rb +3 -4
  24. data/lib/prefab/noop_cache.rb +5 -7
  25. data/lib/prefab/noop_stats.rb +2 -3
  26. data/lib/prefab/options.rb +11 -9
  27. data/lib/prefab/ratelimit_client.rb +11 -13
  28. data/lib/prefab/sse_logger.rb +3 -2
  29. data/lib/prefab/weighted_value_resolver.rb +42 -0
  30. data/lib/prefab/yaml_config_parser.rb +32 -0
  31. data/lib/prefab-cloud-ruby.rb +7 -2
  32. data/lib/prefab_pb.rb +49 -43
  33. data/lib/prefab_services_pb.rb +0 -1
  34. data/prefab-cloud-ruby.gemspec +28 -19
  35. data/test/.prefab.unit_tests.config.yaml +3 -2
  36. data/test/integration_test.rb +98 -0
  37. data/test/integration_test_helpers.rb +37 -0
  38. data/test/test_client.rb +32 -31
  39. data/test/test_config_client.rb +21 -20
  40. data/test/test_config_loader.rb +48 -37
  41. data/test/test_config_resolver.rb +312 -135
  42. data/test/test_config_value_unwrapper.rb +83 -0
  43. data/test/test_criteria_evaluator.rb +533 -0
  44. data/test/test_feature_flag_client.rb +35 -347
  45. data/test/test_helper.rb +18 -14
  46. data/test/test_integration.rb +33 -0
  47. data/test/test_local_config_parser.rb +78 -0
  48. data/test/test_logger.rb +47 -46
  49. data/test/test_weighted_value_resolver.rb +65 -0
  50. metadata +24 -27
  51. data/lib/prefab/config_helper.rb +0 -31
  52. data/run_test_harness_server.sh +0 -8
  53. data/test/harness_server.rb +0 -64
data/lib/prefab_pb.rb CHANGED
@@ -17,12 +17,22 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
17
17
  optional :bytes, :bytes, 3
18
18
  optional :double, :double, 4
19
19
  optional :bool, :bool, 5
20
- optional :feature_flag, :message, 6, "prefab.FeatureFlag"
20
+ optional :weighted_values, :message, 6, "prefab.WeightedValues"
21
21
  optional :limit_definition, :message, 7, "prefab.LimitDefinition"
22
- optional :segment, :message, 8, "prefab.Segment"
23
22
  optional :log_level, :enum, 9, "prefab.LogLevel"
23
+ optional :string_list, :message, 10, "prefab.StringList"
24
24
  end
25
25
  end
26
+ add_message "prefab.StringList" do
27
+ repeated :values, :string, 1
28
+ end
29
+ add_message "prefab.WeightedValue" do
30
+ optional :weight, :int32, 1
31
+ optional :value, :message, 2, "prefab.ConfigValue"
32
+ end
33
+ add_message "prefab.WeightedValues" do
34
+ repeated :weighted_values, :message, 1, "prefab.WeightedValue"
35
+ end
26
36
  add_message "prefab.Configs" do
27
37
  repeated :configs, :message, 1, "prefab.Config"
28
38
  optional :config_service_pointer, :message, 2, "prefab.ConfigServicePointer"
@@ -31,14 +41,24 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
31
41
  optional :id, :int64, 1
32
42
  optional :project_id, :int64, 2
33
43
  optional :key, :string, 3
34
- optional :changed_by, :string, 4
44
+ optional :changed_by, :message, 4, "prefab.ChangedBy"
35
45
  repeated :rows, :message, 5, "prefab.ConfigRow"
36
- repeated :variants, :message, 6, "prefab.FeatureFlagVariant"
46
+ repeated :allowable_values, :message, 6, "prefab.ConfigValue"
47
+ optional :config_type, :enum, 7, "prefab.ConfigType"
48
+ proto3_optional :draftId, :int64, 8
49
+ end
50
+ add_message "prefab.ChangedBy" do
51
+ optional :user_id, :int64, 1
52
+ optional :email, :string, 2
37
53
  end
38
54
  add_message "prefab.ConfigRow" do
39
- optional :project_env_id, :int64, 1
40
- optional :namespace, :string, 2
41
- optional :value, :message, 3, "prefab.ConfigValue"
55
+ proto3_optional :project_env_id, :int64, 1
56
+ repeated :values, :message, 2, "prefab.ConditionalValue"
57
+ map :properties, :string, :message, 3, "prefab.ConfigValue"
58
+ end
59
+ add_message "prefab.ConditionalValue" do
60
+ repeated :criteria, :message, 1, "prefab.Criterion"
61
+ optional :value, :message, 2, "prefab.ConfigValue"
42
62
  end
43
63
  add_message "prefab.LimitResponse" do
44
64
  optional :passed, :bool, 1
@@ -75,20 +95,12 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
75
95
  value :MINIMUM, 1
76
96
  value :MAXIMUM, 2
77
97
  end
78
- add_message "prefab.FeatureFlagVariant" do
79
- proto3_optional :int, :int64, 1
80
- proto3_optional :string, :string, 2
81
- proto3_optional :double, :double, 3
82
- proto3_optional :bool, :bool, 4
83
- optional :name, :string, 5
84
- optional :description, :string, 6
85
- end
86
- add_message "prefab.Criteria" do
87
- optional :property, :string, 1
88
- optional :operator, :enum, 2, "prefab.Criteria.CriteriaOperator"
89
- repeated :values, :string, 3
98
+ add_message "prefab.Criterion" do
99
+ optional :property_name, :string, 1
100
+ optional :operator, :enum, 2, "prefab.Criterion.CriterionOperator"
101
+ optional :value_to_match, :message, 3, "prefab.ConfigValue"
90
102
  end
91
- add_enum "prefab.Criteria.CriteriaOperator" do
103
+ add_enum "prefab.Criterion.CriterionOperator" do
92
104
  value :NOT_SET, 0
93
105
  value :LOOKUP_KEY_IN, 1
94
106
  value :LOOKUP_KEY_NOT_IN, 2
@@ -99,22 +111,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
99
111
  value :PROP_IS_NOT_ONE_OF, 7
100
112
  value :PROP_ENDS_WITH_ONE_OF, 8
101
113
  value :PROP_DOES_NOT_END_WITH_ONE_OF, 9
102
- end
103
- add_message "prefab.Rule" do
104
- optional :criteria, :message, 1, "prefab.Criteria"
105
- repeated :variant_weights, :message, 2, "prefab.VariantWeight"
106
- end
107
- add_message "prefab.Segment" do
108
- repeated :criterion, :message, 1, "prefab.Criteria"
109
- end
110
- add_message "prefab.VariantWeight" do
111
- optional :weight, :int32, 1
112
- optional :variant_idx, :int32, 2
113
- end
114
- add_message "prefab.FeatureFlag" do
115
- optional :active, :bool, 1
116
- optional :inactive_variant_idx, :int32, 2
117
- repeated :rules, :message, 5, "prefab.Rule"
114
+ value :HIERARCHICAL_MATCH, 10
118
115
  end
119
116
  add_message "prefab.Identity" do
120
117
  proto3_optional :lookup, :string, 1
@@ -184,6 +181,14 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
184
181
  optional :sequence_name, :string, 3
185
182
  optional :size, :int64, 4
186
183
  end
184
+ add_enum "prefab.ConfigType" do
185
+ value :NOT_SET_CONFIG_TYPE, 0
186
+ value :CONFIG, 1
187
+ value :FEATURE_FLAG, 2
188
+ value :LOG_LEVEL, 3
189
+ value :SEGMENT, 4
190
+ value :LIMIT_DEFINITION, 5
191
+ end
187
192
  add_enum "prefab.LogLevel" do
188
193
  value :NOT_SET_LOG_LEVEL, 0
189
194
  value :TRACE, 1
@@ -205,20 +210,20 @@ end
205
210
  module Prefab
206
211
  ConfigServicePointer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigServicePointer").msgclass
207
212
  ConfigValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigValue").msgclass
213
+ StringList = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.StringList").msgclass
214
+ WeightedValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.WeightedValue").msgclass
215
+ WeightedValues = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.WeightedValues").msgclass
208
216
  Configs = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Configs").msgclass
209
217
  Config = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Config").msgclass
218
+ ChangedBy = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ChangedBy").msgclass
210
219
  ConfigRow = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigRow").msgclass
220
+ ConditionalValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConditionalValue").msgclass
211
221
  LimitResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitResponse").msgclass
212
222
  LimitResponse::LimitPolicyNames = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitResponse.LimitPolicyNames").enummodule
213
223
  LimitRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitRequest").msgclass
214
224
  LimitRequest::LimitCombiner = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LimitRequest.LimitCombiner").enummodule
215
- FeatureFlagVariant = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.FeatureFlagVariant").msgclass
216
- Criteria = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Criteria").msgclass
217
- Criteria::CriteriaOperator = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Criteria.CriteriaOperator").enummodule
218
- Rule = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Rule").msgclass
219
- Segment = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Segment").msgclass
220
- VariantWeight = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.VariantWeight").msgclass
221
- FeatureFlag = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.FeatureFlag").msgclass
225
+ Criterion = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Criterion").msgclass
226
+ Criterion::CriterionOperator = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Criterion.CriterionOperator").enummodule
222
227
  Identity = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Identity").msgclass
223
228
  ClientConfigValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ClientConfigValue").msgclass
224
229
  ConfigEvaluations = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigEvaluations").msgclass
@@ -231,6 +236,7 @@ module Prefab
231
236
  CreationResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.CreationResponse").msgclass
232
237
  IdBlock = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.IdBlock").msgclass
233
238
  IdBlockRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.IdBlockRequest").msgclass
239
+ ConfigType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigType").enummodule
234
240
  LogLevel = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.LogLevel").enummodule
235
241
  OnFailure = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.OnFailure").enummodule
236
242
  end
@@ -1,4 +1,3 @@
1
- # frozen_string_literal: true
2
1
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
2
  # Source: prefab.proto for package 'prefab'
4
3
 
@@ -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.20.0 ruby lib
5
+ # stub: prefab-cloud-ruby 0.21.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "0.20.0"
9
+ s.version = "0.21.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-12-02"
14
+ s.date = "2023-02-27"
15
15
  s.description = "RateLimits & Config as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -20,7 +20,9 @@ Gem::Specification.new do |s|
20
20
  ]
21
21
  s.files = [
22
22
  ".envrc",
23
+ ".envrc.sample",
23
24
  ".github/workflows/ruby.yml",
25
+ ".gitmodules",
24
26
  ".tool-versions",
25
27
  "CODEOWNERS",
26
28
  "Gemfile",
@@ -35,15 +37,17 @@ Gem::Specification.new do |s|
35
37
  "lib/prefab/cancellable_interceptor.rb",
36
38
  "lib/prefab/client.rb",
37
39
  "lib/prefab/config_client.rb",
38
- "lib/prefab/config_helper.rb",
39
40
  "lib/prefab/config_loader.rb",
40
41
  "lib/prefab/config_resolver.rb",
42
+ "lib/prefab/config_value_unwrapper.rb",
43
+ "lib/prefab/criteria_evaluator.rb",
41
44
  "lib/prefab/error.rb",
42
45
  "lib/prefab/errors/initialization_timeout_error.rb",
43
46
  "lib/prefab/errors/invalid_api_key_error.rb",
44
47
  "lib/prefab/errors/missing_default_error.rb",
45
48
  "lib/prefab/feature_flag_client.rb",
46
49
  "lib/prefab/internal_logger.rb",
50
+ "lib/prefab/local_config_parser.rb",
47
51
  "lib/prefab/logger_client.rb",
48
52
  "lib/prefab/murmer3.rb",
49
53
  "lib/prefab/noop_cache.rb",
@@ -51,20 +55,27 @@ Gem::Specification.new do |s|
51
55
  "lib/prefab/options.rb",
52
56
  "lib/prefab/ratelimit_client.rb",
53
57
  "lib/prefab/sse_logger.rb",
58
+ "lib/prefab/weighted_value_resolver.rb",
59
+ "lib/prefab/yaml_config_parser.rb",
54
60
  "lib/prefab_pb.rb",
55
61
  "lib/prefab_services_pb.rb",
56
62
  "prefab-cloud-ruby.gemspec",
57
- "run_test_harness_server.sh",
58
63
  "test/.prefab.default.config.yaml",
59
64
  "test/.prefab.unit_tests.config.yaml",
60
- "test/harness_server.rb",
65
+ "test/integration_test.rb",
66
+ "test/integration_test_helpers.rb",
61
67
  "test/test_client.rb",
62
68
  "test/test_config_client.rb",
63
69
  "test/test_config_loader.rb",
64
70
  "test/test_config_resolver.rb",
71
+ "test/test_config_value_unwrapper.rb",
72
+ "test/test_criteria_evaluator.rb",
65
73
  "test/test_feature_flag_client.rb",
66
74
  "test/test_helper.rb",
67
- "test/test_logger.rb"
75
+ "test/test_integration.rb",
76
+ "test/test_local_config_parser.rb",
77
+ "test/test_logger.rb",
78
+ "test/test_weighted_value_resolver.rb"
68
79
  ]
69
80
  s.homepage = "http://github.com/prefab-cloud/prefab-cloud-ruby".freeze
70
81
  s.licenses = ["MIT".freeze]
@@ -78,31 +89,29 @@ Gem::Specification.new do |s|
78
89
  if s.respond_to? :add_runtime_dependency then
79
90
  s.add_runtime_dependency(%q<concurrent-ruby>.freeze, ["~> 1.0", ">= 1.0.5"])
80
91
  s.add_runtime_dependency(%q<faraday>.freeze, [">= 0"])
81
- s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
82
- s.add_runtime_dependency(%q<grpc>.freeze, [">= 0"])
83
- s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
84
92
  s.add_runtime_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
93
+ s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
94
+ s.add_runtime_dependency(%q<grpc>.freeze, [">= 0"])
95
+ s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
85
96
  s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
86
- s.add_development_dependency(%q<grpc-tools>.freeze, [">= 0"])
87
- s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
88
97
  s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
98
+ s.add_development_dependency(%q<grpc-tools>.freeze, [">= 0"])
89
99
  s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
100
+ s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
90
101
  s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
91
- s.add_development_dependency(%q<thin>.freeze, [">= 0"])
92
102
  else
93
103
  s.add_dependency(%q<concurrent-ruby>.freeze, ["~> 1.0", ">= 1.0.5"])
94
104
  s.add_dependency(%q<faraday>.freeze, [">= 0"])
95
- s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
96
- s.add_dependency(%q<grpc>.freeze, [">= 0"])
97
- s.add_dependency(%q<google-protobuf>.freeze, [">= 0"])
98
105
  s.add_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
106
+ s.add_dependency(%q<google-protobuf>.freeze, [">= 0"])
107
+ s.add_dependency(%q<grpc>.freeze, [">= 0"])
108
+ s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
99
109
  s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
100
- s.add_dependency(%q<grpc-tools>.freeze, [">= 0"])
101
- s.add_dependency(%q<rdoc>.freeze, [">= 0"])
102
110
  s.add_dependency(%q<bundler>.freeze, [">= 0"])
111
+ s.add_dependency(%q<grpc-tools>.freeze, [">= 0"])
103
112
  s.add_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
113
+ s.add_dependency(%q<rdoc>.freeze, [">= 0"])
104
114
  s.add_dependency(%q<simplecov>.freeze, [">= 0"])
105
- s.add_dependency(%q<thin>.freeze, [">= 0"])
106
115
  end
107
116
  end
108
117
 
@@ -9,8 +9,9 @@ sample: test sample value
9
9
  enabled_flag: true
10
10
  disabled_flag: false
11
11
  flag_with_a_value: { "feature_flag": "true", value: "all-features" }
12
- in_lookup_key: { "feature_flag": "true", value: true, criteria: { operator: LOOKUP_KEY_IN, values: [ "abc123", "xyz987" ] } }
13
- just_my_domain: { "feature_flag": "true", value: "new-version", criteria: { operator: PROP_IS_ONE_OF, property: "domain", values: [ "prefab.cloud", "example.com" ] } }
12
+ in_lookup_key: { "feature_flag": "true", value: true, criterion: { operator: LOOKUP_KEY_IN, values: [ "abc123", "xyz987" ] } }
13
+ just_my_domain: { "feature_flag": "true", value: "new-version", criterion: { operator: PROP_IS_ONE_OF, property: "domain", values: [ "prefab.cloud", "example.com" ] } }
14
+
14
15
  nested:
15
16
  values:
16
17
  _: top level
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ class IntegrationTest
4
+ attr_reader :func
5
+ attr_reader :input
6
+ attr_reader :expected
7
+ attr_reader :test_client
8
+
9
+ def initialize(test_data)
10
+ @client_overrides = parse_client_overrides(test_data['client_overrides'])
11
+ @func = parse_function(test_data['function'])
12
+ @input = parse_input(test_data['input'])
13
+ @expected = parse_expected(test_data['expected'])
14
+ test_client = :"#{test_data['client']}"
15
+ @test_client = base_client.send(test_client)
16
+ end
17
+
18
+ def test_type
19
+ if @expected[:status] == 'raise'
20
+ :raise
21
+ elsif @expected[:value].nil?
22
+ :nil
23
+ elsif @func == :feature_is_on_for?
24
+ :feature_flag
25
+ else
26
+ :simple_equality
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def parse_client_overrides(overrides)
33
+ Hash[
34
+ (overrides || {}).map do |(k, v)|
35
+ [k.to_sym, v]
36
+ end
37
+ ]
38
+ end
39
+
40
+ def parse_function(function)
41
+ case function
42
+ when 'get_or_raise' then :get
43
+ when 'enabled' then :feature_is_on_for?
44
+ else :"#{function}"
45
+ end
46
+ end
47
+
48
+ def parse_input(input)
49
+ if input['key']
50
+ parse_config_input(input)
51
+ elsif input['flag']
52
+ parse_ff_input(input)
53
+ end
54
+ end
55
+
56
+ def parse_config_input(input)
57
+ if !input['default'].nil?
58
+ [input['key'], input['default']]
59
+ else
60
+ [input['key']]
61
+ end
62
+ end
63
+
64
+ def parse_ff_input(input)
65
+ [input['flag'], input['lookup_key'], input['properties'] || {}]
66
+ end
67
+
68
+ def parse_expected(expected)
69
+ {
70
+ status: expected['status'],
71
+ error: parse_error_type(expected['error']),
72
+ message: expected['message'],
73
+ value: expected['value']
74
+ }
75
+ end
76
+
77
+ def parse_error_type(error_type)
78
+ case error_type
79
+ when 'missing_default' then Prefab::Errors::MissingDefaultError
80
+ end
81
+ end
82
+
83
+ def base_client
84
+ @_base_client ||= Prefab::Client.new(base_client_options)
85
+ end
86
+
87
+ def base_client_options
88
+ @_options ||= Prefab::Options.new(**{
89
+ prefab_config_override_dir: 'none',
90
+ prefab_config_classpath_dir: 'test',
91
+ prefab_envs: ['unit_tests'],
92
+ prefab_datasources: Prefab::Options::DATASOURCES::ALL,
93
+ api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'],
94
+ prefab_api_url: 'https://api.staging-prefab.cloud',
95
+ prefab_grpc_url: 'grpc.staging-prefab.cloud:443'
96
+ }.merge(@client_overrides))
97
+ end
98
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IntegrationTestHelpers
4
+ SUBMODULE_PATH = 'test/prefab-cloud-integration-test-data'
5
+ RAISE_IF_NO_TESTS_FOUND = ENV['PREFAB_INTEGRATION_TEST_RAISE'] == 'true'
6
+
7
+ def self.find_integration_tests
8
+ version = find_integration_test_version
9
+
10
+ files = find_versioned_test_files(version)
11
+
12
+ if files.none?
13
+ message = "No integration tests found for version: #{version}"
14
+ raise message if RAISE_IF_NO_TESTS_FOUND
15
+
16
+ puts message
17
+
18
+ end
19
+
20
+ files
21
+ end
22
+
23
+ def self.find_integration_test_version
24
+ File.read(File.join(SUBMODULE_PATH, 'version')).strip
25
+ rescue StandardError => e
26
+ puts "No version found for integration tests: #{e.message}"
27
+ end
28
+
29
+ def self.find_versioned_test_files(version)
30
+ if version.nil?
31
+ []
32
+ else
33
+ Dir[File.join(SUBMODULE_PATH, "tests/#{version}/**/*")]
34
+ .select { |file| file =~ /\.ya?ml$/ }
35
+ end
36
+ end
37
+ end
data/test/test_client.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'test_helper'
3
4
 
4
5
  class TestClient < Minitest::Test
@@ -7,25 +8,25 @@ class TestClient < Minitest::Test
7
8
  end
8
9
 
9
10
  def test_get
10
- assert_equal "test sample value", @client.get("sample")
11
- assert_equal 123, @client.get("sample_int")
11
+ assert_equal 'test sample value', @client.get('sample')
12
+ assert_equal 123, @client.get('sample_int')
12
13
  end
13
14
 
14
15
  def test_get_with_default
15
16
  # A `false` value is not replaced with the default
16
- assert_equal false, @client.get("false_value", "red")
17
+ assert_equal false, @client.get('false_value', 'red')
17
18
 
18
19
  # A falsy value is not replaced with the default
19
- assert_equal 0, @client.get("zero_value", "red")
20
+ assert_equal 0, @client.get('zero_value', 'red')
20
21
 
21
22
  # A missing value returns the default
22
- assert_equal "buckets", @client.get("missing_value", "buckets")
23
+ assert_equal 'buckets', @client.get('missing_value', 'buckets')
23
24
  end
24
25
 
25
26
  def test_get_with_missing_default
26
27
  # it raises by default
27
28
  err = assert_raises(Prefab::Errors::MissingDefaultError) do
28
- assert_nil @client.get("missing_value")
29
+ assert_nil @client.get('missing_value')
29
30
  end
30
31
 
31
32
  assert_match(/No value found for key/, err.message)
@@ -33,51 +34,51 @@ class TestClient < Minitest::Test
33
34
 
34
35
  # you can opt-in to return `nil` instead
35
36
  client = new_client(on_no_default: Prefab::Options::ON_NO_DEFAULT::RETURN_NIL)
36
- assert_nil client.get("missing_value")
37
+ assert_nil client.get('missing_value')
37
38
  end
38
39
 
39
40
  def test_enabled
40
- assert_equal false, @client.enabled?("does_not_exist")
41
- assert_equal true, @client.enabled?("enabled_flag")
42
- assert_equal false, @client.enabled?("disabled_flag")
43
- assert_equal false, @client.enabled?("flag_with_a_value")
41
+ assert_equal false, @client.enabled?('does_not_exist')
42
+ assert_equal true, @client.enabled?('enabled_flag')
43
+ assert_equal false, @client.enabled?('disabled_flag')
44
+ assert_equal false, @client.enabled?('flag_with_a_value')
44
45
  end
45
46
 
46
47
  def test_ff_enabled_with_lookup_key
47
- assert_equal false, @client.enabled?("in_lookup_key", "jimmy")
48
- assert_equal true, @client.enabled?("in_lookup_key", "abc123")
49
- assert_equal true, @client.enabled?("in_lookup_key", "xyz987")
48
+ assert_equal false, @client.enabled?('in_lookup_key', 'jimmy')
49
+ assert_equal true, @client.enabled?('in_lookup_key', 'abc123')
50
+ assert_equal true, @client.enabled?('in_lookup_key', 'xyz987')
50
51
  end
51
52
 
52
53
  def test_ff_get_with_lookup_key
53
- assert_nil @client.get("in_lookup_key", "jimmy")
54
- assert_equal "DEFAULT", @client.get("in_lookup_key", "jimmy", {}, "DEFAULT")
54
+ assert_nil @client.get('in_lookup_key', 'jimmy')
55
+ assert_equal 'DEFAULT', @client.get('in_lookup_key', 'jimmy', {}, 'DEFAULT')
55
56
 
56
- assert_equal true, @client.get("in_lookup_key", "abc123")
57
- assert_equal true, @client.get("in_lookup_key", "xyz987")
57
+ assert_equal true, @client.get('in_lookup_key', 'abc123')
58
+ assert_equal true, @client.get('in_lookup_key', 'xyz987')
58
59
  end
59
60
 
60
61
  def test_ff_enabled_with_attributes
61
- assert_equal false, @client.enabled?("just_my_domain", "abc123", { domain: "gmail.com" })
62
- assert_equal false, @client.enabled?("just_my_domain", "abc123", { domain: "prefab.cloud" })
63
- assert_equal false, @client.enabled?("just_my_domain", "abc123", { domain: "example.com" })
62
+ assert_equal false, @client.enabled?('just_my_domain', 'abc123', { domain: 'gmail.com' })
63
+ assert_equal false, @client.enabled?('just_my_domain', 'abc123', { domain: 'prefab.cloud' })
64
+ assert_equal false, @client.enabled?('just_my_domain', 'abc123', { domain: 'example.com' })
64
65
  end
65
66
 
66
67
  def test_ff_get_with_attributes
67
- assert_nil @client.get("just_my_domain", "abc123", { domain: "gmail.com" })
68
- assert_equal "DEFAULT", @client.get("just_my_domain", "abc123", { domain: "gmail.com" }, "DEFAULT")
68
+ assert_nil @client.get('just_my_domain', 'abc123', { domain: 'gmail.com' })
69
+ assert_equal 'DEFAULT', @client.get('just_my_domain', 'abc123', { domain: 'gmail.com' }, 'DEFAULT')
69
70
 
70
- assert_equal "new-version", @client.get("just_my_domain", "abc123", { domain: "prefab.cloud" })
71
- assert_equal "new-version", @client.get("just_my_domain", "abc123", { domain: "example.com" })
71
+ assert_equal 'new-version', @client.get('just_my_domain', 'abc123', { domain: 'prefab.cloud' })
72
+ assert_equal 'new-version', @client.get('just_my_domain', 'abc123', { domain: 'example.com' })
72
73
  end
73
74
 
74
75
  def test_getting_feature_flag_value
75
- assert_equal false, @client.enabled?("flag_with_a_value")
76
- assert_equal "all-features", @client.get("flag_with_a_value")
76
+ assert_equal false, @client.enabled?('flag_with_a_value')
77
+ assert_equal 'all-features', @client.get('flag_with_a_value')
77
78
  end
78
79
 
79
80
  def test_ssl_certs
80
- certs = @client.send(:ssl_certs).split("-----BEGIN CERTIFICATE-----")
81
+ certs = @client.send(:ssl_certs).split('-----BEGIN CERTIFICATE-----')
81
82
 
82
83
  # This is a smoke test to make sure multiple certs are loaded
83
84
  assert certs.length > 1
@@ -87,9 +88,9 @@ class TestClient < Minitest::Test
87
88
 
88
89
  def new_client(overrides = {})
89
90
  options = Prefab::Options.new(**{
90
- prefab_config_override_dir: "none",
91
- prefab_config_classpath_dir: "test",
92
- prefab_envs: ["unit_tests"],
91
+ prefab_config_override_dir: 'none',
92
+ prefab_config_classpath_dir: 'test',
93
+ prefab_envs: ['unit_tests'],
93
94
  prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
94
95
  }.merge(overrides))
95
96
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'test_helper'
3
4
 
4
5
  class TestConfigClient < Minitest::Test
5
6
  def setup
6
7
  options = Prefab::Options.new(
7
- prefab_config_override_dir: "none",
8
- prefab_config_classpath_dir: "test",
9
- prefab_envs: "unit_tests",
8
+ prefab_config_override_dir: 'none',
9
+ prefab_config_classpath_dir: 'test',
10
+ prefab_envs: 'unit_tests',
10
11
  prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
11
12
  )
12
13
 
@@ -14,59 +15,59 @@ class TestConfigClient < Minitest::Test
14
15
  end
15
16
 
16
17
  def test_load
17
- assert_equal "test sample value", @config_client.get("sample")
18
- assert_equal 123, @config_client.get("sample_int")
19
- assert_equal 12.12, @config_client.get("sample_double")
20
- assert_equal true, @config_client.get("sample_bool")
21
- assert_equal :ERROR, @config_client.get("log-level.app")
18
+ assert_equal 'test sample value', @config_client.get('sample')
19
+ assert_equal 123, @config_client.get('sample_int')
20
+ assert_equal 12.12, @config_client.get('sample_double')
21
+ assert_equal true, @config_client.get('sample_bool')
22
+ assert_equal :ERROR, @config_client.get('log-level.app')
22
23
  end
23
24
 
24
25
  def test_initialization_timeout_error
25
26
  options = Prefab::Options.new(
26
- api_key: "123-ENV-KEY-SDK",
27
+ api_key: '123-ENV-KEY-SDK',
27
28
  initialization_timeout_sec: 0.01,
28
29
  logdev: StringIO.new
29
30
  )
30
31
 
31
32
  err = assert_raises(Prefab::Errors::InitializationTimeoutError) do
32
- Prefab::Client.new(options).config_client.get("anything")
33
+ Prefab::Client.new(options).config_client.get('anything')
33
34
  end
34
35
 
35
36
  assert_match(/couldn't initialize in 0.01 second timeout/, err.message)
36
37
  end
37
38
 
38
39
  def test_prefab_envs_is_forgiving
39
- assert_equal ["my_env"], Prefab::Options.new(
40
- prefab_envs: "my_env",
40
+ assert_equal ['my_env'], Prefab::Options.new(
41
+ prefab_envs: 'my_env'
41
42
  ).prefab_envs
42
43
 
43
- assert_equal ["my_env", "a_second_env"], Prefab::Options.new(
44
- prefab_envs: ["my_env", "a_second_env"],
44
+ assert_equal %w[my_env a_second_env], Prefab::Options.new(
45
+ prefab_envs: %w[my_env a_second_env]
45
46
  ).prefab_envs
46
47
  end
47
48
 
48
49
  def test_prefab_envs_env_var
49
- ENV["PREFAB_ENVS"] = "one,two"
50
- assert_equal ["one", "two"], Prefab::Options.new().prefab_envs
50
+ ENV['PREFAB_ENVS'] = 'one,two'
51
+ assert_equal %w[one two], Prefab::Options.new.prefab_envs
51
52
  end
52
53
 
53
54
  def test_invalid_api_key_error
54
55
  options = Prefab::Options.new(
55
- api_key: "",
56
+ api_key: ''
56
57
  )
57
58
 
58
59
  err = assert_raises(Prefab::Errors::InvalidApiKeyError) do
59
- Prefab::Client.new(options).config_client.get("anything")
60
+ Prefab::Client.new(options).config_client.get('anything')
60
61
  end
61
62
 
62
63
  assert_match(/No API key/, err.message)
63
64
 
64
65
  options = Prefab::Options.new(
65
- api_key: "invalid",
66
+ api_key: 'invalid'
66
67
  )
67
68
 
68
69
  err = assert_raises(Prefab::Errors::InvalidApiKeyError) do
69
- Prefab::Client.new(options).config_client.get("anything")
70
+ Prefab::Client.new(options).config_client.get('anything')
70
71
  end
71
72
 
72
73
  assert_match(/format is invalid/, err.message)