2009/5/13 Louis Erickson <[email protected]>
>
> I haven't been able to get a test user logging in and out yet, though.
>
> I have several sections of my application that redirect the user away if
> they are not logged in.  I have another that returns a 404 if they don't
> have access, so prying users can't find it (as easily).
>
> My tests are currently based on the stubs generated by myapp_create,
> and use Catalyst::Test.  I could move them to WWW::Mechanize::Catalyst if
> it would help.
>
> I can't tell if Catalyst::Test supports cookies.  Does it?  Or do I need
> to use WWW::Mechanize::Catalyst for that?
>
> I've read some suggestions on how to go about this, and found a couple.
>
> 1> Use WWW::Mechanize::Catalyst to log the user in
> 2> Use the mock user in config to set a user who is logged in.
>
> The problem with really logging the user in is that the login is a set of
> site-wide cookies generated by a Single Sign On system.  That system may
> or may not have a test instance running.  If it does, cookies stored from
> it probably won't work with cookies from 'localhost' like the local test
> app wants.
>

The approach we used a year or two back was
1. In your application config file MyApp/conf/myapp.pl  set up multiple
authentication realms

  authentication => {
      default_realm => 'members',
      realms => {
         members => {
            credential => {
               class => 'Password',
               password_field => 'password',
               password_type => 'crypted',
            },
            store => {
               ...
            },

         },
         debug => {
            credential => {
               class => 'Password',
               password_field => 'password',
               password_type => 'clear',
            },
            store => {
               class => 'Minimal',
               users => {
                  test => {
                    login => 'user',
                    password => 'pass',
                    roles => [qw/ user /],
                  },
                  admin => {
                    login => 'admin',
                    password => 'pass',
                    roles => [qw/ admin /],
                  },
               },
            },
         },

2. In root controller that checks authentication, have a case that checks
for environment variables DEBUG_REALM, DEBUG_USER, DEBUG_PASS and if set use
them to perform $c->authenticate() manually rather than redirecting to the
login screen

sub auto : Private {
    my ($self, $c) = @_;

    # Allow unauthenticated users to reach the login page.
    if ($c->action eq $c->controller('Web')->action_for('login')) {
        return 1;
    }

    # allow access during interactive debugging or from test scripts
    if ( $ENV{DEBUG_USER} ) {
      my $realm = $ENV{DEBUG_REALM}||'default';

      if ( $realm eq 'debug' ) # auth against built in debug users in
configuration
      {
        $c->authenticate({
          username => ($ENV{DEBUG_USER}||'test'), # 'username' needed
for 'debug' realm Minimal authentication
          password => ($ENV{DEBUG_PASS}||'pass'),
          }, $realm )
       || die "cannot perform debug authentication";
      }
      else # auth against normal database backend
      {
        $c->authenticate({
          login    => ($ENV{DEBUG_USER}||'test'), # 'login' needed for
default 'members' realm
          password => ($ENV{DEBUG_PASS}||'pass'),
          }, $realm )
       || die "cannot perform env authentication";

      }

    }

    if (!$c->user_exists) {

        $c->response->redirect($c->uri_for('/web/login/' .
$c->request->action));
        # Return 0 to cancel 'post-auto' processing and prevent use of
application
        return 0;
    }

    # resend cookie to extend its life
    $c->session_expires;

return 1; }
# normal interactive login point

sub login :Local {
    my ($self, $c, @path) = @_;
    my $username = $c->request->params->{username} || "";
    my $password = $c->request->params->{password} || "";

    if ($username && $password) {
        if ($c->authenticate({ login => $username, password => $password }) ) {
    ...


3. Add a couple of helper scripts that run the test web server with
different auth realms for debugging/testing

script/myapp_server_with_auth_envvars.pl

#!/bin/sh
# run test server with auto auth
DEBUG_USER=cust DEBUG_PASS=cust DEBUG_REALM=members perl -d
script/myapp_server.pl -k

script/myapp_server_with_debugrealm_auth_envvars.pl

#!/bin/sh
# run test server with debug auth
DEBUG_USER=test DEBUG_PASS=pass DEBUG_REALM=debug perl -d
script/myapp_server.pl -k


4. Basic testing using Catalyst::Test

use strict;
use warnings;
use Test::More tests => 2;

BEGIN { use_ok 'Catalyst::Test', 'MyApp' }

ok( request('/web/login')->is_success, 'Request should succeed' );
...


5. Web testing
Set up a test database/fixture with known data, start up web server using
debug auth realm via script/myapp_server_with_auth_envvars.pl and then use
Test::WWW::Mechanize::Catalyst to exercise your application

use strict;
use warnings;
use Test::More;

eval "use Test::WWW::Mechanize::Catalyst 'MyApp'";
plan $@
    ? ( skip_all => 'Test::WWW::Mechanize::Catalyst required' )
    : ( tests => 36 );

ok( my $mech = Test::WWW::Mechanize::Catalyst->new, 'Created mech object' );

# logout screen redirects to login screen
$mech->get_ok( 'http://localhost/web/logout', 'logout' );
$mech->content_contains('Log on using', 'logout redirects to login screen');

diag "check login authentication is required to access extranet screens";
#
# turn off automatic redirect follow so we can check response code

$mech->requests_redirectable([]);# 1. check redirect code and location

$mech->get( 'http://localhost/web/extranet/list/booking' );
is($mech->response->headers->{status}, 302, 'unauthed user is
redirected away from page requiring auth');
like($mech->response->headers->{location}, qw|/web/login/|, 'redirect
is to login page');

# 2. check all protected paths
for (qw|
    index
    home
    booking
    ...

 |)
{
  my $path = '/web/extranet/'.$_;
  $mech->get( 'http://localhost/'.$path);
  is($mech->response->headers->{status}, 302, 'unauth redirect for '.$path);
}

# allow automatic redirect again
$mech->requests_redirectable([qw/ GET HEAD POST /]);

# get login screen
$mech->get_ok( 'http://localhost/web/login', 'get login' );
$mech->content_contains('Log on using', 'login contains Log on using');
# login
$mech->submit_form(
  fields => {
      username => 'cust',
      password => 'cust',
  },
);
# check logged in successfully
$mech->content_contains('Welcome to the', 'successfully logged in screen');

diag "screen tests";
$mech->get_ok( 'http://localhost/web/extranet/home', 'get home' );
$mech->content_contains('Welcome to the', 'home contains welcome');

$mech->get_ok( 'http://localhost/web/extranet/list/booking', 'list/booking' );
$mech->content_contains('25843011', 'booking list contains booking 25843011');

...


I hope that helps and doesn't get too mangled by the mailer.

Regards, Peter
http://perl.dragonstaff.co.uk
_______________________________________________
List: [email protected]
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/[email protected]/
Dev site: http://dev.catalyst.perl.org/

Reply via email to