Hard times… :(

Dear people,

I somehow lost the right way. In the second (the creative) part, I had some serious trouble to get the right start. I wrote some tests, but they were either trivial or there were no good way to handle the situation right. One of my first tests:

my $c = Mojo::Client->singleton->app(app);

# GET a 404
my $tx = $c->get('/doesnotexist');
ok(!$tx->success,                       'not successful');
is($tx->res->code,      404,            'right status');
like($tx->res->body,    qr/not found/i, 'right content');

Cool, eh? My first try to get smarter tests was handling wrong Content-Length headers. There are two possibilities, too less content or too much:

get '/too_short' => sub {
    my $self = shift;
    $self->res->headers->content_length(42);
    $self->render(text => '1234567');
};

get '/too_much' => sub {
    my $self = shift;
    $self->res->headers->content_length(2);
    $self->render(text => '1234567');
};

my $c = Mojo::Client->singleton->app(app)->keep_alive_timeout(1);

# Wrong Content-Length header (too short)
my $tx = $c->get('/too_short');
my $cl = $tx->res->headers->content_length;
is($cl,             42,         'right Content-Length header');
is($tx->res->body,  '1234567',  'right content');

# Wrong Content-Length header (too long)
$tx = $c->get('/too_much');
$cl = $tx->res->headers->content_length;
is($cl,             2,      'right Content-Length header');
is($tx->res->body,  '12',   'shortened content');

OK. I couldn’t figure out why the first test gets the right results (after the keep alive timeout), but the second yields to a non-terminating test script. I tried a few days to debug this thing, but failed. It seems that there’s no good way to handle this things. Test no. 1, test no. 2.

My problem then was that I felt shame about not having any good tests and stopped communicating to my mentor and other Mojolicious guys for a long time. OK, I never really stopped working on better tests, but I widely missed the chance to get help from them. That’s completely my fault and I’m taking the full responsibility for the things I did. The GSoC program deadline is in two days and I might fail.

However, the time of not communicating is over, I talked to Marcus and Sebastian, which are both sad about how things evolved. I will present some of my better tests here, hoping they will help Mojolicious, whatever my GSoC project results will be:

Client: Parsing requests with absolute URIs

GET http://mojolicio.us/ HTTP/1.1
Host: apache.org

When receiving a request which has an absolute URI in the start line, the host header must be ignored, as stated in RFC 2616, Section 5.2. Mojolicious behaves almost right, but the apache.org still sits in $req->url->base. The test on github

Client: Handling broken Redirects

A typical redirect has the 30* status code and a Location header, which is the location the client should look for the requested ressource. This patch tests the behaviour of the client when it gets a relative URL or no Location header.

Parsing broken chunked messages

The chunked transfer encoding is a way to transfer data between server and client without knowing the message size in advance. The body is splitted in small chunks which have a number which informs about the chunk size:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain
Transfer-Encoding: chunked

4
abcd
9
abcdefghi

If that number is wrong, the message parser stops, but it doesn’t give any error messages: chunked request, chunked response

Server: handling wrong request methods

For HTTP requests, the request method (like GET, POST or TRACE, I didn’t even knew that one before!) is essential. There exist status codes for server responses on wrong request methods, which aren’t used by Mojo: 405 Method not allowed for a wrong method on that resource and 501 Method not implemented for unknown methods (like FOO). Their use is marked as SHOULD in the HTTP 1.1 RFC, so these tests may be useless: wrong method handling tests

Server: no bad requests

This is some kind of a follow-up on the last topic and was a bit tricky for me. Most things can be tested with a Lite app and the built in tester client, but to check the handling of bad requests, the client is completely useless. It just doesn’t want to send bad requests (which is a feature, but not for me), so I needed to write my own … um … client with IO::Socket.

If the host (provided by start line or Host header) is not a valid host on that server, it needs to respond with a 400 Bad request status (RFC 2616, Section 5.2 again). Mojo responds with a 200 OK: test script draft

Server: Range requests

The Range header allows a client to request parts of a ressource by telling which range it wants to receive:

Range: bytes=42-99

In case of a wrong range (like with a ressource of byte length 17 in the example above), the server SHOULD respond with a 416 Requested Range Not Satisfiable status, which it doesn’t.

I also added tests to check the Content-Range response header in this situations, which works pretty good in Mojolicious. Only in the 416 case this tests fail.

There are more minor test cases in my bulletproofing branch, but they are mostly not that important.

To be continued.

Notes

  1. dodi-randolph reblogged this from memowe-gsoc
  2. memowe-gsoc posted this