7 use lib "$FindBin::Bin/lib";
11 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 2; }
13 use Test::More tests => 99*$iters;
14 use Catalyst::Test 'TestApp';
16 if ( $ENV{CAT_BENCHMARK} ) {
18 Benchmark::timethis( $iters, \&run_tests );
29 # This is a simple test where the parent and child actions are
30 # within the same controller.
34 TestApp::Controller::Action::Chained->begin
35 TestApp::Controller::Action::Chained->foo
36 TestApp::Controller::Action::Chained->endpoint
37 TestApp::Controller::Action::Chained->end
40 my $expected = join( ", ", @expected );
42 ok( my $response = request('http://localhost/chained/foo/1/end/2'), 'chained + local endpoint' );
43 is( $response->header('X-Catalyst-Executed'),
44 $expected, 'Executed actions' );
45 is( $response->content, '1; 2', 'Content OK' );
49 # This makes sure the above isn't found if the argument for the
50 # end action isn't supplied.
55 ok( my $response = request('http://localhost/chained/foo/1/end'),
56 'chained + local endpoint; missing last argument' );
57 is( $response->header('X-Catalyst-Executed'),
58 $expected, 'Executed actions' );
59 is( $response->header('Status'), 500, 'Status OK' );
63 # Tests the case when the child action is placed in a subcontroller.
67 TestApp::Controller::Action::Chained->begin
68 TestApp::Controller::Action::Chained->foo
69 TestApp::Controller::Action::Chained::Foo->spoon
70 TestApp::Controller::Action::Chained->end
73 my $expected = join( ", ", @expected );
75 ok( my $response = request('http://localhost/chained/foo/1/spoon'), 'chained + subcontroller endpoint' );
76 is( $response->header('X-Catalyst-Executed'),
77 $expected, 'Executed actions' );
78 is( $response->content, '1; ', 'Content OK' );
82 # Tests if the relative specification (e.g.: Chained('bar') ) works
87 TestApp::Controller::Action::Chained->begin
88 TestApp::Controller::Action::Chained->bar
89 TestApp::Controller::Action::Chained->finale
90 TestApp::Controller::Action::Chained->end
93 my $expected = join( ", ", @expected );
95 ok( my $response = request('http://localhost/chained/bar/1/spoon'), 'chained + relative endpoint' );
96 is( $response->header('X-Catalyst-Executed'),
97 $expected, 'Executed actions' );
98 is( $response->content, '; 1, spoon', 'Content OK' );
102 # Just a test for multiple arguments.
106 TestApp::Controller::Action::Chained->begin
107 TestApp::Controller::Action::Chained->foo2
108 TestApp::Controller::Action::Chained->endpoint2
109 TestApp::Controller::Action::Chained->end
112 my $expected = join( ", ", @expected );
114 ok( my $response = request('http://localhost/chained/foo2/10/20/end2/15/25'),
115 'chained + local (2 args each)' );
116 is( $response->header('X-Catalyst-Executed'),
117 $expected, 'Executed actions' );
118 is( $response->content, '10, 20; 15, 25', 'Content OK' );
122 # The first three-chain test tries to call the action with :Args(1)
123 # specification. There's also a one action with a :CaptureArgs(1)
124 # attribute, that should not be dispatched to.
128 TestApp::Controller::Action::Chained->begin
129 TestApp::Controller::Action::Chained->one_end
130 TestApp::Controller::Action::Chained->end
133 my $expected = join( ", ", @expected );
135 ok( my $response = request('http://localhost/chained/one/23'),
136 'three-chain (only first)' );
137 is( $response->header('X-Catalyst-Executed'),
138 $expected, 'Executed actions' );
139 is( $response->content, '; 23', 'Content OK' );
143 # This is the second three-chain test, it goes for the action that
144 # handles "/one/$cap/two/$arg1/$arg2" paths. Should be the two action
145 # having :Args(2), not the one having :CaptureArgs(2).
149 TestApp::Controller::Action::Chained->begin
150 TestApp::Controller::Action::Chained->one
151 TestApp::Controller::Action::Chained->two_end
152 TestApp::Controller::Action::Chained->end
155 my $expected = join( ", ", @expected );
157 ok( my $response = request('http://localhost/chained/one/23/two/23/46'),
158 'three-chain (up to second)' );
159 is( $response->header('X-Catalyst-Executed'),
160 $expected, 'Executed actions' );
161 is( $response->content, '23; 23, 46', 'Content OK' );
165 # Last of the three-chain tests. Has no concurrent action with :CaptureArgs
166 # and is more thought to simply test the chain as a whole and the 'two'
167 # action specifying :CaptureArgs.
171 TestApp::Controller::Action::Chained->begin
172 TestApp::Controller::Action::Chained->one
173 TestApp::Controller::Action::Chained->two
174 TestApp::Controller::Action::Chained->three_end
175 TestApp::Controller::Action::Chained->end
178 my $expected = join( ", ", @expected );
180 ok( my $response = request('http://localhost/chained/one/23/two/23/46/three/1/2/3'),
181 'three-chain (all three)' );
182 is( $response->header('X-Catalyst-Executed'),
183 $expected, 'Executed actions' );
184 is( $response->content, '23, 23, 46; 1, 2, 3', 'Content OK' );
188 # Tests dispatching on number of arguments for :Args. This should be
189 # dispatched to the action expecting one argument.
193 TestApp::Controller::Action::Chained->begin
194 TestApp::Controller::Action::Chained->multi1
195 TestApp::Controller::Action::Chained->end
198 my $expected = join( ", ", @expected );
200 ok( my $response = request('http://localhost/chained/multi/23'),
201 'multi-action (one arg)' );
202 is( $response->header('X-Catalyst-Executed'),
203 $expected, 'Executed actions' );
204 is( $response->content, '; 23', 'Content OK' );
208 # Belongs to the former test and goes for the action expecting two arguments.
212 TestApp::Controller::Action::Chained->begin
213 TestApp::Controller::Action::Chained->multi2
214 TestApp::Controller::Action::Chained->end
217 my $expected = join( ", ", @expected );
219 ok( my $response = request('http://localhost/chained/multi/23/46'),
220 'multi-action (two args)' );
221 is( $response->header('X-Catalyst-Executed'),
222 $expected, 'Executed actions' );
223 is( $response->content, '; 23, 46', 'Content OK' );
227 # Dispatching on argument count again, this time we provide too many
228 # arguments, so dispatching should fail.
231 my $expected = undef;
233 ok( my $response = request('http://localhost/chained/multi/23/46/67'),
234 'multi-action (three args, should lead to error)' );
235 is( $response->header('X-Catalyst-Executed'),
236 $expected, 'Executed actions' );
237 is( $response->header('Status'), 500, 'Status OK' );
241 # This tests the case when an action says it's the child of an action in
246 TestApp::Controller::Action::Chained->begin
247 TestApp::Controller::Action::Chained::Foo->higher_root
248 TestApp::Controller::Action::Chained->higher_root
249 TestApp::Controller::Action::Chained->end
252 my $expected = join( ", ", @expected );
254 ok( my $response = request('http://localhost/chained/higher_root/23/bar/11'),
255 'root higher than child' );
256 is( $response->header('X-Catalyst-Executed'),
257 $expected, 'Executed actions' );
258 is( $response->content, '23; 11', 'Content OK' );
262 # Just a more complex version of the former test. It tests if a controller ->
263 # subcontroller -> controller dispatch works.
267 TestApp::Controller::Action::Chained->begin
268 TestApp::Controller::Action::Chained->pcp1
269 TestApp::Controller::Action::Chained::Foo->pcp2
270 TestApp::Controller::Action::Chained->pcp3
271 TestApp::Controller::Action::Chained->end
274 my $expected = join( ", ", @expected );
276 ok( my $response = request('http://localhost/chained/pcp1/1/pcp2/2/pcp3/3'),
277 'parent -> child -> parent' );
278 is( $response->header('X-Catalyst-Executed'),
279 $expected, 'Executed actions' );
280 is( $response->content, '1, 2; 3', 'Content OK' );
284 # Tests dispatch on capture number. This test is for a one capture action.
288 TestApp::Controller::Action::Chained->begin
289 TestApp::Controller::Action::Chained->multi_cap1
290 TestApp::Controller::Action::Chained->multi_cap_end1
291 TestApp::Controller::Action::Chained->end
294 my $expected = join( ", ", @expected );
296 ok( my $response = request('http://localhost/chained/multi_cap/1/baz'),
297 'dispatch on capture num 1' );
298 is( $response->header('X-Catalyst-Executed'),
299 $expected, 'Executed actions' );
300 is( $response->content, '1; ', 'Content OK' );
304 # Belongs to the former test. This one goes for the action expecting two
309 TestApp::Controller::Action::Chained->begin
310 TestApp::Controller::Action::Chained->multi_cap2
311 TestApp::Controller::Action::Chained->multi_cap_end2
312 TestApp::Controller::Action::Chained->end
315 my $expected = join( ", ", @expected );
317 ok( my $response = request('http://localhost/chained/multi_cap/1/2/baz'),
318 'dispatch on capture num 2' );
319 is( $response->header('X-Catalyst-Executed'),
320 $expected, 'Executed actions' );
321 is( $response->content, '1, 2; ', 'Content OK' );
325 # Tests the priority of a slurpy arguments action (with :Args) against
326 # two actions chained together. The two actions should win.
330 TestApp::Controller::Action::Chained->begin
331 TestApp::Controller::Action::Chained->priority_a2
332 TestApp::Controller::Action::Chained->priority_a2_end
333 TestApp::Controller::Action::Chained->end
336 my $expected = join( ", ", @expected );
338 ok( my $response = request('http://localhost/chained/priority_a/1/end/2'),
339 'priority - slurpy args vs. parent/child' );
340 is( $response->header('X-Catalyst-Executed'),
341 $expected, 'Executed actions' );
342 is( $response->content, '1; 2', 'Content OK' );
346 # This belongs to the former test but tests if two chained actions have
347 # priority over an action with the exact arguments.
351 TestApp::Controller::Action::Chained->begin
352 TestApp::Controller::Action::Chained->priority_b2
353 TestApp::Controller::Action::Chained->priority_b2_end
354 TestApp::Controller::Action::Chained->end
357 my $expected = join( ", ", @expected );
359 ok( my $response = request('http://localhost/chained/priority_b/1/end/2'),
360 'priority - fixed args vs. parent/child' );
361 is( $response->header('X-Catalyst-Executed'),
362 $expected, 'Executed actions' );
363 is( $response->content, '1; 2', 'Content OK' );
367 # This belongs to the former test but tests if two chained actions have
368 # priority over an action with one child action not having the Args() attr set.
372 TestApp::Controller::Action::Chained->begin
373 TestApp::Controller::Action::Chained->priority_c1
374 TestApp::Controller::Action::Chained->priority_c2_xyz
375 TestApp::Controller::Action::Chained->end
378 my $expected = join( ", ", @expected );
380 ok( my $response = request('http://localhost/chained/priority_c/1/xyz/'),
381 'priority - no Args() order mismatch' );
382 is( $response->header('X-Catalyst-Executed'),
383 $expected, 'Executed actions' );
384 is( $response->content, '1; ', 'Content OK' );
388 # Test dispatching between two controllers that are on the same level and
389 # therefor have no parent/child relationship.
393 TestApp::Controller::Action::Chained->begin
394 TestApp::Controller::Action::Chained::Bar->cross1
395 TestApp::Controller::Action::Chained::Foo->cross2
396 TestApp::Controller::Action::Chained->end
399 my $expected = join( ", ", @expected );
401 ok( my $response = request('http://localhost/chained/cross/1/end/2'),
402 'cross controller w/o par/child relation' );
403 is( $response->header('X-Catalyst-Executed'),
404 $expected, 'Executed actions' );
405 is( $response->content, '1; 2', 'Content OK' );
409 # This is for testing if the arguments got passed to the actions
414 TestApp::Controller::Action::Chained->begin
415 TestApp::Controller::Action::Chained::PassedArgs->first
416 TestApp::Controller::Action::Chained::PassedArgs->second
417 TestApp::Controller::Action::Chained::PassedArgs->third
418 TestApp::Controller::Action::Chained::PassedArgs->end
421 my $expected = join( ", ", @expected );
423 ok( my $response = request('http://localhost/chained/passedargs/a/1/b/2/c/3'),
424 'Correct arguments passed to actions' );
425 is( $response->header('X-Catalyst-Executed'),
426 $expected, 'Executed actions' );
427 is( $response->content, '1; 2; 3', 'Content OK' );
431 # The :Args attribute is optional, we check the action not specifying
432 # it with these tests.
436 TestApp::Controller::Action::Chained->begin
437 TestApp::Controller::Action::Chained->opt_args
438 TestApp::Controller::Action::Chained->end
441 my $expected = join( ", ", @expected );
443 ok( my $response = request('http://localhost/chained/opt_args/1/2/3'),
444 'Optional :Args attribute working' );
445 is( $response->header('X-Catalyst-Executed'),
446 $expected, 'Executed actions' );
447 is( $response->content, '; 1, 2, 3', 'Content OK' );
451 # Tests for optional PathPart attribute.
455 TestApp::Controller::Action::Chained->begin
456 TestApp::Controller::Action::Chained->opt_pp_start
457 TestApp::Controller::Action::Chained->opt_pathpart
458 TestApp::Controller::Action::Chained->end
461 my $expected = join( ", ", @expected );
463 ok( my $response = request('http://localhost/chained/optpp/1/opt_pathpart/2'),
464 'Optional :PathName attribute working' );
465 is( $response->header('X-Catalyst-Executed'),
466 $expected, 'Executed actions' );
467 is( $response->content, '1; 2', 'Content OK' );
471 # Tests for optional PathPart *and* Args attributes.
475 TestApp::Controller::Action::Chained->begin
476 TestApp::Controller::Action::Chained->opt_all_start
477 TestApp::Controller::Action::Chained->oa
478 TestApp::Controller::Action::Chained->end
481 my $expected = join( ", ", @expected );
483 ok( my $response = request('http://localhost/chained/optall/1/oa/2/3'),
484 'Optional :PathName *and* :Args attributes working' );
485 is( $response->header('X-Catalyst-Executed'),
486 $expected, 'Executed actions' );
487 is( $response->content, '1; 2, 3', 'Content OK' );
491 # Test if :Chained is the same as :Chained('/')
495 TestApp::Controller::Action::Chained->begin
496 TestApp::Controller::Action::Chained->rootdef
497 TestApp::Controller::Action::Chained->end
500 my $expected = join( ", ", @expected );
502 ok( my $response = request('http://localhost/chained/rootdef/23'),
503 ":Chained is the same as :Chained('/')" );
504 is( $response->header('X-Catalyst-Executed'),
505 $expected, 'Executed actions' );
506 is( $response->content, '; 23', 'Content OK' );
510 # Test if :Chained('.') is working
514 TestApp::Controller::Action::Chained->begin
515 TestApp::Controller::Action::Chained->parentchain
516 TestApp::Controller::Action::Chained::ParentChain->child
517 TestApp::Controller::Action::Chained->end
520 my $expected = join( ", ", @expected );
522 ok( my $response = request('http://localhost/chained/parentchain/1/child/2'),
523 ":Chained('.') chains to parent controller action" );
524 is( $response->header('X-Catalyst-Executed'),
525 $expected, 'Executed actions' );
526 is( $response->content, '1; 2', 'Content OK' );
530 # Test behaviour of auto actions returning '1' for the chain.
534 TestApp::Controller::Action::Chained->begin
535 TestApp::Controller::Action::Chained::Auto->auto
536 TestApp::Controller::Action::Chained::Auto::Foo->auto
537 TestApp::Controller::Action::Chained::Auto->foo
538 TestApp::Controller::Action::Chained::Auto::Foo->fooend
539 TestApp::Controller::Action::Chained->end
542 my $expected = join( ", ", @expected );
544 ok( my $response = request('http://localhost/chained/autochain1/1/fooend/2'),
545 "Behaviour when auto returns 1 correct" );
546 is( $response->header('X-Catalyst-Executed'),
547 $expected, 'Executed actions' );
548 is( $response->content, '1; 2', 'Content OK' );
552 # Test behaviour of auto actions returning '0' for the chain.
556 TestApp::Controller::Action::Chained->begin
557 TestApp::Controller::Action::Chained::Auto->auto
558 TestApp::Controller::Action::Chained::Auto::Bar->auto
559 TestApp::Controller::Action::Chained->end
562 my $expected = join( ", ", @expected );
564 ok( my $response = request('http://localhost/chained/autochain2/1/barend/2'),
565 "Behaviour when auto returns 0 correct" );
566 is( $response->header('X-Catalyst-Executed'),
567 $expected, 'Executed actions' );
568 is( $response->content, '1; 2', 'Content OK' );
572 # Test what auto actions are run when namespaces are changed
577 TestApp::Controller::Action::Chained->begin
578 TestApp::Controller::Action::Chained::Auto->auto
579 TestApp::Controller::Action::Chained::Auto::Foo->auto
580 TestApp::Controller::Action::Chained::Auto::Bar->crossloose
581 TestApp::Controller::Action::Chained::Auto::Foo->crossend
582 TestApp::Controller::Action::Chained->end
585 my $expected = join( ", ", @expected );
587 ok( my $response = request('http://localhost/chained/auto_cross/1/crossend/2'),
588 "Correct auto actions are run on cross controller dispatch" );
589 is( $response->header('X-Catalyst-Executed'),
590 $expected, 'Executed actions' );
591 is( $response->content, '1; 2', 'Content OK' );
595 # Test forwarding from auto action in chain dispatch.
599 TestApp::Controller::Action::Chained->begin
600 TestApp::Controller::Action::Chained::Auto->auto
601 TestApp::Controller::Action::Chained::Auto::Forward->auto
602 TestApp::Controller::Action::Chained::Auto->fw3
603 TestApp::Controller::Action::Chained::Auto->fw1
604 TestApp::Controller::Action::Chained::Auto::Forward->forwardend
605 TestApp::Controller::Action::Chained->end
608 my $expected = join( ", ", @expected );
610 ok( my $response = request('http://localhost/chained/auto_forward/1/forwardend/2'),
611 "Forwarding out of auto in chain" );
612 is( $response->header('X-Catalyst-Executed'),
613 $expected, 'Executed actions' );
614 is( $response->content, '1; 2', 'Content OK' );
618 # Detaching out of the auto action of a chain.
622 TestApp::Controller::Action::Chained->begin
623 TestApp::Controller::Action::Chained::Auto->auto
624 TestApp::Controller::Action::Chained::Auto::Detach->auto
625 TestApp::Controller::Action::Chained::Auto->fw3
626 TestApp::Controller::Action::Chained->end
629 my $expected = join( ", ", @expected );
631 ok( my $response = request('http://localhost/chained/auto_detach/1/detachend/2'),
632 "Detaching out of auto in chain" );
633 is( $response->header('X-Catalyst-Executed'),
634 $expected, 'Executed actions' );
635 is( $response->content, '1; 2', 'Content OK' );
639 # Test forwarding from auto action in chain dispatch.
642 my $expected = undef;
644 ok( my $response = request('http://localhost/chained/loose/23'),
645 "Loose end is not callable" );
646 is( $response->header('X-Catalyst-Executed'),
647 $expected, 'Executed actions' );
648 is( $response->header('Status'), 500, 'Status OK' );
652 # Test forwarding out of a chain.
656 TestApp::Controller::Action::Chained->begin
657 TestApp::Controller::Action::Chained->chain_fw_a
658 TestApp::Controller::Action::Chained->fw_dt_target
659 TestApp::Controller::Action::Chained->chain_fw_b
660 TestApp::Controller::Action::Chained->end
663 my $expected = join( ", ", @expected );
665 ok( my $response = request('http://localhost/chained/chain_fw/1/end/2'),
666 "Forwarding out a chain" );
667 is( $response->header('X-Catalyst-Executed'),
668 $expected, 'Executed actions' );
669 is( $response->content, '1; 2', 'Content OK' );
673 # Test detaching out of a chain.
677 TestApp::Controller::Action::Chained->begin
678 TestApp::Controller::Action::Chained->chain_dt_a
679 TestApp::Controller::Action::Chained->fw_dt_target
680 TestApp::Controller::Action::Chained->end
683 my $expected = join( ", ", @expected );
685 ok( my $response = request('http://localhost/chained/chain_dt/1/end/2'),
686 "Forwarding out a chain" );
687 is( $response->header('X-Catalyst-Executed'),
688 $expected, 'Executed actions' );
689 is( $response->content, '1; 2', 'Content OK' );