gitlab-experiment 0.4.7 → 0.4.8

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
  SHA256:
3
- metadata.gz: a26425622afb7aa3f341ff403192963e276876b65902237018f852117168a19a
4
- data.tar.gz: 0a5238c73a4b0217810b4f8161df6452b683b21a6573f1b657517302cef9cef0
3
+ metadata.gz: cf6802aee233e6124ae21b95a164a92be868f5c5eda19e9560a813ac9f0ade0a
4
+ data.tar.gz: e8691d32ae73422e172176477c54966edc187ec72a43030070b3412e9f15d346
5
5
  SHA512:
6
- metadata.gz: 567ca93e3f931c167bc1766490b07e1535db72e3b5da5986715412746354945ed799dab4c075e91c5015aa922bf5d7e5a82bdc940808aa8100c8897d5ee623b7
7
- data.tar.gz: 3f053ed2ad8bdfc2201aacaef9c723332fba260f4f4cb54c65a92539d74ec100297540c34c97579c99723f0d98e98dc57cbe383a0731128d623b0a58b4786d7c
6
+ metadata.gz: 0a9eded639610b17e6b0cccbd17a232d187fd9bddc68047cfa14a01500e17f0f6ba78e93e7cd08d87a0cdce6e15e31198d00b0976bb72ff7de5115be15c50859
7
+ data.tar.gz: a6cdae13a053ab7c2e0ae8cdb6934db927a856263a8759499f072c9364be6f6ca6ac8bc5e279f4512e04fc930d2491fe09a72909a949ce57ff64c4971ab43a65
@@ -66,6 +66,10 @@ module Gitlab
66
66
  yield self if block_given?
67
67
  end
68
68
 
69
+ def inspect
70
+ "#<#{self.class.name || 'AnonymousClass'}:#{format('0x%016X', __id__)} @name=#{name} @signature=#{signature}>"
71
+ end
72
+
69
73
  def context(value = nil)
70
74
  return @context if value.blank?
71
75
 
@@ -9,14 +9,32 @@ module Gitlab
9
9
  raise ArgumentError, 'variant must be a symbol or false' unless variant.is_a?(Symbol)
10
10
 
11
11
  klass = Gitlab::Experiment.send(:constantize, name) # rubocop:disable GitlabSecurity/PublicSend
12
- allow(klass).to receive(:new).and_wrap_original do |new, *args, &block|
13
- new.call(*args).tap do |instance|
14
- allow(instance).to receive(:enabled?).and_return(true)
15
- allow(instance).to receive(:resolve_variant_name).and_return(variant.to_s)
16
12
 
17
- block.call(instance) if block.present?
18
- end
19
- end
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)
16
+ allow_any_instance_of(klass).to receive(:resolve_variant_name).and_return(variant.to_s)
17
+ end
18
+ end
19
+
20
+ def wrapped_experiment(experiment, shallow: false, failure: nil, &block)
21
+ if shallow
22
+ yield experiment if block.present?
23
+ return experiment
24
+ end
25
+
26
+ receive_wrapped_new = receive(:new).and_wrap_original do |new, *new_args, &new_block|
27
+ instance = new.call(*new_args)
28
+ instance.tap(&block) if block.present?
29
+ instance.tap(&new_block) if new_block.present?
30
+ instance
31
+ end
32
+
33
+ klass = experiment.class == Class ? experiment : experiment.class
34
+ if failure
35
+ expect(klass).to receive_wrapped_new, failure
36
+ else
37
+ allow(klass).to receive_wrapped_new
20
38
  end
21
39
  end
22
40
  end
@@ -24,10 +42,27 @@ module Gitlab
24
42
  module RSpecMatchers
25
43
  extend RSpec::Matchers::DSL
26
44
 
45
+ def require_experiment(experiment, matcher_name, classes: false)
46
+ klass = experiment.class == Class ? experiment : experiment.class
47
+ unless klass <= Gitlab::Experiment
48
+ raise(
49
+ ArgumentError,
50
+ "#{matcher_name} matcher is limited to experiment instances#{classes ? ' and classes' : ''}"
51
+ )
52
+ end
53
+
54
+ if experiment == klass && !classes
55
+ raise ArgumentError, "#{matcher_name} matcher requires an instance of an experiment"
56
+ end
57
+
58
+ experiment != klass
59
+ end
60
+
27
61
  matcher :exclude do |context|
28
62
  ivar = :'@excluded'
29
63
 
30
64
  match do |experiment|
65
+ require_experiment(experiment, 'exclude')
31
66
  experiment.context(context)
32
67
 
33
68
  experiment.instance_variable_set(ivar, nil)
@@ -47,6 +82,7 @@ module Gitlab
47
82
  ivar = :'@variant_name'
48
83
 
49
84
  match do |experiment|
85
+ require_experiment(experiment, 'segment')
50
86
  experiment.context(context)
51
87
 
52
88
  experiment.instance_variable_set(ivar, nil)
@@ -72,29 +108,74 @@ module Gitlab
72
108
 
73
109
  def message_details
74
110
  message = ''
75
- message += %(\n into: #{@expected}) if @expected
76
- message += %(\n actual: #{@actual}) if @actual
111
+ message += %( into variant\n expected variant: #{@expected}) if @expected
112
+ message += %(\n actual variant: #{@actual}) if @actual
77
113
  message
78
114
  end
79
115
  end
80
116
 
81
117
  matcher :track do |event, *event_args|
82
118
  match do |experiment|
83
- wrapped(experiment) { |instance| expect(instance).to receive_with(event, *event_args) }
119
+ expect_tracking_on(experiment, event, *event_args)
84
120
  end
85
121
 
86
122
  match_when_negated do |experiment|
87
- wrapped(experiment) { |instance| expect(instance).not_to receive_with(event, *event_args) }
123
+ expect_tracking_on(experiment, event, *event_args, negated: true)
88
124
  end
89
125
 
90
- def wrapped(experiment, &block)
91
- allow(experiment.class).to receive(:new).and_wrap_original do |new, *new_args|
92
- new.call(*new_args).tap(&block)
126
+ chain :for do |expected_variant|
127
+ raise ArgumentError, 'variant name must be provided' if expected.blank?
128
+
129
+ @expected_variant = expected_variant.to_s
130
+ end
131
+
132
+ chain(:with_context) { |expected_context| @expected_context = expected_context }
133
+ chain(:on_any_instance) { @on_self = false }
134
+
135
+ def expect_tracking_on(experiment, event, *event_args, negated: false)
136
+ @experiment = experiment
137
+ @on_self = true if require_experiment(experiment, 'track', classes: !@on_self) && @on_self.nil?
138
+ wrapped_experiment(experiment, shallow: @on_self, failure: failure_message(:no_new, event)) do |instance|
139
+ @experiment = instance
140
+ allow(@experiment).to receive(:track)
141
+
142
+ if negated
143
+ expect(@experiment).not_to receive_tracking_call_for(event, *event_args)
144
+ else
145
+ expect(@experiment).to receive_tracking_call_for(event, *event_args)
146
+ end
93
147
  end
94
148
  end
95
149
 
96
- def receive_with(*args)
97
- receive(:track).with(*args) # rubocop:disable CodeReuse/ActiveRecord
150
+ def receive_tracking_call_for(event, *event_args)
151
+ receive(:track).with(*[event, *event_args]) do # rubocop:disable CodeReuse/ActiveRecord
152
+ if @expected_variant
153
+ expect(@experiment.variant.name).to eq(@expected_variant), failure_message(:variant, event)
154
+ end
155
+
156
+ if @expected_context
157
+ expect(@experiment.context.value).to include(@expected_context), failure_message(:context, event)
158
+ end
159
+ end
160
+ end
161
+
162
+ def failure_message(failure_type, event)
163
+ case failure_type
164
+ when :variant
165
+ <<~MESSAGE.strip
166
+ expected #{@experiment.inspect} to have tracked #{event.inspect} for variant
167
+ expected variant: #{@expected_variant}
168
+ actual variant: #{@experiment.variant.name}
169
+ MESSAGE
170
+ when :context
171
+ <<~MESSAGE.strip
172
+ expected #{@experiment.inspect} to have tracked #{event.inspect} with context
173
+ expected context: #{@expected_context}
174
+ actual context: #{@experiment.context.value}
175
+ MESSAGE
176
+ when :no_new
177
+ %(expected #{@experiment.inspect} to have tracked #{event.inspect}, but no new instances were created)
178
+ end
98
179
  end
99
180
  end
100
181
  end
@@ -103,9 +184,10 @@ end
103
184
 
104
185
  RSpec.configure do |config|
105
186
  config.include Gitlab::Experiment::RSpecHelpers
187
+ config.include Gitlab::Experiment::Dsl
106
188
 
107
189
  config.include Gitlab::Experiment::RSpecMatchers, :experiment
108
- config.define_derived_metadata(file_path: %r{/spec/experiments/}) do |metadata|
190
+ config.define_derived_metadata(file_path: Regexp.new('/spec/experiments/')) do |metadata|
109
191
  metadata[:type] = :experiment
110
192
  end
111
193
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  class Experiment
5
- VERSION = '0.4.7'
5
+ VERSION = '0.4.8'
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.4.7
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport