eeny-meeny 2.1.4 → 2.2.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: 593babb310531c408fd76d2e1d3acc142ee4f98a
4
- data.tar.gz: 2cb7489e568834c7aa6ac01105d8be9fd4088fcf
3
+ metadata.gz: 9bdb7307a93707a324593a1cb18098053225834c
4
+ data.tar.gz: 8e6895a3a9c53cea18980a419fda79ee97eff00b
5
5
  SHA512:
6
- metadata.gz: ba008a88abe4141df40a3685149037737a562a82b35b9ec290b93154c51a917604034d9ce73f3724e04678dd6c44573f7e2f00e2443e44738673a8a02e838471
7
- data.tar.gz: 5d24cb185e1e8ea075957664f5597399c2346cfaffd0f56bdfa934e05bc7c58ffa259115306362e3fcda02840083cf82f7a68367391a108c570e250a62c13d20
6
+ metadata.gz: 4635a786f22f51f5f9402a7822cd061a3c3cad729448ec323834c5f21b86438fd902d4a2a180d290d25c33a097c5a65136f4c1c6f0b58cfa7632797cb6a7f600
7
+ data.tar.gz: '09965f4d8b1685cda659b4e31c0fa8de8b536a78e9976a7a7823b0561933ba1f639722284375e45cb6bad5452f38f199dd81b8121e6fef084ccb93b5d81feb9a'
@@ -1,3 +1,13 @@
1
+ ### 2.2.0 (2018-07-24)
2
+
3
+ Features:
4
+
5
+ - Let `Eeny::Meeny::Middleware` remove deprecated experiment cookies (for undefined and inactive experiements)
6
+
7
+ Changes:
8
+
9
+ - Renamed `EenyMeeny::Cookie::COOKIE_PREFIX` to `EenyMeeny::Cookie::EXPERIMENT_PREFIX`
10
+
1
11
  ### 2.1.4 (2017-10-04)
2
12
 
3
13
  Changes:
@@ -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 = '2017-10-04'
6
+ s.date = '2018-07-24'
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'
@@ -24,34 +24,15 @@ module EenyMeeny
24
24
  query_parameters = query_hash(env)
25
25
  now = Time.zone.now
26
26
  new_cookies = {}
27
+ delete_cookies = find_deprecated_cookies(cookies, now)
27
28
  # Prepare for experiments.
28
29
  @experiments.each do |experiment|
29
30
  # Skip inactive experiments
30
31
  next unless experiment.active?(now)
31
- # Trigger experiment through query parameters
32
- cookie_name = EenyMeeny::Cookie.cookie_name(experiment)
33
- has_experiment_trigger = EenyMeeny.config.query_parameters[:experiment] && query_parameters.key?(cookie_name)
34
- # skip experiments that already have a cookie
35
- next unless has_experiment_trigger || !cookies.key?(cookie_name)
36
- cookie = if has_experiment_trigger
37
- # Trigger experiment variation through query parameter.
38
- EenyMeeny::Cookie.create_for_experiment_variation(experiment, query_parameters[cookie_name].to_sym, @cookie_config)
39
- else
40
- EenyMeeny::Cookie.create_for_experiment(experiment, @cookie_config)
41
- end
42
- # Set HTTP_COOKIE header to enable experiment on first pageview
43
- env = add_or_replace_http_cookie(env, cookie)
44
- new_cookies[cookie.name] = cookie
45
- end
46
- # Prepare smoke tests (if enabled through query parameters)
47
- if EenyMeeny.config.query_parameters[:smoke_test]
48
- if query_parameters.key?('smoke_test_id') && (query_parameters['smoke_test_id'] =~ /\A[A-Za-z_]+\z/)
49
- # Set HTTP_COOKIE header to enable smoke test on first pageview
50
- cookie = EenyMeeny::Cookie.create_for_smoke_test(query_parameters['smoke_test_id'], @cookie_config)
51
- env = add_or_replace_http_cookie(env, cookie)
52
- new_cookies[cookie.name] = cookie
53
- end
32
+ env, new_cookies = prepare_experiment(env, cookies, new_cookies, query_parameters, experiment)
54
33
  end
34
+ # Prepare smoke tests
35
+ env, new_cookies = prepare_smoke_test(env, new_cookies, query_parameters)
55
36
  # Delegate to app
56
37
  status, headers, body = @app.call(env)
57
38
  response = Rack::Response.new(body, status, headers)
@@ -59,11 +40,57 @@ module EenyMeeny
59
40
  new_cookies.each do |key, value|
60
41
  response.set_cookie(key,value.to_h)
61
42
  end
43
+ delete_cookies.each do |key, value|
44
+ response.delete_cookie(key, value: value, path: @cookie_config[:path], same_site: @cookie_config[:same_site])
45
+ end
62
46
  response.finish
63
47
  end
64
48
 
65
49
  private
66
50
 
51
+ def find_deprecated_cookies(cookies, now)
52
+ deprecated_cookies = {}
53
+ cookies.each do |cookie_name, value|
54
+ # Skip any cookie that does not have the 'eeny_meeny_' prefix
55
+ next unless cookie_name.to_s.start_with?(EenyMeeny::Cookie::EXPERIMENT_PREFIX)
56
+ # Mark cookies that does not match any existing active experiment as 'deprecated'.
57
+ experiment = EenyMeeny::Experiment.find_by_cookie_name(cookie_name)
58
+ next if experiment && experiment.active?(now)
59
+ deprecated_cookies[cookie_name] = value
60
+ end
61
+ deprecated_cookies
62
+ end
63
+
64
+ def prepare_experiment(env, cookies, new_cookies, query_parameters, experiment)
65
+ # Trigger experiment through query parameters
66
+ cookie_name = EenyMeeny::Cookie.cookie_name(experiment)
67
+ has_experiment_trigger = EenyMeeny.config.query_parameters[:experiment] && query_parameters.key?(cookie_name)
68
+ # Skip experiments that already have a cookie
69
+ return env, new_cookies unless has_experiment_trigger || !cookies.key?(cookie_name)
70
+ cookie = if has_experiment_trigger
71
+ # Trigger experiment variation through query parameter.
72
+ EenyMeeny::Cookie.create_for_experiment_variation(experiment, query_parameters[cookie_name].to_sym, @cookie_config)
73
+ else
74
+ EenyMeeny::Cookie.create_for_experiment(experiment, @cookie_config)
75
+ end
76
+ # Set HTTP_COOKIE header to enable experiment on first pageview
77
+ env = add_or_replace_http_cookie(env, cookie)
78
+ new_cookies[cookie.name] = cookie
79
+ return env, new_cookies
80
+ end
81
+
82
+ def prepare_smoke_test(env, new_cookies, query_parameters)
83
+ # Skip if the EenyMeeny 'smoke test' query parameters configuration is disabled.
84
+ return env, new_cookies unless EenyMeeny.config.query_parameters[:smoke_test]
85
+ # Skip if no valid 'smoke_test_id' query parameter present
86
+ return env, new_cookies unless query_parameters.key?('smoke_test_id') && (query_parameters['smoke_test_id'] =~ /\A[A-Za-z_]+\z/)
87
+ # Set HTTP_COOKIE header to enable smoke test on first pageview
88
+ cookie = EenyMeeny::Cookie.create_for_smoke_test(query_parameters['smoke_test_id'], @cookie_config)
89
+ env = add_or_replace_http_cookie(env, cookie)
90
+ new_cookies[cookie.name] = cookie
91
+ return env, new_cookies
92
+ end
93
+
67
94
  def query_hash(env)
68
95
  # Query Params are only relevant if EenyMeeny.config have them enabled.
69
96
  return {} unless EenyMeeny.config.query_parameters[:experiment] || EenyMeeny.config.query_parameters[:smoke_test]
@@ -2,7 +2,7 @@ require 'rack'
2
2
 
3
3
  module EenyMeeny
4
4
  class Cookie
5
- COOKIE_PREFIX = 'eeny_meeny_'.freeze
5
+ EXPERIMENT_PREFIX = 'eeny_meeny_'.freeze
6
6
  SMOKE_TEST_PREFIX = 'smoke_test_'.freeze
7
7
 
8
8
  attr_accessor :value
@@ -52,7 +52,7 @@ module EenyMeeny
52
52
 
53
53
  def self.cookie_name(experiment)
54
54
  return if experiment.nil?
55
- COOKIE_PREFIX+experiment.id.to_s+'_v'+experiment.version.to_s
55
+ EXPERIMENT_PREFIX+experiment.id.to_s+'_v'+experiment.version.to_s
56
56
  end
57
57
 
58
58
  def self.read(cookie_string)
@@ -4,6 +4,9 @@ require 'active_support/core_ext/enumerable'
4
4
 
5
5
  module EenyMeeny
6
6
  class Experiment
7
+
8
+ COOKIE_EXPERIMENT_ID_REGEX = /\Aeeny_meeny_(.+)_v\d+\z/.freeze
9
+
7
10
  attr_reader :id, :name, :version, :variations, :total_weight, :end_at, :start_at
8
11
 
9
12
  def self.find_all
@@ -17,6 +20,12 @@ module EenyMeeny
17
20
  new(experiment_id, **experiment) if experiment
18
21
  end
19
22
 
23
+ def self.find_by_cookie_name(cookie_name)
24
+ if cookie_name =~ COOKIE_EXPERIMENT_ID_REGEX
25
+ find_by_id($1)
26
+ end
27
+ end
28
+
20
29
  def initialize(id, name: '', version: 1, variations: {}, start_at: nil, end_at: nil)
21
30
  @id = id
22
31
  @name = name
@@ -1,3 +1,3 @@
1
1
  module EenyMeeny
2
- VERSION = '2.1.4'
2
+ VERSION = '2.2.0'
3
3
  end
@@ -70,6 +70,22 @@ describe EenyMeeny::Middleware do
70
70
  end
71
71
  end
72
72
 
73
+ context 'and the request contains a cookie from an undefined experiment' do
74
+ let(:request) { Rack::MockRequest.new(subject) }
75
+
76
+ before(:example) do
77
+ @original_request_cookies = 'test=abc;eeny_meeny_undefined_experiment_v1=thevaluedoesntmatter;'
78
+ @response = request.get('/test',
79
+ 'CONTENT_TYPE' => 'text/plain',
80
+ 'HTTP_COOKIE' => @original_request_cookies)
81
+ end
82
+
83
+
84
+ it "instructs the browser to remove through the 'Set-Cookie' header on the response" do
85
+ expect(@response['Set-Cookie']).to include('eeny_meeny_undefined_experiment_v1=thevaluedoesntmatter; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000; SameSite=Strict')
86
+ end
87
+ end
88
+
73
89
  context 'and given an experiment query parameter' do
74
90
  let(:request) { Rack::MockRequest.new(initialize_app(secure: false)) }
75
91
 
@@ -194,4 +194,17 @@ describe EenyMeeny::Experiment do
194
194
  end
195
195
  end
196
196
 
197
+ describe '.find_by_cookie_name', experiments: true do
198
+ context 'when the given cookie name matches a configured experiment' do
199
+ it 'returns the experiment' do
200
+ expect(described_class.find_by_cookie_name(:eeny_meeny_my_page_v1)).to be_a EenyMeeny::Experiment
201
+ end
202
+ end
203
+
204
+ context 'when the given cookie name does not match a configured experiment' do
205
+ it 'returns nil' do
206
+ expect(described_class.find_by_cookie_name(:eeny_meeny_undefined_experiment_v2)).to be_nil
207
+ end
208
+ end
209
+ end
197
210
  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.1.4
4
+ version: 2.2.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: 2017-10-04 00:00:00.000000000 Z
11
+ date: 2018-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -190,9 +190,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
190
  version: '0'
191
191
  requirements: []
192
192
  rubyforge_project:
193
- rubygems_version: 2.4.8
193
+ rubygems_version: 2.6.13
194
194
  signing_key:
195
195
  specification_version: 4
196
196
  summary: A simple split and smoke testing tool for Rails
197
197
  test_files: []
198
- has_rdoc: