3 Catalyst::Manual::Deployment - Deploying Catalyst
9 L<Catalyst::Manual::Deployment::Apache::mod_perl>
15 L<Catalyst::Manual::Deployment::Apache::FastCGI>
18 =head2 mod_perl Deployment
20 mod_perl is not the best solution for many applications, but we'll list some
21 pros and cons so you can decide for yourself. The other (recommended)
22 deployment option is FastCGI, for which see below.
28 mod_perl is fast and your app will be loaded in memory
29 within each Apache process.
31 =head4 Shared memory for multiple apps
33 If you need to run several Catalyst apps on the same server, mod_perl will
34 share the memory for common modules.
40 Since your application is fully loaded in memory, every Apache process will
41 be rather large. This means a large Apache process will be tied up while
42 serving static files, large files, or dealing with slow clients. For this
43 reason, it is best to run a two-tiered web architecture with a lightweight
44 frontend server passing dynamic requests to a large backend mod_perl
49 Any changes made to the core code of your app require a full Apache restart.
50 Catalyst does not support Apache::Reload or StatINC. This is another good
51 reason to run a frontend web server where you can set up an
52 C<ErrorDocument 502> page to report that your app is down for maintenance.
54 =head4 Cannot run multiple versions of the same app
56 It is not possible to run two different versions of the same application in
57 the same Apache instance because the namespaces will collide.
59 =head4 Cannot run different versions of libraries.
61 If you have two different applications which run on the same machine,
62 which need two different versions of a library then the only way to do
63 this is to have per-vhost perl interpreters (with different library paths).
64 This is entirely possible, but nullifies all the memory sharing benefits that
65 you get from having multiple applications sharing the same interpreter.
69 Now that we have that out of the way, let's talk about setting up mod_perl
70 to run a Catalyst app.
72 =head4 1. Install Catalyst::Engine::Apache
74 You should install the latest versions of both Catalyst and
75 Catalyst::Engine::Apache. The Apache engines were separated from the
76 Catalyst core in version 5.50 to allow for updates to the engine without
77 requiring a new Catalyst release.
79 =head4 2. Install Apache with mod_perl
81 Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly
82 recommended. With Apache 2, make sure you are using the prefork MPM and not
83 the worker MPM. The reason for this is that many Perl modules are not
84 thread-safe and may have problems running within the threaded worker
85 environment. Catalyst is thread-safe however, so if you know what you're
86 doing, you may be able to run using worker.
88 In Debian, the following commands should get you going.
90 apt-get install apache2-mpm-prefork
91 apt-get install libapache2-mod-perl2
93 =head4 3. Configure your application
95 Every Catalyst application will automagically become a mod_perl handler
96 when run within mod_perl. This makes the configuration extremely easy.
97 Here is a basic Apache 2 configuration.
99 PerlSwitches -I/var/www/MyApp/lib
104 PerlResponseHandler MyApp
107 The most important line here is C<PerlModule MyApp>. This causes mod_perl
108 to preload your entire application into shared memory, including all of your
109 controller, model, and view classes and configuration. If you have -Debug
110 mode enabled, you will see the startup output scroll by when you first
113 For an example Apache 1.3 configuration, please see the documentation for
114 L<Catalyst::Engine::Apache::MP13>.
118 That's it, your app is now a full-fledged mod_perl application! Try it out
119 by going to http://your.server.com/.
123 =head4 Non-root location
125 You may not always want to run your app at the root of your server or virtual
126 host. In this case, it's a simple change to run at any non-root location
131 PerlResponseHandler MyApp
134 When running this way, it is best to make use of the C<uri_for> method in
135 Catalyst for constructing correct links.
137 =head4 Static file handling
139 Static files can be served directly by Apache for a performance boost.
141 DocumentRoot /var/www/MyApp/root
143 SetHandler default-handler
146 This will let all files within root/static be handled directly by Apache. In
147 a two-tiered setup, the frontend server should handle static files.
148 The configuration to do this on the frontend will vary.
150 The same is accomplished in lighttpd with the following snippet:
152 $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" {
156 "socket" => "/tmp/myapp.socket",
157 "check-local" => "disable",
163 Which serves everything in the img, static, css directories
164 statically, as well as the favicon file.
166 Note the path of the application needs to be stated explicitly in the
167 web server configuration for both these recipes.
169 =head2 Catalyst on shared hosting
171 So, you want to put your Catalyst app out there for the whole world to
172 see, but you don't want to break the bank. There is an answer - if you
173 can get shared hosting with FastCGI and a shell, you can install your
174 Catalyst app in a local directory on your shared host. First, run
178 and go through the standard CPAN configuration process. Then exit out
179 without installing anything. Next, open your .bashrc and add
181 export PATH=$HOME/local/bin:$HOME/local/script:$PATH
182 perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'`
183 export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
185 and log out, then back in again (or run C<". .bashrc"> if you
186 prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add
188 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local],
189 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
191 Now you can install the modules you need using CPAN as normal; they
192 will be installed into your local directory, and perl will pick them
193 up. Finally, change directory into the root of your virtual host and
194 symlink your application's script directory in:
196 cd path/to/mydomain.com
197 ln -s ~/lib/MyApp/script script
199 And add the following lines to your .htaccess file (assuming the server
200 is setup to handle .pl as fcgi - you may need to rename the script to
201 myapp_fastcgi.fcgi and/or use a SetHandler directive):
204 RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl
205 RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
207 Now C<http://mydomain.com/> should now Just Work. Congratulations, now
208 you can tell your friends about your new website (or in our case, tell
209 the client it's time to pay the invoice :) )
211 =head2 FastCGI Deployment
213 FastCGI is a high-performance extension to CGI. It is suitable
214 for production environments.
220 FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you;
221 your app runs as multiple persistent processes ready to receive connections
226 When using external FastCGI servers, your application runs as a standalone
227 application server. It may be restarted independently from the web server.
228 This allows for a more robust environment and faster reload times when
229 pushing new app changes. The frontend server can even be configured to
230 display a friendly "down for maintenance" page while the application is
233 =head4 Load-balancing
235 You can launch your application on multiple backend servers and allow the
236 frontend web server to load-balance between all of them. And of course, if
237 one goes down, your app continues to run fine.
239 =head4 Multiple versions of the same app
241 Each FastCGI application is a separate process, so you can run different
242 versions of the same app on a single server.
244 =head4 Can run with threaded Apache
246 Since your app is not running inside of Apache, the faster mpm_worker module
247 can be used without worrying about the thread safety of your application.
251 You may have to disable mod_deflate. If you experience page hangs with
252 mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/
254 =head4 More complex environment
256 With FastCGI, there are more things to monitor and more processes running
257 than when using mod_perl.
261 =head4 1. Install Apache with mod_fastcgi
263 mod_fastcgi for Apache is a third party module, and can be found at
264 L<http://www.fastcgi.com/>. It is also packaged in many distributions,
265 for example, libapache2-mod-fastcgi in Debian. You will also need to install
266 the L<FCGI> module from cpan.
268 Important Note! If you experience difficulty properly rendering pages,
269 try disabling Apache's mod_deflate (Deflate Module), e.g. 'a2dismod deflate'.
271 =head4 2. Configure your application
273 # Serve static content directly
274 DocumentRoot /var/www/MyApp/root
275 Alias /static /var/www/MyApp/root/static
277 FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
278 Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
280 # Or, run at the root
281 Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
283 The above commands will launch 3 app processes and make the app available at
286 =head3 Standalone server mode
288 While not as easy as the previous method, running your app as an external
289 server gives you much more flexibility.
291 First, launch your app as a standalone server listening on a socket.
293 script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
295 You can also listen on a TCP port if your web server is not on the same
298 script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
300 You will probably want to write an init script to handle starting/stopping
301 of the app using the pid file.
303 Now, we simply configure Apache to connect to the running server.
305 # 502 is a Bad Gateway error, and will occur if the backend server is down
306 # This allows us to display a friendly static page that says "down for
308 Alias /_errors /var/www/MyApp/root/error-pages
309 ErrorDocument 502 /_errors/502.html
311 FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
312 Alias /myapp/ /tmp/myapp.fcgi/
314 # Or, run at the root
315 Alias / /tmp/myapp.fcgi/
319 L<Catalyst::Engine::FastCGI>.
321 =head2 Development server deployment
323 The development server is a mini web server written in perl. If you
324 expect a low number of hits or you don't need mod_perl/FastCGI speed,
325 you could use the development server as the application server with a
326 lightweight proxy web server at the front. However, consider using
327 L<Catalyst::Engine::HTTP::Prefork> for this kind of deployment instead, since
328 it can better handle multiple concurrent requests without forking, or can
329 prefork a set number of servers for improved performance.
333 As this is an application server setup, the pros are the same as
334 FastCGI (with the exception of speed).
339 The development server is what you create your code on, so if it works
340 here, it should work in production!
346 Not as fast as mod_perl or FastCGI. Needs to fork for each request
347 that comes in - make sure static files are served by the web server to
352 =head4 Start up the development server
354 script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid
356 You will probably want to write an init script to handle stop/starting
357 the app using the pid file.
359 =head4 Configuring Apache
361 Make sure mod_proxy is enabled and add:
363 # Serve static content directly
364 DocumentRoot /var/www/MyApp/root
365 Alias /static /var/www/MyApp/root/static
373 # Need to specifically stop these paths from being passed to proxy
375 ProxyPass /favicon.ico !
377 ProxyPass / http://localhost:8080/
378 ProxyPassReverse / http://localhost:8080/
380 # This is optional if you'd like to show a custom error page
381 # if the proxy is not available
382 ErrorDocument 502 /static/error_pages/http502.html
384 You can wrap the above within a VirtualHost container if you want
385 different apps served on the same host.
387 =head2 Quick deployment: Building PAR Packages
389 You have an application running on your development box, but then you
390 have to quickly move it to another one for
391 demonstration/deployment/testing...
393 PAR packages can save you from a lot of trouble here. They are usual Zip
394 files that contain a blib tree; you can even include all prereqs and a
395 perl interpreter by setting a few flags!
397 =head3 Follow these few points to try it out!
399 1. Install Catalyst and PAR 0.89 (or later)
401 % perl -MCPAN -e 'install Catalyst'
403 % perl -MCPAN -e 'install PAR'
406 2. Create a application
412 Recent versions of Catalyst (5.62 and up) include
413 L<Module::Install::Catalyst>, which simplifies the process greatly. From the shell in your application directory:
418 You can customise the PAR creation process by special "catalyst_par_*" commands
419 available from L<Module::Install::Catalyst>. You can add these commands in your
420 Makefile.PL just before the line containing "catalyst;"
422 #Makefile.PL example with extra PAR options
423 use inc::Module::Install;
426 all_from 'lib\MyApp.pm';
428 requires 'Catalyst::Runtime' => '5.80005';
433 catalyst_par_core(1); # bundle perl core modules in the resulting PAR
434 catalyst_par_multiarch(1); # build a multi-architecture PAR file
435 catalyst_par_classes(qw/
436 Some::Additional::Module
438 /); # specify additional modules you want to be included into PAR
441 install_script glob('script/*.pl');
445 Congratulations! Your package "myapp.par" is ready, the following
446 steps are just optional.
448 3. Test your PAR package with "parl" (no typo)
452 [parl] myapp[.par] [script] [arguments]
455 parl myapp.par myapp_server.pl -r
465 % parl myapp.par myapp_server.pl
466 You can connect to your server at http://localhost:3000
468 Yes, this nifty little starter application gets automatically included.
469 You can also use "catalyst_par_script('myapp_server.pl')" to set a
470 default script to execute.
472 6. Want to create a binary that includes the Perl interpreter?
474 % pp -o myapp myapp.par
475 % ./myapp myapp_server.pl
476 You can connect to your server at http://localhost:3000
478 =head2 Serving static content
480 Serving static content in Catalyst used to be somewhat tricky; the use
481 of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
482 This plugin will automatically serve your static content during development,
483 but allows you to easily switch to Apache (or other server) in a
484 production environment.
486 =head3 Introduction to Static::Simple
488 Static::Simple is a plugin that will help to serve static content for your
489 application. By default, it will serve most types of files, excluding some
490 standard Template Toolkit extensions, out of your B<root> file directory. All
491 files are served by path, so if B<images/me.jpg> is requested, then
492 B<root/images/me.jpg> is found and served.
496 Using the plugin is as simple as setting your use line in MyApp.pm to include:
498 use Catalyst qw/Static::Simple/;
500 and already files will be served.
504 Static content is best served from a single directory within your root
505 directory. Having many different directories such as C<root/css> and
506 C<root/images> requires more code to manage, because you must separately
507 identify each static directory--if you decide to add a C<root/js>
508 directory, you'll need to change your code to account for it. In
509 contrast, keeping all static directories as subdirectories of a main
510 C<root/static> directory makes things much easier to manage. Here's an
511 example of a typical root directory structure:
515 root/controller/stuff.tt
518 root/static/css/main.css
519 root/static/images/logo.jpg
520 root/static/js/code.js
523 All static content lives under C<root/static>, with everything else being
524 Template Toolkit files.
530 You may of course want to change the default locations, and make
531 Static::Simple look somewhere else, this is as easy as:
533 MyApp->config->{static}->{include_path} = [
534 MyApp->config->{root},
538 When you override include_path, it will not automatically append the
539 normal root path, so you need to add it yourself if you still want
540 it. These will be searched in order given, and the first matching file
543 =item Static directories
545 If you want to force some directories to be only static, you can set
546 them using paths relative to the root dir, or regular expressions:
548 MyApp->config->{static}->{dirs} = [
553 =item File extensions
555 By default, the following extensions are not served (that is, they will
556 be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
559 MyApp->config->{static}->{ignore_extensions} = [
560 qw/tmpl tt tt2 html xhtml/
563 =item Ignoring directories
565 Entire directories can be ignored. If used with include_path,
566 directories relative to the include_path dirs will also be ignored:
568 MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
572 =head3 More information
574 L<http://search.cpan.org/dist/Catalyst-Plugin-Static-Simple/>
576 =head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
578 In some situations you might want to control things more directly,
579 using L<Catalyst::Plugin::Static>.
581 In your main application class (MyApp.pm), load the plugin:
583 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
585 You will also need to make sure your end method does I<not> forward
586 static content to the view, perhaps like this:
589 my ( $self, $c ) = @_;
591 $c->forward( 'MyApp::View::TT' )
592 unless ( $c->res->body || !$c->stash->{template} );
595 This code will only forward to the view if a template has been
596 previously defined by a controller and if there is not already data in
597 C<$c-E<gt>res-E<gt>body>.
599 Next, create a controller to handle requests for the /static path. Use
600 the Helper to save time. This command will create a stub controller as
601 C<lib/MyApp/Controller/Static.pm>.
603 $ script/myapp_create.pl controller Static
605 Edit the file and add the following methods:
607 # serve all files under /static as static files
608 sub default : Path('/static') {
609 my ( $self, $c ) = @_;
611 # Optional, allow the browser to cache the content
612 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
614 $c->serve_static; # from Catalyst::Plugin::Static
617 # also handle requests for /favicon.ico
618 sub favicon : Path('/favicon.ico') {
619 my ( $self, $c ) = @_;
624 You can also define a different icon for the browser to use instead of
625 favicon.ico by using this in your HTML header:
627 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
629 =head3 Common problems with the Static plugin
631 The Static plugin makes use of the C<shared-mime-info> package to
632 automatically determine MIME types. This package is notoriously
633 difficult to install, especially on win32 and OS X. For OS X the easiest
634 path might be to install Fink, then use C<apt-get install
635 shared-mime-info>. Restart the server, and everything should be fine.
637 Make sure you are using the latest version (>= 0.16) for best
638 results. If you are having errors serving CSS files, or if they get
639 served as text/plain instead of text/css, you may have an outdated
640 shared-mime-info version. You may also wish to simply use the following
641 code in your Static controller:
643 if ($c->req->path =~ /css$/i) {
644 $c->serve_static( "text/css" );
649 =head3 Serving Static Files with Apache
651 When using Apache, you can bypass Catalyst and any Static
652 plugins/controllers controller by intercepting requests for the
653 C<root/static> path at the server level. All that is required is to
654 define a DocumentRoot and add a separate Location block for your static
655 content. Here is a complete config for this application under mod_perl
659 use lib qw(/var/www/MyApp/lib);
664 ServerName myapp.example.com
665 DocumentRoot /var/www/MyApp/root
667 SetHandler perl-script
670 <LocationMatch "/(static|favicon.ico)">
671 SetHandler default-handler
675 And here's a simpler example that'll get you started:
677 Alias /static/ "/my/static/files/"
684 Catalyst makes it easy to employ several different types of caching to
685 speed up your applications.
689 There are three wrapper plugins around common CPAN cache modules:
690 Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
691 used to cache the result of slow operations.
693 The Catalyst Advent Calendar uses the FileCache plugin to cache the
694 rendered XHTML version of the source POD document. This is an ideal
695 application for a cache because the source document changes
696 infrequently but may be viewed many times.
698 use Catalyst qw/Cache::FileCache/;
703 sub render_pod : Local {
704 my ( self, $c ) = @_;
706 # the cache is keyed on the filename and the modification time
707 # to check for updates to the file.
708 my $file = $c->path_to( 'root', '2005', '11.pod' );
709 my $mtime = ( stat $file )->mtime;
711 my $cached_pod = $c->cache->get("$file $mtime");
712 if ( !$cached_pod ) {
713 $cached_pod = do_slow_pod_rendering();
714 # cache the result for 12 hours
715 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
717 $c->stash->{pod} = $cached_pod;
720 We could actually cache the result forever, but using a value such as 12 hours
721 allows old entries to be automatically expired when they are no longer needed.
725 Another method of caching is to cache the entire HTML page. While this is
726 traditionally handled by a front-end proxy server like Squid, the Catalyst
727 PageCache plugin makes it trivial to cache the entire output from
728 frequently-used or slow actions.
730 Many sites have a busy content-filled front page that might look something
731 like this. It probably takes a while to process, and will do the exact same
732 thing for every single user who views the page.
734 sub front_page : Path('/') {
735 my ( $self, $c ) = @_;
737 $c->forward( 'get_news_articles' );
738 $c->forward( 'build_lots_of_boxes' );
739 $c->forward( 'more_slow_stuff' );
741 $c->stash->{template} = 'index.tt';
744 We can add the PageCache plugin to speed things up.
746 use Catalyst qw/Cache::FileCache PageCache/;
748 sub front_page : Path ('/') {
749 my ( $self, $c ) = @_;
751 $c->cache_page( 300 );
753 # same processing as above
756 Now the entire output of the front page, from <html> to </html>, will be
757 cached for 5 minutes. After 5 minutes, the next request will rebuild the
758 page and it will be re-cached.
760 Note that the page cache is keyed on the page URI plus all parameters, so
761 requests for / and /?foo=bar will result in different cache items. Also,
762 only GET requests will be cached by the plugin.
764 You can even get that front-end Squid proxy to help out by enabling HTTP
765 headers for the cached page.
767 MyApp->config->{page_cache}->{set_http_headers} = 1;
769 This would now set the following headers so proxies and browsers may cache
770 the content themselves.
772 Cache-Control: max-age=($expire_time - time)
773 Expires: $expire_time
774 Last-Modified: $cache_created_time
776 =head3 Template Caching
778 Template Toolkit provides support for caching compiled versions of your
779 templates. To enable this in Catalyst, use the following configuration.
780 TT will cache compiled templates keyed on the file mtime, so changes will
781 still be automatically detected.
783 package MyApp::View::TT;
787 use base 'Catalyst::View::TT';
790 COMPILE_DIR => '/tmp/template_cache',
797 See the documentation for each cache plugin for more details and other
798 available configuration options.
800 L<Catalyst::Plugin::Cache::FastMmap>
801 L<Catalyst::Plugin::Cache::FileCache>
802 L<Catalyst::Plugin::Cache::Memcached>
803 L<Catalyst::Plugin::PageCache>
804 L<http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Config.pod#Caching_and_Compiling_Options>
808 Testing is an integral part of the web application development
809 process. Tests make multi developer teams easier to coordinate, and
810 they help ensure that there are no nasty surprises after upgrades or
815 Catalyst provides a convenient way of testing your application during
816 development and before deployment in a real environment.
818 C<Catalyst::Test> makes it possible to run the same tests both locally
819 (without an external daemon) and against a remote server via HTTP.
823 Let's examine a skeleton application's C<t/> directory:
825 mundus:~/MyApp chansen$ ls -l t/
827 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
828 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
829 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
835 Verifies that the application loads, compiles, and returns a successful
840 Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
841 environment variable is true.
843 =item C<03podcoverage.t>
845 Verifies that all methods/functions have POD coverage. Only executed if the
846 C<TEST_POD> environment variable is true.
850 =head3 Creating tests
852 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
853 1 use Test::More tests => 2;
854 2 BEGIN { use_ok( Catalyst::Test, 'MyApp' ) }
856 4 ok( request('/')->is_success );
858 The first line declares how many tests we are going to run, in this case
859 two. The second line tests and loads our application in test mode. The
860 fourth line verifies that our application returns a successful response.
862 C<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
863 take three different arguments:
867 =item A string which is a relative or absolute URI.
870 request('http://www.host.com/my/path');
872 =item An instance of C<URI>.
874 request( URI->new('http://www.host.com/my/path') );
876 =item An instance of C<HTTP::Request>.
878 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
882 C<request> returns an instance of C<HTTP::Response> and C<get> returns the
883 content (body) of the response.
885 =head3 Running tests locally
887 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
888 t/01app............ok
889 t/02pod............ok
890 t/03podcoverage....ok
891 All tests successful.
892 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
894 C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
895 will see debug logs between tests.
897 C<TEST_POD=1> enables POD checking and coverage.
899 C<prove> A command-line tool that makes it easy to run tests. You can
900 find out more about it from the links below.
902 =head3 Running tests remotely
904 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
906 All tests successful.
907 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
909 C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
910 your application. In C<CGI> or C<FastCGI> it should be the host and path
913 =head3 C<Test::WWW::Mechanize> and Catalyst
915 Be sure to check out C<Test::WWW::Mechanize::Catalyst>. It makes it easy to
916 test HTML, forms and links. A short example of usage:
918 use Test::More tests => 6;
919 BEGIN { use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' ) }
921 my $mech = Test::WWW::Mechanize::Catalyst->new;
922 $mech->get_ok("http://localhost/", 'Got index page');
923 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
924 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
925 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
926 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
928 =head3 Further Reading
936 =item Test::WWW::Mechanize::Catalyst
938 L<http://search.cpan.org/dist/Test-WWW-Mechanize-Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm>
940 =item Test::WWW::Mechanize
942 L<http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
946 L<http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
950 L<http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
954 L<http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
958 L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
962 L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
964 =item HTTP::Request::Common
966 L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Common.pm>
970 L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
974 L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
978 L<http://search.cpan.org/dist/URI/URI.pm>
982 L<http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
986 L<http://search.cpan.org/dist/Test-Pod/Pod.pm>
988 =item Test::Pod::Coverage
990 L<http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
992 =item prove (Test::Harness)
994 L<http://search.cpan.org/dist/Test-Harness/bin/prove>
998 =head3 More Information
1000 L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
1001 L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
1005 Catalyst Contributors, see Catalyst.pm
1009 This library is free software. You can redistribute it and/or modify it under
1010 the same terms as Perl itself.