eeny-meeny 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +175 -9
- data/eeny-meeny.gemspec +3 -2
- data/lib/eeny-meeny.rb +28 -1
- data/lib/eeny-meeny/experiment_helper.rb +12 -10
- data/lib/eeny-meeny/middleware.rb +14 -21
- data/lib/eeny-meeny/models/cookie.rb +104 -0
- data/lib/eeny-meeny/{encryptor.rb → models/encryptor.rb} +0 -0
- data/lib/eeny-meeny/{experiment.rb → models/experiment.rb} +19 -2
- data/lib/eeny-meeny/{variation.rb → models/variation.rb} +0 -0
- data/lib/eeny-meeny/railtie.rb +15 -14
- data/lib/eeny-meeny/routing/experiment_constraint.rb +19 -0
- data/lib/eeny-meeny/routing/smoke_test_constraint.rb +15 -0
- data/lib/eeny-meeny/version.rb +1 -1
- data/lib/tasks/cookie.rake +48 -0
- data/spec/eeny-meeny/middleware_spec.rb +15 -18
- data/spec/eeny-meeny/models/cookie_spec.rb +137 -0
- data/spec/eeny-meeny/models/experiment_spec.rb +181 -0
- data/spec/eeny-meeny/{variation_spec.rb → models/variation_spec.rb} +1 -1
- data/spec/eeny-meeny/routing/experiment_constraint_spec.rb +39 -0
- data/spec/eeny-meeny/routing/smoke_test_constraint_spec.rb +35 -0
- data/spec/fixtures/experiments.yml +12 -0
- data/spec/spec_helper.rb +18 -1
- data/spec/tasks/cookie_task_spec.rb +72 -0
- metadata +31 -13
- data/lib/eeny-meeny/middleware_helper.rb +0 -25
- data/lib/eeny-meeny/route_constraint.rb +0 -33
- data/lib/eeny-meeny/shared_methods.rb +0 -23
- data/spec/eeny-meeny/experiment_spec.rb +0 -62
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'eeny-meeny/variation'
|
1
|
+
require 'eeny-meeny/models/variation'
|
2
2
|
require 'active_support/time'
|
3
3
|
require 'active_support/core_ext/enumerable'
|
4
4
|
|
@@ -6,6 +6,17 @@ module EenyMeeny
|
|
6
6
|
class Experiment
|
7
7
|
attr_reader :id, :name, :version, :variations, :total_weight, :end_at, :start_at
|
8
8
|
|
9
|
+
def self.find_all
|
10
|
+
EenyMeeny.config.experiments.map do |id, experiment|
|
11
|
+
new(id, **experiment)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.find_by_id(experiment_id)
|
16
|
+
experiment = EenyMeeny.config.experiments[experiment_id.to_sym]
|
17
|
+
new(experiment_id, **experiment) if experiment
|
18
|
+
end
|
19
|
+
|
9
20
|
def initialize(id, name: '', version: 1, variations: {}, start_at: nil, end_at: nil)
|
10
21
|
@id = id
|
11
22
|
@name = name
|
@@ -14,11 +25,17 @@ module EenyMeeny
|
|
14
25
|
Variation.new(variation_id, **variation)
|
15
26
|
end
|
16
27
|
@total_weight = (@variations.empty? ? 1.0 : @variations.sum { |variation| variation.weight.to_f })
|
17
|
-
|
18
28
|
@start_at = Time.zone.parse(start_at) if start_at
|
19
29
|
@end_at = Time.zone.parse(end_at) if end_at
|
20
30
|
end
|
21
31
|
|
32
|
+
def active?(now = Time.zone.now)
|
33
|
+
return true if @start_at.nil? && @end_at.nil?
|
34
|
+
return true if @end_at.nil? && (@start_at && (now > @start_at)) # specified start - open-ended
|
35
|
+
return true if @start_at.nil? && (@end_at && (now < @end_at)) # unspecified start - specified end
|
36
|
+
!!((@start_at && (now > @start_at)) && (@end_at && (now < @end_at))) # specified start and end
|
37
|
+
end
|
38
|
+
|
22
39
|
def pick_variation
|
23
40
|
Hash[
|
24
41
|
@variations.map do |variation|
|
File without changes
|
data/lib/eeny-meeny/railtie.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
|
+
require 'eeny-meeny'
|
1
2
|
require 'eeny-meeny/experiment_helper'
|
2
3
|
require 'eeny-meeny/middleware'
|
3
4
|
|
4
5
|
module EenyMeeny
|
5
6
|
class Railtie < Rails::Railtie
|
6
7
|
config.eeny_meeny = ActiveSupport::OrderedOptions.new
|
7
|
-
# default config values. these can be changed in the rails environment configuration.
|
8
|
-
config.eeny_meeny.experiments = []
|
9
|
-
config.eeny_meeny.secure = true
|
10
|
-
config.eeny_meeny.secret = '9fc8b966eca7d03d55df40c01c10b8e02bf1f9d12d27b8968d53eb53e8c239902d00bf6afae5e726ce1111159eeb2f8f0e77233405db1d82dd71397f651a0a4f'
|
11
|
-
config.eeny_meeny.cookies = ActiveSupport::OrderedOptions.new
|
12
|
-
config.eeny_meeny.cookies.path = '/'
|
13
|
-
config.eeny_meeny.cookies.same_site = :strict
|
14
8
|
|
15
|
-
initializer 'eeny_meeny.
|
9
|
+
initializer 'eeny_meeny.configure' do |app|
|
10
|
+
# Configrue EenyMeeny (defaults set in eeny_meeny.rb)
|
11
|
+
EenyMeeny.configure do |config|
|
12
|
+
config.cookies = app.config.eeny_meeny[:cookies] if app.config.eeny_meeny.has_key?(:cookies)
|
13
|
+
config.experiments = app.config.eeny_meeny[:experiments] if app.config.eeny_meeny.has_key?(:experiments)
|
14
|
+
config.secret = app.config.eeny_meeny[:secret] if app.config.eeny_meeny.has_key?(:secret)
|
15
|
+
config.secure = app.config.eeny_meeny[:secure] if app.config.eeny_meeny.has_key?(:secure)
|
16
|
+
end
|
17
|
+
# Include Helpers in ActionController and ActionView
|
16
18
|
ActionController::Base.send :include, EenyMeeny::ExperimentHelper
|
17
19
|
ActionView::Base.send :include, EenyMeeny::ExperimentHelper
|
20
|
+
# Insert Middleware
|
21
|
+
app.middleware.insert_before 'ActionDispatch::Cookies', EenyMeeny::Middleware
|
22
|
+
end
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
config.eeny_meeny.secure,
|
22
|
-
config.eeny_meeny.secret,
|
23
|
-
config.eeny_meeny.cookies.path,
|
24
|
-
config.eeny_meeny.cookies.same_site
|
24
|
+
rake_tasks do
|
25
|
+
load 'tasks/cookie.rake'
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'eeny-meeny/models/cookie'
|
2
|
+
require 'eeny-meeny/models/experiment'
|
3
|
+
|
4
|
+
module EenyMeeny
|
5
|
+
class ExperimentConstraint
|
6
|
+
|
7
|
+
def initialize(experiment_id, variation_id: nil)
|
8
|
+
@experiment = EenyMeeny::Experiment.find_by_id(experiment_id)
|
9
|
+
@variation_id = variation_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(request)
|
13
|
+
return false unless @experiment.active?
|
14
|
+
cookie = EenyMeeny::Cookie.read(request.cookie_jar[EenyMeeny::Cookie.cookie_name(@experiment)])
|
15
|
+
return false if cookie.nil? # Not participating in experiment
|
16
|
+
(@variation_id.nil? || @variation_id == cookie[:variation].id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'eeny-meeny/models/cookie'
|
2
|
+
|
3
|
+
module EenyMeeny
|
4
|
+
class SmokeTestConstraint
|
5
|
+
|
6
|
+
def initialize(smoke_test_id, version: 1)
|
7
|
+
@smoke_test_cookie_name = EenyMeeny::Cookie.smoke_test_name(smoke_test_id, version: version)
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(request)
|
11
|
+
cookie = EenyMeeny::Cookie.read(request.cookie_jar[@smoke_test_cookie_name])
|
12
|
+
!cookie.nil?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/eeny-meeny/version.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'eeny-meeny/models/cookie'
|
3
|
+
require 'eeny-meeny/models/experiment'
|
4
|
+
|
5
|
+
def write_cookie(experiment_id, variation_id: nil)
|
6
|
+
experiment = EenyMeeny::Experiment.find_by_id(experiment_id)
|
7
|
+
raise "Experiment with id '#{experiment_id}' not found!" if experiment.nil?
|
8
|
+
if variation_id.nil?
|
9
|
+
EenyMeeny::Cookie.create_for_experiment(experiment, EenyMeeny.config.cookies)
|
10
|
+
else
|
11
|
+
EenyMeeny::Cookie.create_for_experiment_variation(experiment, variation_id, EenyMeeny.config.cookies)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :eeny_meeny do
|
16
|
+
|
17
|
+
namespace :cookie do
|
18
|
+
desc 'Create a valid EenyMeeny experiment cookie'
|
19
|
+
task :experiment, [:experiment_id] => :environment do |t, args|
|
20
|
+
raise "Missing 'experiment_id' parameter" if (args['experiment_id'].nil? || args['experiment_id'].empty?)
|
21
|
+
experiment_id = args['experiment_id'].to_sym
|
22
|
+
cookie = write_cookie(experiment_id)
|
23
|
+
puts cookie
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Create a valid EenyMeeny experiment cookie for a specific variation'
|
27
|
+
task :experiment_variation, [:experiment_id, :variation_id] => :environment do |t, args|
|
28
|
+
raise "Missing 'experiment_id' parameter" if (args['experiment_id'].nil? || args['experiment_id'].empty?)
|
29
|
+
raise "Missing 'variation_id' parameter" if (args['variation_id'].nil? || args['variation_id'].empty?)
|
30
|
+
experiment_id = args['experiment_id'].to_sym
|
31
|
+
variation_id = args['variation_id'].to_sym
|
32
|
+
cookie = write_cookie(experiment_id, variation_id: variation_id)
|
33
|
+
puts cookie
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Create a valid EenyMeeny smoke test cookie'
|
37
|
+
task :smoke_test, [:smoke_test_id, :version] => :environment do |t, args|
|
38
|
+
raise "Missing 'smoke_test_id' parameter" if (args['smoke_test_id'].nil? || args['smoke_test_id'].empty?)
|
39
|
+
smoke_test_id = args['smoke_test_id']
|
40
|
+
version = args['version'] || 1
|
41
|
+
cookie = EenyMeeny::Cookie.create_for_smoke_test(smoke_test_id, version: version)
|
42
|
+
puts cookie
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
end
|
@@ -1,35 +1,32 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'eeny-meeny/encryptor'
|
2
|
+
require 'eeny-meeny/models/encryptor'
|
3
3
|
require 'eeny-meeny/middleware'
|
4
4
|
|
5
5
|
def initialize_app(secure: true, secret: 'test', path: '/', same_site: :strict)
|
6
|
-
|
7
|
-
|
6
|
+
EenyMeeny.reset!
|
7
|
+
EenyMeeny.configure do |config|
|
8
|
+
config.cookies = { path: path, same_site: same_site }
|
9
|
+
config.experiments = YAML.load_file(File.join('spec','fixtures','experiments.yml'))
|
10
|
+
config.secret = secret
|
11
|
+
config.secure = secure
|
12
|
+
end
|
13
|
+
described_class.new(app)
|
8
14
|
end
|
9
15
|
|
10
16
|
describe EenyMeeny::Middleware do
|
11
17
|
|
12
18
|
let(:app) { MockRackApp.new }
|
13
|
-
before(:example) do
|
14
|
-
allow(Time).to receive_message_chain(:zone, :now) { Time.now }
|
15
|
-
end
|
16
19
|
|
17
20
|
describe 'when initialized' do
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
expect(instance.instance_variable_get(:@encryptor)).to be_a EenyMeeny::Encryptor
|
24
|
-
end
|
22
|
+
subject { initialize_app }
|
23
|
+
|
24
|
+
it 'sets the experiments' do
|
25
|
+
expect(subject.instance_variable_get(:@experiments)).to be
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
instance = initialize_app(secure: false)
|
30
|
-
expect(instance.instance_variable_get(:@secure)).to be false
|
31
|
-
expect(instance.instance_variable_get(:@encryptor)).to be nil
|
32
|
-
end
|
28
|
+
it 'sets the cookie config' do
|
29
|
+
expect(subject.instance_variable_get(:@cookie_config)).to be
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'eeny-meeny/models/cookie'
|
3
|
+
require 'eeny-meeny/models/experiment'
|
4
|
+
|
5
|
+
describe EenyMeeny::Cookie do
|
6
|
+
describe 'when initialized' do
|
7
|
+
subject do
|
8
|
+
described_class.new(name: 'test', value: '12345')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'sets the instance variables correctly' do
|
12
|
+
expect(subject.name).to eq('test')
|
13
|
+
expect(subject.value).to eq('12345')
|
14
|
+
expect(subject.expires).to be
|
15
|
+
expect(subject.httponly).to be
|
16
|
+
expect(subject.same_site).to be_nil
|
17
|
+
expect(subject.path).to be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#to_h' do
|
21
|
+
it 'returns cookie options' do
|
22
|
+
options = subject.to_h
|
23
|
+
expect(options).to be_a Hash
|
24
|
+
expect(options.keys.sort).to eq([:value, :httponly, :expires].sort)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.create_for_smoke_test' do
|
30
|
+
context 'given a smoke test id' do
|
31
|
+
it 'creates a cookie' do
|
32
|
+
instance = described_class.create_for_smoke_test(:shadow)
|
33
|
+
expect(instance).to be_a EenyMeeny::Cookie
|
34
|
+
expect(instance.name).to eq(described_class.smoke_test_name(:shadow))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.create_for_experiment', experiments: true do
|
40
|
+
context 'given an experiment' do
|
41
|
+
it 'creates a cookie' do
|
42
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
43
|
+
instance = described_class.create_for_experiment(experiment)
|
44
|
+
expect(instance).to be_a EenyMeeny::Cookie
|
45
|
+
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'and given cookie options' do
|
49
|
+
it 'creates a cookie with the given options' do
|
50
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
51
|
+
instance = described_class.create_for_experiment(experiment, same_site: :fun_stuff)
|
52
|
+
expect(instance).to be_a EenyMeeny::Cookie
|
53
|
+
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
54
|
+
expect(instance.same_site).to eq(:fun_stuff)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '.create_for_experiment_variation', experiments: true do
|
61
|
+
context 'given an experiment and an variation id' do
|
62
|
+
it 'creates a cookie for that variation' do
|
63
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
64
|
+
instance = described_class.create_for_experiment_variation(experiment, :new)
|
65
|
+
expect(instance).to be_a EenyMeeny::Cookie
|
66
|
+
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
67
|
+
expect(described_class.read(instance.value)[:variation].id).to eq(:new)
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'and given cookie options' do
|
71
|
+
it 'creates a cookie for that variation with the given options' do
|
72
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
73
|
+
instance = described_class.create_for_experiment_variation(experiment, :new, same_site: :fun_stuff)
|
74
|
+
expect(instance).to be_a EenyMeeny::Cookie
|
75
|
+
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
76
|
+
expect(instance.same_site).to eq(:fun_stuff)
|
77
|
+
expect(described_class.read(instance.value)[:variation].id).to eq(:new)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '.smoke_test_name' do
|
84
|
+
context 'given a smoke_test_id' do
|
85
|
+
it 'returns the smoke test cookie name' do
|
86
|
+
expect(described_class.smoke_test_name(:something)).to eq('smoke_test_something_v1')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '.cookie_name', experiments: true do
|
92
|
+
context 'given an experiment' do
|
93
|
+
it 'returns the experiment cookie name' do
|
94
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
95
|
+
expect(described_class.cookie_name(experiment)).to eq('eeny_meeny_my_page_v1')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '.read', experiments: true do
|
101
|
+
context 'given an empty cookie string' do
|
102
|
+
it 'returns nil' do
|
103
|
+
expect(described_class.read(nil)).to be_nil
|
104
|
+
expect(described_class.read('')).to be_nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when EenyMeeny.config.secure = true' do
|
109
|
+
context 'and given a valid cookie string' do
|
110
|
+
it 'decrypts the string and returns the cookie hash' do
|
111
|
+
valid_cookie_string = 'DhtZMLAtVpWiruuq6BdQ+YEeDTK4G1p0HQLeyKFZd2+fD8YyT004p56S03yXsE/kzCASnD9O1sk1tsIHDZ8W2gq+5zQD3fu2aqqLm461FOfy0En4/LqHCP0J0VYol3Py0BlhepjSGDuJrRU7TdKZWsG2/dCiMVLjMf0Pt00NZWooUvQfRz9SCzaFL0mywoVrY1ErKKQCNEPmLREaxavCng=='
|
112
|
+
expect(described_class.read(valid_cookie_string)).to be_a Hash
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'and given an invalid cookie string' do
|
117
|
+
it 'returns nil' do
|
118
|
+
expect(described_class.read('qwedasdafagasdaasdasd')).to be_nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when EenyMeeny.config.secure = false' do
|
124
|
+
context 'and given a valid cookie string' do
|
125
|
+
it 'returns the cookie hash' do
|
126
|
+
EenyMeeny.configure do |config|
|
127
|
+
config.secure = false
|
128
|
+
config.experiments = YAML.load_file(File.join('spec','fixtures','experiments.yml'))
|
129
|
+
end
|
130
|
+
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
131
|
+
valid_cookie_string = described_class.create_for_experiment(experiment).value
|
132
|
+
expect(described_class.read(valid_cookie_string)).to be_a Hash
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'eeny-meeny/models/experiment'
|
3
|
+
require 'eeny-meeny/models/variation'
|
4
|
+
|
5
|
+
def experiment_with_time(time = {})
|
6
|
+
experiment_options = {
|
7
|
+
name: 'Test 1',
|
8
|
+
variations: {
|
9
|
+
a: { name: 'A' },
|
10
|
+
b: { name: 'B' }}
|
11
|
+
}.merge(time)
|
12
|
+
described_class.new(:experiment_1,
|
13
|
+
**experiment_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe EenyMeeny::Experiment do
|
17
|
+
describe 'when initialized' do
|
18
|
+
|
19
|
+
context 'with weighted variations' do
|
20
|
+
subject do
|
21
|
+
described_class.new(:experiment_1,
|
22
|
+
name: 'Test 1',
|
23
|
+
variations: {
|
24
|
+
a: { name: 'A', weight: 0.5 },
|
25
|
+
b: { name: 'B', weight: 0.3 }})
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'sets the instance variables' do
|
29
|
+
expect(subject.id).to eq(:experiment_1)
|
30
|
+
expect(subject.name).to eq('Test 1')
|
31
|
+
expect(subject.variations).to be_a Array
|
32
|
+
expect(subject.variations.size).to eq(2)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has a 'total_weight' equal to the sum of the variation weights" do
|
36
|
+
expect(subject.total_weight).to eq(0.8)
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#pick_variation' do
|
40
|
+
it 'picks a variation' do
|
41
|
+
expect(subject.pick_variation).to be_a EenyMeeny::Variation
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with non-weighted variations' do
|
47
|
+
subject do
|
48
|
+
described_class.new(:experiment_1,
|
49
|
+
name: 'Test 1',
|
50
|
+
variations: {
|
51
|
+
a: { name: 'A' },
|
52
|
+
b: { name: 'B' }})
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sets the instance variables' do
|
56
|
+
expect(subject.id).to eq(:experiment_1)
|
57
|
+
expect(subject.name).to eq('Test 1')
|
58
|
+
expect(subject.variations).to be_a Array
|
59
|
+
expect(subject.variations.size).to eq(2)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "has a 'total_weight' equal to the number of the variation weights" do
|
63
|
+
expect(subject.total_weight).to eq(2)
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#pick_variation' do
|
67
|
+
it 'picks a variation' do
|
68
|
+
expect(subject.pick_variation).to be_a EenyMeeny::Variation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#active?' do
|
73
|
+
context 'when the experiment neither have a start_at or end_at time' do
|
74
|
+
it 'returns true' do
|
75
|
+
expect(subject.active?).to be true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when the experiment only have an end_at time' do
|
80
|
+
context 'and the current time < end_at' do
|
81
|
+
it 'returns true' do
|
82
|
+
instance = experiment_with_time(end_at: (Time.zone.now+3600).iso8601)
|
83
|
+
expect(instance.active?).to be true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'and the current time > end_at' do
|
88
|
+
it 'returns false' do
|
89
|
+
instance = experiment_with_time(end_at: (Time.zone.now-3600).iso8601)
|
90
|
+
expect(instance.active?).to be false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when the experiment only have a start_at time' do
|
96
|
+
context 'and the current time < start_at' do
|
97
|
+
it 'returns false' do
|
98
|
+
instance = experiment_with_time(start_at: (Time.zone.now+3600).iso8601)
|
99
|
+
expect(instance.active?).to be false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'and the current time > start_at' do
|
104
|
+
it 'returns true' do
|
105
|
+
instance = experiment_with_time(start_at: (Time.zone.now-3600).iso8601)
|
106
|
+
expect(instance.active?).to be true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when the experiment both have a start_at and end_at time' do
|
112
|
+
context 'and current_time < start_at' do
|
113
|
+
it 'returns false' do
|
114
|
+
instance = experiment_with_time(start_at: (Time.zone.now+3600).iso8601,
|
115
|
+
end_at: (Time.zone.now+7200).iso8601)
|
116
|
+
expect(instance.active?).to be false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'and current_time > start_at and current time < end_at' do
|
121
|
+
it 'returns true' do
|
122
|
+
instance = experiment_with_time(start_at: (Time.zone.now-3600).iso8601,
|
123
|
+
end_at: (Time.zone.now+7200).iso8601)
|
124
|
+
expect(instance.active?).to be true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'and current time > start_at and current time > end_at' do
|
129
|
+
it 'returns false' do
|
130
|
+
instance = experiment_with_time(start_at: (Time.zone.now-7200).iso8601,
|
131
|
+
end_at: (Time.zone.now-3600).iso8601)
|
132
|
+
expect(instance.active?).to be false
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '.find_all' do
|
141
|
+
context 'when the EenyMeeny is configured with experiments', experiments: true do
|
142
|
+
it 'returns those experiments' do
|
143
|
+
instances = described_class.find_all
|
144
|
+
expect(instances).to be_a Array
|
145
|
+
expect(instances.size).to eq(2)
|
146
|
+
instances.each do |instance|
|
147
|
+
expect(instance).to be_a EenyMeeny::Experiment
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when EenyMeeny is not configured with experiments' do
|
153
|
+
it 'returns an empty array' do
|
154
|
+
expect(described_class.find_all).to eq([])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '.find_by_id' do
|
160
|
+
context 'when EenyMeeny is configured with experiments', experiments: true do
|
161
|
+
context 'and the given id exists' do
|
162
|
+
it 'returns the experiment' do
|
163
|
+
expect(described_class.find_by_id(:my_page)).to be_a EenyMeeny::Experiment
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'and the given id does not exist' do
|
168
|
+
it 'returns nil' do
|
169
|
+
expect(described_class.find_by_id(:experiment_missing)).to be_nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'when EenyMeeny is not configured with experiments' do
|
175
|
+
it 'returns nil' do
|
176
|
+
expect(described_class.find_by_id(:experiment_missing)).to be_nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|