PSGI is very easy to understand: a black box, something goes in, something goes out. What goes in: a request made of a path and headers. What goes out: a response with a content and more headers.
Plack::Test follows this structure. What you have to test is the black box, you inject the request in it and analyze the response you receive back.
Important thing to understand is that Plack::Test is something very different from an emulation of a browser like LWP::UserAgent. Most important difference is, obviously, in session management, because that's something that should survive between calls and in Plack::test every call is a test by itself, with no memory of what happens around it.
What do you have to do if you want to test something like a login using Plack::Test? Well, the solution is very easy because the concept of session is AN ILLUSION throughout all the web. It's not just Plack::Test, the HTTP protocol itself is session-less. The "session" you see is just a set of tricks that clients and servers do under the hood.
As we said: a request go, a response returns, nothing more, so the session is something that must be hidden there. In particular, session is controlled throught headers, in particular headers that control browser cookies.
There're a lot of documentation about how cookies and response headers have to interact and probably studying it could be very interesting, but HTTP::Cookies module contains all the knowledge you need so learn to use it will be enough.
Let's do a login and get the response from it:
$r = $cb->( POST '/admin/login', [ user => 'admin', password => 'admin' ] );
Response object $r contain many headers, one of that ask the client to write in a cookie the identifier of dancer session. We can use HTTP::Cookies to extract this information.
my $jar = HTTP::Cookies->new;
$jar->extract_cookies($r);
Now we want that, in the next call, the server find us logged in.
When a browser does a request to a site, it passes in the request all the informations related to the cookies it has. This way it can say to the server what is its dances session identifier. Using that, the server can retrieve any information about the caller, like its status as logged user.
Let's cook a call for admin homepage.
my $req = HTTP::Request->new(GET => $site . '/admin');
WARNING: Remember to ALWAYS create request with complete URL, starting from http, otherwise HTTP::Cookies method add_cookie_header will not work!
Now we want that this call carry information about the cookies of the previous call, where logged in user session was configured. We just have to get information out from the cookie jar.
$jar->add_cookie_header($req);
Now this req will been seen by the server as the logged user from the previous call did it.
Well, if you configured in a clever way the server too.
Remember? There's no memory between requests client-side AS server-side. Client memory is in the cookies and HTTP::Cookies helps us to manage it. Where is server memory?
Standard session management in Dancer leave session information in RAM. On a development server this is enough, but a development server is something that stay alive between different calls so you can consider information stored in RAM persistent. Plack::Test instantiate the black box fresh new at every call so information about sessions is always trashed at the end of it.
Harddisk is more reliable if you want to store persisten information so switch session management to YAML when doing this kind of test.
Here is a little example of what we said.
Who looks at a screwdriver and thinks, "Ooh, this could be a little more sonic"?
Showing posts with label Test. Show all posts
Showing posts with label Test. Show all posts
Sunday, 9 November 2014
Tuesday, 4 November 2014
The darkest hour
I've been away from this place for long time, I know, and I also know that also Strehler has been left with no updates for many months. There're technical questions about all this silence and I want to explain them here.
This summer Dancer2 reached release 0.150000, quite an improvement! A lot of things changed with this release of the framework, most of them related to the concept of App.
Major architectural changes are something I know I have to deal with, talking about Strehler's developement. Dancer2 code is not stable, it's usually considered alpha and I know that chasing its releases is one of the most difficult but important tasks for me as mantainer of a module based on it.
Problem is 0.150000 Dancer2 was too much. I described the issue introduced by this release here, Briefly, an App installed in your local repository gives a lot of trouble when it's time to read configuration files, because App uses its own path to find site resources, ignoring the path of the script that manage site startup.
For now, in my opinion, there's no way to solve the question fixing Strehler. Problem is inside Dancer2 architecture so I hope that the Dancer2 development team will do something. Waiting for it, this is what I can say if you want to use Strehler:
This summer Dancer2 reached release 0.150000, quite an improvement! A lot of things changed with this release of the framework, most of them related to the concept of App.
Major architectural changes are something I know I have to deal with, talking about Strehler's developement. Dancer2 code is not stable, it's usually considered alpha and I know that chasing its releases is one of the most difficult but important tasks for me as mantainer of a module based on it.
Problem is 0.150000 Dancer2 was too much. I described the issue introduced by this release here, Briefly, an App installed in your local repository gives a lot of trouble when it's time to read configuration files, because App uses its own path to find site resources, ignoring the path of the script that manage site startup.
For now, in my opinion, there's no way to solve the question fixing Strehler. Problem is inside Dancer2 architecture so I hope that the Dancer2 development team will do something. Waiting for it, this is what I can say if you want to use Strehler:
- Strehler latest release is perfectly working with any Dancer2 0.14x release. So, if you don't update Dancer2 packages too much you have nothig to fear.
- You can make Strehler works with Dancer2 0.15. You just have to ignore all the tests and run your site setting the environmental variable DANCER_CONFDIR as the directory where your config file is. It's quite simple and I know I could consider it the definitive fallback, but it's not clean and still I don't know how to use it to run the test suit, so I take this as a temporary workaround.
Well, I don't have much more to say, this is the situation at today. I hope it will change soon and I think it will, but patience, for a bit, has to be your new best friend.
Last announcement: Strehler has now a site. Click here for it. Important articles from this blog will be reported there, as a place to aggregate every communication about the development.
Labels:
Dancer2,
environment,
release,
site,
Strehler,
Test,
version 0.150000
Wednesday, 21 May 2014
Strehler 1.1.9 released
Released but not perfect. There're little problems about documentation and I probably found a little error in strehler script, layout function. Well, as usual...
I'm not sure I can find a way to test Strehler script but I should, at least to check if it gives an error in standard situations. The script, in my opinion, is a very sensitive part of the package. Strehler script go to war on the open ground of user's file system, it can find strange things and fight insidious enemies, it deserves attention. For example, I'm not sure how it works under Windows...
Another point in my TO-DO list is find a way to see how CPAN page will be rendered, after package upload, just to avoid little glitches in documentation as I'm experimenting now.
Well, stop with the bad things, a Strehler release is always something to celebrate, 1.1.9 bring order in FormFu elements and configuration and we love it for that!
I'm not sure I can find a way to test Strehler script but I should, at least to check if it gives an error in standard situations. The script, in my opinion, is a very sensitive part of the package. Strehler script go to war on the open ground of user's file system, it can find strange things and fight insidious enemies, it deserves attention. For example, I'm not sure how it works under Windows...
Another point in my TO-DO list is find a way to see how CPAN page will be rendered, after package upload, just to avoid little glitches in documentation as I'm experimenting now.
Well, stop with the bad things, a Strehler release is always something to celebrate, 1.1.9 bring order in FormFu elements and configuration and we love it for that!
Sunday, 29 September 2013
404 Ghost workaround
A little recap:
Here I stated a problem about phantom 404 and a (wrong) solution to it.
Here I confessed I was working on the issue.
Here It's the work I'm doing with a long and boring description of the problem that I'll not repeat in this blog.
...but probably you don't want to wait until the problem is really closed because you have (as me) a package that you want on CPAN to share it with the world.
Oh yes, the problem! Let me say it with few words:
You have a plugin that modify the request path in a before hook. You want that, when the user write (for example) /prefix/good/path, your plugin change it to /good/path. Obviously the code that will answer to this will be:
get '/good/path' => sub {...}
You don't define anything about /prefix/good/path because the plugin will always change it, so you'll never need to answer with it.
This works! I can swear it calling Wotan on my side. But when you try to test it with dzil test the test you wrote fails.
Long explanation for why this happen, as I said, is here. Little workaround you can use to stop this happening is adding a public directory under the t with just a dummy file. This way fix the problem and make you test suit running flawless!
Here I stated a problem about phantom 404 and a (wrong) solution to it.
Here I confessed I was working on the issue.
Here It's the work I'm doing with a long and boring description of the problem that I'll not repeat in this blog.
...but probably you don't want to wait until the problem is really closed because you have (as me) a package that you want on CPAN to share it with the world.
Oh yes, the problem! Let me say it with few words:
You have a plugin that modify the request path in a before hook. You want that, when the user write (for example) /prefix/good/path, your plugin change it to /good/path. Obviously the code that will answer to this will be:
get '/good/path' => sub {...}
You don't define anything about /prefix/good/path because the plugin will always change it, so you'll never need to answer with it.
This works! I can swear it calling Wotan on my side. But when you try to test it with dzil test the test you wrote fails.
Long explanation for why this happen, as I said, is here. Little workaround you can use to stop this happening is adding a public directory under the t with just a dummy file. This way fix the problem and make you test suit running flawless!
Labels:
404,
Dancer2,
Dancer2::Plugin,
dzil,
github,
path,
plugin,
pull request,
Test,
workaround
Friday, 28 June 2013
LWP::UserAgent: a browser
Last time we had a lot of fun playing with Test::TCP and LWP::UserAgent, but we're not done yet with these toys, there's something more I want to say about them.
So we can test our Dancer2 route:
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://127.0.0.1:$port/route/");
ok($res->is_success);
is($res->content, 'my content');
Sometime this is not enough. In the code I'm developing redirect is important as success, how can I test this? Well, I suppose...
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://127.0.0.1:$port/redirecting_route/");
is($res->code, 302);
But result is:
# got: '200'
# expected: '302'
So we can test our Dancer2 route:
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://127.0.0.1:$port/route/");
ok($res->is_success);
is($res->content, 'my content');
Sometime this is not enough. In the code I'm developing redirect is important as success, how can I test this? Well, I suppose...
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://127.0.0.1:$port/redirecting_route/");
is($res->code, 302);
But result is:
# got: '200'
# expected: '302'
What's wrong?
You could think (I did, at last) that LWP::UserAgent is just a "tester", something to do "ping" on internet sites and see what come back. It's not, LWP::UserAgent is powerful because it's a complete working browser, like Firefox, Opera, Chrome or IE. It's not good in rendering pages, ok, but the data-flow it can manage is the same you can see while surfing the web.
What a normal browser like Firefox do when there's a redirect?
Simple:
CALL -> 302 -> NEW PAGE -> 200
Though you're giving back a redirect for a route you still want to give a page, a success result, at the end of the navigation chain. LWP::UserAgent follow all the chain without asking for nothing, as your browser, bringing back the final 200 response.
Ok, LWP::UserAgent is cool and I'll use it to fetch good pron, I promise, but now I'm looking for something that check my Dancer2 App doing the right redirect!
Test is just a bit more complex:
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://127.0.0.1:$port/redirecting_route/");
is($res->is_success and $res->previous);
Call ends with a 200 but a previous URL was registered and we're redirecting from there. You can see this URL in $res->previous but knowing it's there is enough to say we're redirecting.
Something more about the browser powers of LWP::UserAgent?
What if you need to test sessions? How Dancer2 trace client sessions? With a session cookie, obviously. And LWP::UserAgent can manage them too? Obviously again, but remember to give it a cookie_jar to use:
$ua->cookie_jar({file => "cookies.txt"});
Rememeber. With LWP::UserAgent you're not just trying out your site. You're literally surfing it!
my $res = $ua->get("http://127.0.0.1:$port/redirecting_route/");
is($res->is_success and $res->previous);
Call ends with a 200 but a previous URL was registered and we're redirecting from there. You can see this URL in $res->previous but knowing it's there is enough to say we're redirecting.
Something more about the browser powers of LWP::UserAgent?
What if you need to test sessions? How Dancer2 trace client sessions? With a session cookie, obviously. And LWP::UserAgent can manage them too? Obviously again, but remember to give it a cookie_jar to use:
$ua->cookie_jar({file => "cookies.txt"});
Rememeber. With LWP::UserAgent you're not just trying out your site. You're literally surfing it!
Labels:
200,
cookies,
Dancer2,
LWP::UserAgent,
redirect 302,
sessions,
Test,
Test::TCP
Subscribe to:
Posts (Atom)