abingo 1.1.0
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.
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +92 -0
- data/MIT-LICENSE +20 -0
- data/README +109 -0
- data/Rakefile +24 -0
- data/abingo.gemspec +19 -0
- data/generators/abingo_migration/abingo_migration_generator.rb +24 -0
- data/generators/abingo_migration/templates/abingo_migration.rb +31 -0
- data/lib/abingo.rb +315 -0
- data/lib/abingo/alternative.rb +25 -0
- data/lib/abingo/controller/dashboard.rb +29 -0
- data/lib/abingo/conversion_rate.rb +9 -0
- data/lib/abingo/experiment.rb +107 -0
- data/lib/abingo/rails/controller/dashboard.rb +13 -0
- data/lib/abingo/statistics.rb +90 -0
- data/lib/abingo/version.rb +3 -0
- data/lib/abingo/views/dashboard/_experiment.erb +43 -0
- data/lib/abingo/views/dashboard/index.erb +20 -0
- data/lib/abingo_sugar.rb +49 -0
- data/lib/abingo_view_helper.rb +45 -0
- data/strip.rb +11 -0
- data/test/abingo_test.rb +187 -0
- data/test/test_helper.rb +34 -0
- data/uninstall.rb +1 -0
- metadata +89 -0
data/strip.rb
ADDED
data/test/abingo_test.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AbingoTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
#Wipes cache, D/B prior to doing a test run.
|
6
|
+
Abingo.cache.clear
|
7
|
+
Abingo::Experiment.delete_all
|
8
|
+
Abingo::Alternative.delete_all
|
9
|
+
|
10
|
+
test "identity automatically assigned" do
|
11
|
+
assert Abingo.identity != nil
|
12
|
+
end
|
13
|
+
|
14
|
+
test "alternative parsing" do
|
15
|
+
array = %w{a b c}
|
16
|
+
assert_equal array, Abingo.parse_alternatives(array)
|
17
|
+
assert_equal 65, Abingo.parse_alternatives(65).size
|
18
|
+
assert_equal 4, Abingo.parse_alternatives(2..5).size
|
19
|
+
assert !(Abingo.parse_alternatives(2..5).include? 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
test "experiment creation" do
|
23
|
+
assert_equal 0, Abingo::Experiment.count
|
24
|
+
assert_equal 0, Abingo::Alternative.count
|
25
|
+
alternatives = %w{A B}
|
26
|
+
alternative_selected = Abingo.test("unit_test_sample_A", alternatives)
|
27
|
+
assert_equal 1, Abingo::Experiment.count
|
28
|
+
assert_equal 2, Abingo::Alternative.count
|
29
|
+
assert alternatives.include?(alternative_selected)
|
30
|
+
end
|
31
|
+
|
32
|
+
test "exists works right" do
|
33
|
+
Abingo.test("exist works right", %w{does does_not})
|
34
|
+
assert Abingo::Experiment.exists?("exist works right")
|
35
|
+
end
|
36
|
+
|
37
|
+
test "alternatives picked consistently" do
|
38
|
+
alternative_picked = Abingo.test("consistency_test", 1..100)
|
39
|
+
100.times do
|
40
|
+
assert_equal alternative_picked, Abingo.test("consistency_test", 1..100)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
test "participation works" do
|
45
|
+
new_tests = %w{participationA participationB participationC}
|
46
|
+
new_tests.map do |test_name|
|
47
|
+
Abingo.test(test_name, 1..5)
|
48
|
+
end
|
49
|
+
|
50
|
+
participating_tests = Abingo.cache.read("Abingo::participating_tests::#{Abingo.identity}") || []
|
51
|
+
|
52
|
+
new_tests.map do |test_name|
|
53
|
+
assert participating_tests.include? test_name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
test "participants counted" do
|
58
|
+
test_name = "participants_counted_test"
|
59
|
+
alternative = Abingo.test(test_name, %w{a b c})
|
60
|
+
|
61
|
+
ex = Abingo::Experiment.find_by_test_name(test_name)
|
62
|
+
lookup = Abingo::Alternative.calculate_lookup(test_name, alternative)
|
63
|
+
chosen_alt = Abingo::Alternative.find_by_lookup(lookup)
|
64
|
+
assert_equal 1, ex.participants
|
65
|
+
assert_equal 1, chosen_alt.participants
|
66
|
+
end
|
67
|
+
|
68
|
+
test "conversion tracking by test name" do
|
69
|
+
test_name = "conversion_test_by_name"
|
70
|
+
alternative = Abingo.test(test_name, %w{a b c})
|
71
|
+
Abingo.bingo!(test_name)
|
72
|
+
ex = Abingo::Experiment.find_by_test_name(test_name)
|
73
|
+
lookup = Abingo::Alternative.calculate_lookup(test_name, alternative)
|
74
|
+
chosen_alt = Abingo::Alternative.find_by_lookup(lookup)
|
75
|
+
assert_equal 1, ex.conversions
|
76
|
+
assert_equal 1, chosen_alt.conversions
|
77
|
+
Abingo.bingo!(test_name)
|
78
|
+
|
79
|
+
#Should still only have one because this conversion should not be double counted.
|
80
|
+
#We haven't specified that in the test options.
|
81
|
+
assert_equal 1, Abingo::Experiment.find_by_test_name(test_name).conversions
|
82
|
+
end
|
83
|
+
|
84
|
+
test "conversion tracking by conversion name" do
|
85
|
+
conversion_name = "purchase"
|
86
|
+
tests = %w{conversionTrackingByConversionNameA conversionTrackingByConversionNameB conversionTrackingByConversionNameC}
|
87
|
+
tests.map do |test_name|
|
88
|
+
Abingo.test(test_name, %w{A B}, :conversion => conversion_name)
|
89
|
+
end
|
90
|
+
|
91
|
+
Abingo.bingo!(conversion_name)
|
92
|
+
tests.map do |test_name|
|
93
|
+
assert_equal 1, Abingo::Experiment.find_by_test_name(test_name).conversions
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
test "short circuiting works" do
|
98
|
+
conversion_name = "purchase"
|
99
|
+
test_name = "short circuit test"
|
100
|
+
alt_picked = Abingo.test(test_name, %w{A B}, :conversion => conversion_name)
|
101
|
+
ex = Abingo::Experiment.find_by_test_name(test_name)
|
102
|
+
alt_not_picked = (%w{A B} - [alt_picked]).first
|
103
|
+
|
104
|
+
ex.end_experiment!(alt_not_picked, conversion_name)
|
105
|
+
|
106
|
+
ex.reload
|
107
|
+
assert_equal "Finished", ex.status
|
108
|
+
|
109
|
+
Abingo.bingo!(test_name) #Should not be counted, test is over.
|
110
|
+
assert_equal 0, ex.conversions
|
111
|
+
|
112
|
+
old_identity = Abingo.identity
|
113
|
+
Abingo.identity = "shortCircuitTestNewIdentity"
|
114
|
+
Abingo.test(test_name, %w{A B}, :conversion => conversion_name)
|
115
|
+
Abingo.identity = old_identity
|
116
|
+
ex.reload
|
117
|
+
assert_equal 1, ex.participants #Original identity counted, new identity not counted b/c test stopped
|
118
|
+
end
|
119
|
+
|
120
|
+
test "proper experiment creation in high concurrency" do
|
121
|
+
conversion_name = "purchase"
|
122
|
+
test_name = "high_concurrency_test"
|
123
|
+
alternatives = %w{foo bar}
|
124
|
+
|
125
|
+
threads = []
|
126
|
+
5.times do
|
127
|
+
threads << Thread.new do
|
128
|
+
Abingo.test(test_name, alternatives, conversion_name)
|
129
|
+
1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
sleep(10)
|
133
|
+
assert_equal 1, Abingo::Experiment.count_by_sql(["select count(id) from experiments where test_name = ?", test_name])
|
134
|
+
end
|
135
|
+
|
136
|
+
test "non-humans are ignored for participation and conversions if not explicitly counted" do
|
137
|
+
Abingo.options[:count_humans_only] = true
|
138
|
+
Abingo.options[:expires_in] = 1.hour
|
139
|
+
Abingo.options[:expires_in_for_bots] = 3.seconds
|
140
|
+
first_identity = Abingo.identity = "unsure_if_human#{Time.now.to_i}"
|
141
|
+
test_name = "are_you_a_human"
|
142
|
+
Abingo.test(test_name, %w{does_not matter})
|
143
|
+
|
144
|
+
assert_false Abingo.is_human?, "Identity not marked as human yet."
|
145
|
+
|
146
|
+
ex = Abingo::Experiment.find_by_test_name(test_name)
|
147
|
+
Abingo.bingo!(test_name)
|
148
|
+
assert_equal 0, ex.participants, "Not human yet, so should have no participants."
|
149
|
+
assert_equal 0, ex.conversions, "Not human yet, so should have no conversions."
|
150
|
+
|
151
|
+
Abingo.human!
|
152
|
+
|
153
|
+
#Setting up second participant who doesn't convert.
|
154
|
+
Abingo.identity = "unsure_if_human_2_#{Time.now.to_i}"
|
155
|
+
Abingo.test(test_name, %w{does_not matter})
|
156
|
+
Abingo.human!
|
157
|
+
|
158
|
+
ex = Abingo::Experiment.find_by_test_name(test_name)
|
159
|
+
assert_equal 2, ex.participants, "Now that we're human, our participation should matter."
|
160
|
+
assert_equal 1, ex.conversions, "Now that we're human, our conversions should matter, but only one of us converted."
|
161
|
+
end
|
162
|
+
|
163
|
+
test "Participating tests for a given identity" do
|
164
|
+
Abingo.identity = "test_participant"
|
165
|
+
test_names = (1..3).map {|t| "participating_test_test_name #{t}"}
|
166
|
+
test_alternatives = %w{yes no}
|
167
|
+
test_names.each {|test_name| Abingo.test(test_name, test_alternatives)}
|
168
|
+
ex = Abingo::Experiment.last
|
169
|
+
ex.end_experiment!("no") #End final of 3 tests, leaving 2 presently running
|
170
|
+
|
171
|
+
assert_equal 2, Abingo.participating_tests.size #Pairs for two tests
|
172
|
+
Abingo.participating_tests.each do |key, value|
|
173
|
+
assert test_names.include? key
|
174
|
+
assert test_alternatives.include? value
|
175
|
+
end
|
176
|
+
|
177
|
+
assert_equal 3, Abingo.participating_tests(false).size #pairs for three tests
|
178
|
+
Abingo.participating_tests(false).each do |key, value|
|
179
|
+
assert test_names.include? key
|
180
|
+
assert test_alternatives.include? value
|
181
|
+
end
|
182
|
+
|
183
|
+
Abingo.identity = "test_nonparticipant"
|
184
|
+
assert_equal({}, Abingo.participating_tests)
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
if Rails::VERSION::MAJOR.to_i >= 3
|
5
|
+
require 'rails/all'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
require 'active_support'
|
9
|
+
require 'active_support/railtie'
|
10
|
+
require 'active_support/core_ext'
|
11
|
+
require 'active_support/test_case'
|
12
|
+
|
13
|
+
require 'action_controller'
|
14
|
+
require 'action_controller/caching'
|
15
|
+
require 'active_record'
|
16
|
+
require 'active_record/base'
|
17
|
+
|
18
|
+
require 'rails'
|
19
|
+
require 'rails/application'
|
20
|
+
|
21
|
+
require 'rails/railtie'
|
22
|
+
|
23
|
+
#We need to load the whole Rails application to properly initialize Rails.cache and other constants. Oh boy.
|
24
|
+
#We're going to parse it out of RAILS_PATH/config.ru using a little metaprogramming magic.
|
25
|
+
require ::File.expand_path('../../../../../config/environment', __FILE__)
|
26
|
+
lines = File.open(::File.expand_path('../../../../../config.ru', __FILE__)).readlines.select {|a| a =~ /::Application/}
|
27
|
+
application_name = lines.first[/[^ ]*::/].gsub(":", "")
|
28
|
+
Kernel.const_get(application_name).const_get("Application").initialize!
|
29
|
+
else
|
30
|
+
#Rails 2 testing
|
31
|
+
require 'active_support'
|
32
|
+
require 'active_support/test_case'
|
33
|
+
end
|
34
|
+
|
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: abingo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Glenn Gillen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &70225544745500 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70225544745500
|
25
|
+
description: A split testing framework for Rails 3.x.x
|
26
|
+
email:
|
27
|
+
- me@glenngillen.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- Gemfile.lock
|
35
|
+
- MIT-LICENSE
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- abingo.gemspec
|
39
|
+
- generators/abingo_migration/abingo_migration_generator.rb
|
40
|
+
- generators/abingo_migration/templates/abingo_migration.rb
|
41
|
+
- lib/abingo.rb
|
42
|
+
- lib/abingo/alternative.rb
|
43
|
+
- lib/abingo/controller/dashboard.rb
|
44
|
+
- lib/abingo/conversion_rate.rb
|
45
|
+
- lib/abingo/experiment.rb
|
46
|
+
- lib/abingo/rails/controller/dashboard.rb
|
47
|
+
- lib/abingo/statistics.rb
|
48
|
+
- lib/abingo/version.rb
|
49
|
+
- lib/abingo/views/dashboard/_experiment.erb
|
50
|
+
- lib/abingo/views/dashboard/index.erb
|
51
|
+
- lib/abingo_sugar.rb
|
52
|
+
- lib/abingo_view_helper.rb
|
53
|
+
- strip.rb
|
54
|
+
- test/abingo_test.rb
|
55
|
+
- test/test_helper.rb
|
56
|
+
- uninstall.rb
|
57
|
+
homepage: https://github.com/glenngillen/abingo
|
58
|
+
licenses: []
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
hash: -3437429555840451377
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
hash: -3437429555840451377
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.15
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: The ABingo split testing framework for Rails 3.x.x from Patrick McKenzie
|
87
|
+
test_files:
|
88
|
+
- test/abingo_test.rb
|
89
|
+
- test/test_helper.rb
|