use 5.24.0;
# tests Starman with SessionTest app; use 'PLACK_ENV=test' to load test.yml to
# suppress debug output, or omit for verbose output; call test script as:
# env [PLACK_ENV=test] PLACK_TEST_IMPL=Server PLACK_SERVER=Starman \
# prove -lv t/
# see "Plack::Test test_psgi and Test::WWW::Mechanize" test:
# Plack::Test test_psgi test IS using Starman as intended, with 5 workers, but
# behaviour is different to application, delayed form submission does not cause
# CSRF token validation failure
use Test::More;
use Plack::Test;
use HTTP::Cookies;
use Data::Printer;
use Plack::Request;
# use Time::HiRes qw//;
use Plack::Test::Agent;
use LWP::Protocol::PSGI;
use Test::WWW::Mechanize;
use HTTP::Request::Common;
use Test::WWW::Mechanize::PSGI;
use Term::ANSIColor qw(:constants);
use constant TESTS => 23;
warn '=' x 76 . "\n";
if ( $ENV{PLACK_SERVER} && $ENV{PLACK_SERVER} eq 'Starman' ) {
warn 'runs tests using Starman server; outputs server start up and shut down '
. "messages; sleeps for\n";
warn "a few seconds between some tests\n"; # warn outputs even without -v flag
}
else {
die q!usage: env [PLACK_ENV=test] PLACK_TEST_IMPL=Server !
. qq!PLACK_SERVER=Starman prove -l t/session.t\n!;
}
warn '=' x 91 . "\n";
sleep 5;
#-------------------------------------------------------------------------------
sub debug {
my $response = shift; # p $response;
p $response->content;
# print $fh $response->content;
}
sub test_title { say BRIGHT_CYAN, "\n" . '-' x 10 . ' ' . $_[0], RESET }
sub _sleep { my $t = shift; say ".....sleeping for $t seconds"; sleep $t; }
#-------------------------------------------------------------------------------
use_ok('SessionTest'); # p %ENV; exit;
my $app = SessionTest->to_app;
my $csrf_tkn_str = 'CSRF token: {SSHA}';
my $csrf_tkn_re = 'CSRF token: \{SSHA\}'; # escaped for regex for perl >= 5.30
my $success_msg = 'SUCCESS: valid CSRF token';
my $failure_msg = 'ERROR: invalid CSRF token';
{
test_title('Plack::Test::Agent');
my $local_agent = Plack::Test::Agent->new(app => $app);
my $server_agent = Plack::Test::Agent->new(
app => $app,
server => 'HTTP::Server::PSGI'
);
my $local_res = $local_agent->get( '/sessiontest' );
my $server_res = $server_agent->get( '/sessiontest' );
ok $local_res->is_success, 'local GET /sessiontest should succeed';
ok $server_res->is_success, 'server GET /sessiontest should succeed';
}
{ # HTTP::Server::PSGI - works, Starman & Twiggy don't
test_title('Plack::Test::Agent with HTTP::Server::PSGI & agent->get_mech');
my $agent = Plack::Test::Agent->new(
app => $app,
server => 'HTTP::Server::PSGI'
);
my $mech = $agent->get_mech; # debug($mech);
$mech->get_ok('/sessiontest'); # debug($mech);
$mech->content_contains($csrf_tkn_str);
# p $mech->response->header('Server');
$mech->submit; # debug($mech);
$mech->text_contains($success_msg, 'OK: valid CSRF token');
_sleep(3);
$mech->submit; # debug($mech);
# this should fail:
$mech->text_contains($success_msg, 'OK: valid CSRF token');
}
{ # HTTP::Server::PSGI - works, Starman & Twiggy don't
test_title('Plack::Test::Agent with Starman and agent->get_mech');
my $agent = Plack::Test::Agent->new(
app => $app,
server => 'Starman', # causes following msg to appear:
# Passed serialize value of none is incompatible with multiple
# ports - using default serialize
);
my $mech = $agent->get_mech; # debug($mech);
$mech->get_ok('/sessiontest'); # debug($mech);
$mech->content_contains($csrf_tkn_str);
# p $mech->response->header('Server');
$mech->submit; # debug($mech); exit;
SKIP: {
skip( q!this fails valid CSRF token test!, 1 );
$mech->text_contains($success_msg, 'OK: valid CSRF token');
}
_sleep(3);
$mech->submit; # debug($mech);
# this should fail:
SKIP: {
skip( q!this fails valid CSRF token test!, 1 );
$mech->text_contains($success_msg, 'OK: valid CSRF token');
}
}
{
test_title('LWP::Protocol::PSGI and Test::WWW::Mechanize');
my $psgi_app = SessionTest::runner()->psgi_app;
LWP::Protocol::PSGI->register($psgi_app);
my $mech = Test::WWW::Mechanize->new;
$mech->get_ok('http://localhost/sessiontest'); # debug($mech); exit;
$mech->content_contains($csrf_tkn_str);
# p $mech->response->header('Server');
_sleep(3);
$mech->submit; # debug($mech);
# this should fail:
# $mech->text_contains($failure_msg, 'OK: invalid CSRF token');
$mech->text_contains($success_msg, 'OK: valid CSRF token');
}
{
test_title('Plack::Test simple OO interface');
my $test = Plack::Test->create($app);
my $res = $test->request(GET '/sessiontest'); # p $res->request;
like $res->content, qr/$csrf_tkn_re/;
# how to submit form ?
}
{
test_title('Test::WWW::Mechanize::PSGI');
my $mech = Test::WWW::Mechanize::PSGI->new(app => $app);
$mech->get_ok('/sessiontest');
# p $mech->response->header('Server');
is( $mech->ct, 'text/html', 'Is text/html' );
$mech->content_contains($csrf_tkn_str);
$mech->submit; # p $mech->content;
$mech->text_contains($success_msg, 'OK: valid CSRF token');
_sleep(3);
# this should fail:
# $mech->text_contains($failure_msg, 'OK: invalid CSRF token');
$mech->text_contains($success_msg, 'OK: valid CSRF token');
}
{ ####### uses Starman from command-line env
test_title('Plack::Test test_psgi');
test_psgi $app, sub {
my $cb = shift; # p $cb;
my $res = $cb->(GET '/sessiontest'); # p $res;
like $res->content, qr/$csrf_tkn_re/;
# how to submit form ?
};
}
{ ####### uses Starman from command-line env
test_title('Plack::Test test_psgi and Test::WWW::Mechanize');
my $mech = Test::WWW::Mechanize->new;
test_psgi $app, sub {
my $cb = shift; # p $cb;
$mech->get('http://localhost/sessiontest'); # p $mech->content;
# p $mech->response->header('Server');
$mech->content_contains($csrf_tkn_str, 'OK: valid CSRF token');
### proves starman is running multiple workers:
# _sleep(30); # now run 'ps aux | grep starman' - shows 5 workers !!
_sleep(3);
$mech->submit; # p $mech->content;
# this should fail:
# $mech->text_contains($failure_msg, 'OK: invalid CSRF token');
$mech->text_contains($success_msg, 'OK: valid CSRF token');
};
# now run 'ps aux | grep starman' - shows 0 workers
}
done_testing(TESTS);