1 require "#{File.dirname(__FILE__)}/../../abstract_unit"
2 require 'action_controller/cgi_process'
3 require 'action_controller/cgi_ext'
9 attr_reader :output_cookies, :output_hidden
15 attr_reader :data, :original, :cookie_options
20 class CookieStoreTest < Test::Unit::TestCase
21 def self.default_session_options
22 { 'database_manager' => CGI::Session::CookieStore,
23 'session_key' => '_myapp_session',
24 'secret' => 'Keep it secret; keep it safe.',
30 { :empty => ['BAgw--0686dcaccc01040f4bd4f35fe160afe9bc04c330', {}],
31 :a_one => ['BAh7BiIGYWkG--5689059497d7f122a7119f171aef81dcfd807fec', { 'a' => 1 }],
32 :typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--9d20154623b9eeea05c62ab819be0e2483238759', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
33 :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }] }
37 ENV.delete('HTTP_COOKIE')
40 def test_raises_argument_error_if_missing_session_key
41 [nil, ''].each do |blank|
42 assert_raise(ArgumentError, blank.inspect) { new_session 'session_key' => blank }
46 def test_raises_argument_error_if_missing_secret
47 [nil, ''].each do |blank|
48 assert_raise(ArgumentError, blank.inspect) { new_session 'secret' => blank }
52 def test_reconfigures_session_to_omit_id_cookie_and_hidden_field
53 new_session do |session|
54 assert_equal true, @options['no_hidden']
55 assert_equal true, @options['no_cookies']
59 def test_restore_unmarshals_missing_cookie_as_empty_hash
60 new_session do |session|
61 assert_nil session.dbman.data
62 assert_nil session['test']
63 assert_equal Hash.new, session.dbman.data
67 def test_restore_unmarshals_good_cookies
68 cookies(:empty, :a_one, :typical).each do |value, expected|
70 new_session do |session|
71 assert_nil session['lazy loads the data hash']
72 assert_equal expected, session.dbman.data
77 def test_restore_deletes_tampered_cookies
79 new_session do |session|
80 assert_raise(CGI::Session::CookieStore::TamperedWithCookie) { session['fail'] }
81 assert_cookie_deleted session
85 def test_close_doesnt_write_cookie_if_data_is_blank
86 new_session do |session|
87 assert_no_cookies session
89 assert_no_cookies session
93 def test_close_doesnt_write_cookie_if_data_is_unchanged
94 set_cookie! cookie_value(:typical)
95 new_session do |session|
96 assert_no_cookies session
97 session['user_id'] = session['user_id']
99 assert_no_cookies session
103 def test_close_raises_when_data_overflows
104 set_cookie! cookie_value(:empty)
105 new_session do |session|
106 session['overflow'] = 'bye!' * 1024
107 assert_raise(CGI::Session::CookieStore::CookieOverflow) { session.close }
108 assert_no_cookies session
112 def test_close_marshals_and_writes_cookie
113 set_cookie! cookie_value(:typical)
114 new_session do |session|
115 assert_no_cookies session
116 session['flash'] = {}
117 assert_no_cookies session
119 assert_equal 1, session.cgi.output_cookies.size
120 cookie = session.cgi.output_cookies.first
121 assert_cookie cookie, cookie_value(:flashed)
125 def test_delete_writes_expired_empty_cookie_and_sets_data_to_nil
126 set_cookie! cookie_value(:typical)
127 new_session do |session|
128 assert_no_cookies session
130 assert_cookie_deleted session
132 # @data is set to nil so #close doesn't send another cookie.
134 assert_cookie_deleted session
138 def test_new_session_doesnt_reuse_deleted_cookie_data
139 set_cookie! cookie_value(:typical)
141 new_session do |session|
142 assert_not_nil session['user_id']
145 # Start a new session using the same CGI instance.
146 post_delete_session = CGI::Session.new(session.cgi, self.class.default_session_options)
147 assert_nil post_delete_session['user_id']
152 def assert_no_cookies(session)
153 assert_nil session.cgi.output_cookies, session.cgi.output_cookies.inspect
156 def assert_cookie_deleted(session, message = 'Expected session deletion cookie to be set')
157 assert_equal 1, session.cgi.output_cookies.size
158 cookie = session.cgi.output_cookies.first
159 assert_cookie cookie, nil, 1.year.ago.to_date, message
162 def assert_cookie(cookie, value = nil, expires = nil, message = nil)
163 assert_equal '_myapp_session', cookie.name, message
164 assert_equal [value].compact, cookie.value, message
165 assert_equal expires, cookie.expires ? cookie.expires.to_date : cookie.expires, message
170 self.class.cookies.values_at(*which)
173 def cookie_value(which)
174 self.class.cookies[which].first
177 def set_cookie!(value)
178 ENV['HTTP_COOKIE'] = "_myapp_session=#{value}"
181 def new_session(options = {})
183 assert_nil cgi.output_hidden, "Output hidden params should be empty: #{cgi.output_hidden.inspect}"
184 assert_nil cgi.output_cookies, "Output cookies should be empty: #{cgi.output_cookies.inspect}"
186 @options = self.class.default_session_options.merge(options)
187 session = CGI::Session.new(cgi, @options)
189 assert_nil cgi.output_hidden, "Output hidden params should be empty: #{cgi.output_hidden.inspect}"
190 assert_nil cgi.output_cookies, "Output cookies should be empty: #{cgi.output_cookies.inspect}"
192 yield session if block_given?
198 ENV['REQUEST_METHOD'] = 'GET'
199 ENV['HTTP_HOST'] = 'example.com'
200 ENV['QUERY_STRING'] = ''
202 cgi = CGI.new('query', StringIO.new(''))
203 yield cgi if block_given?
209 class CookieStoreWithBlockAsSecretTest < CookieStoreTest
210 def self.default_session_options
211 CookieStoreTest.default_session_options.merge 'secret' => Proc.new { 'Keep it secret; keep it safe.' }
216 class CookieStoreWithMD5DigestTest < CookieStoreTest
217 def self.default_session_options
218 CookieStoreTest.default_session_options.merge 'digest' => 'MD5'
222 { :empty => ['BAgw--0415cc0be9579b14afc22ee2d341aa21', {}],
223 :a_one => ['BAh7BiIGYWkG--5a0ed962089cc6600ff44168a5d59bc8', { 'a' => 1 }],
224 :typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--f426763f6ef435b3738b493600db8d64', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
225 :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }] }