eeny-meeny 2.0.0 → 2.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.
- 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
|