eeny-meeny 2.0.0 → 2.1.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 +15 -0
- data/README.md +24 -12
- data/eeny-meeny.gemspec +1 -1
- data/lib/eeny-meeny.rb +7 -6
- data/lib/eeny-meeny/experiment_helper.rb +4 -3
- data/lib/eeny-meeny/middleware.rb +37 -9
- data/lib/eeny-meeny/models/cookie.rb +6 -15
- data/lib/eeny-meeny/models/experiment.rb +4 -0
- data/lib/eeny-meeny/models/variation.rb +0 -8
- data/lib/eeny-meeny/railtie.rb +5 -4
- data/lib/eeny-meeny/routing/experiment_constraint.rb +4 -4
- data/lib/eeny-meeny/version.rb +1 -1
- data/spec/eeny-meeny/experiment_helper_spec.rb +88 -0
- data/spec/eeny-meeny/middleware_spec.rb +41 -0
- data/spec/eeny-meeny/models/cookie_spec.rb +5 -5
- data/spec/eeny-meeny/models/experiment_spec.rb +16 -0
- data/spec/mock_rack_app.rb +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d6f1ff00ff903e788dcf59c336dce5748f18852
|
4
|
+
data.tar.gz: 153b807882e56f14e0865d3b9648e2b3aea747f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 977ead352b9f734e1ac1af86f0c6c5649ff68f8e1accac7efe159b6bd1a17a26bf397efbcce7b6c1b47c14650a24944fc87ab7956094ce105147351fcd03f5f1
|
7
|
+
data.tar.gz: 02e9d69b318010e3fab99e947699d78b053245a1089b871f615a0e05c3ec7f26d58aa1b4a9c37ab72339de7ed7567f51a59e6d93ad29d7c064a355aef83d0b86
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
### 2.1.0 (2016-10-02)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Trigger experiment variations with query parameters
|
6
|
+
- Trigger smoke tests with query parameters
|
7
|
+
|
8
|
+
Bugfixes:
|
9
|
+
|
10
|
+
- Fixed error that caused 'participates_in?' to throw error when the given experiment_id did not exist.
|
11
|
+
|
12
|
+
Other Changes:
|
13
|
+
|
14
|
+
- Reduced size of experiment cookies. Now only the picked variation_id is stored in the cookie itself.
|
15
|
+
|
1
16
|
### 2.0.0 (2016-09-11)
|
2
17
|
|
3
18
|
Features:
|
data/README.md
CHANGED
@@ -24,6 +24,7 @@ The following configurations are available:
|
|
24
24
|
* `cookies` Defaults to `{ http_only: true, path: '/', same_site: :strict }`. Sets the eeny-meeny cookie attributes. The valid attributes are listed in the section below.
|
25
25
|
* `secure` Defaults to `true`. Determines if eeny-meeny cookies should be encrypted or not.
|
26
26
|
* `secret` Sets the secret used for encrypting experiment cookies.
|
27
|
+
* `query_parameters` Defaults to `{ experiment: true, smoke_test: true }`. Controls whether experiments variations and smoke tests can be triggered through query parameters.
|
27
28
|
* `experiments` Defaults to `{}`. It is easiest to load this from a `.yml` file with `YAML.load_file(File.join('config','experiments.yml'))`. The YAML file should have a structure matching the following example:
|
28
29
|
|
29
30
|
```
|
@@ -36,13 +37,11 @@ The following configurations are available:
|
|
36
37
|
:a:
|
37
38
|
:name: Variation A
|
38
39
|
:weight: 0.8
|
39
|
-
:
|
40
|
-
:message: A rocks, B sucks
|
40
|
+
:custom_attribute: A rocks, B sucks
|
41
41
|
:b:
|
42
42
|
:name: Variation B
|
43
43
|
:weight: 0.2
|
44
|
-
:
|
45
|
-
:message: B is an all-star!
|
44
|
+
:custom_attribute: B is an all-star!
|
46
45
|
```
|
47
46
|
|
48
47
|
Valid cookie attributes:
|
@@ -100,16 +99,16 @@ Rake tasks
|
|
100
99
|
-------------
|
101
100
|
`eeny-meeny` adds the following rake tasks to your project.
|
102
101
|
|
103
|
-
* `eeny_meeny:
|
104
|
-
* `eeny_meeny:
|
105
|
-
* `eeny_meeny:
|
102
|
+
* `eeny_meeny:cookie:experiment[experiment_id]`. Creates and outputs a valid cookie for the given experiment id.
|
103
|
+
* `eeny_meeny:cookie:experiment_variation[experiment_id,variation_id]` creates and outputs a valid cookie for the given variation of the experiment with the given experiment_id.
|
104
|
+
* `eeny_meeny:cookie:smoke_test[smoke_test_id,version]` Creates and outputs a valid smoke test cookie for a smoke test with the given id and version. `version` will default to `1` if not given.
|
106
105
|
|
107
106
|
You can execute the rake tasks like this:
|
108
107
|
|
109
|
-
* `rake eeny_meeny:
|
110
|
-
* `rake eeny_meeny:
|
111
|
-
* `rake eeny_meeny:
|
112
|
-
* `rake eeny_meeny:
|
108
|
+
* `rake eeny_meeny:cookie:experimet[experiment_id]`
|
109
|
+
* `rake eeny_meeny:cookie:experimet_variation[experiment_id, a]`
|
110
|
+
* `rake eeny_meeny:cookie:smoke_test[shadow]`
|
111
|
+
* `rake eeny_meeny:cookie:smoke_test[shadow,2]`
|
113
112
|
|
114
113
|
You can add the resulting cookie to your browser by copying the cookie string and use the following command in the JS console of your browser.
|
115
114
|
|
@@ -119,6 +118,18 @@ document.cookie = '<cookie string excluding httponly>';
|
|
119
118
|
|
120
119
|
Please note that the `HttpOnly` attribute will prevent you from adding the cookie to your browser through JS. You will therefor have to remove the `HttpOnly` part of the cookie string before adding the cookie to your browser.
|
121
120
|
|
121
|
+
Query parameters
|
122
|
+
-------------
|
123
|
+
By default it is possible to trigger smoke tests and experiment variations through query parameters.
|
124
|
+
|
125
|
+
Executing a request to `/?smoke_test_id=my_secret` will trigger the `my_secret` smoke test.
|
126
|
+
|
127
|
+
Executing a request to `/?eeny_meeny_my_page_v1=old` will trigger the `old` varition of the `my_page` experiment.
|
128
|
+
|
129
|
+
For experiments the parameter needs to match the pattern `eeny_meeny_<experiment_id>_v<experiment_version>=<variation_id>`
|
130
|
+
|
131
|
+
Please note that this behavior can be disabled through the `query_parameters` configuration.
|
132
|
+
|
122
133
|
Setting up Experiments
|
123
134
|
-------------
|
124
135
|
It is easiest to define your experiments in YAML files and load them with as shown in the **Configuration** section.
|
@@ -137,7 +148,8 @@ A variation needs the following information:
|
|
137
148
|
* `variation_id` This is the key that encapsulates the rest of your variation configuration in the YAML file (see `:a:` the **Configuration** section).
|
138
149
|
* `name` The name/title of your varition.
|
139
150
|
* `weight` The weight of the variation. Defaults to `1`. This can be a floating or integer number. The final weight of the variation will be `weight / sum_of_variation_weights`.
|
140
|
-
|
151
|
+
|
152
|
+
You can define additional variation attributes as part of the experiment configuration. These attributes will be accessible as a `Hash` returned from the `options` method on variation objects.
|
141
153
|
|
142
154
|
If you want to force all your users to get their experiment cookie updated, then you can change the `version` option on your experiment. This might for instance be useful if you want to remove an under-performing variation from your experiment. Or when gradually rolling a feature out to the public.
|
143
155
|
|
data/eeny-meeny.gemspec
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/eeny-meeny/version', __FILE__)
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'eeny-meeny'
|
5
5
|
s.version = EenyMeeny::VERSION.dup
|
6
|
-
s.date = '2016-
|
6
|
+
s.date = '2016-10-02'
|
7
7
|
s.summary = "A simple split and smoke testing tool for Rails"
|
8
8
|
s.authors = ["Christian Orthmann"]
|
9
9
|
s.email = 'christian.orthmann@gmail.com'
|
data/lib/eeny-meeny.rb
CHANGED
@@ -5,16 +5,17 @@ require 'eeny-meeny/models/encryptor'
|
|
5
5
|
module EenyMeeny
|
6
6
|
|
7
7
|
class Config
|
8
|
-
attr_accessor :cookies, :experiments, :secret, :secure
|
8
|
+
attr_accessor :cookies, :experiments, :secret, :secure, :query_parameters
|
9
9
|
|
10
10
|
attr_reader :encryptor
|
11
11
|
|
12
12
|
def initialize
|
13
|
-
@cookies
|
14
|
-
@experiments
|
15
|
-
@secret
|
16
|
-
@secure
|
17
|
-
@encryptor
|
13
|
+
@cookies = { http_only: true, path: '/', same_site: :strict }
|
14
|
+
@experiments = {}
|
15
|
+
@secret = '9fc8b966eca7d03d55df40c01c10b8e02bf1f9d12d27b8968d53eb53e8c239902d00bf6afae5e726ce1111159eeb2f8f0e77233405db1d82dd71397f651a0a4f'
|
16
|
+
@secure = true
|
17
|
+
@encryptor = (@secure ? EenyMeeny::Encryptor.new(@secret) : nil)
|
18
|
+
@query_parameters = { experiment: true, smoke_test: true }
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -5,9 +5,10 @@ module EenyMeeny::ExperimentHelper
|
|
5
5
|
|
6
6
|
def participates_in?(experiment_id, variation_id: nil)
|
7
7
|
experiment = EenyMeeny::Experiment.find_by_id(experiment_id)
|
8
|
-
return unless experiment.active?
|
9
|
-
|
10
|
-
|
8
|
+
return unless !experiment.nil? && experiment.active?
|
9
|
+
participant_variation_id = read_cookie(EenyMeeny::Cookie.cookie_name(experiment))
|
10
|
+
return if variation_id && variation_id != participant_variation_id
|
11
|
+
experiment.find_variation(participant_variation_id)
|
11
12
|
end
|
12
13
|
|
13
14
|
def smoke_test?(smoke_test_id, version: 1)
|
@@ -24,17 +24,28 @@ module EenyMeeny
|
|
24
24
|
@experiments.each do |experiment|
|
25
25
|
# Skip inactive experiments
|
26
26
|
next unless experiment.active?(now)
|
27
|
+
# Trigger experiment through query parmeters
|
28
|
+
cookie_name = EenyMeeny::Cookie.cookie_name(experiment)
|
29
|
+
has_experiment_trigger = EenyMeeny.config.query_parameters[:experiment] && request.params.has_key?(cookie_name)
|
27
30
|
# skip experiments that already have a cookie
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
if has_experiment_trigger || !cookies.has_key?(cookie_name)
|
32
|
+
cookie = if has_experiment_trigger
|
33
|
+
# Trigger experiment variation through query parameter.
|
34
|
+
EenyMeeny::Cookie.create_for_experiment_variation(experiment, request.params[cookie_name].to_sym, @cookie_config)
|
35
|
+
else
|
36
|
+
EenyMeeny::Cookie.create_for_experiment(experiment, @cookie_config)
|
37
|
+
end
|
31
38
|
# Set HTTP_COOKIE header to enable experiment on first pageview
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
env = add_http_cookie(env, cookie, precede: has_experiment_trigger)
|
40
|
+
new_cookies[cookie.name] = cookie
|
41
|
+
end
|
42
|
+
end
|
43
|
+
# Prepare smoke tests (if enabled through query parameters)
|
44
|
+
if EenyMeeny.config.query_parameters[:smoke_test]
|
45
|
+
if request.params.has_key?('smoke_test_id') && (request.params['smoke_test_id'] =~ /[A-Za-z_]+/)
|
46
|
+
# Set HTTP_COOKIE header to enable smoke test on first pageview
|
47
|
+
cookie = EenyMeeny::Cookie.create_for_smoke_test(request.params['smoke_test_id'])
|
48
|
+
env = add_http_cookie(env, cookie, precede: true)
|
38
49
|
new_cookies[cookie.name] = cookie
|
39
50
|
end
|
40
51
|
end
|
@@ -53,5 +64,22 @@ module EenyMeeny
|
|
53
64
|
end
|
54
65
|
response.finish
|
55
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def add_http_cookie(env, cookie, precede: false)
|
70
|
+
env['Set-Cookie'] = ''
|
71
|
+
Rack::Utils.set_cookie_header!(env,
|
72
|
+
cookie.name,
|
73
|
+
cookie.to_h)
|
74
|
+
env['HTTP_COOKIE'] = '' if env['HTTP_COOKIE'].nil?
|
75
|
+
if precede
|
76
|
+
# Prepend cookie to the 'HTTP_COOKIE' header. This ensures it overwrites existing cookies when present.
|
77
|
+
env['HTTP_COOKIE'] = env['Set-Cookie'] + '; ' + env['HTTP_COOKIE']
|
78
|
+
else
|
79
|
+
env['HTTP_COOKIE'] += '; ' unless env['HTTP_COOKIE'].empty?
|
80
|
+
env['HTTP_COOKIE'] += env['Set-Cookie']
|
81
|
+
end
|
82
|
+
env
|
83
|
+
end
|
56
84
|
end
|
57
85
|
end
|
@@ -9,14 +9,11 @@ module EenyMeeny
|
|
9
9
|
attr_reader :name, :expires, :httponly, :same_site, :path
|
10
10
|
|
11
11
|
def self.create_for_experiment_variation(experiment, variation_id, config = {})
|
12
|
-
variation = experiment.
|
12
|
+
variation = experiment.find_variation(variation_id)
|
13
13
|
raise "Variation '#{variation_id}' not found for Experiment '#{experiment.id}'" if variation.nil?
|
14
14
|
options = {
|
15
15
|
name: cookie_name(experiment),
|
16
|
-
value:
|
17
|
-
name: experiment.name,
|
18
|
-
variation: variation
|
19
|
-
})
|
16
|
+
value: variation.id.to_s
|
20
17
|
}
|
21
18
|
options[:expires] = experiment.end_at if experiment.end_at
|
22
19
|
if EenyMeeny.config.secure
|
@@ -28,10 +25,7 @@ module EenyMeeny
|
|
28
25
|
def self.create_for_experiment(experiment, config = {})
|
29
26
|
options = {
|
30
27
|
name: cookie_name(experiment),
|
31
|
-
value:
|
32
|
-
name: experiment.name,
|
33
|
-
variation: experiment.pick_variation
|
34
|
-
})
|
28
|
+
value: experiment.pick_variation.id.to_s
|
35
29
|
}
|
36
30
|
options[:expires] = experiment.end_at if experiment.end_at
|
37
31
|
if EenyMeeny.config.secure
|
@@ -43,10 +37,7 @@ module EenyMeeny
|
|
43
37
|
def self.create_for_smoke_test(smoke_test_id, version: 1, **config)
|
44
38
|
options = {
|
45
39
|
name: smoke_test_name(smoke_test_id, version: version),
|
46
|
-
value:
|
47
|
-
name: smoke_test_id,
|
48
|
-
version: version
|
49
|
-
})
|
40
|
+
value: smoke_test_id.to_s
|
50
41
|
}
|
51
42
|
if EenyMeeny.config.secure
|
52
43
|
options[:value] = EenyMeeny.config.encryptor.encrypt(options[:value])
|
@@ -67,8 +58,8 @@ module EenyMeeny
|
|
67
58
|
def self.read(cookie_string)
|
68
59
|
return if cookie_string.nil? || cookie_string.empty?
|
69
60
|
begin
|
70
|
-
return
|
71
|
-
|
61
|
+
return cookie_string unless EenyMeeny.config.secure # Cookie encryption disabled.
|
62
|
+
EenyMeeny.config.encryptor.decrypt(cookie_string)
|
72
63
|
rescue
|
73
64
|
nil # Return nil if cookie is invalid.
|
74
65
|
end
|
@@ -36,6 +36,10 @@ module EenyMeeny
|
|
36
36
|
!!((@start_at && (now > @start_at)) && (@end_at && (now < @end_at))) # specified start and end
|
37
37
|
end
|
38
38
|
|
39
|
+
def find_variation(variation_id)
|
40
|
+
@variations.detect { |v| v.id.to_s == variation_id.to_s }
|
41
|
+
end
|
42
|
+
|
39
43
|
def pick_variation
|
40
44
|
Hash[
|
41
45
|
@variations.map do |variation|
|
data/lib/eeny-meeny/railtie.rb
CHANGED
@@ -9,10 +9,11 @@ module EenyMeeny
|
|
9
9
|
initializer 'eeny_meeny.configure' do |app|
|
10
10
|
# Configrue EenyMeeny (defaults set in eeny_meeny.rb)
|
11
11
|
EenyMeeny.configure do |config|
|
12
|
-
config.cookies
|
13
|
-
config.experiments
|
14
|
-
config.secret
|
15
|
-
config.secure
|
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
|
+
config.query_parameters = app.config.eeny_meeny[:query_parameters] if app.config.eeny_meeny.has_key?(:query_parameters)
|
16
17
|
end
|
17
18
|
# Include Helpers in ActionController and ActionView
|
18
19
|
ActionController::Base.send :include, EenyMeeny::ExperimentHelper
|
@@ -10,10 +10,10 @@ module EenyMeeny
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def matches?(request)
|
13
|
-
return false unless @experiment.active?
|
14
|
-
|
15
|
-
return false if
|
16
|
-
(@variation_id.nil? || @variation_id ==
|
13
|
+
return false unless !@experiment.nil? && @experiment.active?
|
14
|
+
participant_variation_id = EenyMeeny::Cookie.read(request.cookie_jar[EenyMeeny::Cookie.cookie_name(@experiment)])
|
15
|
+
return false if participant_variation_id.nil? # Not participating in experiment
|
16
|
+
(@variation_id.nil? || @variation_id == participant_variation_id)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/eeny-meeny/version.rb
CHANGED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'eeny-meeny/middleware'
|
3
|
+
require 'eeny-meeny/experiment_helper'
|
4
|
+
require 'eeny-meeny/models/experiment'
|
5
|
+
require 'eeny-meeny/models/variation'
|
6
|
+
require 'eeny-meeny/models/cookie'
|
7
|
+
require 'rack/test'
|
8
|
+
|
9
|
+
describe EenyMeeny::ExperimentHelper, experiments: true do
|
10
|
+
|
11
|
+
subject do
|
12
|
+
Object.new.extend(EenyMeeny::ExperimentHelper)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:request) do
|
16
|
+
Rack::MockSession.new(EenyMeeny::Middleware.new(MockRackApp.new))
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#participates_in?' do
|
20
|
+
context 'given an experiment id' do
|
21
|
+
let(:request_with_cookie) do
|
22
|
+
request.set_cookie(EenyMeeny::Cookie.create_for_experiment(EenyMeeny::Experiment.find_by_id(:my_page)).to_s)
|
23
|
+
request
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'of an active experiment' do
|
27
|
+
context 'with a valid experiment cookie' do
|
28
|
+
it "returns the user's experiment variation" do
|
29
|
+
allow(subject).to receive(:cookies).and_return(request_with_cookie.cookie_jar)
|
30
|
+
expect(subject.participates_in?(:my_page)).to be_a EenyMeeny::Variation
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'without an experiment cookie' do
|
35
|
+
it 'returns nil' do
|
36
|
+
allow(subject).to receive(:cookies).and_return(request.cookie_jar)
|
37
|
+
expect(subject.participates_in?(:my_page)).to be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'of an inactive experiment' do
|
43
|
+
context 'with a valid experiment cookie' do
|
44
|
+
let(:request_with_expired_cookie) do
|
45
|
+
request.set_cookie(EenyMeeny::Cookie.create_for_experiment(EenyMeeny::Experiment.find_by_id(:expired)).to_s)
|
46
|
+
request
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns nil' do
|
50
|
+
allow(subject).to receive(:cookies).and_return(request_with_expired_cookie.cookie_jar)
|
51
|
+
expect(subject.participates_in?(:expired)).to be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'that does not exist among the experiments' do
|
57
|
+
it 'returns nil' do
|
58
|
+
allow(subject).to receive(:cookies).and_return(request_with_cookie.cookie_jar)
|
59
|
+
expect(subject.participates_in?(:this_does_not_exist)).to be_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#smoke_test?' do
|
66
|
+
context 'given a smoke test id' do
|
67
|
+
let(:request_with_smoke_test) do
|
68
|
+
request.set_cookie(EenyMeeny::Cookie.create_for_smoke_test(:my_smoke_test).to_s)
|
69
|
+
request
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'and a request with a valid smoke test cookie' do
|
73
|
+
it 'returns the smoke test' do
|
74
|
+
allow(subject).to receive(:cookies).and_return(request_with_smoke_test.cookie_jar)
|
75
|
+
expect(subject.smoke_test?(:my_smoke_test)).to be
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'and a request without a smoke test cookie' do
|
80
|
+
it 'returns nil' do
|
81
|
+
allow(subject).to receive(:cookies).and_return(request.cookie_jar)
|
82
|
+
expect(subject.smoke_test?(:my_smoke_test)).to be_nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -69,6 +69,47 @@ describe EenyMeeny::Middleware do
|
|
69
69
|
expect(@response['Set-Cookie']).to be nil
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
context 'and given an experiment query parameter' do
|
74
|
+
let(:request) { Rack::MockRequest.new(subject) }
|
75
|
+
|
76
|
+
before(:example) do
|
77
|
+
@response = request.get('/test?eeny_meeny_my_page_v1=old', 'CONTENT_TYPE' => 'text/plain')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'selects the correct variation' do
|
81
|
+
modified_request = Rack::Request.new(app)
|
82
|
+
expect(EenyMeeny::Cookie.read(modified_request.cookies['eeny_meeny_my_page_v1'])).to eq('old')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "sets the 'HTTP_COOKIE' header on the request" do
|
86
|
+
expect(app['HTTP_COOKIE']).to be
|
87
|
+
expect(app['HTTP_COOKIE']).to include('eeny_meeny_my_page_v1=')
|
88
|
+
end
|
89
|
+
|
90
|
+
it "sets the 'Set-Cookie' header on the response" do
|
91
|
+
expect(@response['Set-Cookie']).to be
|
92
|
+
expect(@response['Set-Cookie']).to include('eeny_meeny_my_page_v1=')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'and given a smoke test query parameter' do
|
97
|
+
let(:request) { Rack::MockRequest.new(subject) }
|
98
|
+
|
99
|
+
before(:example) do
|
100
|
+
@response = request.get('/test?smoke_test_id=my_smoke_test', 'CONTENT_TYPE' => 'text/plain')
|
101
|
+
end
|
102
|
+
|
103
|
+
it "sets the 'HTTP_COOKIE' header on the request" do
|
104
|
+
expect(app['HTTP_COOKIE']).to be
|
105
|
+
expect(app['HTTP_COOKIE']).to include('smoke_test_my_smoke_test_v1=')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "sets the 'Set-Cookie' header on the response" do
|
109
|
+
expect(@response['Set-Cookie']).to be
|
110
|
+
expect(@response['Set-Cookie']).to include('smoke_test_my_smoke_test_v1=')
|
111
|
+
end
|
112
|
+
end
|
72
113
|
end
|
73
114
|
|
74
115
|
end
|
@@ -64,7 +64,7 @@ describe EenyMeeny::Cookie do
|
|
64
64
|
instance = described_class.create_for_experiment_variation(experiment, :new)
|
65
65
|
expect(instance).to be_a EenyMeeny::Cookie
|
66
66
|
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
67
|
-
expect(described_class.read(instance.value)
|
67
|
+
expect(described_class.read(instance.value)).to eq('new')
|
68
68
|
end
|
69
69
|
|
70
70
|
context 'and given cookie options' do
|
@@ -74,7 +74,7 @@ describe EenyMeeny::Cookie do
|
|
74
74
|
expect(instance).to be_a EenyMeeny::Cookie
|
75
75
|
expect(instance.name).to eq(described_class.cookie_name(experiment))
|
76
76
|
expect(instance.same_site).to eq(:fun_stuff)
|
77
|
-
expect(described_class.read(instance.value)
|
77
|
+
expect(described_class.read(instance.value)).to eq('new')
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -108,8 +108,8 @@ describe EenyMeeny::Cookie do
|
|
108
108
|
context 'when EenyMeeny.config.secure = true' do
|
109
109
|
context 'and given a valid cookie string' do
|
110
110
|
it 'decrypts the string and returns the cookie hash' do
|
111
|
-
valid_cookie_string = '
|
112
|
-
expect(described_class.read(valid_cookie_string)).to
|
111
|
+
valid_cookie_string = 'x0bVgNAjEdiNUk9Zfr7IoVN51c8vj8Ah2yMmTbq1ANm8tF8/XpB0kLhViHmocuAgplaIkkTpdii55Gaq0rXgzw=='
|
112
|
+
expect(described_class.read(valid_cookie_string)).to eq('new')
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
@@ -129,7 +129,7 @@ describe EenyMeeny::Cookie do
|
|
129
129
|
end
|
130
130
|
experiment = EenyMeeny::Experiment.find_by_id(:my_page)
|
131
131
|
valid_cookie_string = described_class.create_for_experiment(experiment).value
|
132
|
-
expect(described_class.read(valid_cookie_string)).to
|
132
|
+
expect(described_class.read(valid_cookie_string)).to match(/old|new/)
|
133
133
|
end
|
134
134
|
end
|
135
135
|
end
|
@@ -63,6 +63,22 @@ describe EenyMeeny::Experiment do
|
|
63
63
|
expect(subject.total_weight).to eq(2)
|
64
64
|
end
|
65
65
|
|
66
|
+
describe '#find_variation' do
|
67
|
+
context 'given an existing variation id' do
|
68
|
+
it 'returns the given variation' do
|
69
|
+
variation = subject.find_variation(:a)
|
70
|
+
expect(variation).to be_a EenyMeeny::Variation
|
71
|
+
expect(variation.id).to eq(:a)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'given a non-existing variation id' do
|
76
|
+
it 'returns nil' do
|
77
|
+
expect(subject.find_variation(:this_does_not_exist)).to be_nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
66
82
|
describe '#pick_variation' do
|
67
83
|
it 'picks a variation' do
|
68
84
|
expect(subject.pick_variation).to be_a EenyMeeny::Variation
|
data/spec/mock_rack_app.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eeny-meeny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Orthmann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- lib/eeny-meeny/routing/smoke_test_constraint.rb
|
159
159
|
- lib/eeny-meeny/version.rb
|
160
160
|
- lib/tasks/cookie.rake
|
161
|
+
- spec/eeny-meeny/experiment_helper_spec.rb
|
161
162
|
- spec/eeny-meeny/middleware_spec.rb
|
162
163
|
- spec/eeny-meeny/models/cookie_spec.rb
|
163
164
|
- spec/eeny-meeny/models/experiment_spec.rb
|