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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34311644231b710c6ce1e10c5fb6f4410bd4ed5d
4
- data.tar.gz: fa951cdb99821c5cd8d0c032d0048875b210193f
3
+ metadata.gz: 3d6f1ff00ff903e788dcf59c336dce5748f18852
4
+ data.tar.gz: 153b807882e56f14e0865d3b9648e2b3aea747f4
5
5
  SHA512:
6
- metadata.gz: 46a37bb2552e814042c625c3e864073ac4133f295eec99e8a646b4331182060299981b3e8248e7bda8f3c5c2c629ae276a49f0ca9c4290700c22fc840ee0f508
7
- data.tar.gz: 03653ee7e0e9eee45bfe2f0efe87e92df72bf7a74d6546dfae2947330eba02e8dd218bb0f070b55967081b7f00be3dd501596b92af8328b65d3c9d150cb5b6f3
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
- :options:
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
- :options:
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:cookies:experiment[experiment_id]`. Creates and outputs a valid cookie for the given experiment id.
104
- * `eeny_meeny:cookies:experiment_variation[experiment_id,variation_id]` creates and outputs a valid cookie for the given variation of the experiment with the given experiment_id.
105
- * `eeny_meeny:cookies: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.
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:cookies:experimet[experiment_id]`
110
- * `rake eeny_meeny:cookies:experimet_variation[experiment_id, a]`
111
- * `rake eeny_meeny:cookies:smoke_test[shadow]`
112
- * `rake eeny_meeny:cookies:smoke_test[shadow,2]`
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
- * `options` (optional) a hash with variation specific information that you want stored want to use in your experiment. Notice that this information will be stored in the experiment cookie so avoid putting sensitive data in there - especially if you choose to disable the cookie encryption.
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-09-11'
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 = { http_only: true, path: '/', same_site: :strict }
14
- @experiments = {}
15
- @secret = '9fc8b966eca7d03d55df40c01c10b8e02bf1f9d12d27b8968d53eb53e8c239902d00bf6afae5e726ce1111159eeb2f8f0e77233405db1d82dd71397f651a0a4f'
16
- @secure = true
17
- @encryptor = (@secure ? EenyMeeny::Encryptor.new(@secret) : nil)
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
- cookie = read_cookie(EenyMeeny::Cookie.cookie_name(experiment))
10
- cookie[:variation] unless cookie.nil? || (variation_id.present? && variation_id != cookie[:variation].id)
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
- unless cookies.has_key?(EenyMeeny::Cookie.cookie_name(experiment))
29
- env['Set-Cookie'] = ''
30
- cookie = EenyMeeny::Cookie.create_for_experiment(experiment, @cookie_config)
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
- Rack::Utils.set_cookie_header!(env,
33
- cookie.name,
34
- cookie.to_h)
35
- env['HTTP_COOKIE'] = '' if env['HTTP_COOKIE'].nil?
36
- env['HTTP_COOKIE'] += '; ' unless env['HTTP_COOKIE'].empty?
37
- env['HTTP_COOKIE'] += env['Set-Cookie']
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.variations.detect { |variation| variation.id == variation_id }
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: Marshal.dump({
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: Marshal.dump({
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: Marshal.dump({
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 Marshal.load(cookie_string) unless EenyMeeny.config.secure # Cookie encryption disabled.
71
- Marshal.load(EenyMeeny.config.encryptor.decrypt(cookie_string))
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|
@@ -8,13 +8,5 @@ module EenyMeeny
8
8
  @weight = weight
9
9
  @options = options
10
10
  end
11
-
12
- def marshal_dump
13
- [@id, { name: @name, weight: @weight, **@options }]
14
- end
15
-
16
- def marshal_load(array)
17
- send :initialize, array[0], **array[1]
18
- end
19
11
  end
20
12
  end
@@ -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 = 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)
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
- 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)
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
@@ -1,3 +1,3 @@
1
1
  module EenyMeeny
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -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)[:variation].id).to eq(:new)
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)[:variation].id).to eq(:new)
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 = 'DhtZMLAtVpWiruuq6BdQ+YEeDTK4G1p0HQLeyKFZd2+fD8YyT004p56S03yXsE/kzCASnD9O1sk1tsIHDZ8W2gq+5zQD3fu2aqqLm461FOfy0En4/LqHCP0J0VYol3Py0BlhepjSGDuJrRU7TdKZWsG2/dCiMVLjMf0Pt00NZWooUvQfRz9SCzaFL0mywoVrY1ErKKQCNEPmLREaxavCng=='
112
- expect(described_class.read(valid_cookie_string)).to be_a Hash
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 be_a Hash
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
@@ -16,4 +16,7 @@ class MockRackApp
16
16
  @env[key]
17
17
  end
18
18
 
19
+ def []=(key,value)
20
+ @env[key] = value
21
+ end
19
22
  end
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.0.0
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-09-11 00:00:00.000000000 Z
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