It's a known issue:
https://webrat.lighthouseapp.com/projects/10503/tickets/190-sinatra-sessions-do-not-persist
The reason is that Sinatra is assuming unit testing of routes (rather
than integration testing) where you can do:
post "/logout", {}, :session => {:user => 1}
I proposed a patch [1] [2] that keeps backwards compatibility but it
didn't get applied (I don't remember why).
Ryan, can we bring the discussion here?
[1] http://github.com/djanowski/sinatra/commit/14f6c00f19b86757b7e6b5583f9a1e61113318bf
[2] http://github.com/djanowski/sinatra/commit/629e87ee67a025984b8a864eba5273e387abfd55
Can we think of an example of a test relying on sessions being
disabled? Besides, I think the current implementation is a little
weird: sessions are disabled but you're able to pass a :session to
your requests regardless.
The only breakage that I can see is when you stub a method on an
object, pass it with :session and expect it to be the actual instance
received by the application. The patch is backwards-compatible if
you're not doing this (it serializes your :session so the Rack
middleware can load the cookie properly).
It seems to me that many people are complaining about this odd behavior.
Can anyone please chime in if they see a scenario where this patch
would break a test?
I'm not sure I follow. We're not talking about deprecating the ability
to pass a :session key to your requests. You'll still be able to do
that, of course.
I agree that mixing them in the same test doesn't make a lot of sense.
But I do have integration tests and unit tests – the former rely on
the session working normally, and the latter can provide a :session
key if needed for specific scenarios (like you said, when you're doing
lower-level tests like making sure things blow up on certain
conditions, etc.).
> I would completely support an optional plugin enabling sessions for tests,
> or even configuration option to switch between the two methods. But I think
> trying to mix the two together will only lead to more confusion.
The proposed patch lets you use whichever method you prefer (or use
both for different purposes) without any additional plugins or
configuration. You can use Webrat for your integration tests and still
do unit testing and pass specific values in the :session key.
Sorry, I meant "Bryan" not "Ryan" :[
What some of us are saying is that we want to *fix* the code, not
patch it in some weird way. Both Ryan and Blake agreed that that extra
check doesn't make sense. What we're trying to discuss here is whether
this fix is completely backwards-compatible or not.
In fact, it mostly works. My main app has some strangeness whereby
sessions only work in test if I enable Rack::Session::Pool but my
little test app is showing none of that.
However, I am having trouble getting the ":session =>" syntax Damian
mentioned to work from my test. Damian, can you check my code at
http://gist.github.com/131374
and see if I'm doing something weird?
> If you're going to act as a browser and store session state, then you
> shouldn't be mucking about with the session directly. What's the testing
> scenario for the combination of tracking session state, but still being able
> to manipulate it externally?
Ah, that's a good question. So should/does Rack::Test support
*cookies* or does it support *sessions*? And what should/does Sinatra
do with each before and after a test?
- A
1) It only works at all if ENV['RACK_ENV'] = 'test' is the first line.
Arguably the environment should only matter if you're connecting to a
database... Oddly, in dev mode the only failure is
test_logout_with_session_passed_explicitly; the ones where the test is
truly mimicking a browser work fine.
2) In test mode, there are two failures, both integration tests. I
suppose this is because in test mode Sinatra is not setting
rack.session on the response, which is what this thread is about.
- A
---
Alex Chaffee - al...@stinky.com - http://alexch.github.com
Stalk me: http://friendfeed.com/alexch | http://twitter.com/alexch |
http://alexch.tumblr.com
What's the point of adding a new environment instead of fixing Sinatra?
I don't really understand what is it that you fear.
--
Michel
Yes. What's disabled is the conversion from an encoded Cookie header
value to a Hash on the request. Most tests in the wild today simply
pass the session hash directly in "rack.session" -- this avoids the
encode/decode step. You're not typically trying to test session
*encoding* in your app, you're trying to test that the deserialized
session is accessed and modified properly. If the :sessions option is
enabled, the hash passed in "rack.session" is replaced with an empty
hash unless the session data is encoded and passed in a Cookie header.
Also, how do you propose testing sessions when something other than
Rack::Session::Cookie is used? The current behavior just removes an
implementation detail that's typically irrelevant to the target of the
tests.
> The only breakage that I can see is when you stub a method on an
> object, pass it with :session and expect it to be the actual instance
> received by the application. The patch is backwards-compatible if
> you're not doing this (it serializes your :session so the Rack
> middleware can load the cookie properly).
I must have misread 14f6c00 when I was looking at this before the
0.9.2 release because I don't remember seeing the encode step. I think
mapping the :session option to HTTP_COOKIE was throwing me off:
http://github.com/djanowski/sinatra/commit/629e87ee67a025984b8a864eba5273e387abfd55#L0R79
At any rate, this does look to be backwards compatible. I'll cherry
pick it onto the 0.9.x branch and see if we get any spec failures.
I'm not sure how many more 0.9.x releases we'll be doing after 0.9.3
(which is already packaged and tagged) though. All of "sinatra/test"
has been removed on master, so the only relevant issue there is
whether sessions should be disabled by default. Does anyone know if
Rack::Test expects the app to perform cookie decode? If so, we should
adjust the default.
> It seems to me that many people are complaining about this odd behavior.
I think the confusion comes from interpreting "sessions are disabled"
as "you can't use the rack.session env var or access sessions in your
app" instead of "don't add encoding/decoding of cookie based sessions
using Rack's built in middleware." But, yeah, this does seem to be
something that trips people up.
Thanks,
Ryan
It seems there is a bug (unconfirmed) in Rack::Test that prevents one to
use it with Rack::Session::Cookie. I'll be looking into it shortly.
Please chill down, btw.
Thanks,
--
Simon Rozet <si...@rozet.name> http://atonie.org
For the record, if you want to use Webrat, just don't use #enable.
Call #use directly:
use Rack::Session:Cookie
If you are using Rack::Test and still want to pass :session in your
unit tests: http://gist.github.com/134800