sdk-reforge 1.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.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc.sample +3 -0
  3. data/.github/CODEOWNERS +2 -0
  4. data/.github/pull_request_template.md +8 -0
  5. data/.github/workflows/ruby.yml +48 -0
  6. data/.gitmodules +3 -0
  7. data/.rubocop.yml +13 -0
  8. data/.tool-versions +1 -0
  9. data/CHANGELOG.md +257 -0
  10. data/CODEOWNERS +1 -0
  11. data/Gemfile +29 -0
  12. data/Gemfile.lock +182 -0
  13. data/LICENSE.txt +20 -0
  14. data/README.md +105 -0
  15. data/Rakefile +63 -0
  16. data/VERSION +1 -0
  17. data/compile_protos.sh +20 -0
  18. data/dev/allocation_stats +60 -0
  19. data/dev/benchmark +40 -0
  20. data/dev/console +12 -0
  21. data/dev/script_setup.rb +18 -0
  22. data/lib/prefab_pb.rb +77 -0
  23. data/lib/reforge/caching_http_connection.rb +95 -0
  24. data/lib/reforge/client.rb +133 -0
  25. data/lib/reforge/config_client.rb +275 -0
  26. data/lib/reforge/config_client_presenter.rb +18 -0
  27. data/lib/reforge/config_loader.rb +67 -0
  28. data/lib/reforge/config_resolver.rb +84 -0
  29. data/lib/reforge/config_value_unwrapper.rb +123 -0
  30. data/lib/reforge/config_value_wrapper.rb +18 -0
  31. data/lib/reforge/context.rb +241 -0
  32. data/lib/reforge/context_shape.rb +20 -0
  33. data/lib/reforge/context_shape_aggregator.rb +70 -0
  34. data/lib/reforge/criteria_evaluator.rb +345 -0
  35. data/lib/reforge/duration.rb +58 -0
  36. data/lib/reforge/encryption.rb +65 -0
  37. data/lib/reforge/error.rb +6 -0
  38. data/lib/reforge/errors/env_var_parse_error.rb +11 -0
  39. data/lib/reforge/errors/initialization_timeout_error.rb +12 -0
  40. data/lib/reforge/errors/invalid_sdk_key_error.rb +19 -0
  41. data/lib/reforge/errors/missing_default_error.rb +13 -0
  42. data/lib/reforge/errors/missing_env_var_error.rb +11 -0
  43. data/lib/reforge/errors/uninitialized_error.rb +13 -0
  44. data/lib/reforge/evaluation.rb +53 -0
  45. data/lib/reforge/evaluation_summary_aggregator.rb +86 -0
  46. data/lib/reforge/example_contexts_aggregator.rb +77 -0
  47. data/lib/reforge/exponential_backoff.rb +21 -0
  48. data/lib/reforge/feature_flag_client.rb +43 -0
  49. data/lib/reforge/fixed_size_hash.rb +14 -0
  50. data/lib/reforge/http_connection.rb +45 -0
  51. data/lib/reforge/internal_logger.rb +43 -0
  52. data/lib/reforge/javascript_stub.rb +99 -0
  53. data/lib/reforge/local_config_parser.rb +151 -0
  54. data/lib/reforge/murmer3.rb +50 -0
  55. data/lib/reforge/options.rb +191 -0
  56. data/lib/reforge/periodic_sync.rb +74 -0
  57. data/lib/reforge/prefab.rb +120 -0
  58. data/lib/reforge/rate_limit_cache.rb +41 -0
  59. data/lib/reforge/resolved_config_presenter.rb +86 -0
  60. data/lib/reforge/semver.rb +132 -0
  61. data/lib/reforge/sse_config_client.rb +112 -0
  62. data/lib/reforge/time_helpers.rb +7 -0
  63. data/lib/reforge/weighted_value_resolver.rb +42 -0
  64. data/lib/reforge/yaml_config_parser.rb +34 -0
  65. data/lib/reforge-sdk.rb +57 -0
  66. data/test/fixtures/datafile.json +87 -0
  67. data/test/integration_test.rb +171 -0
  68. data/test/integration_test_helpers.rb +114 -0
  69. data/test/support/common_helpers.rb +201 -0
  70. data/test/support/mock_base_client.rb +41 -0
  71. data/test/support/mock_config_client.rb +19 -0
  72. data/test/support/mock_config_loader.rb +1 -0
  73. data/test/test_caching_http_connection.rb +218 -0
  74. data/test/test_client.rb +351 -0
  75. data/test/test_config_client.rb +84 -0
  76. data/test/test_config_loader.rb +82 -0
  77. data/test/test_config_resolver.rb +502 -0
  78. data/test/test_config_value_unwrapper.rb +270 -0
  79. data/test/test_config_value_wrapper.rb +42 -0
  80. data/test/test_context.rb +271 -0
  81. data/test/test_context_shape.rb +50 -0
  82. data/test/test_context_shape_aggregator.rb +150 -0
  83. data/test/test_criteria_evaluator.rb +1180 -0
  84. data/test/test_duration.rb +37 -0
  85. data/test/test_encryption.rb +16 -0
  86. data/test/test_evaluation_summary_aggregator.rb +162 -0
  87. data/test/test_example_contexts_aggregator.rb +233 -0
  88. data/test/test_exponential_backoff.rb +18 -0
  89. data/test/test_feature_flag_client.rb +16 -0
  90. data/test/test_fixed_size_hash.rb +119 -0
  91. data/test/test_helper.rb +17 -0
  92. data/test/test_integration.rb +75 -0
  93. data/test/test_internal_logger.rb +25 -0
  94. data/test/test_javascript_stub.rb +176 -0
  95. data/test/test_local_config_parser.rb +147 -0
  96. data/test/test_logger_initialization.rb +12 -0
  97. data/test/test_options.rb +93 -0
  98. data/test/test_prefab.rb +16 -0
  99. data/test/test_rate_limit_cache.rb +44 -0
  100. data/test/test_semver.rb +108 -0
  101. data/test/test_sse_config_client.rb +211 -0
  102. data/test/test_weighted_value_resolver.rb +71 -0
  103. metadata +345 -0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'timecop'
5
+
6
+ class TestContextShapeAggregator < Minitest::Test
7
+ DOB = Date.new
8
+
9
+ CONTEXT_1 = Reforge::Context.new({
10
+ 'user' => {
11
+ 'name' => 'user-name',
12
+ 'email' => 'user.email',
13
+ 'age' => 42.5
14
+ },
15
+ 'subscription' => {
16
+ 'plan' => 'advanced',
17
+ 'free' => false
18
+ }
19
+ }).freeze
20
+
21
+ CONTEXT_2 = Reforge::Context.new({
22
+ 'user' => {
23
+ 'name' => 'other-user-name',
24
+ 'dob' => DOB
25
+ },
26
+ 'device' => {
27
+ 'name' => 'device-name',
28
+ 'os' => 'os-name',
29
+ 'version' => 3
30
+ }
31
+ }).freeze
32
+
33
+ CONTEXT_3 = Reforge::Context.new({
34
+ 'subscription' => {
35
+ 'plan' => 'pro',
36
+ 'trial' => true
37
+ }
38
+ }).freeze
39
+
40
+ def test_push
41
+ aggregator = new_aggregator(max_shapes: 9)
42
+
43
+ aggregator.push(CONTEXT_1)
44
+ aggregator.push(CONTEXT_2)
45
+ assert_equal 9, aggregator.data.size
46
+
47
+ # we've reached the limit so no more
48
+ aggregator.push(CONTEXT_3)
49
+ assert_equal 9, aggregator.data.size
50
+
51
+ assert_equal [['user', 'name', 2], ['user', 'email', 2], ['user', 'age', 4], ['subscription', 'plan', 2], ['subscription', 'free', 5], ['user', 'dob', 2], ['device', 'name', 2], ['device', 'os', 2], ['device', 'version', 1]],
52
+ aggregator.data.to_a
53
+ end
54
+
55
+ def test_prepare_data
56
+ aggregator = new_aggregator
57
+
58
+ aggregator.push(CONTEXT_1)
59
+ aggregator.push(CONTEXT_2)
60
+ aggregator.push(CONTEXT_3)
61
+
62
+ data = aggregator.prepare_data
63
+
64
+ assert_equal %w[user subscription device], data.keys
65
+
66
+ assert_equal data['user'], {
67
+ 'name' => 2,
68
+ 'email' => 2,
69
+ 'dob' => 2,
70
+ 'age' => 4
71
+ }
72
+
73
+ assert_equal data['subscription'], {
74
+ 'plan' => 2,
75
+ 'trial' => 5,
76
+ 'free' => 5
77
+ }
78
+
79
+ assert_equal data['device'], {
80
+ 'name' => 2,
81
+ 'os' => 2,
82
+ 'version' => 1
83
+ }
84
+
85
+ assert_equal [], aggregator.data.to_a
86
+ end
87
+
88
+ def test_sync
89
+ client = new_client
90
+
91
+ client.get 'some.key', 'default', CONTEXT_1
92
+ client.get 'some.key', 'default', CONTEXT_2
93
+ client.get 'some.key', 'default', CONTEXT_3
94
+
95
+ requests = wait_for_post_requests(client) do
96
+ client.context_shape_aggregator.send(:sync)
97
+ end
98
+
99
+ assert_equal [
100
+ [
101
+ '/api/v1/telemetry',
102
+ PrefabProto::TelemetryEvents.new(
103
+ instance_hash: client.instance_hash,
104
+ events: [
105
+ PrefabProto::TelemetryEvent.new(context_shapes:
106
+
107
+ PrefabProto::ContextShapes.new(shapes: [
108
+ PrefabProto::ContextShape.new(
109
+ name: 'user', field_types: {
110
+ 'age' => 4, 'dob' => 2, 'email' => 2, 'name' => 2
111
+ }
112
+ ),
113
+ PrefabProto::ContextShape.new(
114
+ name: 'subscription', field_types: {
115
+ 'plan' => 2, 'free' => 5, 'trial' => 5
116
+ }
117
+ ),
118
+ PrefabProto::ContextShape.new(
119
+ name: 'device', field_types: {
120
+ 'version' => 1, 'os' => 2, 'name' => 2
121
+ }
122
+ )
123
+ ]))
124
+ ]
125
+ )
126
+ ]
127
+ ], requests
128
+
129
+ assert_logged [
130
+ 'No success loading checkpoints',
131
+ "Couldn't Initialize In 0. Key some.key. Returning what we have"
132
+ ]
133
+ end
134
+
135
+ private
136
+
137
+ def new_client(overrides = {})
138
+ super(**{
139
+ prefab_datasources: Reforge::Options::DATASOURCES::ALL,
140
+ initialization_timeout_sec: 0,
141
+ on_init_failure: Reforge::Options::ON_INITIALIZATION_FAILURE::RETURN,
142
+ sdk_key: '123-development-yourapikey-SDK',
143
+ context_upload_mode: :shape_only
144
+ }.merge(overrides))
145
+ end
146
+
147
+ def new_aggregator(max_shapes: 1000)
148
+ Reforge::ContextShapeAggregator.new(client: new_client, sync_interval: 1000, max_shapes: max_shapes)
149
+ end
150
+ end