eeny-meeny 2.3.0 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb901520367109f3167e217522a3b712ae71167e04c0458d4dac2b0907b541bc
4
- data.tar.gz: b360de703e230a8aef6fb7ec7211fe24aa2f79007bb2c3344591a452b40d26ae
3
+ metadata.gz: 1d7c9f1940d946cd5a0477150804281712e40fa6153d4924e8d5a06ab1576f00
4
+ data.tar.gz: 6c9a03ce11ba41d70d3a1b9900685f63ad7c45983a40ae520308c37f868a95de
5
5
  SHA512:
6
- metadata.gz: f9e244e1ba2895921276b2fe070689a2694296ce8db150e0f9ddde380608d65e5cda63afe6e130981da0c7eed3e5e32eb67e28b021cfc38cbf8d931d23b4a8e3
7
- data.tar.gz: e84d5450b37db881191650f259a9abe353d63e8ab8cbdda3c666932029ad78774281f8d99ea73491c74f1807d3aad7dce6908b678c779b888b1c79a32b7c3b2d
6
+ metadata.gz: 5c248029984be24e20a0267967b2741db67a8a4a0fa224463ad032d5a438d15915e73367a8befc932510fd46837baeb75640f41a073c9586944aed323182fd44
7
+ data.tar.gz: 94345325d181119efcd8086f32ff267e47a67e98af0a315ef9b93a3d717c43472421d1aa7c2225de7d727732056df94ebad2ca7cf3dd2836d10f0ce83efac4cc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ### 2.4.0 (2025-08-27)
2
+
3
+ Changes:
4
+
5
+ - Support Rails 7.
6
+ - Support rack 3.x.
7
+ - Drop support for rack 1.x.
8
+ - Use header constants from rack to support header case-change from rack 2.x to 3.x.
9
+ - Changed default "same_site" cookie config from "strict" to "lax".
10
+
1
11
  ### 2.3.0 (2021-08-11)
2
12
 
3
13
  Changes:
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 = '2021-08-11'
6
+ s.date = '2025-08-27'
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'
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_development_dependency('simplecov', '~> 0')
19
19
  s.add_development_dependency('simplecov-rcov', '~> 0')
20
20
  s.add_development_dependency('yard', '>= 0.9.11', '< 1.0.0')
21
- s.add_development_dependency('rack-test', '~> 1')
22
- s.add_runtime_dependency('rack', '>= 1.2.1', '< 3')
23
- s.add_runtime_dependency('activesupport', '>= 3.0.0', '< 6.2.0')
21
+ s.add_development_dependency('rack-test', '~> 2')
22
+ s.add_runtime_dependency('rack', '>= 2.0.0', '< 4')
23
+ s.add_runtime_dependency('activesupport', '>= 3.0.0', '< 8')
24
24
  end
@@ -1,5 +1,6 @@
1
1
  require 'rack'
2
2
  require 'time'
3
+ require 'active_support'
3
4
  require 'active_support/time'
4
5
  require 'eeny-meeny/models/experiment'
5
6
  require 'eeny-meeny/models/encryptor'
@@ -8,11 +9,6 @@ require 'eeny-meeny/models/cookie'
8
9
  module EenyMeeny
9
10
  class Middleware
10
11
 
11
- # Headers
12
- HTTP_COOKIE = 'HTTP_COOKIE'.freeze
13
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
14
- QUERY_STRING = 'QUERY_STRING'.freeze
15
-
16
12
  def initialize(app)
17
13
  @app = app
18
14
  @experiments = EenyMeeny::Experiment.find_all
@@ -20,7 +16,7 @@ module EenyMeeny
20
16
  end
21
17
 
22
18
  def call(env)
23
- cookies = Rack::Utils.parse_query(env[HTTP_COOKIE],';,') { |s| Rack::Utils.unescape(s) rescue s }
19
+ cookies = Rack::Utils.parse_query(env[Rack::HTTP_COOKIE],';,') { |s| Rack::Utils.unescape(s) rescue s }
24
20
  query_parameters = query_hash(env)
25
21
  now = Time.zone.now
26
22
  new_cookies = {}
@@ -95,17 +91,17 @@ module EenyMeeny
95
91
  # Query Params are only relevant if EenyMeeny.config have them enabled.
96
92
  return {} unless EenyMeeny.config.query_parameters[:experiment] || EenyMeeny.config.query_parameters[:smoke_test]
97
93
  # Query Params are only relevant to HTTP GET requests.
98
- return {} unless env[REQUEST_METHOD] == 'GET'
99
- Rack::Utils.parse_query(env[QUERY_STRING], '&;')
94
+ return {} unless env[Rack::REQUEST_METHOD] == 'GET'
95
+ Rack::Utils.parse_query(env[Rack::QUERY_STRING], '&;')
100
96
  end
101
97
 
102
98
  def add_or_replace_http_cookie(env, cookie)
103
99
  cookie_name_escaped = Rack::Utils.escape(cookie.name)
104
100
  cookie_string = "#{cookie_name_escaped}=#{Rack::Utils.escape(cookie.value)}"
105
- env[HTTP_COOKIE] = '' if env[HTTP_COOKIE].nil?
106
- return env if env[HTTP_COOKIE].sub!(/#{Regexp.escape(cookie_name_escaped)}=[^;]+/, cookie_string)
107
- env[HTTP_COOKIE] += '; ' unless env[HTTP_COOKIE].empty?
108
- env[HTTP_COOKIE] += cookie_string
101
+ env[Rack::HTTP_COOKIE] = '' if env[Rack::HTTP_COOKIE].nil?
102
+ return env if env[Rack::HTTP_COOKIE].sub!(/#{Regexp.escape(cookie_name_escaped)}=[^;]+/, cookie_string)
103
+ env[Rack::HTTP_COOKIE] += '; ' unless env[Rack::HTTP_COOKIE].empty?
104
+ env[Rack::HTTP_COOKIE] += cookie_string
109
105
  env
110
106
  end
111
107
  end
@@ -1,5 +1,6 @@
1
1
  require 'eeny-meeny/models/cookie'
2
2
  require 'eeny-meeny/models/variation'
3
+ require 'active_support'
3
4
  require 'active_support/time'
4
5
  require 'active_support/core_ext/enumerable'
5
6
 
@@ -1,3 +1,3 @@
1
1
  module EenyMeeny
2
- VERSION = '2.3.0'
2
+ VERSION = '2.4.0'
3
3
  end
data/lib/eeny-meeny.rb CHANGED
@@ -10,7 +10,7 @@ module EenyMeeny
10
10
  attr_reader :encryptor
11
11
 
12
12
  def initialize
13
- @cookies = { http_only: true, path: '/', same_site: :strict }
13
+ @cookies = { http_only: true, path: '/', same_site: :lax }
14
14
  @experiments = {}
15
15
  @secret = '9fc8b966eca7d03d55df40c01c10b8e02bf1f9d12d27b8968d53eb53e8c239902d00bf6afae5e726ce1111159eeb2f8f0e77233405db1d82dd71397f651a0a4f'
16
16
  @secure = true
@@ -11,33 +11,24 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
11
11
  Object.new.extend(EenyMeeny::ExperimentHelper)
12
12
  end
13
13
 
14
- let(:request) do
15
- Rack::MockSession.new(EenyMeeny::Middleware.new(MockRackApp.new))
16
- end
14
+ let(:app) { EenyMeeny::Middleware.new(MockRackApp.new) }
15
+ let(:experiment) { EenyMeeny::Experiment.find_by_id(:my_page) }
17
16
 
18
17
  describe '#participates_in?' do
19
18
  context 'given an experiment id' do
20
- let(:request_with_cookie) do
21
- request.set_cookie(EenyMeeny::Cookie.create_for_experiment(EenyMeeny::Experiment.find_by_id(:my_page)).to_s)
22
- request
23
- end
24
-
25
19
  context 'of an active experiment' do
26
20
  context 'with a valid experiment cookie' do
27
21
  it "returns the user's experiment variation" do
28
- allow(subject).to receive(:cookies).and_return(request_with_cookie.cookie_jar)
22
+ get '/test'
23
+ allow(subject).to receive(:cookies).and_return(current_session.cookie_jar)
29
24
  expect(subject.participates_in?(:my_page)).to be_a EenyMeeny::Variation
30
25
  end
31
26
 
32
27
  context 'and given a variation id' do
33
- let(:request_with_variation_cookie) do
34
- request.set_cookie(EenyMeeny::Cookie.create_for_experiment_variation(EenyMeeny::Experiment.find_by_id(:my_page), :new).to_s)
35
- request
36
- end
37
-
38
28
  context 'that matches the variation id the cookie' do
39
29
  it "returns the user's experiment variation" do
40
- allow(subject).to receive(:cookies).and_return(request_with_variation_cookie.cookie_jar)
30
+ get '/test' , EenyMeeny::Cookie.cookie_name(experiment) => :new
31
+ allow(subject).to receive(:cookies).and_return(current_session.cookie_jar)
41
32
  expect(subject.participates_in?(:my_page, variation_id: :new)).to be_a EenyMeeny::Variation
42
33
  expect(subject.participates_in?(:my_page, variation_id: 'new')).to be_a EenyMeeny::Variation
43
34
  end
@@ -45,7 +36,8 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
45
36
 
46
37
  context 'that does not match the variation id the cookie' do
47
38
  it 'returns nil' do
48
- allow(subject).to receive(:cookies).and_return(request_with_variation_cookie.cookie_jar)
39
+ get '/test', EenyMeeny::Cookie.cookie_name(experiment) => :new
40
+ allow(subject).to receive(:cookies).and_return(current_session.cookie_jar)
49
41
  expect(subject.participates_in?(:my_page, variation_id: :old)).to be_nil
50
42
  expect(subject.participates_in?(:my_page, variation_id: 'old')).to be_nil
51
43
  end
@@ -55,7 +47,7 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
55
47
 
56
48
  context 'without an experiment cookie' do
57
49
  it 'returns nil' do
58
- allow(subject).to receive(:cookies).and_return(request.cookie_jar)
50
+ allow(subject).to receive(:cookies).and_return({})
59
51
  expect(subject.participates_in?(:my_page)).to be_nil
60
52
  end
61
53
  end
@@ -63,13 +55,15 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
63
55
 
64
56
  context 'of an inactive experiment' do
65
57
  context 'with a valid experiment cookie' do
66
- let(:request_with_expired_cookie) do
67
- request.set_cookie(EenyMeeny::Cookie.create_for_experiment(EenyMeeny::Experiment.find_by_id(:expired)).to_s)
68
- request
58
+ let(:experiment) { EenyMeeny::Experiment.find_by_id(:expired) }
59
+ let(:cookie_jar) do
60
+ {
61
+ "#{EenyMeeny::Cookie.cookie_name(experiment)}" => EenyMeeny::Cookie.create_for_experiment(experiment).to_s
62
+ }
69
63
  end
70
64
 
71
65
  it 'returns nil' do
72
- allow(subject).to receive(:cookies).and_return(request_with_expired_cookie.cookie_jar)
66
+ allow(subject).to receive(:cookies).and_return(cookie_jar)
73
67
  expect(subject.participates_in?(:expired)).to be_nil
74
68
  end
75
69
  end
@@ -77,7 +71,8 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
77
71
 
78
72
  context 'that does not exist among the experiments' do
79
73
  it 'returns nil' do
80
- allow(subject).to receive(:cookies).and_return(request_with_cookie.cookie_jar)
74
+ get '/test'
75
+ allow(subject).to receive(:cookies).and_return(current_session.cookie_jar)
81
76
  expect(subject.participates_in?(:this_does_not_exist)).to be_nil
82
77
  end
83
78
  end
@@ -86,21 +81,17 @@ describe EenyMeeny::ExperimentHelper, experiments: true do
86
81
 
87
82
  describe '#smoke_test?' do
88
83
  context 'given a smoke test id' do
89
- let(:request_with_smoke_test) do
90
- request.set_cookie(EenyMeeny::Cookie.create_for_smoke_test(:my_smoke_test).to_s)
91
- request
92
- end
93
-
94
84
  context 'and a request with a valid smoke test cookie' do
95
85
  it 'returns the smoke test' do
96
- allow(subject).to receive(:cookies).and_return(request_with_smoke_test.cookie_jar)
86
+ get '/test', smoke_test_id: "my_smoke_test"
87
+ allow(subject).to receive(:cookies).and_return(current_session.cookie_jar)
97
88
  expect(subject.smoke_test?(:my_smoke_test)).to be
98
89
  end
99
90
  end
100
91
 
101
92
  context 'and a request without a smoke test cookie' do
102
93
  it 'returns nil' do
103
- allow(subject).to receive(:cookies).and_return(request.cookie_jar)
94
+ allow(subject).to receive(:cookies).and_return({})
104
95
  expect(subject.smoke_test?(:my_smoke_test)).to be_nil
105
96
  end
106
97
  end
@@ -1,7 +1,7 @@
1
1
  require 'eeny-meeny/models/encryptor'
2
2
  require 'eeny-meeny/middleware'
3
3
 
4
- def initialize_app(secure: true, secret: 'test', path: '/', same_site: :strict)
4
+ def initialize_app(secure: true, secret: 'test', path: '/', same_site: :lax)
5
5
  EenyMeeny.reset!
6
6
  EenyMeeny.configure do |config|
7
7
  config.cookies = { path: path, same_site: same_site }
@@ -12,6 +12,16 @@ def initialize_app(secure: true, secret: 'test', path: '/', same_site: :strict)
12
12
  described_class.new(app)
13
13
  end
14
14
 
15
+ def request_options(http_cookie_header: nil)
16
+ options = {
17
+ 'CONTENT_TYPE' => 'text/plain',
18
+ lint: true
19
+ }
20
+ return options unless http_cookie_header
21
+
22
+ options.merge({ Rack::HTTP_COOKIE => http_cookie_header })
23
+ end
24
+
15
25
  describe EenyMeeny::Middleware do
16
26
 
17
27
  let(:app) { MockRackApp.new }
@@ -40,13 +50,13 @@ describe EenyMeeny::Middleware do
40
50
  end
41
51
 
42
52
  it "sets the 'HTTP_COOKIE' header on the request" do
43
- expect(app['HTTP_COOKIE']).to be
44
- expect(app['HTTP_COOKIE'].length).to be > 0
53
+ expect(app[Rack::HTTP_COOKIE]).to be
54
+ expect(app[Rack::HTTP_COOKIE].length).to be > 0
45
55
  end
46
56
 
47
57
  it "sets the 'Set-Cookie' header on the response" do
48
- expect(@response['Set-Cookie']).to be
49
- expect(@response['Set-Cookie'].length).to be > 0
58
+ expect(@response[Rack::SET_COOKIE]).to be
59
+ expect(@response[Rack::SET_COOKIE].length).to be > 0
50
60
  end
51
61
  end
52
62
 
@@ -56,16 +66,15 @@ describe EenyMeeny::Middleware do
56
66
  before(:example) do
57
67
  @original_request_cookies = 'test=abc;eeny_meeny_my_page_v1=on1tOQ5hiKdA0biVZVwvTUQcmkODacwdpi%2FedQJIYQz9KdWYAXqzCafF5Dqqa6xtHFBdXYVmz%2Bp4%2FigmKz4hBVYZbJU%2FMwBbvYG%2BIoBelk10PxwtyxbA%2BiDzFT4jZeiTkNOmZ3rp1Gzz74JjT4aocqB187p7SrpeM2jfyZ8ZKPOiZs6tXf0QoXkV%2BZbtxJLRPr5lgmGxslfM8vCIm1%2F0HQ%3D%3D;eeny_meeny_versioned_v3=UUgXwn3j0%2BOL2cpov4duTnuCJPc621yHd6GjuXpN0gnYLDASTsDpyk01CnFY5ZYCAo%2BgLO%2BwTbsYObP8dp30rA%3D%3D;'
58
68
  @response = request.get('/test',
59
- 'CONTENT_TYPE' => 'text/plain',
60
- 'HTTP_COOKIE' => @original_request_cookies)
69
+ request_options(http_cookie_header: @original_request_cookies))
61
70
  end
62
71
 
63
72
  it "does not change the 'HTTP_COOKIE' header on the request" do
64
- expect(app['HTTP_COOKIE']).to eq(@original_request_cookies)
73
+ expect(app[Rack::HTTP_COOKIE]).to eq(@original_request_cookies)
65
74
  end
66
75
 
67
76
  it "does not set the 'Set-Cookie' header on the response" do
68
- expect(@response['Set-Cookie']).to be nil
77
+ expect(@response[Rack::SET_COOKIE]).to be nil
69
78
  end
70
79
  end
71
80
 
@@ -73,19 +82,18 @@ describe EenyMeeny::Middleware do
73
82
  let(:request) { Rack::MockRequest.new(subject) }
74
83
  let(:cookie_value) { 'eeny_meeny_undefined_experiment_v1=thevaluedoesntmatter' }
75
84
  let(:return_value) do
76
- "#{cookie_value}; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Strict"
85
+ 'eeny_meeny_undefined_experiment_v1=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax'
77
86
  end
78
87
 
79
88
  before(:example) do
80
89
  @original_request_cookies = "test=abc;#{cookie_value};"
81
90
  @response = request.get('/test',
82
- 'CONTENT_TYPE' => 'text/plain',
83
- 'HTTP_COOKIE' => @original_request_cookies)
91
+ request_options(http_cookie_header: @original_request_cookies))
84
92
  end
85
93
 
86
94
 
87
95
  it "instructs the browser to remove through the 'Set-Cookie' header on the response" do
88
- expect(@response['Set-Cookie']).to include(return_value)
96
+ expect(@response[Rack::SET_COOKIE]).to include(return_value)
89
97
  end
90
98
  end
91
99
 
@@ -97,18 +105,17 @@ describe EenyMeeny::Middleware do
97
105
  end
98
106
 
99
107
  it 'selects the correct variation' do
100
- expect(app['HTTP_COOKIE']).to include('eeny_meeny_my_page_v1=old')
101
- expect(app['HTTP_COOKIE']).to_not include('eeny_meeny_my_page_v1=new')
108
+ expect(app[Rack::HTTP_COOKIE]).to include('eeny_meeny_my_page_v1=old')
109
+ expect(app[Rack::HTTP_COOKIE]).to_not include('eeny_meeny_my_page_v1=new')
102
110
  end
103
111
 
104
112
  it "sets the 'HTTP_COOKIE' header on the request" do
105
- expect(app['HTTP_COOKIE']).to be
106
- expect(app['HTTP_COOKIE']).to include('eeny_meeny_my_page_v1=')
113
+ expect(app[Rack::HTTP_COOKIE]).to be
114
+ expect(app[Rack::HTTP_COOKIE]).to include('eeny_meeny_my_page_v1=')
107
115
  end
108
116
 
109
117
  it "sets the 'Set-Cookie' header on the response" do
110
- expect(@response['Set-Cookie']).to be
111
- expect(@response['Set-Cookie']).to include('eeny_meeny_my_page_v1=')
118
+ expect_set_cookie_with(response: @response, value: 'eeny_meeny_my_page_v1=')
112
119
  end
113
120
  end
114
121
 
@@ -120,15 +127,13 @@ describe EenyMeeny::Middleware do
120
127
  end
121
128
 
122
129
  it "sets the 'HTTP_COOKIE' header on the request" do
123
- expect(app['HTTP_COOKIE']).to be
124
- expect(app['HTTP_COOKIE']).to include('smoke_test_my_smoke_test_v1=')
130
+ expect(app[Rack::HTTP_COOKIE]).to be
131
+ expect(app[Rack::HTTP_COOKIE]).to include('smoke_test_my_smoke_test_v1=')
125
132
  end
126
133
 
127
134
  it "sets the 'Set-Cookie' header on the response" do
128
- expect(@response['Set-Cookie']).to be
129
- expect(@response['Set-Cookie']).to include('smoke_test_my_smoke_test_v1=')
135
+ expect_set_cookie_with(response: @response, value: 'smoke_test_my_smoke_test_v1=')
130
136
  end
131
137
  end
132
138
  end
133
-
134
139
  end
@@ -1,27 +1,21 @@
1
1
  require 'eeny-meeny/models/experiment'
2
2
  require 'eeny-meeny/models/variation'
3
3
 
4
- def experiment_with_time(time = {})
5
- experiment_options = {
6
- name: 'Test 1',
7
- variations: {
8
- a: { name: 'A' },
9
- b: { name: 'B' }}
10
- }.merge(time)
11
- described_class.new(:experiment_1,
12
- **experiment_options)
13
- end
14
-
15
4
  describe EenyMeeny::Experiment do
16
5
  describe 'when initialized' do
6
+ let(:experiment_options) { {} }
7
+ subject do
8
+ build_experiment(**experiment_options)
9
+ end
17
10
 
18
11
  context 'with weighted variations' do
19
- subject do
20
- described_class.new(:experiment_1,
21
- name: 'Test 1',
22
- variations: {
23
- a: { name: 'A', weight: 0.5 },
24
- b: { name: 'B', weight: 0.3 }})
12
+ let(:experiment_options) do
13
+ {
14
+ variations: {
15
+ a: { name: 'A', weight: 0.5 },
16
+ b: { name: 'B', weight: 0.3 }
17
+ }
18
+ }
25
19
  end
26
20
 
27
21
  it 'sets the instance variables' do
@@ -43,14 +37,6 @@ describe EenyMeeny::Experiment do
43
37
  end
44
38
 
45
39
  context 'with non-weighted variations' do
46
- subject do
47
- described_class.new(:experiment_1,
48
- name: 'Test 1',
49
- variations: {
50
- a: { name: 'A' },
51
- b: { name: 'B' }})
52
- end
53
-
54
40
  it 'sets the instance variables' do
55
41
  expect(subject.id).to eq(:experiment_1)
56
42
  expect(subject.name).to eq('Test 1')
@@ -93,58 +79,68 @@ describe EenyMeeny::Experiment do
93
79
 
94
80
  context 'when the experiment only have an end_at time' do
95
81
  context 'and the current time < end_at' do
82
+ let(:experiment_options) { { end_at: (Time.zone.now+3600).iso8601 }}
83
+
96
84
  it 'returns true' do
97
- instance = experiment_with_time(end_at: (Time.zone.now+3600).iso8601)
98
- expect(instance.active?).to be true
85
+ expect(subject.active?).to be true
99
86
  end
100
87
  end
101
88
 
102
89
  context 'and the current time > end_at' do
90
+ let(:experiment_options) { { end_at: (Time.zone.now-3600).iso8601 }}
91
+
103
92
  it 'returns false' do
104
- instance = experiment_with_time(end_at: (Time.zone.now-3600).iso8601)
105
- expect(instance.active?).to be false
93
+ expect(subject.active?).to be false
106
94
  end
107
95
  end
108
96
  end
109
97
 
110
98
  context 'when the experiment only have a start_at time' do
111
99
  context 'and the current time < start_at' do
100
+ let(:experiment_options) { { start_at: (Time.zone.now+3600).iso8601 } }
101
+
112
102
  it 'returns false' do
113
- instance = experiment_with_time(start_at: (Time.zone.now+3600).iso8601)
114
- expect(instance.active?).to be false
103
+ expect(subject.active?).to be false
115
104
  end
116
105
  end
117
106
 
118
107
  context 'and the current time > start_at' do
108
+ let(:experiment_options) { { start_at: (Time.zone.now-3600).iso8601 } }
109
+
119
110
  it 'returns true' do
120
- instance = experiment_with_time(start_at: (Time.zone.now-3600).iso8601)
121
- expect(instance.active?).to be true
111
+ expect(subject.active?).to be true
122
112
  end
123
113
  end
124
114
  end
125
115
 
126
116
  context 'when the experiment both have a start_at and end_at time' do
127
117
  context 'and current_time < start_at' do
118
+ let(:experiment_options) do
119
+ { start_at: (Time.zone.now+3600).iso8601, end_at: (Time.zone.now+7200).iso8601 }
120
+ end
121
+
128
122
  it 'returns false' do
129
- instance = experiment_with_time(start_at: (Time.zone.now+3600).iso8601,
130
- end_at: (Time.zone.now+7200).iso8601)
131
- expect(instance.active?).to be false
123
+ expect(subject.active?).to be false
132
124
  end
133
125
  end
134
126
 
135
127
  context 'and current_time > start_at and current time < end_at' do
128
+ let(:experiment_options) do
129
+ { start_at: (Time.zone.now-3600).iso8601, end_at: (Time.zone.now+7200).iso8601 }
130
+ end
131
+
136
132
  it 'returns true' do
137
- instance = experiment_with_time(start_at: (Time.zone.now-3600).iso8601,
138
- end_at: (Time.zone.now+7200).iso8601)
139
- expect(instance.active?).to be true
133
+ expect(subject.active?).to be true
140
134
  end
141
135
  end
142
136
 
143
137
  context 'and current time > start_at and current time > end_at' do
138
+ let(:experiment_options) do
139
+ { start_at: (Time.zone.now-7200).iso8601, end_at: (Time.zone.now-3600).iso8601 }
140
+ end
141
+
144
142
  it 'returns false' do
145
- instance = experiment_with_time(start_at: (Time.zone.now-7200).iso8601,
146
- end_at: (Time.zone.now-3600).iso8601)
147
- expect(instance.active?).to be false
143
+ expect(subject.active?).to be false
148
144
  end
149
145
  end
150
146
  end
@@ -1,14 +1,11 @@
1
1
  class MockRackApp
2
2
 
3
- attr_reader :request_body
4
-
5
3
  def initialize
6
4
  @request_headers = {}
7
5
  end
8
6
 
9
7
  def call(env)
10
8
  @env = env
11
- @request_body = env['rack.input'].read
12
9
  [200, {'Content-Type' => 'text/plain'}, ['OK']]
13
10
  end
14
11
 
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  require 'simplecov'
2
+ require 'active_support'
2
3
  require 'active_support/time'
3
4
  require 'rspec'
5
+ require 'rack/test'
4
6
  require 'yaml'
5
7
  require 'mock_rack_app'
6
8
  require 'eeny-meeny'
7
9
 
10
+ Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) }
11
+
8
12
  RSpec.configure do |config|
13
+ config.include Rack::Test::Methods
9
14
  config.run_all_when_everything_filtered = true
10
15
  config.filter_run :focus
11
16
  config.order = "random"
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ def expect_set_cookie_with(response: {}, value: '')
4
+ expect(response).to be
5
+ expect(response[Rack::SET_COOKIE]).to be_an(Array)
6
+ expect(response[Rack::SET_COOKIE]).to_not be_empty
7
+ expect(response[Rack::SET_COOKIE].find { |cookie_string| cookie_string.include?(value) }).to be
8
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eeny-meeny/models/experiment'
4
+
5
+ def build_experiment(id: :experiment_1, **options)
6
+ experiment_options = {
7
+ name: 'Test 1',
8
+ variations: {
9
+ a: { name: 'A' },
10
+ b: { name: 'B' }}
11
+ }.merge(options)
12
+ EenyMeeny::Experiment.new(id, **experiment_options)
13
+ 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.3.0
4
+ version: 2.4.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: 2021-08-11 00:00:00.000000000 Z
11
+ date: 2025-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -92,34 +92,34 @@ dependencies:
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '1'
95
+ version: '2'
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '1'
102
+ version: '2'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: rack
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="
108
108
  - !ruby/object:Gem::Version
109
- version: 1.2.1
109
+ version: 2.0.0
110
110
  - - "<"
111
111
  - !ruby/object:Gem::Version
112
- version: '3'
112
+ version: '4'
113
113
  type: :runtime
114
114
  prerelease: false
115
115
  version_requirements: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
- version: 1.2.1
119
+ version: 2.0.0
120
120
  - - "<"
121
121
  - !ruby/object:Gem::Version
122
- version: '3'
122
+ version: '4'
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: activesupport
125
125
  requirement: !ruby/object:Gem::Requirement
@@ -129,7 +129,7 @@ dependencies:
129
129
  version: 3.0.0
130
130
  - - "<"
131
131
  - !ruby/object:Gem::Version
132
- version: 6.2.0
132
+ version: '8'
133
133
  type: :runtime
134
134
  prerelease: false
135
135
  version_requirements: !ruby/object:Gem::Requirement
@@ -139,7 +139,7 @@ dependencies:
139
139
  version: 3.0.0
140
140
  - - "<"
141
141
  - !ruby/object:Gem::Version
142
- version: 6.2.0
142
+ version: '8'
143
143
  description:
144
144
  email: christian.orthmann@gmail.com
145
145
  executables: []
@@ -178,6 +178,8 @@ files:
178
178
  - spec/fixtures/experiments.yml
179
179
  - spec/mock_rack_app.rb
180
180
  - spec/spec_helper.rb
181
+ - spec/support/custom_expectations/expect_cookie_with.rb
182
+ - spec/support/factories/experiment.rb
181
183
  - spec/tasks/cookie_task_spec.rb
182
184
  homepage: http://rubygems.org/gems/eeny-meeny
183
185
  licenses:
@@ -198,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
200
  - !ruby/object:Gem::Version
199
201
  version: '0'
200
202
  requirements: []
201
- rubygems_version: 3.1.4
203
+ rubygems_version: 3.5.3
202
204
  signing_key:
203
205
  specification_version: 4
204
206
  summary: A simple split and smoke testing tool for Rails