rack-redic 0.5.0 → 0.6.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
  SHA1:
3
- metadata.gz: b908eba6dfd16a9c0288fc441f5034a71d90182b
4
- data.tar.gz: 3670a26907451fee9bfbe96b47563e4048fd0d69
3
+ metadata.gz: 0343dd0cb8b4c338b4ffb2f103969e6aa9681556
4
+ data.tar.gz: f8493e153c5f85648d55d5e99433351645e52cb7
5
5
  SHA512:
6
- metadata.gz: 171a60f038d7a62e9af3f5bcf577f89efe7db6a7ea1aaeb73a0de3025147818ed461a9fa2cffb6fff44622006fe90dbbc600d5140a004e668eea670a4006dc29
7
- data.tar.gz: 6e7ff29f664c03f3901dd869a9784837c0a815de439a0f966fc507f5f6ee9bdeb34a3aa2e39fb0189ea33762b5f7d322faf74d4202b38baf81d7c1b7658cd48b
6
+ metadata.gz: 5dbfc8659cc61a1610acb82c1306da982f1ca07bdc39295394743c928ee04d53b038f5454e892dc64eee93b49b605fa4f5005f304b550d855122533fdf893384
7
+ data.tar.gz: ad56f8b4d338f9b6a375309397ab28969a0c92485b159c064d1017816328b408365e38845a976ddf6a58afbad74571d6c3439e1abeaa7cf8f4ac50c6443703cd
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -30,14 +30,16 @@ module Rack
30
30
  class Redic < Abstract::Persisted
31
31
  REDIS_URL = 'REDIS_URL'.freeze
32
32
 
33
+ attr_reader :storage
34
+
33
35
  def initialize(app, options = {})
34
36
  super
35
37
 
36
38
  @mutex = Mutex.new
37
39
  @storage = Storage.new(
38
40
  options[:expire_after],
39
- options.fetch(:marshaller, Marshal),
40
- options.fetch(:url, ENV.fetch(REDIS_URL))
41
+ options.fetch(:marshaller) { Marshal },
42
+ options.fetch(:url) { ENV.fetch(REDIS_URL) }
41
43
  )
42
44
  end
43
45
 
@@ -52,8 +54,9 @@ module Rack
52
54
  # Find the session (or generate a blank one).
53
55
  def find_session(_req, sid)
54
56
  @mutex.synchronize do
55
- sid ||= generate_sid
56
- session = @storage.get(sid) || @storage.init(sid, {})
57
+ unless sid && session = @storage.get(sid)
58
+ sid, session = generate_sid, {}
59
+ end
57
60
 
58
61
  [sid, session]
59
62
  end
@@ -100,11 +103,6 @@ module Rack
100
103
  @storage.call(EXISTS, id) != ZERO
101
104
  end
102
105
 
103
- def init(sid, initial)
104
- set(sid, initial)
105
- initial
106
- end
107
-
108
106
  def get(id)
109
107
  deserialize(@storage.call(GET, id))
110
108
  end
data/rack-redic.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'rack-redic'
5
- spec.version = '0.5.0'
5
+ spec.version = '0.6.0'
6
6
  spec.authors = ['Evan Lecklider']
7
7
  spec.email = ['evan@lecklider.com']
8
8
 
@@ -11,7 +11,10 @@ Gem::Specification.new do |spec|
11
11
  spec.homepage = 'https://github.com/evanleck/rack-redic'
12
12
  spec.license = 'MIT'
13
13
  spec.files = `git ls-files`.split("\n")
14
+ spec.test_files = spec.files.grep(/^spec/)
14
15
 
15
16
  spec.add_dependency 'rack'
16
17
  spec.add_dependency 'redic'
18
+
19
+ spec.add_development_dependency 'rspec'
17
20
  end
@@ -0,0 +1,234 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ require 'rack/lint'
4
+ require 'rack/mock'
5
+
6
+ # These tests are unceremoniously copied and modified from
7
+ # https://github.com/rack/rack/blob/master/test/spec_session_memcache.rb.
8
+ describe Rack::Session::Redic do
9
+ ROOT = '/'
10
+
11
+ session_key = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS[:key]
12
+ session_match = /#{session_key}=([0-9a-fA-F]+);/
13
+
14
+ incrementor = lambda do |env|
15
+ env['rack.session']['counter'] ||= 0
16
+ env['rack.session']['counter'] += 1
17
+
18
+ Rack::Response.new(env['rack.session'].inspect).to_a
19
+ end
20
+
21
+ drop_session = Rack::Lint.new(proc do |env|
22
+ env['rack.session.options'][:drop] = true
23
+ incrementor.call(env)
24
+ end)
25
+
26
+ renew_session = Rack::Lint.new(proc do |env|
27
+ env['rack.session.options'][:renew] = true
28
+ incrementor.call(env)
29
+ end)
30
+
31
+ defer_session = Rack::Lint.new(proc do |env|
32
+ env['rack.session.options'][:defer] = true
33
+ incrementor.call(env)
34
+ end)
35
+
36
+ skip_session = Rack::Lint.new(proc do |env|
37
+ env['rack.session.options'][:skip] = true
38
+ incrementor.call(env)
39
+ end)
40
+
41
+ incrementor = Rack::Lint.new(incrementor)
42
+
43
+ it 'creates a new cookie' do
44
+ redic = Rack::Session::Redic.new(incrementor)
45
+ res = Rack::MockRequest.new(redic).get(ROOT)
46
+
47
+ expect(res[Rack::SET_COOKIE]).to include("#{ session_key }=")
48
+ expect(res.body).to eq('{"counter"=>1}')
49
+ end
50
+
51
+ it 'determines session from a cookie' do
52
+ redic = Rack::Session::Redic.new(incrementor)
53
+ req = Rack::MockRequest.new(redic)
54
+ res = req.get(ROOT)
55
+
56
+ cookie = res[Rack::SET_COOKIE]
57
+
58
+ expect(req.get(ROOT, Rack::HTTP_COOKIE => cookie).body).to eq('{"counter"=>2}')
59
+ expect(req.get(ROOT, Rack::HTTP_COOKIE => cookie).body).to eq('{"counter"=>3}')
60
+ end
61
+
62
+ it 'determines session only from a cookie by default' do
63
+ redic = Rack::Session::Redic.new(incrementor)
64
+ req = Rack::MockRequest.new(redic)
65
+ res = req.get(ROOT)
66
+ sid = res[Rack::SET_COOKIE][session_match, 1]
67
+
68
+ expect(req.get("/?rack.session=#{sid}").body).to eq('{"counter"=>1}')
69
+ expect(req.get("/?rack.session=#{sid}").body).to eq('{"counter"=>1}')
70
+ end
71
+
72
+ it 'determines session from params' do
73
+ redic = Rack::Session::Redic.new(incrementor, cookie_only: false)
74
+ req = Rack::MockRequest.new(redic)
75
+ res = req.get(ROOT)
76
+ sid = res[Rack::SET_COOKIE][session_match, 1]
77
+
78
+ expect(req.get("/?rack.session=#{sid}").body).to eq('{"counter"=>2}')
79
+ expect(req.get("/?rack.session=#{sid}").body).to eq('{"counter"=>3}')
80
+ end
81
+
82
+ it 'survives nonexistant cookies' do
83
+ bad_cookie = "rack.session=#{ SecureRandom.hex(16) }"
84
+
85
+ redic = Rack::Session::Redic.new(incrementor)
86
+ res = Rack::MockRequest.new(redic).get(ROOT, Rack::HTTP_COOKIE => bad_cookie)
87
+
88
+ expect(res.body).to eq('{"counter"=>1}')
89
+
90
+ cookie = res[Rack::SET_COOKIE][session_match]
91
+ expect(cookie).not_to match(/#{ bad_cookie }/)
92
+ end
93
+
94
+ it 'maintains freshness' do
95
+ redic = Rack::Session::Redic.new(incrementor, expire_after: 3)
96
+ res = Rack::MockRequest.new(redic).get(ROOT)
97
+ expect(res.body).to include('"counter"=>1')
98
+
99
+ cookie = res[Rack::SET_COOKIE]
100
+ res = Rack::MockRequest.new(redic).get(ROOT, Rack::HTTP_COOKIE => cookie)
101
+
102
+ expect(res[Rack::SET_COOKIE]).to eq(cookie)
103
+ expect(res.body).to include('"counter"=>2')
104
+
105
+ puts 'Sleeping to expire session' if $DEBUG
106
+ sleep 4
107
+
108
+ res = Rack::MockRequest.new(redic).get(ROOT, Rack::HTTP_COOKIE => cookie)
109
+ expect(res[Rack::SET_COOKIE]).not_to eq(cookie)
110
+ expect(res.body).to include('"counter"=>1')
111
+ end
112
+
113
+ it 'does not send the same session id if it did not change' do
114
+ redic = Rack::Session::Redic.new(incrementor)
115
+ req = Rack::MockRequest.new(redic)
116
+
117
+ res0 = req.get(ROOT)
118
+ cookie = res0[Rack::SET_COOKIE][session_match]
119
+ expect(res0.body).to eq('{"counter"=>1}')
120
+
121
+ res1 = req.get(ROOT, Rack::HTTP_COOKIE => cookie)
122
+ expect(res1[Rack::SET_COOKIE]).to eq(nil)
123
+ expect(res1.body).to eq('{"counter"=>2}')
124
+
125
+ res2 = req.get(ROOT, Rack::HTTP_COOKIE => cookie)
126
+ expect(res2[Rack::SET_COOKIE]).to eq(nil)
127
+ expect(res2.body).to eq('{"counter"=>3}')
128
+ end
129
+
130
+ it 'deletes cookies with :drop option' do
131
+ redic = Rack::Session::Redic.new(incrementor)
132
+ req = Rack::MockRequest.new(redic)
133
+ drop = Rack::Utils::Context.new(redic, drop_session)
134
+ dreq = Rack::MockRequest.new(drop)
135
+
136
+ res1 = req.get(ROOT)
137
+ session = (cookie = res1[Rack::SET_COOKIE])[session_match]
138
+ expect(res1.body).to eq('{"counter"=>1}')
139
+
140
+ res2 = dreq.get(ROOT, Rack::HTTP_COOKIE => cookie)
141
+ expect(res2[Rack::SET_COOKIE]).to eq(nil)
142
+ expect(res2.body).to eq('{"counter"=>2}')
143
+
144
+ res3 = req.get(ROOT, Rack::HTTP_COOKIE => cookie)
145
+ expect(res3[Rack::SET_COOKIE][session_match]).not_to eq(session)
146
+ expect(res3.body).to eq('{"counter"=>1}')
147
+ end
148
+
149
+ it 'provides new session id with :renew option' do
150
+ redic = Rack::Session::Redic.new(incrementor)
151
+ req = Rack::MockRequest.new(redic)
152
+ renew = Rack::Utils::Context.new(redic, renew_session)
153
+ rreq = Rack::MockRequest.new(renew)
154
+
155
+ res1 = req.get(ROOT)
156
+ session = (cookie = res1[Rack::SET_COOKIE])[session_match]
157
+ expect(res1.body).to eq('{"counter"=>1}')
158
+
159
+ res2 = rreq.get(ROOT, Rack::HTTP_COOKIE => cookie)
160
+ new_cookie = res2[Rack::SET_COOKIE]
161
+ new_session = new_cookie[session_match]
162
+ expect(new_session).not_to eq(session)
163
+ expect(res2.body).to eq('{"counter"=>2}')
164
+
165
+ res3 = req.get(ROOT, Rack::HTTP_COOKIE => new_cookie)
166
+ expect(res3.body).to eq('{"counter"=>3}')
167
+
168
+ # Old cookie was deleted
169
+ res4 = req.get(ROOT, Rack::HTTP_COOKIE => cookie)
170
+ expect(res4.body).to eq('{"counter"=>1}')
171
+ end
172
+
173
+ it 'omits cookie with :defer option but still updates the state' do
174
+ redic = Rack::Session::Redic.new(incrementor)
175
+ count = Rack::Utils::Context.new(redic, incrementor)
176
+ defer = Rack::Utils::Context.new(redic, defer_session)
177
+ dreq = Rack::MockRequest.new(defer)
178
+ creq = Rack::MockRequest.new(count)
179
+
180
+ res0 = dreq.get(ROOT)
181
+ expect(res0[Rack::SET_COOKIE]).to eq(nil)
182
+ expect(res0.body).to eq('{"counter"=>1}')
183
+
184
+ res0 = creq.get(ROOT)
185
+ res1 = dreq.get(ROOT, Rack::HTTP_COOKIE => res0[Rack::SET_COOKIE])
186
+ expect(res1.body).to eq('{"counter"=>2}')
187
+ res2 = dreq.get(ROOT, Rack::HTTP_COOKIE => res0[Rack::SET_COOKIE])
188
+ expect(res2.body).to eq('{"counter"=>3}')
189
+ end
190
+
191
+ it 'omits cookie and state update with :skip option' do
192
+ redic = Rack::Session::Redic.new(incrementor)
193
+ count = Rack::Utils::Context.new(redic, incrementor)
194
+ skip = Rack::Utils::Context.new(redic, skip_session)
195
+ sreq = Rack::MockRequest.new(skip)
196
+ creq = Rack::MockRequest.new(count)
197
+
198
+ res0 = sreq.get(ROOT)
199
+ expect(res0[Rack::SET_COOKIE]).to eq(nil)
200
+ expect(res0.body).to eq('{"counter"=>1}')
201
+
202
+ res0 = creq.get(ROOT)
203
+ res1 = sreq.get(ROOT, Rack::HTTP_COOKIE => res0[Rack::SET_COOKIE])
204
+ expect(res1.body).to eq('{"counter"=>2}')
205
+ res2 = sreq.get(ROOT, Rack::HTTP_COOKIE => res0[Rack::SET_COOKIE])
206
+ expect(res2.body).to eq('{"counter"=>2}')
207
+ end
208
+
209
+ it 'updates deep hashes correctly' do
210
+ hash_check = proc do |env|
211
+ session = env['rack.session']
212
+
213
+ if session.include?('test')
214
+ session[:f][:g][:h] = :j
215
+ else
216
+ session.update a: :b, c: { d: :e }, f: { g: { h: :i } }, 'test' => true
217
+ end
218
+
219
+ [200, {}, [session.inspect]]
220
+ end
221
+
222
+ redic = Rack::Session::Redic.new(hash_check)
223
+ req = Rack::MockRequest.new(redic)
224
+
225
+ res0 = req.get(ROOT)
226
+ session_id = (cookie = res0[Rack::SET_COOKIE])[session_match, 1]
227
+ ses0 = redic.storage.get(session_id)
228
+
229
+ req.get(ROOT, Rack::HTTP_COOKIE => cookie)
230
+ ses1 = redic.storage.get(session_id)
231
+
232
+ expect(ses1).not_to eq(ses0)
233
+ end
234
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Ensure we have this set before trying to initialize anything.
5
+ ENV['REDIS_URL'] ||= 'redis://localhost:6379'
6
+
7
+ require 'rack/session/redic'
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ describe Rack::Session::Redic::Storage do
5
+ subject do
6
+ Rack::Session::Redic::Storage.new(nil, Marshal, ENV['REDIS_URL'])
7
+ end
8
+
9
+ it 'returns nil for empty keys' do
10
+ expect(subject.get('not-here')).to eq(nil)
11
+ end
12
+
13
+ it 'saves objects' do
14
+ object = { saved: true }
15
+ subject.set('saving', object)
16
+
17
+ expect(subject.get('saving')).to eq(object)
18
+ subject.delete('saving') # Cleanup.
19
+ end
20
+
21
+ it 'checks the existence of keys' do
22
+ subject.set('exists', false)
23
+
24
+ expect(subject.exists?('exists')).to eq(true)
25
+ end
26
+
27
+ it 'deletes objects' do
28
+ object = { deleted: true }
29
+ subject.set('deleted', object)
30
+
31
+ expect(subject.get('deleted')).to eq(object)
32
+ subject.delete('deleted')
33
+
34
+ expect(subject.get('deleted')).to eq(nil)
35
+ end
36
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-redic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Lecklider
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-03 00:00:00.000000000 Z
11
+ date: 2017-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: Rack::Session in Redis via Redic
42
56
  email:
43
57
  - evan@lecklider.com
@@ -46,6 +60,7 @@ extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
62
  - ".gitignore"
63
+ - ".rspec"
49
64
  - CODE_OF_CONDUCT.md
50
65
  - Gemfile
51
66
  - LICENSE.txt
@@ -53,6 +68,9 @@ files:
53
68
  - Rakefile
54
69
  - lib/rack/session/redic.rb
55
70
  - rack-redic.gemspec
71
+ - spec/session_redic_spec.rb
72
+ - spec/spec_helper.rb
73
+ - spec/storage_spec.rb
56
74
  homepage: https://github.com/evanleck/rack-redic
57
75
  licenses:
58
76
  - MIT
@@ -73,8 +91,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
91
  version: '0'
74
92
  requirements: []
75
93
  rubyforge_project:
76
- rubygems_version: 2.6.10
94
+ rubygems_version: 2.6.12
77
95
  signing_key:
78
96
  specification_version: 4
79
97
  summary: Rack::Session in Redis via Redic
80
- test_files: []
98
+ test_files:
99
+ - spec/session_redic_spec.rb
100
+ - spec/spec_helper.rb
101
+ - spec/storage_spec.rb