From: Tomas Doran Date: Sat, 6 Aug 2011 15:26:08 +0000 (+0100) Subject: Pull deployment info out X-Git-Tag: 5.8901~12 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=commitdiff_plain;h=01b62b15107b5d8bb4e1eb173ab8629f2ea647e9 Pull deployment info out --- diff --git a/lib/Catalyst/Manual/Deployment.pod b/lib/Catalyst/Manual/Deployment.pod new file mode 100644 index 0000000..8dfecc8 --- /dev/null +++ b/lib/Catalyst/Manual/Deployment.pod @@ -0,0 +1,1012 @@ +=head1 NAME + +Catalyst::Manual::Deployment - Deploying Catalyst + +=head1 + +=head1 mod_perl + +L + +=head1 FastCGI + +=head2 Apache + +L + + +=head2 mod_perl Deployment + +mod_perl is not the best solution for many applications, but we'll list some +pros and cons so you can decide for yourself. The other (recommended) +deployment option is FastCGI, for which see below. + +=head3 Pros + +=head4 Speed + +mod_perl is fast and your app will be loaded in memory +within each Apache process. + +=head4 Shared memory for multiple apps + +If you need to run several Catalyst apps on the same server, mod_perl will +share the memory for common modules. + +=head3 Cons + +=head4 Memory usage + +Since your application is fully loaded in memory, every Apache process will +be rather large. This means a large Apache process will be tied up while +serving static files, large files, or dealing with slow clients. For this +reason, it is best to run a two-tiered web architecture with a lightweight +frontend server passing dynamic requests to a large backend mod_perl +server. + +=head4 Reloading + +Any changes made to the core code of your app require a full Apache restart. +Catalyst does not support Apache::Reload or StatINC. This is another good +reason to run a frontend web server where you can set up an +C page to report that your app is down for maintenance. + +=head4 Cannot run multiple versions of the same app + +It is not possible to run two different versions of the same application in +the same Apache instance because the namespaces will collide. + +=head4 Cannot run different versions of libraries. + +If you have two different applications which run on the same machine, +which need two different versions of a library then the only way to do +this is to have per-vhost perl interpreters (with different library paths). +This is entirely possible, but nullifies all the memory sharing benefits that +you get from having multiple applications sharing the same interpreter. + +=head4 Setup + +Now that we have that out of the way, let's talk about setting up mod_perl +to run a Catalyst app. + +=head4 1. Install Catalyst::Engine::Apache + +You should install the latest versions of both Catalyst and +Catalyst::Engine::Apache. The Apache engines were separated from the +Catalyst core in version 5.50 to allow for updates to the engine without +requiring a new Catalyst release. + +=head4 2. Install Apache with mod_perl + +Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly +recommended. With Apache 2, make sure you are using the prefork MPM and not +the worker MPM. The reason for this is that many Perl modules are not +thread-safe and may have problems running within the threaded worker +environment. Catalyst is thread-safe however, so if you know what you're +doing, you may be able to run using worker. + +In Debian, the following commands should get you going. + + apt-get install apache2-mpm-prefork + apt-get install libapache2-mod-perl2 + +=head4 3. Configure your application + +Every Catalyst application will automagically become a mod_perl handler +when run within mod_perl. This makes the configuration extremely easy. +Here is a basic Apache 2 configuration. + + PerlSwitches -I/var/www/MyApp/lib + PerlModule MyApp + + + SetHandler modperl + PerlResponseHandler MyApp + + +The most important line here is C. This causes mod_perl +to preload your entire application into shared memory, including all of your +controller, model, and view classes and configuration. If you have -Debug +mode enabled, you will see the startup output scroll by when you first +start Apache. + +For an example Apache 1.3 configuration, please see the documentation for +L. + +=head3 Test It + +That's it, your app is now a full-fledged mod_perl application! Try it out +by going to http://your.server.com/. + +=head3 Other Options + +=head4 Non-root location + +You may not always want to run your app at the root of your server or virtual +host. In this case, it's a simple change to run at any non-root location +of your choice. + + + SetHandler modperl + PerlResponseHandler MyApp + + +When running this way, it is best to make use of the C method in +Catalyst for constructing correct links. + +=head4 Static file handling + +Static files can be served directly by Apache for a performance boost. + + DocumentRoot /var/www/MyApp/root + + SetHandler default-handler + + +This will let all files within root/static be handled directly by Apache. In +a two-tiered setup, the frontend server should handle static files. +The configuration to do this on the frontend will vary. + +The same is accomplished in lighttpd with the following snippet: + + $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" { + fastcgi.server = ( + "" => ( + "MyApp" => ( + "socket" => "/tmp/myapp.socket", + "check-local" => "disable", + ) + ) + ) + } + +Which serves everything in the img, static, css directories +statically, as well as the favicon file. + +Note the path of the application needs to be stated explicitly in the +web server configuration for both these recipes. + +=head2 Catalyst on shared hosting + +So, you want to put your Catalyst app out there for the whole world to +see, but you don't want to break the bank. There is an answer - if you +can get shared hosting with FastCGI and a shell, you can install your +Catalyst app in a local directory on your shared host. First, run + + perl -MCPAN -e shell + +and go through the standard CPAN configuration process. Then exit out +without installing anything. Next, open your .bashrc and add + + export PATH=$HOME/local/bin:$HOME/local/script:$PATH + perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'` + export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB + +and log out, then back in again (or run C<". .bashrc"> if you +prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add + + 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local], + 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local], + +Now you can install the modules you need using CPAN as normal; they +will be installed into your local directory, and perl will pick them +up. Finally, change directory into the root of your virtual host and +symlink your application's script directory in: + + cd path/to/mydomain.com + ln -s ~/lib/MyApp/script script + +And add the following lines to your .htaccess file (assuming the server +is setup to handle .pl as fcgi - you may need to rename the script to +myapp_fastcgi.fcgi and/or use a SetHandler directive): + + RewriteEngine On + RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl + RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L] + +Now C should now Just Work. Congratulations, now +you can tell your friends about your new website (or in our case, tell +the client it's time to pay the invoice :) ) + +=head2 FastCGI Deployment + +FastCGI is a high-performance extension to CGI. It is suitable +for production environments. + +=head3 Pros + +=head4 Speed + +FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you; +your app runs as multiple persistent processes ready to receive connections +from the web server. + +=head4 App Server + +When using external FastCGI servers, your application runs as a standalone +application server. It may be restarted independently from the web server. +This allows for a more robust environment and faster reload times when +pushing new app changes. The frontend server can even be configured to +display a friendly "down for maintenance" page while the application is +restarting. + +=head4 Load-balancing + +You can launch your application on multiple backend servers and allow the +frontend web server to load-balance between all of them. And of course, if +one goes down, your app continues to run fine. + +=head4 Multiple versions of the same app + +Each FastCGI application is a separate process, so you can run different +versions of the same app on a single server. + +=head4 Can run with threaded Apache + +Since your app is not running inside of Apache, the faster mpm_worker module +can be used without worrying about the thread safety of your application. + +=head3 Cons + +You may have to disable mod_deflate. If you experience page hangs with +mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/ + +=head4 More complex environment + +With FastCGI, there are more things to monitor and more processes running +than when using mod_perl. + +=head3 Setup + +=head4 1. Install Apache with mod_fastcgi + +mod_fastcgi for Apache is a third party module, and can be found at +L. It is also packaged in many distributions, +for example, libapache2-mod-fastcgi in Debian. You will also need to install +the L module from cpan. + +Important Note! If you experience difficulty properly rendering pages, +try disabling Apache's mod_deflate (Deflate Module), e.g. 'a2dismod deflate'. + +=head4 2. Configure your application + + # Serve static content directly + DocumentRoot /var/www/MyApp/root + Alias /static /var/www/MyApp/root/static + + FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3 + Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/ + + # Or, run at the root + Alias / /var/www/MyApp/script/myapp_fastcgi.pl/ + +The above commands will launch 3 app processes and make the app available at +/myapp/ + +=head3 Standalone server mode + +While not as easy as the previous method, running your app as an external +server gives you much more flexibility. + +First, launch your app as a standalone server listening on a socket. + + script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d + +You can also listen on a TCP port if your web server is not on the same +machine. + + script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d + +You will probably want to write an init script to handle starting/stopping +of the app using the pid file. + +Now, we simply configure Apache to connect to the running server. + + # 502 is a Bad Gateway error, and will occur if the backend server is down + # This allows us to display a friendly static page that says "down for + # maintenance" + Alias /_errors /var/www/MyApp/root/error-pages + ErrorDocument 502 /_errors/502.html + + FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket + Alias /myapp/ /tmp/myapp.fcgi/ + + # Or, run at the root + Alias / /tmp/myapp.fcgi/ + +=head3 More Info + +L. + +=head2 Development server deployment + +The development server is a mini web server written in perl. If you +expect a low number of hits or you don't need mod_perl/FastCGI speed, +you could use the development server as the application server with a +lightweight proxy web server at the front. However, consider using +L for this kind of deployment instead, since +it can better handle multiple concurrent requests without forking, or can +prefork a set number of servers for improved performance. + +=head3 Pros + +As this is an application server setup, the pros are the same as +FastCGI (with the exception of speed). +It is also: + +=head4 Simple + +The development server is what you create your code on, so if it works +here, it should work in production! + +=head3 Cons + +=head4 Speed + +Not as fast as mod_perl or FastCGI. Needs to fork for each request +that comes in - make sure static files are served by the web server to +save forking. + +=head3 Setup + +=head4 Start up the development server + + script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid + +You will probably want to write an init script to handle stop/starting +the app using the pid file. + +=head4 Configuring Apache + +Make sure mod_proxy is enabled and add: + + # Serve static content directly + DocumentRoot /var/www/MyApp/root + Alias /static /var/www/MyApp/root/static + + ProxyRequests Off + + Order deny,allow + Allow from all + + + # Need to specifically stop these paths from being passed to proxy + ProxyPass /static ! + ProxyPass /favicon.ico ! + + ProxyPass / http://localhost:8080/ + ProxyPassReverse / http://localhost:8080/ + + # This is optional if you'd like to show a custom error page + # if the proxy is not available + ErrorDocument 502 /static/error_pages/http502.html + +You can wrap the above within a VirtualHost container if you want +different apps served on the same host. + +=head2 Quick deployment: Building PAR Packages + +You have an application running on your development box, but then you +have to quickly move it to another one for +demonstration/deployment/testing... + +PAR packages can save you from a lot of trouble here. They are usual Zip +files that contain a blib tree; you can even include all prereqs and a +perl interpreter by setting a few flags! + +=head3 Follow these few points to try it out! + +1. Install Catalyst and PAR 0.89 (or later) + + % perl -MCPAN -e 'install Catalyst' + ... + % perl -MCPAN -e 'install PAR' + ... + +2. Create a application + + % catalyst.pl MyApp + ... + % cd MyApp + +Recent versions of Catalyst (5.62 and up) include +L, which simplifies the process greatly. From the shell in your application directory: + + % perl Makefile.PL + % make catalyst_par + +You can customise the PAR creation process by special "catalyst_par_*" commands +available from L. You can add these commands in your +Makefile.PL just before the line containing "catalyst;" + + #Makefile.PL example with extra PAR options + use inc::Module::Install; + + name 'MyApp'; + all_from 'lib\MyApp.pm'; + + requires 'Catalyst::Runtime' => '5.80005'; + + ... + + + catalyst_par_core(1); # bundle perl core modules in the resulting PAR + catalyst_par_multiarch(1); # build a multi-architecture PAR file + catalyst_par_classes(qw/ + Some::Additional::Module + Some::Other::Module + /); # specify additional modules you want to be included into PAR + catalyst; + + install_script glob('script/*.pl'); + auto_install; + WriteAll; + +Congratulations! Your package "myapp.par" is ready, the following +steps are just optional. + +3. Test your PAR package with "parl" (no typo) + + % parl myapp.par + Usage: + [parl] myapp[.par] [script] [arguments] + + Examples: + parl myapp.par myapp_server.pl -r + myapp myapp_cgi.pl + + Available scripts: + myapp_cgi.pl + myapp_create.pl + myapp_fastcgi.pl + myapp_server.pl + myapp_test.pl + + % parl myapp.par myapp_server.pl + You can connect to your server at http://localhost:3000 + +Yes, this nifty little starter application gets automatically included. +You can also use "catalyst_par_script('myapp_server.pl')" to set a +default script to execute. + +6. Want to create a binary that includes the Perl interpreter? + + % pp -o myapp myapp.par + % ./myapp myapp_server.pl + You can connect to your server at http://localhost:3000 + +=head2 Serving static content + +Serving static content in Catalyst used to be somewhat tricky; the use +of L makes everything much easier. +This plugin will automatically serve your static content during development, +but allows you to easily switch to Apache (or other server) in a +production environment. + +=head3 Introduction to Static::Simple + +Static::Simple is a plugin that will help to serve static content for your +application. By default, it will serve most types of files, excluding some +standard Template Toolkit extensions, out of your B file directory. All +files are served by path, so if B is requested, then +B is found and served. + +=head3 Usage + +Using the plugin is as simple as setting your use line in MyApp.pm to include: + + use Catalyst qw/Static::Simple/; + +and already files will be served. + +=head3 Configuring + +Static content is best served from a single directory within your root +directory. Having many different directories such as C and +C requires more code to manage, because you must separately +identify each static directory--if you decide to add a C +directory, you'll need to change your code to account for it. In +contrast, keeping all static directories as subdirectories of a main +C directory makes things much easier to manage. Here's an +example of a typical root directory structure: + + root/ + root/content.tt + root/controller/stuff.tt + root/header.tt + root/static/ + root/static/css/main.css + root/static/images/logo.jpg + root/static/js/code.js + + +All static content lives under C, with everything else being +Template Toolkit files. + +=over 4 + +=item Include Path + +You may of course want to change the default locations, and make +Static::Simple look somewhere else, this is as easy as: + + MyApp->config->{static}->{include_path} = [ + MyApp->config->{root}, + '/path/to/my/files' + ]; + +When you override include_path, it will not automatically append the +normal root path, so you need to add it yourself if you still want +it. These will be searched in order given, and the first matching file +served. + +=item Static directories + +If you want to force some directories to be only static, you can set +them using paths relative to the root dir, or regular expressions: + + MyApp->config->{static}->{dirs} = [ + 'static', + qr/^(images|css)/, + ]; + +=item File extensions + +By default, the following extensions are not served (that is, they will +be processed by Catalyst): B. This list can +be replaced easily: + + MyApp->config->{static}->{ignore_extensions} = [ + qw/tmpl tt tt2 html xhtml/ + ]; + +=item Ignoring directories + +Entire directories can be ignored. If used with include_path, +directories relative to the include_path dirs will also be ignored: + + MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ]; + +=back + +=head3 More information + +L + +=head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl) + +In some situations you might want to control things more directly, +using L. + +In your main application class (MyApp.pm), load the plugin: + + use Catalyst qw/-Debug FormValidator Static OtherPlugin/; + +You will also need to make sure your end method does I forward +static content to the view, perhaps like this: + + sub end : Private { + my ( $self, $c ) = @_; + + $c->forward( 'MyApp::View::TT' ) + unless ( $c->res->body || !$c->stash->{template} ); + } + +This code will only forward to the view if a template has been +previously defined by a controller and if there is not already data in +C<$c-Eres-Ebody>. + +Next, create a controller to handle requests for the /static path. Use +the Helper to save time. This command will create a stub controller as +C. + + $ script/myapp_create.pl controller Static + +Edit the file and add the following methods: + + # serve all files under /static as static files + sub default : Path('/static') { + my ( $self, $c ) = @_; + + # Optional, allow the browser to cache the content + $c->res->headers->header( 'Cache-Control' => 'max-age=86400' ); + + $c->serve_static; # from Catalyst::Plugin::Static + } + + # also handle requests for /favicon.ico + sub favicon : Path('/favicon.ico') { + my ( $self, $c ) = @_; + + $c->serve_static; + } + +You can also define a different icon for the browser to use instead of +favicon.ico by using this in your HTML header: + + + +=head3 Common problems with the Static plugin + +The Static plugin makes use of the C package to +automatically determine MIME types. This package is notoriously +difficult to install, especially on win32 and OS X. For OS X the easiest +path might be to install Fink, then use C. Restart the server, and everything should be fine. + +Make sure you are using the latest version (>= 0.16) for best +results. If you are having errors serving CSS files, or if they get +served as text/plain instead of text/css, you may have an outdated +shared-mime-info version. You may also wish to simply use the following +code in your Static controller: + + if ($c->req->path =~ /css$/i) { + $c->serve_static( "text/css" ); + } else { + $c->serve_static; + } + +=head3 Serving Static Files with Apache + +When using Apache, you can bypass Catalyst and any Static +plugins/controllers controller by intercepting requests for the +C path at the server level. All that is required is to +define a DocumentRoot and add a separate Location block for your static +content. Here is a complete config for this application under mod_perl +1.x: + + + use lib qw(/var/www/MyApp/lib); + + PerlModule MyApp + + + ServerName myapp.example.com + DocumentRoot /var/www/MyApp/root + + SetHandler perl-script + PerlHandler MyApp + + + SetHandler default-handler + + + +And here's a simpler example that'll get you started: + + Alias /static/ "/my/static/files/" + + SetHandler none + + +=head2 Caching + +Catalyst makes it easy to employ several different types of caching to +speed up your applications. + +=head3 Cache Plugins + +There are three wrapper plugins around common CPAN cache modules: +Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be +used to cache the result of slow operations. + +The Catalyst Advent Calendar uses the FileCache plugin to cache the +rendered XHTML version of the source POD document. This is an ideal +application for a cache because the source document changes +infrequently but may be viewed many times. + + use Catalyst qw/Cache::FileCache/; + + ... + + use File::stat; + sub render_pod : Local { + my ( self, $c ) = @_; + + # the cache is keyed on the filename and the modification time + # to check for updates to the file. + my $file = $c->path_to( 'root', '2005', '11.pod' ); + my $mtime = ( stat $file )->mtime; + + my $cached_pod = $c->cache->get("$file $mtime"); + if ( !$cached_pod ) { + $cached_pod = do_slow_pod_rendering(); + # cache the result for 12 hours + $c->cache->set( "$file $mtime", $cached_pod, '12h' ); + } + $c->stash->{pod} = $cached_pod; + } + +We could actually cache the result forever, but using a value such as 12 hours +allows old entries to be automatically expired when they are no longer needed. + +=head3 Page Caching + +Another method of caching is to cache the entire HTML page. While this is +traditionally handled by a front-end proxy server like Squid, the Catalyst +PageCache plugin makes it trivial to cache the entire output from +frequently-used or slow actions. + +Many sites have a busy content-filled front page that might look something +like this. It probably takes a while to process, and will do the exact same +thing for every single user who views the page. + + sub front_page : Path('/') { + my ( $self, $c ) = @_; + + $c->forward( 'get_news_articles' ); + $c->forward( 'build_lots_of_boxes' ); + $c->forward( 'more_slow_stuff' ); + + $c->stash->{template} = 'index.tt'; + } + +We can add the PageCache plugin to speed things up. + + use Catalyst qw/Cache::FileCache PageCache/; + + sub front_page : Path ('/') { + my ( $self, $c ) = @_; + + $c->cache_page( 300 ); + + # same processing as above + } + +Now the entire output of the front page, from to , will be +cached for 5 minutes. After 5 minutes, the next request will rebuild the +page and it will be re-cached. + +Note that the page cache is keyed on the page URI plus all parameters, so +requests for / and /?foo=bar will result in different cache items. Also, +only GET requests will be cached by the plugin. + +You can even get that front-end Squid proxy to help out by enabling HTTP +headers for the cached page. + + MyApp->config->{page_cache}->{set_http_headers} = 1; + +This would now set the following headers so proxies and browsers may cache +the content themselves. + + Cache-Control: max-age=($expire_time - time) + Expires: $expire_time + Last-Modified: $cache_created_time + +=head3 Template Caching + +Template Toolkit provides support for caching compiled versions of your +templates. To enable this in Catalyst, use the following configuration. +TT will cache compiled templates keyed on the file mtime, so changes will +still be automatically detected. + + package MyApp::View::TT; + + use strict; + use warnings; + use base 'Catalyst::View::TT'; + + __PACKAGE__->config( + COMPILE_DIR => '/tmp/template_cache', + ); + + 1; + +=head3 More Info + +See the documentation for each cache plugin for more details and other +available configuration options. + +L +L +L +L +L + +=head1 Testing + +Testing is an integral part of the web application development +process. Tests make multi developer teams easier to coordinate, and +they help ensure that there are no nasty surprises after upgrades or +alterations. + +=head2 Testing + +Catalyst provides a convenient way of testing your application during +development and before deployment in a real environment. + +C makes it possible to run the same tests both locally +(without an external daemon) and against a remote server via HTTP. + +=head3 Tests + +Let's examine a skeleton application's C directory: + + mundus:~/MyApp chansen$ ls -l t/ + total 24 + -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t + -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t + -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t + +=over 4 + +=item C<01app.t> + +Verifies that the application loads, compiles, and returns a successful +response. + +=item C<02pod.t> + +Verifies that all POD is free from errors. Only executed if the C +environment variable is true. + +=item C<03podcoverage.t> + +Verifies that all methods/functions have POD coverage. Only executed if the +C environment variable is true. + +=back + +=head3 Creating tests + + mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )' + 1 use Test::More tests => 2; + 2 BEGIN { use_ok( Catalyst::Test, 'MyApp' ) } + 3 + 4 ok( request('/')->is_success ); + +The first line declares how many tests we are going to run, in this case +two. The second line tests and loads our application in test mode. The +fourth line verifies that our application returns a successful response. + +C exports two functions, C and C. Each can +take three different arguments: + +=over 4 + +=item A string which is a relative or absolute URI. + + request('/my/path'); + request('http://www.host.com/my/path'); + +=item An instance of C. + + request( URI->new('http://www.host.com/my/path') ); + +=item An instance of C. + + request( HTTP::Request->new( GET => 'http://www.host.com/my/path') ); + +=back + +C returns an instance of C and C returns the +content (body) of the response. + +=head3 Running tests locally + + mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/ + t/01app............ok + t/02pod............ok + t/03podcoverage....ok + All tests successful. + Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU) + +C ensures that debugging is off; if it's enabled you +will see debug logs between tests. + +C enables POD checking and coverage. + +C A command-line tool that makes it easy to run tests. You can +find out more about it from the links below. + +=head3 Running tests remotely + + mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t + t/01app....ok + All tests successful. + Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU) + +C is the absolute deployment URI of +your application. In C or C it should be the host and path +to the script. + +=head3 C and Catalyst + +Be sure to check out C. It makes it easy to +test HTML, forms and links. A short example of usage: + + use Test::More tests => 6; + BEGIN { use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' ) } + + my $mech = Test::WWW::Mechanize::Catalyst->new; + $mech->get_ok("http://localhost/", 'Got index page'); + $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' ); + ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' ); + ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' ); + ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' ); + +=head3 Further Reading + +=over 4 + +=item Catalyst::Test + +L + +=item Test::WWW::Mechanize::Catalyst + +L + +=item Test::WWW::Mechanize + +L + +=item WWW::Mechanize + +L + +=item LWP::UserAgent + +L + +=item HTML::Form + +L + +=item HTTP::Message + +L + +=item HTTP::Request + +L + +=item HTTP::Request::Common + +L + +=item HTTP::Response + +L + +=item HTTP::Status + +L + +=item URI + +L + +=item Test::More + +L + +=item Test::Pod + +L + +=item Test::Pod::Coverage + +L + +=item prove (Test::Harness) + +L + +=back + +=head3 More Information + +L +L + +=head1 AUTHORS + +Catalyst Contributors, see Catalyst.pm + +=head1 COPYRIGHT + +This library is free software. You can redistribute it and/or modify it under +the same terms as Perl itself. + +=cut