gitlab-experiment 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f170ab47c88f393041b3f4b8b69c168d8a159fcfcdf2fe7458ceca75a9b9db
4
- data.tar.gz: 5bc7fe4a5c8a493ce14413c109ac4424bdd61d8b0c3513530963e52586bfaf5f
3
+ metadata.gz: d4b1d80362166d1e86dd434fffe2a8e31676440f48b578e4bfcca4624fc819a8
4
+ data.tar.gz: 4535076f1c77f3faefc92f59be23689a5412f462bda088b67a4fbbdb58c74254
5
5
  SHA512:
6
- metadata.gz: bc52008aea6015b274fb7200c83b14145b355be637f1d286a8c9590df40c5d5e2c1d6da9e6f41f7f1970c576dfb13af69f43610e162eebff642d3945455e1b24
7
- data.tar.gz: 9f16a5b7bdd2ae9ea9b624946d5055878c67d67e3f755900bccdac153c330fab77ed98d1d88b0f1a869e3bbd1b1f347366252db98207513e789c387c6fd509d0
6
+ metadata.gz: d9d3445f7ee60be9d445760f103162861b1983c35ed6a9347e8703bc44c4bef2d7b154a62b2b05aa02c84471b8cfa95f91aa5521ee5743b9afa8ea5b4a4088eb
7
+ data.tar.gz: cb49261fe14971ff76799bac943e5826b04cad84982b8d061cbd7b2843a0817854772f2b3e8e55600023aff9b5266c0ba562df50c47bb90703cb686c4f973ebd
@@ -3,44 +3,78 @@
3
3
  module Gitlab
4
4
  class Experiment
5
5
  module RSpecHelpers
6
- def stub_experiments(experiments)
7
- experiments.each do |name, variant|
8
- variant = :control if variant == false
6
+ def stub_experiments(experiments, times = nil)
7
+ experiments.each { |experiment| wrapped_experiment(experiment, times) }
8
+ end
9
+
10
+ def wrapped_experiment(experiment, times = nil, expected = false, &block)
11
+ klass, experiment_name, variant_name = *experiment_details(experiment)
12
+ base_klass = Configuration.base_class.constantize
9
13
 
10
- base = Configuration.base_class.constantize
11
- klass = base.constantize(name) || base
14
+ # Set expectations on experiment classes so we can and_wrap_original with more specific args
15
+ experiment_klasses = base_klass.descendants.reject { |k| k == klass }
16
+ experiment_klasses.push(base_klass).each do |k|
17
+ allow(k).to receive(:new).and_call_original
18
+ end
12
19
 
13
- # We have to use this high level any_instance behavior as there's
14
- # not an alternative that allows multiple wrappings of `new`.
15
- allow_any_instance_of(klass).to receive(:enabled?).and_return(true)
20
+ receiver = receive(:new)
16
21
 
17
- if variant == true # passing true allows the rollout to do its job
18
- allow_any_instance_of(klass).to receive(:experiment_group?).and_return(true)
19
- else
20
- allow_any_instance_of(klass).to receive(:resolve_variant_name).and_return(variant.to_s)
22
+ # Be specific for BaseClass calls
23
+ receiver = receiver.with(experiment_name, any_args) if experiment_name && klass == base_klass
24
+
25
+ receiver.exactly(times).times if times
26
+
27
+ # Set expectations on experiment class of interest
28
+ allow_or_expect_klass = expected ? expect(klass) : allow(klass)
29
+ allow_or_expect_klass.to receiver.and_wrap_original do |method, *original_args, &original_block|
30
+ method.call(*original_args).tap do |e|
31
+ # Stub internal methods before calling the original_block
32
+ allow(e).to receive(:enabled?).and_return(true)
33
+
34
+ if variant_name == true # passing true allows the rollout to do its job
35
+ allow(e).to receive(:experiment_group?).and_return(true)
36
+ else
37
+ allow(e).to receive(:resolve_variant_name).and_return(variant_name.to_s)
38
+ end
39
+
40
+ # Stub/set expectations before calling the original_block
41
+ yield e if block
42
+
43
+ original_block.call(e) if original_block.present?
21
44
  end
22
45
  end
23
46
  end
24
47
 
25
- def wrapped_experiment(experiment, shallow: false, failure: nil, &block)
26
- if shallow
27
- yield experiment if block.present?
28
- return experiment
29
- end
48
+ private
30
49
 
31
- receive_wrapped_new = receive(:new).and_wrap_original do |new, *new_args, &new_block|
32
- instance = new.call(*new_args)
33
- instance.tap(&block) if block.present?
34
- instance.tap(&new_block) if new_block.present?
35
- instance
50
+ def experiment_details(experiment)
51
+ if experiment.is_a?(Symbol)
52
+ experiment_name = experiment
53
+ variant_name = nil
36
54
  end
37
55
 
38
- klass = experiment.class == Class ? experiment : experiment.class
39
- if failure
40
- expect(klass).to receive_wrapped_new, failure
56
+ experiment_name, variant_name = *experiment if experiment.is_a?(Array)
57
+
58
+ base_klass = Configuration.base_class.constantize
59
+ variant_name = experiment.variant.name if experiment.is_a?(base_klass)
60
+
61
+ if experiment.class.name.nil? # Anonymous class instance
62
+ klass = experiment.class
63
+ elsif experiment.instance_of?(Class) # Class level stubbing, eg. "MyExperiment"
64
+ klass = experiment
41
65
  else
42
- allow(klass).to receive_wrapped_new
66
+ experiment_name ||= experiment.instance_variable_get(:@name)
67
+ klass = base_klass.constantize(experiment_name)
68
+ end
69
+
70
+ if experiment_name && klass == base_klass
71
+ experiment_name = experiment_name.to_sym
72
+
73
+ # For experiment names like: "group/experiment-name"
74
+ experiment_name = experiment_name.to_s if experiment_name.inspect.include?('"')
43
75
  end
76
+
77
+ [klass, experiment_name, variant_name]
44
78
  end
45
79
  end
46
80
 
@@ -135,34 +169,41 @@ module Gitlab
135
169
  end
136
170
 
137
171
  chain(:with_context) { |expected_context| @expected_context = expected_context }
138
- chain(:on_any_instance) { @on_self = false }
172
+
173
+ chain(:on_next_instance) { @on_next_instance = true }
139
174
 
140
175
  def expect_tracking_on(experiment, negated, event, *event_args)
141
- @experiment = experiment
142
- @on_self = true if require_experiment(experiment, 'track', classes: !@on_self) && @on_self.nil?
143
- wrapped_experiment(experiment, shallow: @on_self, failure: failure_message(:no_new, event)) do |instance|
144
- @experiment = instance
145
- allow(@experiment).to receive(:track)
176
+ klass = experiment.instance_of?(Class) ? experiment : experiment.class
177
+ unless klass <= Gitlab::Experiment
178
+ raise(
179
+ ArgumentError,
180
+ "track matcher is limited to experiment instances and classes"
181
+ )
182
+ end
183
+
184
+ expectations = proc do |e|
185
+ @experiment = e
186
+ allow(e).to receive(:track).and_call_original
146
187
 
147
188
  if negated
148
- expect(@experiment).not_to receive_tracking_call_for(event, *event_args)
189
+ expect(e).not_to receive(:track).with(*[event, *event_args])
149
190
  else
150
- expect(@experiment).to receive_tracking_call_for(event, *event_args)
151
- end
152
- end
153
- end
191
+ if @expected_variant
192
+ expect(@experiment.variant.name).to eq(@expected_variant), failure_message(:variant, event)
193
+ end
154
194
 
155
- def receive_tracking_call_for(expected_event, *expected_event_args)
156
- receive(:track).with(*[expected_event, *expected_event_args]).and_wrap_original do |track, event, *event_args|
157
- track.call(event, *event_args) # call the original
195
+ if @expected_context
196
+ expect(@experiment.context.value).to include(@expected_context), failure_message(:context, event)
197
+ end
158
198
 
159
- if @expected_variant
160
- expect(@experiment.variant.name).to eq(@expected_variant), failure_message(:variant, expected_event)
199
+ expect(e).to receive(:track).with(*[event, *event_args]).and_call_original
161
200
  end
201
+ end
162
202
 
163
- if @expected_context
164
- expect(@experiment.context.value).to include(@expected_context), failure_message(:context, expected_event)
165
- end
203
+ if experiment.instance_of?(Class) || @on_next_instance
204
+ wrapped_experiment(experiment, nil, true) { |e| expectations.call(e) }
205
+ else
206
+ expectations.call(experiment)
166
207
  end
167
208
  end
168
209
 
@@ -180,8 +221,6 @@ module Gitlab
180
221
  expected context: #{@expected_context}
181
222
  actual context: #{@experiment.context.value}
182
223
  MESSAGE
183
- when :no_new
184
- %(expected #{@experiment.inspect} to have tracked #{event.inspect}, but no new instances were created)
185
224
  end
186
225
  end
187
226
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  class Experiment
5
- VERSION = '0.5.1'
5
+ VERSION = '0.5.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-17 00:00:00.000000000 Z
11
+ date: 2021-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport