splitclient-rb 5.1.1.pre.rc2-java → 5.1.2-java

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
  SHA1:
3
- metadata.gz: 36950289155252eba415ab9549fab81cc7081708
4
- data.tar.gz: 3cdc11d6fd8613c4ef150484f43437c6995de1c8
3
+ metadata.gz: 300bd19c760f74a20aa21b3c2f1d17f1652c0eb4
4
+ data.tar.gz: b6a959b96fc3f7bfb89dfcafb46b44933e26bc42
5
5
  SHA512:
6
- metadata.gz: e2f60de0ce796ec6f1c50ca3749ceeb5b00e0975520b4d74e973dc9cf554e45c02947e15ba8bac38aa54914e1cc83bcaa667db55f36210ea55e080c968b5bb35
7
- data.tar.gz: 06e12cb8f14f567259bd221b8286d5a798a254cdbdb5012a15d88553a4adad6d94582558dfa50fae22307768e2d49530c0bc266a26233d55d3e30f43e7ff9c4f
6
+ metadata.gz: dda2b8ba1238ec2059dd8e414442417211a87aeb49d656e5103786512e31fb11e854a2f3658b5e0ce19e073f015658d166c34965d6a96a6bec9bfb53aec9936a
7
+ data.tar.gz: 393b9f1280a80e22ac3d7e75a2e0b91bfa370d3667cf6ba88e9ae9c3376643ce69b0c3d3bd4303ed0aead943e3e1ab7e73883b3f2d52a18e0159ab852d98bceb
data/.gitignore CHANGED
@@ -44,5 +44,8 @@ lib/murmurhash/murmurhash.so
44
44
  ext/murmurhash/murmurhash.bundle
45
45
  ext/murmurhash/murmurhash.so
46
46
 
47
- #Ignore dump.rdb
47
+ # Ignore dump.rdb
48
48
  dump.rdb
49
+
50
+ # Ignore Mac OS generated files
51
+ .DS_Store
data/CHANGES.txt CHANGED
@@ -1,3 +1,13 @@
1
+ 5.1.2 (October 26th, 2018)
2
+ - Add input validation for client API methods
3
+
4
+ 5.1.1 (October 4th, 2018)
5
+ - Change get_treatments so that it sends a single latency metric
6
+ - Removed unused call to Redis#scan when adding latencies
7
+ - Removed Redis calls on initialization when SDK is set to consumer mode
8
+ - Change split_config approach so that every property has an accessor
9
+ - Removed @config parameter on most initializers
10
+
1
11
  5.1.0 (September 10th, 2018)
2
12
  - Change `get_api` to return only a Faraday response.
3
13
  - Add `SplitLogger` to clean up logging code and reduce the complexity in several methods.
data/NEWS CHANGED
@@ -1,3 +1,11 @@
1
+ 5.1.2
2
+
3
+ Add input validation for client API methods: get_treatment, get_treatments, track, manager
4
+
5
+ 5.1.1
6
+
7
+ Reduces the number of calls to Redis when calling #client.get_treatments using such cache adapter.
8
+
1
9
  5.1.0
2
10
 
3
11
  Prevent unhandled exceptions from raising when API get calls fail on Segments and Treatments.
@@ -2,8 +2,7 @@ require 'forwardable'
2
2
 
3
3
  require 'splitclient-rb/version'
4
4
 
5
- require 'splitclient-rb/exceptions/impressions_shutdown_exception'
6
- require 'splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception'
5
+ require 'splitclient-rb/exceptions'
7
6
  require 'splitclient-rb/cache/routers/impression_router'
8
7
  require 'splitclient-rb/cache/adapters/memory_adapters/map_adapter'
9
8
  require 'splitclient-rb/cache/adapters/memory_adapters/queue_adapter'
@@ -80,6 +79,7 @@ require 'splitclient-rb/engine/models/split'
80
79
  require 'splitclient-rb/engine/models/label'
81
80
  require 'splitclient-rb/engine/models/treatment'
82
81
  require 'splitclient-rb/utilitites'
82
+ require 'splitclient-rb/validators'
83
83
 
84
84
  # C extension
85
85
  require 'murmurhash/murmurhash_mri'
@@ -26,7 +26,7 @@ module SplitIoClient
26
26
 
27
27
  def get_splits(names)
28
28
  splits = {}
29
- split_names = names.reject(&:empty?).uniq.map { |name| namespace_key(".split.#{name}") }
29
+ split_names = names.map { |name| namespace_key(".split.#{name}") }
30
30
  splits.merge!(
31
31
  @adapter
32
32
  .multiple_strings(split_names)
@@ -1,4 +1,5 @@
1
1
  module SplitIoClient
2
+
2
3
  class SplitClient
3
4
  #
4
5
  # Creates a new split client instance that connects to split.io API.
@@ -17,11 +18,24 @@ module SplitIoClient
17
18
  end
18
19
 
19
20
  def get_treatments(key, split_names, attributes = {})
21
+
22
+ return nil unless SplitIoClient::Validators.valid_get_treatments_parameters(split_names)
23
+
24
+ sanitized_split_names = sanitize_split_names(split_names)
25
+
26
+ if sanitized_split_names.empty?
27
+ SplitIoClient.configuration.logger.warn('get_treatments: split_names is an empty array or has null values')
28
+ return {}
29
+ end
30
+
20
31
  bucketing_key, matching_key = keys_from_key(key)
32
+ bucketing_key = bucketing_key ? bucketing_key.to_s : nil
33
+ matching_key = matching_key ? matching_key.to_s : nil
34
+
21
35
  evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, true)
22
36
  start = Time.now
23
37
  treatments_labels_change_numbers =
24
- @splits_repository.get_splits(split_names).each_with_object({}) do |(name, data), memo|
38
+ @splits_repository.get_splits(sanitized_split_names).each_with_object({}) do |(name, data), memo|
25
39
  memo.merge!(name => get_treatment(key, name, attributes, data, false, true, evaluator))
26
40
  end
27
41
  latency = (Time.now - start) * 1000.0
@@ -34,13 +48,13 @@ module SplitIoClient
34
48
  matching_key, bucketing_key, treatments_labels_change_numbers, time
35
49
  )
36
50
 
37
- route_impressions(split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
51
+ route_impressions(sanitized_split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
38
52
  end
39
53
 
40
- split_names = treatments_labels_change_numbers.keys
54
+ split_names_keys = treatments_labels_change_numbers.keys
41
55
  treatments = treatments_labels_change_numbers.values.map { |v| v[:treatment] }
42
56
 
43
- Hash[split_names.zip(treatments)]
57
+ Hash[split_names_keys.zip(treatments)]
44
58
  end
45
59
 
46
60
  #
@@ -59,68 +73,43 @@ module SplitIoClient
59
73
  key, split_name, attributes = {}, split_data = nil, store_impressions = true,
60
74
  multiple = false, evaluator = nil
61
75
  )
62
- bucketing_key, matching_key = keys_from_key(key)
63
- treatment_data = { label: Engine::Models::Label::DEFINITION_NOT_FOUND, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL }
64
- evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
76
+ control_treatment = { label: Engine::Models::Label::EXCEPTION, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL }
77
+ parsed_control_treatment = parsed_treatment(multiple, control_treatment)
65
78
 
66
- if matching_key.nil?
67
- SplitIoClient.configuration.logger.warn('matching_key was null for split_name: ' + split_name.to_s)
68
- return parsed_treatment(multiple, treatment_data)
69
- end
79
+ bucketing_key, matching_key = keys_from_key(key)
70
80
 
71
- if split_name.nil?
72
- SplitIoClient.configuration.logger.warn('split_name was null for key: ' + key)
73
- return parsed_treatment(multiple, treatment_data)
74
- end
81
+ return parsed_control_treatment unless SplitIoClient::Validators.valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
75
82
 
76
- start = Time.now
83
+ bucketing_key = bucketing_key ? bucketing_key.to_s : nil
84
+ matching_key = matching_key.to_s
85
+ evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
77
86
 
78
87
  begin
88
+ start = Time.now
89
+
79
90
  split = multiple ? split_data : @splits_repository.get_split(split_name)
80
91
 
81
92
  if split.nil?
82
- SplitIoClient.configuration.logger.debug("split_name: #{split_name} does not exist. Returning CONTROL")
83
- return parsed_treatment(multiple, treatment_data)
84
- else
85
- treatment_data =
86
- evaluator.call(
87
- { bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
88
- )
93
+ SplitIoClient.configuration.logger.warn("split_name: #{split_name} does not exist. Returning CONTROL")
94
+ return parsed_control_treatment
89
95
  end
90
- rescue StandardError => error
91
- SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
92
96
 
93
- store_impression(
94
- split_name, matching_key, bucketing_key,
95
- {
96
- treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
97
- label: SplitIoClient::Engine::Models::Label::EXCEPTION
98
- },
99
- store_impressions, attributes
97
+ treatment_data =
98
+ evaluator.call(
99
+ { bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
100
100
  )
101
101
 
102
- return parsed_treatment(multiple, treatment_data)
103
- end
104
-
105
- begin
106
102
  latency = (Time.now - start) * 1000.0
107
- split && store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
103
+ store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
108
104
 
109
105
  # Measure
110
106
  @adapter.metrics.time('sdk.get_treatment', latency) unless multiple
111
107
  rescue StandardError => error
112
108
  SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
113
109
 
114
- store_impression(
115
- split_name, matching_key, bucketing_key,
116
- {
117
- treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
118
- label: SplitIoClient::Engine::Models::Label::EXCEPTION
119
- },
120
- store_impressions, attributes
121
- )
110
+ store_impression(split_name, matching_key, bucketing_key, control_treatment, store_impressions, attributes)
122
111
 
123
- return parsed_treatment(multiple, treatment_data)
112
+ return parsed_control_treatment
124
113
  end
125
114
 
126
115
  parsed_treatment(multiple, treatment_data)
@@ -188,16 +177,23 @@ module SplitIoClient
188
177
  @impression_router ||= SplitIoClient::ImpressionRouter.new
189
178
  end
190
179
 
191
- def track(key, traffic_type, event_type, value = nil)
192
- @events_repository.add(key, traffic_type, event_type, (Time.now.to_f * 1000).to_i, value)
180
+ def track(key, traffic_type_name, event_type, value = nil)
181
+ return false unless SplitIoClient::Validators.valid_track_parameters(key, traffic_type_name, event_type, value)
182
+ begin
183
+ @events_repository.add(key.to_s, traffic_type_name, event_type.to_s, (Time.now.to_f * 1000).to_i, value)
184
+ true
185
+ rescue StandardError => error
186
+ SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
187
+ false
188
+ end
193
189
  end
194
190
 
195
191
  def keys_from_key(key)
196
192
  case key.class.to_s
197
193
  when 'Hash'
198
- key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k.to_s }
194
+ key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k }
199
195
  else
200
- [nil, key].map { |k| k.nil? ? nil : k.to_s }
196
+ [nil, key].map { |k| k.nil? ? nil : k }
201
197
  end
202
198
  end
203
199
 
@@ -212,5 +208,16 @@ module SplitIoClient
212
208
  treatment_data[:treatment]
213
209
  end
214
210
  end
211
+
212
+ def sanitize_split_names(split_names)
213
+ split_names.compact.uniq.select do |split_name|
214
+ if split_name.is_a?(String) && !split_name.empty?
215
+ true
216
+ else
217
+ SplitIoClient.configuration.logger.warn('get_treatments: split_name has to be a non empty string')
218
+ false
219
+ end
220
+ end
221
+ end
215
222
  end
216
223
  end
@@ -4,5 +4,4 @@ class SplitIoClient::Engine::Models::Label
4
4
  EXCEPTION = 'exception'.freeze
5
5
  KILLED = 'killed'.freeze
6
6
  NOT_IN_SPLIT = 'not in split'.freeze
7
- DEFINITION_NOT_FOUND = 'definition not found'.freeze
8
7
  end
@@ -0,0 +1,7 @@
1
+ module SplitIoClient
2
+ class SplitIoError < StandardError; end
3
+
4
+ class ImpressionShutdownException < SplitIoError; end
5
+
6
+ class SDKBlockerTimeoutExpiredException < SplitIoError; end
7
+ end
@@ -43,7 +43,7 @@ module SplitIoClient
43
43
  #
44
44
  # @returns a split view
45
45
  def split(split_name)
46
- return unless @splits_repository
46
+ return unless @splits_repository && SplitIoClient::Validators.valid_split_parameters(split_name)
47
47
 
48
48
  split = @splits_repository.get_split(split_name)
49
49
 
@@ -63,7 +63,6 @@ module SplitIoClient
63
63
  treatments = []
64
64
  end
65
65
 
66
-
67
66
  {
68
67
  name: name,
69
68
  traffic_type_name: split[:trafficTypeName],
@@ -0,0 +1,185 @@
1
+ module SplitIoClient
2
+ module Validators
3
+ extend self
4
+
5
+ def valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
6
+ valid_key?(key) && valid_split_name?(split_name) && valid_matching_key?(matching_key) && valid_bucketing_key?(bucketing_key)
7
+ end
8
+
9
+ def valid_get_treatments_parameters(split_names)
10
+ valid_split_names?(split_names)
11
+ end
12
+
13
+ def valid_track_parameters(key, traffic_type_name, event_type, value)
14
+ valid_track_key?(key) && valid_traffic_type_name?(traffic_type_name) && valid_event_type?(event_type) && valid_value?(value)
15
+ end
16
+
17
+ def valid_split_parameters(split_name)
18
+ valid_split_name?(split_name, :split)
19
+ end
20
+
21
+ private
22
+
23
+ def string?(value)
24
+ value.is_a?(String) || value.is_a?(Symbol)
25
+ end
26
+
27
+ def number_or_string?(value)
28
+ value.is_a?(Numeric) || string?(value)
29
+ end
30
+
31
+ def log_nil(key, method)
32
+ SplitIoClient.configuration.logger.error("#{method}: #{key} cannot be nil")
33
+ end
34
+
35
+ def log_string(key, method)
36
+ SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String or a Symbol")
37
+ end
38
+
39
+ def log_number_or_string(key, method)
40
+ SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String")
41
+ end
42
+
43
+ def log_convert_numeric(key, method)
44
+ SplitIoClient.configuration.logger.warn("#{method}: #{key} is not of type String, converting to String")
45
+ end
46
+
47
+ def valid_split_name?(split_name, method=:get_treatment)
48
+ if split_name.nil?
49
+ log_nil(:split_name, method)
50
+ return false
51
+ end
52
+
53
+ unless string?(split_name)
54
+ log_string(:split_name, method)
55
+ return false
56
+ end
57
+
58
+ return true
59
+ end
60
+
61
+ def valid_key?(key)
62
+ if key.nil?
63
+ log_nil(:key, :get_treatment)
64
+ return false
65
+ end
66
+
67
+ return true
68
+ end
69
+
70
+ def valid_matching_key?(matching_key)
71
+ if matching_key.nil?
72
+ log_nil(:matching_key, :get_treatment)
73
+ return false
74
+ end
75
+
76
+ unless number_or_string?(matching_key)
77
+ log_number_or_string(:matching_key, :get_treatment)
78
+ return false
79
+ end
80
+
81
+ if matching_key.is_a? Numeric
82
+ log_convert_numeric(:matching_key, :get_treatment)
83
+ end
84
+
85
+ return true
86
+ end
87
+
88
+ def valid_bucketing_key?(bucketing_key)
89
+ if bucketing_key.nil?
90
+ SplitIoClient.configuration.logger.warn('get_treatment: key object should have bucketing_key set')
91
+ return true
92
+ end
93
+
94
+ unless number_or_string?(bucketing_key)
95
+ log_number_or_string(:bucketing_key, :get_treatment)
96
+ return false
97
+ end
98
+
99
+ if bucketing_key.is_a? Numeric
100
+ log_convert_numeric(:bucketing_key, :get_treatment)
101
+ end
102
+
103
+ return true
104
+ end
105
+
106
+ def valid_split_names?(split_names)
107
+ if split_names.nil?
108
+ log_nil(:split_names, :get_treatments)
109
+ return false
110
+ end
111
+
112
+ unless split_names.is_a? Array
113
+ SplitIoClient.configuration.logger.warn('get_treatments: split_names must be an Array')
114
+ return false
115
+ end
116
+
117
+ return true
118
+ end
119
+
120
+ def valid_track_key?(key)
121
+ if key.nil?
122
+ log_nil(:key, :track)
123
+ return false
124
+ end
125
+
126
+ unless number_or_string?(key)
127
+ log_number_or_string(:key, :track)
128
+ return false
129
+ end
130
+
131
+ if key.is_a? Numeric
132
+ log_convert_numeric(:key, :track)
133
+ end
134
+
135
+ return true
136
+ end
137
+
138
+ def valid_event_type?(event_type)
139
+ if event_type.nil?
140
+ log_nil(:event_type, :track)
141
+ return false
142
+ end
143
+
144
+ unless string?(event_type)
145
+ log_string(:event_type, :track)
146
+ return false
147
+ end
148
+
149
+ if (event_type.to_s =~ /[a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}/).nil?
150
+ SplitIoClient.configuration.logger.error('track: event_type must adhere to [a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}')
151
+ return false
152
+ end
153
+
154
+ return true
155
+ end
156
+
157
+ def valid_traffic_type_name?(traffic_type_name)
158
+ if traffic_type_name.nil?
159
+ log_nil(:traffic_type_name, :track)
160
+ return false
161
+ end
162
+
163
+ unless string?(traffic_type_name)
164
+ log_string(:traffic_type_name, :track)
165
+ return false
166
+ end
167
+
168
+ if traffic_type_name.empty?
169
+ SplitIoClient.configuration.logger.error('track: traffic_type_name must not be an empty String')
170
+ return false
171
+ end
172
+
173
+ return true
174
+ end
175
+
176
+ def valid_value?(value)
177
+ unless value.is_a?(Numeric) || value.nil?
178
+ SplitIoClient.configuration.logger.error('track: value must be a number')
179
+ return false
180
+ end
181
+
182
+ return true
183
+ end
184
+ end
185
+ end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '5.1.1.pre.rc2'
2
+ VERSION = '5.1.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1.pre.rc2
4
+ version: 5.1.2
5
5
  platform: java
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-03 00:00:00.000000000 Z
11
+ date: 2018-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -321,8 +321,7 @@ files:
321
321
  - lib/splitclient-rb/engine/parser/evaluator.rb
322
322
  - lib/splitclient-rb/engine/parser/partition.rb
323
323
  - lib/splitclient-rb/engine/parser/split_adapter.rb
324
- - lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb
325
- - lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb
324
+ - lib/splitclient-rb/exceptions.rb
326
325
  - lib/splitclient-rb/localhost_split_factory.rb
327
326
  - lib/splitclient-rb/localhost_utils.rb
328
327
  - lib/splitclient-rb/managers/localhost_split_manager.rb
@@ -332,6 +331,7 @@ files:
332
331
  - lib/splitclient-rb/split_factory_builder.rb
333
332
  - lib/splitclient-rb/split_logger.rb
334
333
  - lib/splitclient-rb/utilitites.rb
334
+ - lib/splitclient-rb/validators.rb
335
335
  - lib/splitclient-rb/version.rb
336
336
  - splitclient-rb.gemspec
337
337
  - splitio.yml.example
@@ -353,9 +353,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
353
353
  version: '0'
354
354
  required_rubygems_version: !ruby/object:Gem::Requirement
355
355
  requirements:
356
- - - ">"
356
+ - - ">="
357
357
  - !ruby/object:Gem::Version
358
- version: 1.3.1
358
+ version: '0'
359
359
  requirements: []
360
360
  rubyforge_project:
361
361
  rubygems_version: 2.6.14
@@ -1,4 +0,0 @@
1
- module SplitIoClient
2
- class ImpressionShutdownException < StandardError
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module SplitIoClient
2
- class SDKBlockerTimeoutExpiredException < StandardError
3
- end
4
- end