split 0.7.2 → 0.7.3

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.
@@ -71,7 +71,7 @@
71
71
  <% end %>
72
72
  <% else %>
73
73
  <form action="<%= url experiment.name %>" method='post' onclick="return confirmWinner()">
74
- <input type='hidden' name='alternative' value='<%= alternative.name %>'>
74
+ <input type='hidden' name='alternative' value='<%= h alternative.name %>'>
75
75
  <input type="submit" value="Use this" class="green">
76
76
  </form>
77
77
  <% end %>
@@ -27,12 +27,13 @@ module Split
27
27
  else
28
28
  control_variable(control)
29
29
  end
30
- rescue Errno::ECONNREFUSED => e
30
+ rescue Errno::ECONNREFUSED, Redis::CannotConnectError => e
31
31
  raise(e) unless Split.configuration.db_failover
32
32
  Split.configuration.db_failover_on_db_error.call(e)
33
33
 
34
- if Split.configuration.db_failover_allow_parameter_override && override_present?(experiment_name)
35
- ret = override_alternative(experiment_name)
34
+ if Split.configuration.db_failover_allow_parameter_override
35
+ ret = override_alternative(experiment_name) if override_present?(experiment_name)
36
+ ret = control_variable(control) if split_generically_disabled?
36
37
  end
37
38
  ensure
38
39
  ret ||= control_variable(control)
@@ -97,6 +98,10 @@ module Split
97
98
  params[experiment_name] if override_present?(experiment_name)
98
99
  end
99
100
 
101
+ def split_generically_disabled?
102
+ defined?(params) && params['SPLIT_DISABLE']
103
+ end
104
+
100
105
  def begin_experiment(experiment, alternative_name = nil)
101
106
  alternative_name ||= experiment.control.name
102
107
  ab_user[experiment.key] = alternative_name
@@ -169,6 +174,9 @@ module Split
169
174
  if override_present?(experiment.name) and experiment[override_alternative(experiment.name)]
170
175
  ret = override_alternative(experiment.name)
171
176
  ab_user[experiment.key] = ret if Split.configuration.store_override
177
+ elsif split_generically_disabled?
178
+ ret = experiment.control.name
179
+ ab_user[experiment.key] = ret if Split.configuration.store_override
172
180
  elsif experiment.has_winner?
173
181
  ret = experiment.winner.name
174
182
  else
@@ -1,6 +1,6 @@
1
1
  module Split
2
2
  MAJOR = 0
3
3
  MINOR = 7
4
- PATCH = 2
4
+ PATCH = 3
5
5
  VERSION = [MAJOR, MINOR, PATCH].join('.')
6
6
  end
@@ -3,16 +3,16 @@ require "spec_helper"
3
3
  describe Split::Algorithms::WeightedSample do
4
4
  it "should return an alternative" do
5
5
  experiment = Split::Experiment.find_or_create('link_color', {'blue' => 100}, {'red' => 0 })
6
- Split::Algorithms::WeightedSample.choose_alternative(experiment).class.should == Split::Alternative
6
+ expect(Split::Algorithms::WeightedSample.choose_alternative(experiment).class).to eq(Split::Alternative)
7
7
  end
8
8
 
9
9
  it "should always return a heavily weighted option" do
10
10
  experiment = Split::Experiment.find_or_create('link_color', {'blue' => 100}, {'red' => 0 })
11
- Split::Algorithms::WeightedSample.choose_alternative(experiment).name.should == 'blue'
11
+ expect(Split::Algorithms::WeightedSample.choose_alternative(experiment).name).to eq('blue')
12
12
  end
13
13
 
14
14
  it "should return one of the results" do
15
15
  experiment = Split::Experiment.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
16
- ['red', 'blue'].should include Split::Algorithms::WeightedSample.choose_alternative(experiment).name
16
+ expect(['red', 'blue']).to include Split::Algorithms::WeightedSample.choose_alternative(experiment).name
17
17
  end
18
- end
18
+ end
@@ -4,20 +4,20 @@ describe Split::Algorithms::Whiplash do
4
4
 
5
5
  it "should return an algorithm" do
6
6
  experiment = Split::Experiment.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
7
- Split::Algorithms::Whiplash.choose_alternative(experiment).class.should == Split::Alternative
7
+ expect(Split::Algorithms::Whiplash.choose_alternative(experiment).class).to eq(Split::Alternative)
8
8
  end
9
9
 
10
10
  it "should return one of the results" do
11
11
  experiment = Split::Experiment.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
12
- ['red', 'blue'].should include Split::Algorithms::Whiplash.choose_alternative(experiment).name
12
+ expect(['red', 'blue']).to include Split::Algorithms::Whiplash.choose_alternative(experiment).name
13
13
  end
14
14
 
15
15
  it "should guess floats" do
16
- Split::Algorithms::Whiplash.send(:arm_guess, 0, 0).class.should == Float
17
- Split::Algorithms::Whiplash.send(:arm_guess, 1, 0).class.should == Float
18
- Split::Algorithms::Whiplash.send(:arm_guess, 2, 1).class.should == Float
19
- Split::Algorithms::Whiplash.send(:arm_guess, 1000, 5).class.should == Float
20
- Split::Algorithms::Whiplash.send(:arm_guess, 10, -2).class.should == Float
16
+ expect(Split::Algorithms::Whiplash.send(:arm_guess, 0, 0).class).to eq(Float)
17
+ expect(Split::Algorithms::Whiplash.send(:arm_guess, 1, 0).class).to eq(Float)
18
+ expect(Split::Algorithms::Whiplash.send(:arm_guess, 2, 1).class).to eq(Float)
19
+ expect(Split::Algorithms::Whiplash.send(:arm_guess, 1000, 5).class).to eq(Float)
20
+ expect(Split::Algorithms::Whiplash.send(:arm_guess, 10, -2).class).to eq(Float)
21
21
  end
22
22
 
23
- end
23
+ end
@@ -19,23 +19,23 @@ describe Split::Alternative do
19
19
  let(:goal2) { "refund" }
20
20
 
21
21
  it "should have goals" do
22
- alternative.goals.should eql(["purchase", "refund"])
22
+ expect(alternative.goals).to eq(["purchase", "refund"])
23
23
  end
24
24
 
25
25
  it "should have and only return the name" do
26
- alternative.name.should eql('Basket')
26
+ expect(alternative.name).to eq('Basket')
27
27
  end
28
28
 
29
29
  describe 'weights' do
30
30
  it "should set the weights" do
31
31
  experiment = Split::Experiment.new('basket_text', :alternatives => [{'Basket' => 0.6}, {"Cart" => 0.4}])
32
32
  first = experiment.alternatives[0]
33
- first.name.should == 'Basket'
34
- first.weight.should == 0.6
33
+ expect(first.name).to eq('Basket')
34
+ expect(first.weight).to eq(0.6)
35
35
 
36
36
  second = experiment.alternatives[1]
37
- second.name.should == 'Cart'
38
- second.weight.should == 0.4
37
+ expect(second.name).to eq('Cart')
38
+ expect(second.weight).to eq(0.4)
39
39
  end
40
40
 
41
41
  it "accepts probability on alternatives" do
@@ -50,12 +50,12 @@ describe Split::Alternative do
50
50
  }
51
51
  experiment = Split::Experiment.new(:my_experiment)
52
52
  first = experiment.alternatives[0]
53
- first.name.should == 'control_opt'
54
- first.weight.should == 0.67
53
+ expect(first.name).to eq('control_opt')
54
+ expect(first.weight).to eq(0.67)
55
55
 
56
56
  second = experiment.alternatives[1]
57
- second.name.should == 'second_opt'
58
- second.weight.should == 0.1
57
+ expect(second.name).to eq('second_opt')
58
+ expect(second.weight).to eq(0.1)
59
59
  end
60
60
 
61
61
  it "accepts probability on some alternatives" do
@@ -79,8 +79,8 @@ describe Split::Alternative do
79
79
  ].each do |h|
80
80
  name, weight = h
81
81
  alt = alts.shift
82
- alt.name.should == name
83
- alt.weight.should == weight
82
+ expect(alt.name).to eq(name)
83
+ expect(alt.weight).to eq(weight)
84
84
  end
85
85
  end
86
86
  #
@@ -103,35 +103,35 @@ describe Split::Alternative do
103
103
  ].each do |h|
104
104
  name, weight = h
105
105
  alt = alts.shift
106
- alt.name.should == name
107
- alt.weight.should == weight
106
+ expect(alt.name).to eq(name)
107
+ expect(alt.weight).to eq(weight)
108
108
  end
109
109
  end
110
110
  end
111
111
 
112
112
  it "should have a default participation count of 0" do
113
- alternative.participant_count.should eql(0)
113
+ expect(alternative.participant_count).to eq(0)
114
114
  end
115
115
 
116
116
  it "should have a default completed count of 0 for each goal" do
117
- alternative.completed_count.should eql(0)
118
- alternative.completed_count(goal1).should eql(0)
119
- alternative.completed_count(goal2).should eql(0)
117
+ expect(alternative.completed_count).to eq(0)
118
+ expect(alternative.completed_count(goal1)).to eq(0)
119
+ expect(alternative.completed_count(goal2)).to eq(0)
120
120
  end
121
121
 
122
122
  it "should belong to an experiment" do
123
- alternative.experiment.name.should eql(experiment.name)
123
+ expect(alternative.experiment.name).to eq(experiment.name)
124
124
  end
125
125
 
126
126
  it "should save to redis" do
127
127
  alternative.save
128
- Split.redis.exists('basket_text:Basket').should be true
128
+ expect(Split.redis.exists('basket_text:Basket')).to be true
129
129
  end
130
130
 
131
131
  it "should increment participation count" do
132
132
  old_participant_count = alternative.participant_count
133
133
  alternative.increment_participation
134
- alternative.participant_count.should eql(old_participant_count+1)
134
+ expect(alternative.participant_count).to eq(old_participant_count+1)
135
135
  end
136
136
 
137
137
  it "should increment completed count for each goal" do
@@ -143,9 +143,9 @@ describe Split::Alternative do
143
143
  alternative.increment_completion(goal1)
144
144
  alternative.increment_completion(goal2)
145
145
 
146
- alternative.completed_count.should eql(old_default_completed_count+1)
147
- alternative.completed_count(goal1).should eql(old_completed_count_for_goal1+1)
148
- alternative.completed_count(goal2).should eql(old_completed_count_for_goal2+1)
146
+ expect(alternative.completed_count).to eq(old_default_completed_count+1)
147
+ expect(alternative.completed_count(goal1)).to eq(old_completed_count_for_goal1+1)
148
+ expect(alternative.completed_count(goal2)).to eq(old_completed_count_for_goal2+1)
149
149
  end
150
150
 
151
151
  it "can be reset" do
@@ -154,21 +154,21 @@ describe Split::Alternative do
154
154
  alternative.set_completed_count(5, goal2)
155
155
  alternative.set_completed_count(6)
156
156
  alternative.reset
157
- alternative.participant_count.should eql(0)
158
- alternative.completed_count(goal1).should eql(0)
159
- alternative.completed_count(goal2).should eql(0)
160
- alternative.completed_count.should eql(0)
157
+ expect(alternative.participant_count).to eq(0)
158
+ expect(alternative.completed_count(goal1)).to eq(0)
159
+ expect(alternative.completed_count(goal2)).to eq(0)
160
+ expect(alternative.completed_count).to eq(0)
161
161
  end
162
162
 
163
163
  it "should know if it is the control of an experiment" do
164
- alternative.control?.should be_true
165
- alternative2.control?.should be_false
164
+ expect(alternative.control?).to be_truthy
165
+ expect(alternative2.control?).to be_falsey
166
166
  end
167
167
 
168
168
  describe 'unfinished_count' do
169
169
  it "should be difference between participant and completed counts" do
170
170
  alternative.increment_participation
171
- alternative.unfinished_count.should eql(alternative.participant_count)
171
+ expect(alternative.unfinished_count).to eq(alternative.participant_count)
172
172
  end
173
173
 
174
174
  it "should return the correct unfinished_count" do
@@ -177,35 +177,35 @@ describe Split::Alternative do
177
177
  alternative.set_completed_count(3, goal2)
178
178
  alternative.set_completed_count(2)
179
179
 
180
- alternative.unfinished_count.should eql(1)
180
+ expect(alternative.unfinished_count).to eq(1)
181
181
  end
182
182
  end
183
183
 
184
184
  describe 'conversion rate' do
185
185
  it "should be 0 if there are no conversions" do
186
- alternative.completed_count.should eql(0)
187
- alternative.conversion_rate.should eql(0)
186
+ expect(alternative.completed_count).to eq(0)
187
+ expect(alternative.conversion_rate).to eq(0)
188
188
  end
189
189
 
190
190
  it "calculate conversion rate" do
191
- alternative.stub(:participant_count).and_return(10)
192
- alternative.stub(:completed_count).and_return(4)
193
- alternative.conversion_rate.should eql(0.4)
191
+ expect(alternative).to receive(:participant_count).exactly(6).times.and_return(10)
192
+ expect(alternative).to receive(:completed_count).and_return(4)
193
+ expect(alternative.conversion_rate).to eq(0.4)
194
194
 
195
- alternative.stub(:completed_count).with(goal1).and_return(5)
196
- alternative.conversion_rate(goal1).should eql(0.5)
195
+ expect(alternative).to receive(:completed_count).with(goal1).and_return(5)
196
+ expect(alternative.conversion_rate(goal1)).to eq(0.5)
197
197
 
198
- alternative.stub(:completed_count).with(goal2).and_return(6)
199
- alternative.conversion_rate(goal2).should eql(0.6)
198
+ expect(alternative).to receive(:completed_count).with(goal2).and_return(6)
199
+ expect(alternative.conversion_rate(goal2)).to eq(0.6)
200
200
  end
201
201
  end
202
202
 
203
203
  describe 'z score' do
204
204
 
205
205
  it "should return an error string when the control has 0 people" do
206
- alternative2.z_score.should eql("Needs 30+ participants.")
207
- alternative2.z_score(goal1).should eql("Needs 30+ participants.")
208
- alternative2.z_score(goal2).should eql("Needs 30+ participants.")
206
+ expect(alternative2.z_score).to eq("Needs 30+ participants.")
207
+ expect(alternative2.z_score(goal1)).to eq("Needs 30+ participants.")
208
+ expect(alternative2.z_score(goal2)).to eq("Needs 30+ participants.")
209
209
  end
210
210
 
211
211
  it "should return an error string when the data is skewed or incomplete as per the np > 5 test" do
@@ -216,7 +216,7 @@ describe Split::Alternative do
216
216
  alternative2.participant_count = 50
217
217
  alternative2.set_completed_count(1)
218
218
 
219
- alternative2.z_score.should eql("Needs 5+ conversions.")
219
+ expect(alternative2.z_score).to eq("Needs 5+ conversions.")
220
220
  end
221
221
 
222
222
  it "should return a float for a z_score given proper data" do
@@ -227,8 +227,8 @@ describe Split::Alternative do
227
227
  alternative2.participant_count = 100
228
228
  alternative2.set_completed_count(25)
229
229
 
230
- alternative2.z_score.should be_kind_of(Float)
231
- alternative2.z_score.should_not eql(0)
230
+ expect(alternative2.z_score).to be_kind_of(Float)
231
+ expect(alternative2.z_score).to_not eq(0)
232
232
  end
233
233
 
234
234
  it "should correctly calculate a z_score given proper data" do
@@ -239,14 +239,14 @@ describe Split::Alternative do
239
239
  alternative2.participant_count = 142
240
240
  alternative2.set_completed_count(119)
241
241
 
242
- alternative2.z_score.round(2).should eql(2.58)
242
+ expect(alternative2.z_score.round(2)).to eq(2.58)
243
243
  end
244
244
 
245
245
  it "should be N/A for the control" do
246
246
  control = experiment.control
247
- control.z_score.should eql('N/A')
248
- control.z_score(goal1).should eql('N/A')
249
- control.z_score(goal2).should eql('N/A')
247
+ expect(control.z_score).to eq('N/A')
248
+ expect(control.z_score(goal1)).to eq('N/A')
249
+ expect(control.z_score(goal2)).to eq('N/A')
250
250
  end
251
251
  end
252
252
  end
@@ -5,69 +5,69 @@ describe Split::Configuration do
5
5
  before(:each) { @config = Split::Configuration.new }
6
6
 
7
7
  it "should provide a default value for ignore_ip_addresses" do
8
- @config.ignore_ip_addresses.should eql([])
8
+ expect(@config.ignore_ip_addresses).to eq([])
9
9
  end
10
10
 
11
11
  it "should provide default values for db failover" do
12
- @config.db_failover.should be_false
13
- @config.db_failover_on_db_error.should be_a Proc
12
+ expect(@config.db_failover).to be_falsey
13
+ expect(@config.db_failover_on_db_error).to be_a Proc
14
14
  end
15
15
 
16
16
  it "should not allow multiple experiments by default" do
17
- @config.allow_multiple_experiments.should be_false
17
+ expect(@config.allow_multiple_experiments).to be_falsey
18
18
  end
19
19
 
20
20
  it "should be enabled by default" do
21
- @config.enabled.should be_true
21
+ expect(@config.enabled).to be_truthy
22
22
  end
23
23
 
24
24
  it "disabled is the opposite of enabled" do
25
25
  @config.enabled = false
26
- @config.disabled?.should be_true
26
+ expect(@config.disabled?).to be_truthy
27
27
  end
28
28
 
29
29
  it "should not store the overridden test group per default" do
30
- @config.store_override.should be_false
30
+ expect(@config.store_override).to be_falsey
31
31
  end
32
32
 
33
33
  it "should provide a default pattern for robots" do
34
34
  %w[Baidu Gigabot Googlebot libwww-perl lwp-trivial msnbot SiteUptime Slurp WordPress ZIBB ZyBorg YandexBot AdsBot-Google Wget curl bitlybot facebookexternalhit spider].each do |robot|
35
- @config.robot_regex.should =~ robot
35
+ expect(@config.robot_regex).to match(robot)
36
36
  end
37
37
 
38
- @config.robot_regex.should =~ "EventMachine HttpClient"
39
- @config.robot_regex.should =~ "libwww-perl/5.836"
40
- @config.robot_regex.should =~ "Pingdom.com_bot_version_1.4_(http://www.pingdom.com)"
38
+ expect(@config.robot_regex).to match("EventMachine HttpClient")
39
+ expect(@config.robot_regex).to match("libwww-perl/5.836")
40
+ expect(@config.robot_regex).to match("Pingdom.com_bot_version_1.4_(http://www.pingdom.com)")
41
41
 
42
- @config.robot_regex.should =~ " - "
42
+ expect(@config.robot_regex).to match(" - ")
43
43
  end
44
44
 
45
45
  it "should accept real UAs with the robot regexp" do
46
- @config.robot_regex.should_not =~ "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.4) Gecko/20091017 SeaMonkey/2.0"
47
- @config.robot_regex.should_not =~ "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; F-6.0SP2-20041109; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; InfoPath.3)"
46
+ expect(@config.robot_regex).not_to match("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.4) Gecko/20091017 SeaMonkey/2.0")
47
+ expect(@config.robot_regex).not_to match("Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; F-6.0SP2-20041109; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; InfoPath.3)")
48
48
  end
49
49
 
50
50
  it "should allow adding a bot to the bot list" do
51
51
  @config.bots["newbot"] = "An amazing test bot"
52
- @config.robot_regex.should =~ "newbot"
52
+ expect(@config.robot_regex).to match("newbot")
53
53
  end
54
54
 
55
55
  it "should use the session adapter for persistence by default" do
56
- @config.persistence.should eq(Split::Persistence::SessionAdapter)
56
+ expect(@config.persistence).to eq(Split::Persistence::SessionAdapter)
57
57
  end
58
58
 
59
59
  it "should load a metric" do
60
60
  @config.experiments = {:my_experiment=>
61
61
  {:alternatives=>["control_opt", "other_opt"], :metric=>:my_metric}}
62
62
 
63
- @config.metrics.should_not be_nil
64
- @config.metrics.keys.should == [:my_metric]
63
+ expect(@config.metrics).not_to be_nil
64
+ expect(@config.metrics.keys).to eq([:my_metric])
65
65
  end
66
66
 
67
67
  it "should allow loading of experiment using experment_for" do
68
68
  @config.experiments = {:my_experiment=>
69
69
  {:alternatives=>["control_opt", "other_opt"], :metric=>:my_metric}}
70
- @config.experiment_for(:my_experiment).should == {:alternatives=>["control_opt", ["other_opt"]]}
70
+ expect(@config.experiment_for(:my_experiment)).to eq({:alternatives=>["control_opt", ["other_opt"]]})
71
71
  end
72
72
 
73
73
  context "when experiments are defined via YAML" do
@@ -86,7 +86,7 @@ describe Split::Configuration do
86
86
  end
87
87
 
88
88
  it 'should normalize experiments' do
89
- @config.normalized_experiments.should == {:my_experiment=>{:resettable=>false,:alternatives=>["Control Opt", ["Alt One", "Alt Two"]]}}
89
+ expect(@config.normalized_experiments).to eq({:my_experiment=>{:resettable=>false,:alternatives=>["Control Opt", ["Alt One", "Alt Two"]]}})
90
90
  end
91
91
  end
92
92
 
@@ -112,13 +112,13 @@ describe Split::Configuration do
112
112
  end
113
113
 
114
114
  it "should normalize experiments" do
115
- @config.normalized_experiments.should == {:my_experiment=>{:resettable=>false,:alternatives=>[{"Control Opt"=>0.67},
116
- [{"Alt One"=>0.1}, {"Alt Two"=>0.23}]]}, :another_experiment=>{:alternatives=>["a", ["b"]]}}
115
+ expect(@config.normalized_experiments).to eq({:my_experiment=>{:resettable=>false,:alternatives=>[{"Control Opt"=>0.67},
116
+ [{"Alt One"=>0.1}, {"Alt Two"=>0.23}]]}, :another_experiment=>{:alternatives=>["a", ["b"]]}})
117
117
  end
118
118
 
119
119
  it "should recognize metrics" do
120
- @config.metrics.should_not be_nil
121
- @config.metrics.keys.should == [:my_metric]
120
+ expect(@config.metrics).not_to be_nil
121
+ expect(@config.metrics.keys).to eq([:my_metric])
122
122
  end
123
123
  end
124
124
  end
@@ -139,7 +139,7 @@ describe Split::Configuration do
139
139
  end
140
140
 
141
141
  it "should normalize experiments" do
142
- @config.normalized_experiments.should == {:my_experiment=>{:resettable=>false,:alternatives=>["Control Opt", ["Alt One", "Alt Two"]]}}
142
+ expect(@config.normalized_experiments).to eq({:my_experiment=>{:resettable=>false,:alternatives=>["Control Opt", ["Alt One", "Alt Two"]]}})
143
143
  end
144
144
  end
145
145
 
@@ -177,6 +177,6 @@ describe Split::Configuration do
177
177
  }
178
178
  }
179
179
 
180
- @config.normalized_experiments.should == {:my_experiment=>{:alternatives=>[{"control_opt"=>0.67}, [{"second_opt"=>0.1}, {"third_opt"=>0.23}]]}}
180
+ expect(@config.normalized_experiments).to eq({:my_experiment=>{:alternatives=>[{"control_opt"=>0.67}, [{"second_opt"=>0.1}, {"third_opt"=>0.23}]]}})
181
181
  end
182
182
  end