Saturday 15 November 2014

A matter of time

Strehler 1.3.0 is released. This means that all the problems with Dancer2 0.15x are solved. More than that, requirement about Dancer2 moved up from Dancer2 0.11 to Dancer 0.15002.

In the previous episodes we saw that Dancer2 App, from version 0.15, try to find their configuration file in a directory near the one they are installed, ignoring where is the script that uses them. This was very bad for Strehler becase Strehler apps like Strehler::Admin are installed using CPAN so they are in the local repository, a place where no configuration file can be stored.

Only available solution (for now) is overriding thi behaviour setting environment variable DANCER_CONFDIR to the path where our config.yml actually is. Can we do it inside a script so that we can use this solution in any context, like CPAN tests? The answer is yes, if you know the right things about perl.

First of all, any perl script can access environment variables through the %ENV hash,  a read/write variable always available. So, first step should be to write in your code:

$ENV{DANCER_CONFDIR} = /the/directory/I/want

Now you can think that, including my app, all will work, so you're thinking about something like this:

$ENV{DANCER_CONFDIR} = /the/directory/I/want
use Strehler::Admin

Don't run too fast, this code WILL NOT work.

There's a lot of interesting concepts about perl interpreter behind this problem. Concepts, I hope, one day you'll be curious about. For now it's enough to say that "use" directive will run before DANCER_CONFDIR assignment even though you write it in the end of your file.

 Modules must be loaded before any other piece of code because consistency of any piece of code can be verified only with all the module loaded. Perl interpreter does it without asking nothing, ignoring that you necessary need to do something before.

Can you change this behaviour? Yes, two ways to do it:

  • BEGIN directive will run all the code inside its block before any other code, including use.
BEGIN
{
   $ENV{DANCER_CONFDIR} = /the/directory/I/want
}
use Strehler::Admin;

  • require directive instead of use load the module only when someone ask for it,with no precedence on anything.

$ENV{DANCER_CONFDIR} = /the/directory/I/want
require Strehler::Admin;

You can see an example of this here.

Here are described many ways to configure DANCER_CONFDIR.

Why don't I want to consider this as the definitive solution for the problem? Because I think it's still a dirty way to do things because force you to use an environment variable and disable the original App behaviour that allow each of them to have a separated config file, something that could come useful in some situations.

Sunday 9 November 2014

Plack::Test and Dancer Session

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.



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:


  • 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.