split 4.0.1 → 4.0.2
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 +4 -4
- data/.github/workflows/ci.yml +6 -3
- data/.rubocop.yml +2 -5
- data/CHANGELOG.md +23 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +2 -1
- data/README.md +4 -2
- data/Rakefile +4 -5
- data/gemfiles/5.2.gemfile +1 -3
- data/gemfiles/6.0.gemfile +1 -3
- data/gemfiles/6.1.gemfile +1 -3
- data/gemfiles/7.0.gemfile +2 -3
- data/lib/split/algorithms/block_randomization.rb +5 -6
- data/lib/split/algorithms/whiplash.rb +16 -18
- data/lib/split/algorithms.rb +22 -0
- data/lib/split/alternative.rb +21 -22
- data/lib/split/cache.rb +0 -1
- data/lib/split/combined_experiments_helper.rb +4 -4
- data/lib/split/configuration.rb +83 -84
- data/lib/split/dashboard/helpers.rb +6 -7
- data/lib/split/dashboard/pagination_helpers.rb +53 -54
- data/lib/split/dashboard/public/style.css +5 -2
- data/lib/split/dashboard/views/index.erb +19 -4
- data/lib/split/dashboard.rb +29 -23
- data/lib/split/encapsulated_helper.rb +4 -6
- data/lib/split/experiment.rb +84 -88
- data/lib/split/experiment_catalog.rb +6 -5
- data/lib/split/extensions/string.rb +1 -1
- data/lib/split/goals_collection.rb +8 -10
- data/lib/split/helper.rb +19 -19
- data/lib/split/metric.rb +4 -5
- data/lib/split/persistence/cookie_adapter.rb +44 -47
- data/lib/split/persistence/dual_adapter.rb +7 -8
- data/lib/split/persistence/redis_adapter.rb +2 -3
- data/lib/split/persistence/session_adapter.rb +0 -2
- data/lib/split/persistence.rb +4 -4
- data/lib/split/redis_interface.rb +1 -2
- data/lib/split/trial.rb +23 -24
- data/lib/split/user.rb +12 -13
- data/lib/split/version.rb +1 -1
- data/lib/split/zscore.rb +1 -3
- data/lib/split.rb +26 -25
- data/spec/algorithms/block_randomization_spec.rb +6 -5
- data/spec/algorithms/weighted_sample_spec.rb +6 -5
- data/spec/algorithms/whiplash_spec.rb +4 -5
- data/spec/alternative_spec.rb +35 -36
- data/spec/cache_spec.rb +15 -19
- data/spec/combined_experiments_helper_spec.rb +18 -17
- data/spec/configuration_spec.rb +32 -38
- data/spec/dashboard/pagination_helpers_spec.rb +69 -67
- data/spec/dashboard/paginator_spec.rb +10 -9
- data/spec/dashboard_helpers_spec.rb +19 -18
- data/spec/dashboard_spec.rb +67 -35
- data/spec/encapsulated_helper_spec.rb +12 -14
- data/spec/experiment_catalog_spec.rb +14 -13
- data/spec/experiment_spec.rb +121 -123
- data/spec/goals_collection_spec.rb +17 -15
- data/spec/helper_spec.rb +379 -382
- data/spec/metric_spec.rb +14 -14
- data/spec/persistence/cookie_adapter_spec.rb +23 -8
- data/spec/persistence/dual_adapter_spec.rb +71 -71
- data/spec/persistence/redis_adapter_spec.rb +25 -26
- data/spec/persistence/session_adapter_spec.rb +2 -3
- data/spec/persistence_spec.rb +1 -2
- data/spec/redis_interface_spec.rb +16 -14
- data/spec/spec_helper.rb +15 -13
- data/spec/split_spec.rb +11 -11
- data/spec/support/cookies_mock.rb +1 -2
- data/spec/trial_spec.rb +61 -60
- data/spec/user_spec.rb +36 -36
- data/split.gemspec +20 -20
- metadata +7 -10
- data/.rubocop_todo.yml +0 -226
- data/Appraisals +0 -19
- data/gemfiles/5.0.gemfile +0 -9
- data/gemfiles/5.1.gemfile +0 -9
data/spec/split_spec.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'spec_helper'
|
3
2
|
|
4
|
-
|
3
|
+
require "spec_helper"
|
5
4
|
|
5
|
+
RSpec.describe Split do
|
6
6
|
around(:each) do |ex|
|
7
|
-
old_env, old_redis = [ENV.delete(
|
7
|
+
old_env, old_redis = [ENV.delete("REDIS_URL"), Split.redis]
|
8
8
|
ex.run
|
9
|
-
ENV[
|
9
|
+
ENV["REDIS_URL"] = old_env
|
10
10
|
Split.redis = old_redis
|
11
11
|
end
|
12
12
|
|
13
|
-
describe
|
14
|
-
it
|
15
|
-
Split.redis =
|
13
|
+
describe "#redis=" do
|
14
|
+
it "accepts a url string" do
|
15
|
+
Split.redis = "redis://localhost:6379"
|
16
16
|
expect(Split.redis).to be_a(Redis)
|
17
17
|
|
18
18
|
client = Split.redis.connection
|
@@ -20,8 +20,8 @@ RSpec.describe Split do
|
|
20
20
|
expect(client[:port]).to eq(6379)
|
21
21
|
end
|
22
22
|
|
23
|
-
it
|
24
|
-
Split.redis = {host:
|
23
|
+
it "accepts an options hash" do
|
24
|
+
Split.redis = { host: "localhost", port: 6379, db: 12 }
|
25
25
|
expect(Split.redis).to be_a(Redis)
|
26
26
|
|
27
27
|
client = Split.redis.connection
|
@@ -30,13 +30,13 @@ RSpec.describe Split do
|
|
30
30
|
expect(client[:db]).to eq(12)
|
31
31
|
end
|
32
32
|
|
33
|
-
it
|
33
|
+
it "accepts a valid Redis instance" do
|
34
34
|
other_redis = Redis.new(url: "redis://localhost:6379")
|
35
35
|
Split.redis = other_redis
|
36
36
|
expect(Split.redis).to eq(other_redis)
|
37
37
|
end
|
38
38
|
|
39
|
-
it
|
39
|
+
it "raises an ArgumentError when server cannot be determined" do
|
40
40
|
expect { Split.redis = Object.new }.to raise_error(ArgumentError)
|
41
41
|
end
|
42
42
|
end
|
data/spec/trial_spec.rb
CHANGED
@@ -1,54 +1,55 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "split/trial"
|
4
5
|
|
5
6
|
describe Split::Trial do
|
6
7
|
let(:user) { mock_user }
|
7
|
-
let(:alternatives) { [
|
8
|
+
let(:alternatives) { ["basket", "cart"] }
|
8
9
|
let(:experiment) do
|
9
|
-
Split::Experiment.new(
|
10
|
+
Split::Experiment.new("basket_text", alternatives: alternatives).save
|
10
11
|
end
|
11
12
|
|
12
13
|
it "should be initializeable" do
|
13
|
-
experiment = double(
|
14
|
-
alternative = double(
|
15
|
-
trial = Split::Trial.new(:
|
14
|
+
experiment = double("experiment")
|
15
|
+
alternative = double("alternative", kind_of?: Split::Alternative)
|
16
|
+
trial = Split::Trial.new(experiment: experiment, alternative: alternative)
|
16
17
|
expect(trial.experiment).to eq(experiment)
|
17
18
|
expect(trial.alternative).to eq(alternative)
|
18
19
|
end
|
19
20
|
|
20
21
|
describe "alternative" do
|
21
22
|
it "should use the alternative if specified" do
|
22
|
-
alternative = double(
|
23
|
-
trial = Split::Trial.new(:
|
24
|
-
:
|
23
|
+
alternative = double("alternative", kind_of?: Split::Alternative)
|
24
|
+
trial = Split::Trial.new(experiment: double("experiment"),
|
25
|
+
alternative: alternative, user: user)
|
25
26
|
expect(trial).not_to receive(:choose)
|
26
27
|
expect(trial.alternative).to eq(alternative)
|
27
28
|
end
|
28
29
|
|
29
30
|
it "should load the alternative when the alternative name is set" do
|
30
|
-
experiment = Split::Experiment.new(
|
31
|
+
experiment = Split::Experiment.new("basket_text", alternatives: ["basket", "cart"])
|
31
32
|
experiment.save
|
32
33
|
|
33
|
-
trial = Split::Trial.new(:
|
34
|
-
expect(trial.alternative.name).to eq(
|
34
|
+
trial = Split::Trial.new(experiment: experiment, alternative: "basket")
|
35
|
+
expect(trial.alternative.name).to eq("basket")
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
describe "metadata" do
|
39
40
|
let(:metadata) { Hash[alternatives.map { |k| [k, "Metadata for #{k}"] }] }
|
40
41
|
let(:experiment) do
|
41
|
-
Split::Experiment.new(
|
42
|
+
Split::Experiment.new("basket_text", alternatives: alternatives, metadata: metadata).save
|
42
43
|
end
|
43
44
|
|
44
|
-
it
|
45
|
-
trial = Split::Trial.new(:
|
46
|
-
:
|
47
|
-
expect(trial.metadata).to eq(metadata[
|
45
|
+
it "has metadata on each trial" do
|
46
|
+
trial = Split::Trial.new(experiment: experiment, user: user, metadata: metadata["cart"],
|
47
|
+
override: "cart")
|
48
|
+
expect(trial.metadata).to eq(metadata["cart"])
|
48
49
|
end
|
49
50
|
|
50
|
-
it
|
51
|
-
trial = Split::Trial.new(:
|
51
|
+
it "has metadata on each trial from the experiment" do
|
52
|
+
trial = Split::Trial.new(experiment: experiment, user: user)
|
52
53
|
trial.choose!
|
53
54
|
expect(trial.metadata).to eq(metadata[trial.alternative.name])
|
54
55
|
expect(trial.metadata).to match(/#{trial.alternative.name}/)
|
@@ -56,24 +57,24 @@ describe Split::Trial do
|
|
56
57
|
end
|
57
58
|
|
58
59
|
describe "#choose!" do
|
59
|
-
let(:context) { double(on_trial_callback:
|
60
|
+
let(:context) { double(on_trial_callback: "test callback") }
|
60
61
|
let(:trial) do
|
61
|
-
Split::Trial.new(:
|
62
|
+
Split::Trial.new(user: user, experiment: experiment)
|
62
63
|
end
|
63
64
|
|
64
|
-
shared_examples_for
|
65
|
-
it
|
65
|
+
shared_examples_for "a trial with callbacks" do
|
66
|
+
it "does not run if on_trial callback is not respondable" do
|
66
67
|
Split.configuration.on_trial = :foo
|
67
68
|
allow(context).to receive(:respond_to?).with(:foo, true).and_return false
|
68
69
|
expect(context).to_not receive(:foo)
|
69
70
|
trial.choose! context
|
70
71
|
end
|
71
|
-
it
|
72
|
+
it "runs on_trial callback" do
|
72
73
|
Split.configuration.on_trial = :on_trial_callback
|
73
74
|
expect(context).to receive(:on_trial_callback)
|
74
75
|
trial.choose! context
|
75
76
|
end
|
76
|
-
it
|
77
|
+
it "does not run nil on_trial callback" do
|
77
78
|
Split.configuration.on_trial = nil
|
78
79
|
expect(context).not_to receive(:on_trial_callback)
|
79
80
|
trial.choose! context
|
@@ -88,12 +89,12 @@ describe Split::Trial do
|
|
88
89
|
end
|
89
90
|
|
90
91
|
context "when override is present" do
|
91
|
-
let(:override) {
|
92
|
+
let(:override) { "cart" }
|
92
93
|
let(:trial) do
|
93
|
-
Split::Trial.new(:
|
94
|
+
Split::Trial.new(user: user, experiment: experiment, override: override)
|
94
95
|
end
|
95
96
|
|
96
|
-
it_behaves_like
|
97
|
+
it_behaves_like "a trial with callbacks"
|
97
98
|
|
98
99
|
it "picks the override" do
|
99
100
|
expect(experiment).to_not receive(:next_alternative)
|
@@ -102,7 +103,7 @@ describe Split::Trial do
|
|
102
103
|
|
103
104
|
context "when alternative doesn't exist" do
|
104
105
|
let(:override) { nil }
|
105
|
-
it
|
106
|
+
it "falls back on next_alternative" do
|
106
107
|
expect(experiment).to receive(:next_alternative).and_call_original
|
107
108
|
expect_alternative(trial, alternatives)
|
108
109
|
end
|
@@ -111,7 +112,7 @@ describe Split::Trial do
|
|
111
112
|
|
112
113
|
context "when disabled option is true" do
|
113
114
|
let(:trial) do
|
114
|
-
Split::Trial.new(:
|
115
|
+
Split::Trial.new(user: user, experiment: experiment, disabled: true)
|
115
116
|
end
|
116
117
|
|
117
118
|
it "picks the control", :aggregate_failures do
|
@@ -120,7 +121,7 @@ describe Split::Trial do
|
|
120
121
|
|
121
122
|
expect(context).not_to receive(:on_trial_callback)
|
122
123
|
|
123
|
-
expect_alternative(trial,
|
124
|
+
expect_alternative(trial, "basket")
|
124
125
|
Split.configuration.on_trial = nil
|
125
126
|
end
|
126
127
|
end
|
@@ -132,7 +133,7 @@ describe Split::Trial do
|
|
132
133
|
|
133
134
|
expect(experiment).to_not receive(:next_alternative)
|
134
135
|
expect(context).not_to receive(:on_trial_callback)
|
135
|
-
expect_alternative(trial,
|
136
|
+
expect_alternative(trial, "basket")
|
136
137
|
|
137
138
|
Split.configuration.enabled = true
|
138
139
|
Split.configuration.on_trial = nil
|
@@ -141,45 +142,45 @@ describe Split::Trial do
|
|
141
142
|
|
142
143
|
context "when experiment has winner" do
|
143
144
|
let(:trial) do
|
144
|
-
Split::Trial.new(:
|
145
|
+
Split::Trial.new(user: user, experiment: experiment)
|
145
146
|
end
|
146
147
|
|
147
|
-
it_behaves_like
|
148
|
+
it_behaves_like "a trial with callbacks"
|
148
149
|
|
149
150
|
it "picks the winner" do
|
150
|
-
experiment.winner =
|
151
|
+
experiment.winner = "cart"
|
151
152
|
expect(experiment).to_not receive(:next_alternative)
|
152
153
|
|
153
|
-
expect_alternative(trial,
|
154
|
+
expect_alternative(trial, "cart")
|
154
155
|
end
|
155
156
|
end
|
156
157
|
|
157
158
|
context "when exclude is true" do
|
158
159
|
let(:trial) do
|
159
|
-
Split::Trial.new(:
|
160
|
+
Split::Trial.new(user: user, experiment: experiment, exclude: true)
|
160
161
|
end
|
161
162
|
|
162
|
-
it_behaves_like
|
163
|
+
it_behaves_like "a trial with callbacks"
|
163
164
|
|
164
165
|
it "picks the control" do
|
165
166
|
expect(experiment).to_not receive(:next_alternative)
|
166
|
-
expect_alternative(trial,
|
167
|
+
expect_alternative(trial, "basket")
|
167
168
|
end
|
168
169
|
end
|
169
170
|
|
170
171
|
context "when user is already participating" do
|
171
|
-
it_behaves_like
|
172
|
+
it_behaves_like "a trial with callbacks"
|
172
173
|
|
173
174
|
it "picks the same alternative" do
|
174
|
-
user[experiment.key] =
|
175
|
+
user[experiment.key] = "basket"
|
175
176
|
expect(experiment).to_not receive(:next_alternative)
|
176
177
|
|
177
|
-
expect_alternative(trial,
|
178
|
+
expect_alternative(trial, "basket")
|
178
179
|
end
|
179
180
|
|
180
181
|
context "when alternative is not found" do
|
181
182
|
it "falls back on next_alternative" do
|
182
|
-
user[experiment.key] =
|
183
|
+
user[experiment.key] = "notfound"
|
183
184
|
expect(experiment).to receive(:next_alternative).and_call_original
|
184
185
|
expect_alternative(trial, alternatives)
|
185
186
|
end
|
@@ -213,7 +214,7 @@ describe Split::Trial do
|
|
213
214
|
|
214
215
|
expect(experiment).to_not receive(:next_alternative)
|
215
216
|
expect(context).not_to receive(:on_trial_callback)
|
216
|
-
expect_alternative(trial,
|
217
|
+
expect_alternative(trial, "basket")
|
217
218
|
|
218
219
|
Split.configuration.enabled = true
|
219
220
|
Split.configuration.on_trial = nil
|
@@ -229,9 +230,9 @@ describe Split::Trial do
|
|
229
230
|
end
|
230
231
|
|
231
232
|
describe "#complete!" do
|
232
|
-
context
|
233
|
-
let(:trial) { Split::Trial.new(:
|
234
|
-
it
|
233
|
+
context "when there are no goals" do
|
234
|
+
let(:trial) { Split::Trial.new(user: user, experiment: experiment) }
|
235
|
+
it "should complete the trial" do
|
235
236
|
trial.choose!
|
236
237
|
old_completed_count = trial.alternative.completed_count
|
237
238
|
trial.complete!
|
@@ -241,11 +242,11 @@ describe Split::Trial do
|
|
241
242
|
|
242
243
|
context "when there are many goals" do
|
243
244
|
let(:goals) { [ "goal1", "goal2" ] }
|
244
|
-
let(:trial) { Split::Trial.new(:
|
245
|
+
let(:trial) { Split::Trial.new(user: user, experiment: experiment, goals: goals) }
|
245
246
|
|
246
247
|
it "increments the completed count corresponding to the goals" do
|
247
248
|
trial.choose!
|
248
|
-
old_completed_counts = goals.map{ |goal| [goal, trial.alternative.completed_count(goal)] }.to_h
|
249
|
+
old_completed_counts = goals.map { |goal| [goal, trial.alternative.completed_count(goal)] }.to_h
|
249
250
|
trial.complete!
|
250
251
|
goals.each { | goal | expect(trial.alternative.completed_count(goal)).to eq(old_completed_counts[goal] + 1) }
|
251
252
|
end
|
@@ -253,7 +254,7 @@ describe Split::Trial do
|
|
253
254
|
|
254
255
|
context "when there is 1 goal of type string" do
|
255
256
|
let(:goal) { "goal" }
|
256
|
-
let(:trial) { Split::Trial.new(:
|
257
|
+
let(:trial) { Split::Trial.new(user: user, experiment: experiment, goals: goal) }
|
257
258
|
it "increments the completed count corresponding to the goal" do
|
258
259
|
trial.choose!
|
259
260
|
old_completed_count = trial.alternative.completed_count(goal)
|
@@ -268,7 +269,7 @@ describe Split::Trial do
|
|
268
269
|
|
269
270
|
context "when override is present" do
|
270
271
|
it "stores when store_override is true" do
|
271
|
-
trial = Split::Trial.new(:
|
272
|
+
trial = Split::Trial.new(user: user, experiment: experiment, override: "basket")
|
272
273
|
|
273
274
|
Split.configuration.store_override = true
|
274
275
|
expect(user).to receive("[]=")
|
@@ -277,7 +278,7 @@ describe Split::Trial do
|
|
277
278
|
end
|
278
279
|
|
279
280
|
it "does not store when store_override is false" do
|
280
|
-
trial = Split::Trial.new(:
|
281
|
+
trial = Split::Trial.new(user: user, experiment: experiment, override: "basket")
|
281
282
|
|
282
283
|
expect(user).to_not receive("[]=")
|
283
284
|
trial.choose!
|
@@ -286,7 +287,7 @@ describe Split::Trial do
|
|
286
287
|
|
287
288
|
context "when disabled is present" do
|
288
289
|
it "stores when store_override is true" do
|
289
|
-
trial = Split::Trial.new(:
|
290
|
+
trial = Split::Trial.new(user: user, experiment: experiment, disabled: true)
|
290
291
|
|
291
292
|
Split.configuration.store_override = true
|
292
293
|
expect(user).to receive("[]=")
|
@@ -294,7 +295,7 @@ describe Split::Trial do
|
|
294
295
|
end
|
295
296
|
|
296
297
|
it "does not store when store_override is false" do
|
297
|
-
trial = Split::Trial.new(:
|
298
|
+
trial = Split::Trial.new(user: user, experiment: experiment, disabled: true)
|
298
299
|
|
299
300
|
expect(user).to_not receive("[]=")
|
300
301
|
trial.choose!
|
@@ -303,20 +304,20 @@ describe Split::Trial do
|
|
303
304
|
|
304
305
|
context "when exclude is present" do
|
305
306
|
it "does not store" do
|
306
|
-
trial = Split::Trial.new(:
|
307
|
+
trial = Split::Trial.new(user: user, experiment: experiment, exclude: true)
|
307
308
|
|
308
309
|
expect(user).to_not receive("[]=")
|
309
310
|
trial.choose!
|
310
311
|
end
|
311
312
|
end
|
312
313
|
|
313
|
-
context
|
314
|
+
context "when experiment has winner" do
|
314
315
|
let(:trial) do
|
315
|
-
experiment.winner =
|
316
|
-
Split::Trial.new(:
|
316
|
+
experiment.winner = "cart"
|
317
|
+
Split::Trial.new(user: user, experiment: experiment)
|
317
318
|
end
|
318
319
|
|
319
|
-
it
|
320
|
+
it "does not store" do
|
320
321
|
expect(user).to_not receive("[]=")
|
321
322
|
trial.choose!
|
322
323
|
end
|
data/spec/user_spec.rb
CHANGED
@@ -1,71 +1,73 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "split/experiment_catalog"
|
5
|
+
require "split/experiment"
|
6
|
+
require "split/user"
|
5
7
|
|
6
8
|
describe Split::User do
|
7
|
-
let(:user_keys) { {
|
8
|
-
let(:context) { double(:
|
9
|
-
let(:experiment) { Split::Experiment.new(
|
9
|
+
let(:user_keys) { { "link_color" => "blue" } }
|
10
|
+
let(:context) { double(session: { split: user_keys }) }
|
11
|
+
let(:experiment) { Split::Experiment.new("link_color") }
|
10
12
|
|
11
13
|
before(:each) do
|
12
14
|
@subject = described_class.new(context)
|
13
15
|
end
|
14
16
|
|
15
|
-
it
|
16
|
-
expect(@subject[
|
17
|
+
it "delegates methods correctly" do
|
18
|
+
expect(@subject["link_color"]).to eq(@subject.user["link_color"])
|
17
19
|
end
|
18
20
|
|
19
|
-
context
|
21
|
+
context "#cleanup_old_versions!" do
|
20
22
|
let(:experiment_version) { "#{experiment.name}:1" }
|
21
23
|
let(:second_experiment_version) { "#{experiment.name}_another:1" }
|
22
24
|
let(:third_experiment_version) { "variation_of_#{experiment.name}:1" }
|
23
25
|
let(:user_keys) do
|
24
26
|
{
|
25
|
-
experiment_version =>
|
26
|
-
second_experiment_version =>
|
27
|
-
third_experiment_version =>
|
27
|
+
experiment_version => "blue",
|
28
|
+
second_experiment_version => "red",
|
29
|
+
third_experiment_version => "yellow"
|
28
30
|
}
|
29
31
|
end
|
30
32
|
|
31
33
|
before(:each) { @subject.cleanup_old_versions!(experiment) }
|
32
34
|
|
33
|
-
it
|
35
|
+
it "removes key if old experiment is found" do
|
34
36
|
expect(@subject.keys).not_to include(experiment_version)
|
35
37
|
end
|
36
38
|
|
37
|
-
it
|
39
|
+
it "does not remove other keys" do
|
38
40
|
expect(@subject.keys).to include(second_experiment_version, third_experiment_version)
|
39
41
|
end
|
40
|
-
end
|
42
|
+
end
|
41
43
|
|
42
|
-
context
|
43
|
-
it
|
44
|
+
context "#cleanup_old_experiments!" do
|
45
|
+
it "removes key if experiment is not found" do
|
44
46
|
@subject.cleanup_old_experiments!
|
45
47
|
expect(@subject.keys).to be_empty
|
46
48
|
end
|
47
49
|
|
48
|
-
it
|
49
|
-
allow(Split::ExperimentCatalog).to receive(:find).with(
|
50
|
+
it "removes key if experiment has a winner" do
|
51
|
+
allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
|
50
52
|
allow(experiment).to receive(:start_time).and_return(Date.today)
|
51
53
|
allow(experiment).to receive(:has_winner?).and_return(true)
|
52
54
|
@subject.cleanup_old_experiments!
|
53
55
|
expect(@subject.keys).to be_empty
|
54
56
|
end
|
55
57
|
|
56
|
-
it
|
57
|
-
allow(Split::ExperimentCatalog).to receive(:find).with(
|
58
|
+
it "removes key if experiment has not started yet" do
|
59
|
+
allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
|
58
60
|
allow(experiment).to receive(:has_winner?).and_return(false)
|
59
61
|
@subject.cleanup_old_experiments!
|
60
62
|
expect(@subject.keys).to be_empty
|
61
63
|
end
|
62
64
|
|
63
|
-
context
|
64
|
-
let(:user_keys) { {
|
65
|
+
context "with finished key" do
|
66
|
+
let(:user_keys) { { "link_color" => "blue", "link_color:finished" => true } }
|
65
67
|
|
66
|
-
it
|
67
|
-
allow(Split::ExperimentCatalog).to receive(:find).with(
|
68
|
-
allow(Split::ExperimentCatalog).to receive(:find).with(
|
68
|
+
it "does not remove finished key for experiment without a winner" do
|
69
|
+
allow(Split::ExperimentCatalog).to receive(:find).with("link_color").and_return(experiment)
|
70
|
+
allow(Split::ExperimentCatalog).to receive(:find).with("link_color:finished").and_return(nil)
|
69
71
|
allow(experiment).to receive(:start_time).and_return(Date.today)
|
70
72
|
allow(experiment).to receive(:has_winner?).and_return(false)
|
71
73
|
@subject.cleanup_old_experiments!
|
@@ -74,33 +76,32 @@ describe Split::User do
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
context
|
79
|
+
context "when already cleaned up" do
|
78
80
|
before do
|
79
81
|
@subject.cleanup_old_experiments!
|
80
82
|
end
|
81
83
|
|
82
|
-
it
|
84
|
+
it "does not clean up again" do
|
83
85
|
expect(@subject).to_not receive(:keys_without_finished)
|
84
86
|
@subject.cleanup_old_experiments!
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
context
|
90
|
-
it
|
91
|
+
context "allows user to be loaded from adapter" do
|
92
|
+
it "loads user from adapter (RedisAdapter)" do
|
91
93
|
user = Split::Persistence::RedisAdapter.new(nil, 112233)
|
92
|
-
user[
|
94
|
+
user["foo"] = "bar"
|
93
95
|
|
94
96
|
ab_user = Split::User.find(112233, :redis)
|
95
97
|
|
96
|
-
expect(ab_user[
|
98
|
+
expect(ab_user["foo"]).to eql("bar")
|
97
99
|
end
|
98
100
|
|
99
|
-
it
|
101
|
+
it "returns nil if adapter does not implement a finder method" do
|
100
102
|
ab_user = Split::User.find(112233, :dual_adapter)
|
101
103
|
expect(ab_user).to be_nil
|
102
104
|
end
|
103
|
-
|
104
105
|
end
|
105
106
|
|
106
107
|
context "instantiated with custom adapter" do
|
@@ -114,5 +115,4 @@ describe Split::User do
|
|
114
115
|
expect(@subject.user).to eq(custom_adapter)
|
115
116
|
end
|
116
117
|
end
|
117
|
-
|
118
118
|
end
|
data/split.gemspec
CHANGED
@@ -9,36 +9,36 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.version = Split::VERSION
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
11
|
s.authors = ["Andrew Nesbitt"]
|
12
|
-
s.licenses = [
|
12
|
+
s.licenses = ["MIT"]
|
13
13
|
s.email = ["andrewnez@gmail.com"]
|
14
14
|
s.homepage = "https://github.com/splitrb/split"
|
15
15
|
s.summary = "Rack based split testing framework"
|
16
16
|
|
17
17
|
s.metadata = {
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
"homepage_uri" => "https://github.com/splitrb/split",
|
19
|
+
"changelog_uri" => "https://github.com/splitrb/split/blob/main/CHANGELOG.md",
|
20
|
+
"source_code_uri" => "https://github.com/splitrb/split",
|
21
|
+
"bug_tracker_uri" => "https://github.com/splitrb/split/issues",
|
22
|
+
"wiki_uri" => "https://github.com/splitrb/split/wiki",
|
23
|
+
"mailing_list_uri" => "https://groups.google.com/d/forum/split-ruby"
|
24
|
+
}
|
25
25
|
|
26
|
-
s.required_ruby_version =
|
27
|
-
s.required_rubygems_version =
|
26
|
+
s.required_ruby_version = ">= 2.5.0"
|
27
|
+
s.required_rubygems_version = ">= 2.0.0"
|
28
28
|
|
29
29
|
s.files = `git ls-files`.split("\n")
|
30
30
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
31
31
|
s.require_paths = ["lib"]
|
32
32
|
|
33
|
-
s.add_dependency
|
34
|
-
s.add_dependency
|
35
|
-
s.add_dependency
|
33
|
+
s.add_dependency "redis", ">= 4.2"
|
34
|
+
s.add_dependency "sinatra", ">= 1.2.6"
|
35
|
+
s.add_dependency "rubystats", ">= 0.3.0"
|
36
36
|
|
37
|
-
s.add_development_dependency
|
38
|
-
s.add_development_dependency
|
39
|
-
s.add_development_dependency
|
40
|
-
s.add_development_dependency
|
41
|
-
s.add_development_dependency
|
42
|
-
s.add_development_dependency
|
43
|
-
s.add_development_dependency
|
37
|
+
s.add_development_dependency "bundler", ">= 1.17"
|
38
|
+
s.add_development_dependency "simplecov", "~> 0.15"
|
39
|
+
s.add_development_dependency "rack-test", "~> 2.0"
|
40
|
+
s.add_development_dependency "rake", "~> 13"
|
41
|
+
s.add_development_dependency "rspec", "~> 3.7"
|
42
|
+
s.add_development_dependency "pry", "~> 0.10"
|
43
|
+
s.add_development_dependency "rails", ">= 5.0"
|
44
44
|
end
|