Add option to break a chain if error occurs
[catagits/Catalyst-Runtime.git] / t / aggregate / live_component_controller_action_chained.t
CommitLineData
141459fa 1#!perl
2
3use strict;
4use warnings;
5
6use FindBin;
42da66a9 7use lib "$FindBin::Bin/../lib";
141459fa 8
9our $iters;
10
6b25e555 11BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 1; }
141459fa 12
36c67dc1 13use Test::More;
d527814d 14use URI;
15use URI::QueryParam;
141459fa 16use Catalyst::Test 'TestApp';
17
18if ( $ENV{CAT_BENCHMARK} ) {
19 require Benchmark;
20 Benchmark::timethis( $iters, \&run_tests );
21}
22else {
23 for ( 1 .. $iters ) {
8a6a6581 24 run_tests($_);
141459fa 25 }
26}
922c58d6 27
141459fa 28sub run_tests {
8a6a6581 29 my ($run_number) = @_;
d416846e 30
31 #
32 # This is a simple test where the parent and child actions are
33 # within the same controller.
34 #
141459fa 35 {
36 my @expected = qw[
5882c86e 37 TestApp::Controller::Action::Chained->begin
38 TestApp::Controller::Action::Chained->foo
39 TestApp::Controller::Action::Chained->endpoint
40 TestApp::Controller::Action::Chained->end
141459fa 41 ];
922c58d6 42
141459fa 43 my $expected = join( ", ", @expected );
922c58d6 44
5882c86e 45 ok( my $response = request('http://localhost/chained/foo/1/end/2'), 'chained + local endpoint' );
141459fa 46 is( $response->header('X-Catalyst-Executed'),
47 $expected, 'Executed actions' );
48 is( $response->content, '1; 2', 'Content OK' );
49 }
d416846e 50
51 #
52 # This makes sure the above isn't found if the argument for the
53 # end action isn't supplied.
54 #
55 {
56 my $expected = undef;
57
5882c86e 58 ok( my $response = request('http://localhost/chained/foo/1/end'),
59 'chained + local endpoint; missing last argument' );
d416846e 60 is( $response->header('X-Catalyst-Executed'),
61 $expected, 'Executed actions' );
10ae2631 62 is( $response->code, 500, 'Status OK' );
d416846e 63 }
64
65 #
66 # Tests the case when the child action is placed in a subcontroller.
67 #
141459fa 68 {
69 my @expected = qw[
5882c86e 70 TestApp::Controller::Action::Chained->begin
71 TestApp::Controller::Action::Chained->foo
72 TestApp::Controller::Action::Chained::Foo->spoon
73 TestApp::Controller::Action::Chained->end
141459fa 74 ];
922c58d6 75
141459fa 76 my $expected = join( ", ", @expected );
922c58d6 77
5882c86e 78 ok( my $response = request('http://localhost/chained/foo/1/spoon'), 'chained + subcontroller endpoint' );
141459fa 79 is( $response->header('X-Catalyst-Executed'),
80 $expected, 'Executed actions' );
81 is( $response->content, '1; ', 'Content OK' );
82 }
d416846e 83
84 #
5882c86e 85 # Tests if the relative specification (e.g.: Chained('bar') ) works
d416846e 86 # as expected.
87 #
141459fa 88 {
89 my @expected = qw[
5882c86e 90 TestApp::Controller::Action::Chained->begin
91 TestApp::Controller::Action::Chained->bar
92 TestApp::Controller::Action::Chained->finale
93 TestApp::Controller::Action::Chained->end
141459fa 94 ];
922c58d6 95
141459fa 96 my $expected = join( ", ", @expected );
922c58d6 97
5882c86e 98 ok( my $response = request('http://localhost/chained/bar/1/spoon'), 'chained + relative endpoint' );
141459fa 99 is( $response->header('X-Catalyst-Executed'),
100 $expected, 'Executed actions' );
101 is( $response->content, '; 1, spoon', 'Content OK' );
102 }
d416846e 103
104 #
105 # Just a test for multiple arguments.
106 #
922c58d6 107 {
108 my @expected = qw[
5882c86e 109 TestApp::Controller::Action::Chained->begin
110 TestApp::Controller::Action::Chained->foo2
111 TestApp::Controller::Action::Chained->endpoint2
112 TestApp::Controller::Action::Chained->end
922c58d6 113 ];
114
115 my $expected = join( ", ", @expected );
116
5882c86e 117 ok( my $response = request('http://localhost/chained/foo2/10/20/end2/15/25'),
118 'chained + local (2 args each)' );
922c58d6 119 is( $response->header('X-Catalyst-Executed'),
120 $expected, 'Executed actions' );
121 is( $response->content, '10, 20; 15, 25', 'Content OK' );
122 }
d416846e 123
124 #
125 # The first three-chain test tries to call the action with :Args(1)
1c34f703 126 # specification. There's also a one action with a :CaptureArgs(1)
d416846e 127 # attribute, that should not be dispatched to.
128 #
922c58d6 129 {
130 my @expected = qw[
5882c86e 131 TestApp::Controller::Action::Chained->begin
132 TestApp::Controller::Action::Chained->one_end
133 TestApp::Controller::Action::Chained->end
922c58d6 134 ];
135
136 my $expected = join( ", ", @expected );
137
5882c86e 138 ok( my $response = request('http://localhost/chained/one/23'),
922c58d6 139 'three-chain (only first)' );
140 is( $response->header('X-Catalyst-Executed'),
141 $expected, 'Executed actions' );
142 is( $response->content, '; 23', 'Content OK' );
143 }
d416846e 144
145 #
146 # This is the second three-chain test, it goes for the action that
147 # handles "/one/$cap/two/$arg1/$arg2" paths. Should be the two action
1c34f703 148 # having :Args(2), not the one having :CaptureArgs(2).
d416846e 149 #
922c58d6 150 {
151 my @expected = qw[
5882c86e 152 TestApp::Controller::Action::Chained->begin
153 TestApp::Controller::Action::Chained->one
154 TestApp::Controller::Action::Chained->two_end
155 TestApp::Controller::Action::Chained->end
922c58d6 156 ];
157
158 my $expected = join( ", ", @expected );
159
5882c86e 160 ok( my $response = request('http://localhost/chained/one/23/two/23/46'),
922c58d6 161 'three-chain (up to second)' );
162 is( $response->header('X-Catalyst-Executed'),
163 $expected, 'Executed actions' );
164 is( $response->content, '23; 23, 46', 'Content OK' );
165 }
d416846e 166
167 #
1c34f703 168 # Last of the three-chain tests. Has no concurrent action with :CaptureArgs
d416846e 169 # and is more thought to simply test the chain as a whole and the 'two'
1c34f703 170 # action specifying :CaptureArgs.
d416846e 171 #
922c58d6 172 {
173 my @expected = qw[
5882c86e 174 TestApp::Controller::Action::Chained->begin
175 TestApp::Controller::Action::Chained->one
176 TestApp::Controller::Action::Chained->two
177 TestApp::Controller::Action::Chained->three_end
178 TestApp::Controller::Action::Chained->end
922c58d6 179 ];
180
181 my $expected = join( ", ", @expected );
182
5882c86e 183 ok( my $response = request('http://localhost/chained/one/23/two/23/46/three/1/2/3'),
922c58d6 184 'three-chain (all three)' );
185 is( $response->header('X-Catalyst-Executed'),
186 $expected, 'Executed actions' );
187 is( $response->content, '23, 23, 46; 1, 2, 3', 'Content OK' );
188 }
d416846e 189
190 #
191 # Tests dispatching on number of arguments for :Args. This should be
192 # dispatched to the action expecting one argument.
193 #
922c58d6 194 {
195 my @expected = qw[
5882c86e 196 TestApp::Controller::Action::Chained->begin
197 TestApp::Controller::Action::Chained->multi1
198 TestApp::Controller::Action::Chained->end
922c58d6 199 ];
200
201 my $expected = join( ", ", @expected );
202
5882c86e 203 ok( my $response = request('http://localhost/chained/multi/23'),
922c58d6 204 'multi-action (one arg)' );
205 is( $response->header('X-Catalyst-Executed'),
206 $expected, 'Executed actions' );
207 is( $response->content, '; 23', 'Content OK' );
208 }
d416846e 209
210 #
211 # Belongs to the former test and goes for the action expecting two arguments.
212 #
922c58d6 213 {
214 my @expected = qw[
5882c86e 215 TestApp::Controller::Action::Chained->begin
216 TestApp::Controller::Action::Chained->multi2
217 TestApp::Controller::Action::Chained->end
922c58d6 218 ];
219
220 my $expected = join( ", ", @expected );
221
5882c86e 222 ok( my $response = request('http://localhost/chained/multi/23/46'),
922c58d6 223 'multi-action (two args)' );
224 is( $response->header('X-Catalyst-Executed'),
225 $expected, 'Executed actions' );
226 is( $response->content, '; 23, 46', 'Content OK' );
227 }
d416846e 228
229 #
230 # Dispatching on argument count again, this time we provide too many
231 # arguments, so dispatching should fail.
232 #
233 {
234 my $expected = undef;
235
5882c86e 236 ok( my $response = request('http://localhost/chained/multi/23/46/67'),
d416846e 237 'multi-action (three args, should lead to error)' );
238 is( $response->header('X-Catalyst-Executed'),
239 $expected, 'Executed actions' );
10ae2631 240 is( $response->code, 500, 'Status OK' );
d416846e 241 }
242
243 #
244 # This tests the case when an action says it's the child of an action in
245 # a subcontroller.
246 #
247 {
248 my @expected = qw[
5882c86e 249 TestApp::Controller::Action::Chained->begin
250 TestApp::Controller::Action::Chained::Foo->higher_root
251 TestApp::Controller::Action::Chained->higher_root
252 TestApp::Controller::Action::Chained->end
d416846e 253 ];
254
255 my $expected = join( ", ", @expected );
256
5882c86e 257 ok( my $response = request('http://localhost/chained/higher_root/23/bar/11'),
d416846e 258 'root higher than child' );
259 is( $response->header('X-Catalyst-Executed'),
260 $expected, 'Executed actions' );
261 is( $response->content, '23; 11', 'Content OK' );
262 }
263
264 #
265 # Just a more complex version of the former test. It tests if a controller ->
266 # subcontroller -> controller dispatch works.
267 #
268 {
269 my @expected = qw[
5882c86e 270 TestApp::Controller::Action::Chained->begin
271 TestApp::Controller::Action::Chained->pcp1
272 TestApp::Controller::Action::Chained::Foo->pcp2
273 TestApp::Controller::Action::Chained->pcp3
274 TestApp::Controller::Action::Chained->end
d416846e 275 ];
276
277 my $expected = join( ", ", @expected );
278
5882c86e 279 ok( my $response = request('http://localhost/chained/pcp1/1/pcp2/2/pcp3/3'),
d416846e 280 'parent -> child -> parent' );
281 is( $response->header('X-Catalyst-Executed'),
282 $expected, 'Executed actions' );
283 is( $response->content, '1, 2; 3', 'Content OK' );
284 }
285
286 #
287 # Tests dispatch on capture number. This test is for a one capture action.
288 #
289 {
290 my @expected = qw[
5882c86e 291 TestApp::Controller::Action::Chained->begin
292 TestApp::Controller::Action::Chained->multi_cap1
293 TestApp::Controller::Action::Chained->multi_cap_end1
294 TestApp::Controller::Action::Chained->end
d416846e 295 ];
296
297 my $expected = join( ", ", @expected );
298
5882c86e 299 ok( my $response = request('http://localhost/chained/multi_cap/1/baz'),
d416846e 300 'dispatch on capture num 1' );
301 is( $response->header('X-Catalyst-Executed'),
302 $expected, 'Executed actions' );
303 is( $response->content, '1; ', 'Content OK' );
304 }
305
306 #
307 # Belongs to the former test. This one goes for the action expecting two
308 # captures.
309 #
310 {
311 my @expected = qw[
5882c86e 312 TestApp::Controller::Action::Chained->begin
313 TestApp::Controller::Action::Chained->multi_cap2
314 TestApp::Controller::Action::Chained->multi_cap_end2
315 TestApp::Controller::Action::Chained->end
d416846e 316 ];
317
318 my $expected = join( ", ", @expected );
319
5882c86e 320 ok( my $response = request('http://localhost/chained/multi_cap/1/2/baz'),
d416846e 321 'dispatch on capture num 2' );
322 is( $response->header('X-Catalyst-Executed'),
323 $expected, 'Executed actions' );
324 is( $response->content, '1, 2; ', 'Content OK' );
325 }
326
327 #
328 # Tests the priority of a slurpy arguments action (with :Args) against
329 # two actions chained together. The two actions should win.
330 #
331 {
332 my @expected = qw[
5882c86e 333 TestApp::Controller::Action::Chained->begin
334 TestApp::Controller::Action::Chained->priority_a2
335 TestApp::Controller::Action::Chained->priority_a2_end
336 TestApp::Controller::Action::Chained->end
d416846e 337 ];
338
339 my $expected = join( ", ", @expected );
340
5882c86e 341 ok( my $response = request('http://localhost/chained/priority_a/1/end/2'),
d416846e 342 'priority - slurpy args vs. parent/child' );
343 is( $response->header('X-Catalyst-Executed'),
344 $expected, 'Executed actions' );
345 is( $response->content, '1; 2', 'Content OK' );
346 }
347
348 #
349 # This belongs to the former test but tests if two chained actions have
350 # priority over an action with the exact arguments.
351 #
352 {
353 my @expected = qw[
5882c86e 354 TestApp::Controller::Action::Chained->begin
355 TestApp::Controller::Action::Chained->priority_b2
356 TestApp::Controller::Action::Chained->priority_b2_end
357 TestApp::Controller::Action::Chained->end
d416846e 358 ];
359
360 my $expected = join( ", ", @expected );
361
5882c86e 362 ok( my $response = request('http://localhost/chained/priority_b/1/end/2'),
d416846e 363 'priority - fixed args vs. parent/child' );
364 is( $response->header('X-Catalyst-Executed'),
365 $expected, 'Executed actions' );
366 is( $response->content, '1; 2', 'Content OK' );
367 }
368
369 #
b7ce908f 370 # This belongs to the former test but tests if two chained actions have
371 # priority over an action with one child action not having the Args() attr set.
372 #
373 {
374 my @expected = qw[
375 TestApp::Controller::Action::Chained->begin
376 TestApp::Controller::Action::Chained->priority_c1
377 TestApp::Controller::Action::Chained->priority_c2_xyz
378 TestApp::Controller::Action::Chained->end
379 ];
380
381 my $expected = join( ", ", @expected );
382
383 ok( my $response = request('http://localhost/chained/priority_c/1/xyz/'),
384 'priority - no Args() order mismatch' );
385 is( $response->header('X-Catalyst-Executed'),
386 $expected, 'Executed actions' );
387 is( $response->content, '1; ', 'Content OK' );
388 }
389
390 #
d416846e 391 # Test dispatching between two controllers that are on the same level and
392 # therefor have no parent/child relationship.
393 #
394 {
395 my @expected = qw[
5882c86e 396 TestApp::Controller::Action::Chained->begin
397 TestApp::Controller::Action::Chained::Bar->cross1
398 TestApp::Controller::Action::Chained::Foo->cross2
399 TestApp::Controller::Action::Chained->end
d416846e 400 ];
401
402 my $expected = join( ", ", @expected );
403
5882c86e 404 ok( my $response = request('http://localhost/chained/cross/1/end/2'),
d416846e 405 'cross controller w/o par/child relation' );
406 is( $response->header('X-Catalyst-Executed'),
407 $expected, 'Executed actions' );
408 is( $response->content, '1; 2', 'Content OK' );
409 }
b25353e5 410
411 #
412 # This is for testing if the arguments got passed to the actions
413 # correctly.
414 #
415 {
416 my @expected = qw[
5882c86e 417 TestApp::Controller::Action::Chained->begin
418 TestApp::Controller::Action::Chained::PassedArgs->first
419 TestApp::Controller::Action::Chained::PassedArgs->second
420 TestApp::Controller::Action::Chained::PassedArgs->third
421 TestApp::Controller::Action::Chained::PassedArgs->end
b25353e5 422 ];
423
424 my $expected = join( ", ", @expected );
425
5882c86e 426 ok( my $response = request('http://localhost/chained/passedargs/a/1/b/2/c/3'),
b25353e5 427 'Correct arguments passed to actions' );
428 is( $response->header('X-Catalyst-Executed'),
429 $expected, 'Executed actions' );
430 is( $response->content, '1; 2; 3', 'Content OK' );
431 }
47f9968d 432
433 #
434 # The :Args attribute is optional, we check the action not specifying
435 # it with these tests.
436 #
437 {
438 my @expected = qw[
5882c86e 439 TestApp::Controller::Action::Chained->begin
440 TestApp::Controller::Action::Chained->opt_args
441 TestApp::Controller::Action::Chained->end
47f9968d 442 ];
443
444 my $expected = join( ", ", @expected );
445
5882c86e 446 ok( my $response = request('http://localhost/chained/opt_args/1/2/3'),
47f9968d 447 'Optional :Args attribute working' );
448 is( $response->header('X-Catalyst-Executed'),
449 $expected, 'Executed actions' );
450 is( $response->content, '; 1, 2, 3', 'Content OK' );
451 }
9cc84996 452
453 #
454 # Tests for optional PathPart attribute.
455 #
456 {
457 my @expected = qw[
5882c86e 458 TestApp::Controller::Action::Chained->begin
459 TestApp::Controller::Action::Chained->opt_pp_start
460 TestApp::Controller::Action::Chained->opt_pathpart
461 TestApp::Controller::Action::Chained->end
9cc84996 462 ];
463
464 my $expected = join( ", ", @expected );
465
5882c86e 466 ok( my $response = request('http://localhost/chained/optpp/1/opt_pathpart/2'),
9cc84996 467 'Optional :PathName attribute working' );
468 is( $response->header('X-Catalyst-Executed'),
469 $expected, 'Executed actions' );
470 is( $response->content, '1; 2', 'Content OK' );
471 }
472
473 #
474 # Tests for optional PathPart *and* Args attributes.
475 #
476 {
477 my @expected = qw[
5882c86e 478 TestApp::Controller::Action::Chained->begin
479 TestApp::Controller::Action::Chained->opt_all_start
480 TestApp::Controller::Action::Chained->oa
481 TestApp::Controller::Action::Chained->end
9cc84996 482 ];
483
484 my $expected = join( ", ", @expected );
485
5882c86e 486 ok( my $response = request('http://localhost/chained/optall/1/oa/2/3'),
9cc84996 487 'Optional :PathName *and* :Args attributes working' );
488 is( $response->header('X-Catalyst-Executed'),
489 $expected, 'Executed actions' );
490 is( $response->content, '1; 2, 3', 'Content OK' );
491 }
0e853a7f 492
493 #
494 # Test if :Chained is the same as :Chained('/')
495 #
496 {
497 my @expected = qw[
498 TestApp::Controller::Action::Chained->begin
499 TestApp::Controller::Action::Chained->rootdef
500 TestApp::Controller::Action::Chained->end
501 ];
502
503 my $expected = join( ", ", @expected );
504
505 ok( my $response = request('http://localhost/chained/rootdef/23'),
506 ":Chained is the same as :Chained('/')" );
507 is( $response->header('X-Catalyst-Executed'),
508 $expected, 'Executed actions' );
509 is( $response->content, '; 23', 'Content OK' );
510 }
511
512 #
f88e7f69 513 # Test if :Chained('.') is working
0e853a7f 514 #
515 {
516 my @expected = qw[
517 TestApp::Controller::Action::Chained->begin
518 TestApp::Controller::Action::Chained->parentchain
519 TestApp::Controller::Action::Chained::ParentChain->child
520 TestApp::Controller::Action::Chained->end
521 ];
522
523 my $expected = join( ", ", @expected );
524
525 ok( my $response = request('http://localhost/chained/parentchain/1/child/2'),
526 ":Chained('.') chains to parent controller action" );
527 is( $response->header('X-Catalyst-Executed'),
528 $expected, 'Executed actions' );
529 is( $response->content, '1; 2', 'Content OK' );
530 }
2349aeea 531
532 #
2f381252 533 # Test if :Chained('../act') is working
534 #
535 {
536 my @expected = qw[
537 TestApp::Controller::Action::Chained->begin
538 TestApp::Controller::Action::Chained->one
539 TestApp::Controller::Action::Chained::ParentChain->chained_rel
540 TestApp::Controller::Action::Chained->end
541 ];
542
543 my $expected = join( ", ", @expected );
544
545 ok( my $response = request('http://localhost/chained/one/1/chained_rel/3/2'),
546 ":Chained('../action') chains to correct action" );
547 is( $response->header('X-Catalyst-Executed'),
548 $expected, 'Executed actions' );
549 is( $response->content, '1; 3, 2', 'Content OK' );
550 }
551
552 #
553 # Test if ../ works to go up more than one level
554 #
555 {
556 my @expected = qw[
557 TestApp::Controller::Action::Chained->begin
558 TestApp::Controller::Action::Chained->one
559 TestApp::Controller::Action::Chained::ParentChain::Relative->chained_rel_two
560 TestApp::Controller::Action::Chained->end
561 ];
562
563 my $expected = join( ", ", @expected );
564
565 ok( my $response = request('http://localhost/chained/one/1/chained_rel_two/42/23'),
566 "../ works to go up more than one level" );
567 is( $response->header('X-Catalyst-Executed'),
568 $expected, 'Executed actions' );
569 is( $response->content, '1; 42, 23', 'Content OK' );
570 }
571
572 #
573 # Test if :ChainedParent is working
574 #
575 {
576 my @expected = qw[
577 TestApp::Controller::Action::Chained->begin
578 TestApp::Controller::Action::Chained->loose
579 TestApp::Controller::Action::Chained::ParentChain->loose
580 TestApp::Controller::Action::Chained->end
581 ];
582
583 my $expected = join( ", ", @expected );
584
585 ok( my $response = request('http://localhost/chained/loose/4/loose/a/b'),
586 ":Chained('../action') chains to correct action" );
587 is( $response->header('X-Catalyst-Executed'),
588 $expected, 'Executed actions' );
589 is( $response->content, '4; a, b', 'Content OK' );
590 }
591
592 #
593 # Test if :Chained('../name/act') is working
594 #
595 {
596 my @expected = qw[
597 TestApp::Controller::Action::Chained->begin
598 TestApp::Controller::Action::Chained::Bar->cross1
599 TestApp::Controller::Action::Chained::ParentChain->up_down
600 TestApp::Controller::Action::Chained->end
601 ];
602
603 my $expected = join( ", ", @expected );
604
605 ok( my $response = request('http://localhost/chained/cross/4/up_down/5'),
606 ":Chained('../action') chains to correct action" );
607 is( $response->header('X-Catalyst-Executed'),
608 $expected, 'Executed actions' );
609 is( $response->content, '4; 5', 'Content OK' );
610 }
611
612 #
2349aeea 613 # Test behaviour of auto actions returning '1' for the chain.
614 #
615 {
616 my @expected = qw[
617 TestApp::Controller::Action::Chained->begin
618 TestApp::Controller::Action::Chained::Auto->auto
619 TestApp::Controller::Action::Chained::Auto::Foo->auto
620 TestApp::Controller::Action::Chained::Auto->foo
621 TestApp::Controller::Action::Chained::Auto::Foo->fooend
622 TestApp::Controller::Action::Chained->end
623 ];
624
625 my $expected = join( ", ", @expected );
626
627 ok( my $response = request('http://localhost/chained/autochain1/1/fooend/2'),
628 "Behaviour when auto returns 1 correct" );
629 is( $response->header('X-Catalyst-Executed'),
630 $expected, 'Executed actions' );
631 is( $response->content, '1; 2', 'Content OK' );
632 }
633
634 #
635 # Test behaviour of auto actions returning '0' for the chain.
636 #
637 {
638 my @expected = qw[
639 TestApp::Controller::Action::Chained->begin
640 TestApp::Controller::Action::Chained::Auto->auto
641 TestApp::Controller::Action::Chained::Auto::Bar->auto
642 TestApp::Controller::Action::Chained->end
643 ];
644
645 my $expected = join( ", ", @expected );
646
647 ok( my $response = request('http://localhost/chained/autochain2/1/barend/2'),
648 "Behaviour when auto returns 0 correct" );
649 is( $response->header('X-Catalyst-Executed'),
650 $expected, 'Executed actions' );
651 is( $response->content, '1; 2', 'Content OK' );
652 }
653
654 #
655 # Test what auto actions are run when namespaces are changed
656 # horizontally.
657 #
658 {
659 my @expected = qw[
660 TestApp::Controller::Action::Chained->begin
661 TestApp::Controller::Action::Chained::Auto->auto
662 TestApp::Controller::Action::Chained::Auto::Foo->auto
663 TestApp::Controller::Action::Chained::Auto::Bar->crossloose
664 TestApp::Controller::Action::Chained::Auto::Foo->crossend
665 TestApp::Controller::Action::Chained->end
666 ];
667
668 my $expected = join( ", ", @expected );
669
670 ok( my $response = request('http://localhost/chained/auto_cross/1/crossend/2'),
671 "Correct auto actions are run on cross controller dispatch" );
672 is( $response->header('X-Catalyst-Executed'),
673 $expected, 'Executed actions' );
674 is( $response->content, '1; 2', 'Content OK' );
675 }
676
677 #
678 # Test forwarding from auto action in chain dispatch.
679 #
680 {
681 my @expected = qw[
682 TestApp::Controller::Action::Chained->begin
683 TestApp::Controller::Action::Chained::Auto->auto
684 TestApp::Controller::Action::Chained::Auto::Forward->auto
685 TestApp::Controller::Action::Chained::Auto->fw3
686 TestApp::Controller::Action::Chained::Auto->fw1
687 TestApp::Controller::Action::Chained::Auto::Forward->forwardend
688 TestApp::Controller::Action::Chained->end
689 ];
690
691 my $expected = join( ", ", @expected );
692
693 ok( my $response = request('http://localhost/chained/auto_forward/1/forwardend/2'),
694 "Forwarding out of auto in chain" );
695 is( $response->header('X-Catalyst-Executed'),
696 $expected, 'Executed actions' );
697 is( $response->content, '1; 2', 'Content OK' );
698 }
699
700 #
701 # Detaching out of the auto action of a chain.
702 #
703 {
704 my @expected = qw[
705 TestApp::Controller::Action::Chained->begin
706 TestApp::Controller::Action::Chained::Auto->auto
707 TestApp::Controller::Action::Chained::Auto::Detach->auto
708 TestApp::Controller::Action::Chained::Auto->fw3
709 TestApp::Controller::Action::Chained->end
710 ];
711
712 my $expected = join( ", ", @expected );
713
714 ok( my $response = request('http://localhost/chained/auto_detach/1/detachend/2'),
715 "Detaching out of auto in chain" );
716 is( $response->header('X-Catalyst-Executed'),
717 $expected, 'Executed actions' );
718 is( $response->content, '1; 2', 'Content OK' );
719 }
720
721 #
722 # Test forwarding from auto action in chain dispatch.
723 #
724 {
725 my $expected = undef;
726
727 ok( my $response = request('http://localhost/chained/loose/23'),
728 "Loose end is not callable" );
729 is( $response->header('X-Catalyst-Executed'),
730 $expected, 'Executed actions' );
10ae2631 731 is( $response->code, 500, 'Status OK' );
2349aeea 732 }
733
734 #
735 # Test forwarding out of a chain.
736 #
737 {
738 my @expected = qw[
739 TestApp::Controller::Action::Chained->begin
740 TestApp::Controller::Action::Chained->chain_fw_a
741 TestApp::Controller::Action::Chained->fw_dt_target
742 TestApp::Controller::Action::Chained->chain_fw_b
743 TestApp::Controller::Action::Chained->end
744 ];
745
746 my $expected = join( ", ", @expected );
747
748 ok( my $response = request('http://localhost/chained/chain_fw/1/end/2'),
749 "Forwarding out a chain" );
750 is( $response->header('X-Catalyst-Executed'),
751 $expected, 'Executed actions' );
752 is( $response->content, '1; 2', 'Content OK' );
753 }
754
755 #
756 # Test detaching out of a chain.
757 #
758 {
759 my @expected = qw[
760 TestApp::Controller::Action::Chained->begin
761 TestApp::Controller::Action::Chained->chain_dt_a
762 TestApp::Controller::Action::Chained->fw_dt_target
763 TestApp::Controller::Action::Chained->end
764 ];
765
766 my $expected = join( ", ", @expected );
767
768 ok( my $response = request('http://localhost/chained/chain_dt/1/end/2'),
769 "Forwarding out a chain" );
770 is( $response->header('X-Catalyst-Executed'),
771 $expected, 'Executed actions' );
772 is( $response->content, '1; 2', 'Content OK' );
773 }
8a6a6581 774
775 #
569b665e 776 #
777 #
778 {
779 my @expected = qw[
780 TestApp::Controller::Action::Chained->begin
781 TestApp::Controller::Action::Chained->chain_die_a
782 TestApp::Controller::Action::Chained->end
783 ];
784
785 my $expected = join( ", ", @expected );
786
787 ok( my $response = request('http://localhost/chained/chain_die/1/end/2'),
788 "Break a chain in the middle" );
789 is( $response->header('X-Catalyst-Executed'),
790 $expected, 'Executed actions' );
791 is( $response->content, 'FATAL ERROR: break in the middle of a chain', 'Content OK' );
792 }
793
794 #
81e75875 795 # Tests that an uri_for to a chained root index action
796 # returns the right value.
797 #
798 {
799 ok( my $response = request(
800 'http://localhost/action/chained/to_root' ),
801 'uri_for with chained root action as arg' );
10ae2631 802 like( $response->content,
de19de2e 803 qr(URI:https?://[^/]+/),
81e75875 804 'Correct URI generated' );
805 }
806
807 #
8a6a6581 808 # Test interception of recursive chains. This test was added because at
809 # one point during the :Chained development, Catalyst used to hang on
810 # recursive chains.
811 #
812 {
813 eval { require 'TestAppChainedRecursive.pm' };
05a90578 814 if ($run_number == 1) {
815 ok( ! $@, "Interception of recursive chains" );
816 }
817 else { pass( "Interception of recursive chains already tested" ) }
8a6a6581 818 }
819
820 #
821 # Test failure of absolute path part arguments.
822 #
823 {
824 eval { require 'TestAppChainedAbsolutePathPart.pm' };
825 if ($run_number == 1) {
826 like( $@, qr(foo/foo),
827 "Usage of absolute path part argument emits error" );
828 }
829 else { pass( "Error on absolute path part arguments already tested" ) }
830 }
f505df49 831
832 #
caaf37ad 833 # Test chained actions in the root controller
834 #
835 {
836 my @expected = qw[
caaf37ad 837 TestApp::Controller::Action::Chained::Root->rootsub
838 TestApp::Controller::Action::Chained::Root->endpointsub
a0a66cb8 839 TestApp::Controller::Root->end
caaf37ad 840 ];
841
842 my $expected = join( ", ", @expected );
843
844 ok( my $response = request('http://localhost/rootsub/1/endpointsub/2'), 'chained in root namespace' );
845 is( $response->header('X-Catalyst-Executed'),
846 $expected, 'Executed actions' );
f720422c 847 is( $response->content, '', 'Content OK' );
caaf37ad 848 }
849
850 #
f505df49 851 # Complex path with multiple empty pathparts
852 #
853 {
854 my @expected = qw[
855 TestApp::Controller::Action::Chained->begin
856 TestApp::Controller::Action::Chained->mult_nopp_base
857 TestApp::Controller::Action::Chained->mult_nopp_all
858 TestApp::Controller::Action::Chained->end
859 ];
860
861 my $expected = join( ", ", @expected );
862
863 ok( my $response = request('http://localhost/chained/mult_nopp'),
864 "Complex path with multiple empty pathparts" );
865 is( $response->header('X-Catalyst-Executed'),
866 $expected, 'Executed actions' );
867 is( $response->content, '; ', 'Content OK' );
868 }
869
953c176d 870 #
055abad1 871 # Complex path with multiple non-capturing pathparts
872 # PathPart('') CaptureArgs(0), PathPart('foo') CaptureArgs(0), PathPart('') Args(0)
873 # should win over PathPart('') CaptureArgs(1), PathPart('') Args(0)
874 #
875 {
876 my @expected = qw[
877 TestApp::Controller::Action::Chained->begin
878 TestApp::Controller::Action::Chained->mult_nopp2_base
879 TestApp::Controller::Action::Chained->mult_nopp2_nocap
880 TestApp::Controller::Action::Chained->mult_nopp2_action
881 TestApp::Controller::Action::Chained->mult_nopp2_action_default
882 TestApp::Controller::Action::Chained->end
883 ];
884
885 my $expected = join( ", ", @expected );
886
887 ok( my $response = request('http://localhost/chained/mult_nopp2/action'),
888 "Complex path with multiple non-capturing pathparts" );
055abad1 889 is( $response->header('X-Catalyst-Executed'),
890 $expected, 'Executed actions' );
891 is( $response->content, '; ', 'Content OK' );
055abad1 892 }
893
894 #
953c176d 895 # Higher Args() hiding more specific CaptureArgs chains sections
896 #
897 {
898 my @expected = qw[
899 TestApp::Controller::Action::Chained->begin
900 TestApp::Controller::Action::Chained->cc_base
901 TestApp::Controller::Action::Chained->cc_link
902 TestApp::Controller::Action::Chained->cc_anchor
903 TestApp::Controller::Action::Chained->end
904 ];
905
906 my $expected = join ', ', @expected;
907
908 ok( my $response = request('http://localhost/chained/choose_capture/anchor.html'),
909 'Choose between an early Args() and a later more ideal chain' );
910 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
911 is( $response->content => '; ', 'Content OK' );
912 }
913
914 #
915 # Less specific chain not being seen correctly due to earlier looser capture
916 #
917 {
918 my @expected = qw[
919 TestApp::Controller::Action::Chained->begin
920 TestApp::Controller::Action::Chained->cc_base
921 TestApp::Controller::Action::Chained->cc_b
922 TestApp::Controller::Action::Chained->cc_b_link
923 TestApp::Controller::Action::Chained->cc_b_anchor
924 TestApp::Controller::Action::Chained->end
925 ];
926
927 my $expected = join ', ', @expected;
928
929 ok( my $response = request('http://localhost/chained/choose_capture/b/a/anchor.html'),
930 'Choose between a more specific chain and an earlier looser one' );
931 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
932 is( $response->content => 'a; ', 'Content OK' );
933 }
934
935 #
936 # Check we get the looser one when it's the correct match
937 #
938 {
939 my @expected = qw[
940 TestApp::Controller::Action::Chained->begin
941 TestApp::Controller::Action::Chained->cc_base
942 TestApp::Controller::Action::Chained->cc_a
943 TestApp::Controller::Action::Chained->cc_a_link
944 TestApp::Controller::Action::Chained->cc_a_anchor
945 TestApp::Controller::Action::Chained->end
946 ];
947
948 my $expected = join ', ', @expected;
949
950 ok( my $response = request('http://localhost/chained/choose_capture/a/a/anchor.html'),
951 'Choose between a more specific chain and an earlier looser one' );
952 is( $response->header('X-Catalyst-Executed') => $expected, 'Executed actions');
953 is( $response->content => 'a; anchor.html', 'Content OK' );
954 }
955
fd91d0c6 956 # CaptureArgs(1) PathPart('...') should win over CaptureArgs(2) PathPart('')
957 {
958 my @expected = qw[
959 TestApp::Controller::Action::Chained->begin
960 TestApp::Controller::Action::Chained::CaptureArgs->base
961 TestApp::Controller::Action::Chained::CaptureArgs->one_arg
962 TestApp::Controller::Action::Chained::CaptureArgs->edit_one_arg
963 TestApp::Controller::Action::Chained::CaptureArgs->end
964 ];
965
966 my $expected = join( ", ", @expected );
967
968 # should dispatch to /base/one_args/edit_one_arg
969 ok( my $response = request('http://localhost/captureargs/one/edit'),
970 'Correct arg order ran' );
ad9c323c 971 TODO: {
972 local $TODO = 'Known bug';
fd91d0c6 973 is( $response->header('X-Catalyst-Executed'),
974 $expected, 'Executed actions' );
975 is( $response->content, 'base; one_arg; edit_one_arg', 'Content OK' );
ad9c323c 976 }
fd91d0c6 977 }
978
1c24a6c4 979 # PathPart('...') Args(1) should win over CaptureArgs(2) PathPart('')
980 {
981 my @expected = qw[
982 TestApp::Controller::Action::Chained->begin
983 TestApp::Controller::Action::Chained::CaptureArgs->base
984 TestApp::Controller::Action::Chained::CaptureArgs->test_one_arg
985 TestApp::Controller::Action::Chained::CaptureArgs->end
986 ];
987
988 my $expected = join( ", ", @expected );
989
990 # should dispatch to /base/test_one_arg
991 ok( my $response = request('http://localhost/captureargs/test/one'),
992 'Correct pathpart/arg ran' );
993 TODO: {
994 local $TODO = 'Known bug';
995 is( $response->header('X-Catalyst-Executed'),
996 $expected, 'Executed actions' );
997 is( $response->content, 'base; test_plus_arg; one;', 'Content OK' );
998 }
999 }
1000
953c176d 1001 #
1002 # Args(0) should win over Args() if we actually have no arguments.
1003 {
1004 my @expected = qw[
1005 TestApp::Controller::Action::Chained->begin
1006 TestApp::Controller::Action::Chained::ArgsOrder->base
1007 TestApp::Controller::Action::Chained::ArgsOrder->index
1008 TestApp::Controller::Action::Chained::ArgsOrder->end
1009 ];
1010
1011 my $expected = join( ", ", @expected );
1012
1013 # With no args, we should run "index"
1014 ok( my $response = request('http://localhost/argsorder/'),
1015 'Correct arg order ran' );
1016 is( $response->header('X-Catalyst-Executed'),
1017 $expected, 'Executed actions' );
1018 is( $response->content, 'base; ; index; ', 'Content OK' );
1019
1020 # With args given, run "all"
1021 ok( $response = request('http://localhost/argsorder/X'),
1022 'Correct arg order ran' );
1023 is( $response->header('X-Catalyst-Executed'),
1024 join(", ",
1025 qw[
1026 TestApp::Controller::Action::Chained->begin
1027 TestApp::Controller::Action::Chained::ArgsOrder->base
1028 TestApp::Controller::Action::Chained::ArgsOrder->all
1029 TestApp::Controller::Action::Chained::ArgsOrder->end
1030 ])
1031 );
1032 is( $response->content, 'base; ; all; X', 'Content OK' );
1033
1034 }
6365b527 1035
2f381252 1036 #
1037 # PathPrefix
1038 #
1039 {
1040 my @expected = qw[
1041 TestApp::Controller::Action::Chained->begin
1042 TestApp::Controller::Action::Chained::PathPrefix->instance
1043 TestApp::Controller::Action::Chained->end
1044 ];
1045
1046 my $expected = join( ", ", @expected );
1047
1048 ok( my $response = request('http://localhost/action/chained/pathprefix/1'),
1049 "PathPrefix (as an endpoint)" );
1050 is( $response->header('X-Catalyst-Executed'),
1051 $expected, 'Executed actions' );
1052 is( $response->content, '; 1', 'Content OK' );
1053 }
1054
1055 #
1056 # static paths vs. captures
1057 #
1058 {
1059 my @expected = qw[
1060 TestApp::Controller::Action::Chained->begin
1061 TestApp::Controller::Action::Chained->apan
1062 TestApp::Controller::Action::Chained->korv
1063 TestApp::Controller::Action::Chained->static_end
1064 TestApp::Controller::Action::Chained->end
1065 ];
1066
1067 my $expected = join( ", ", @expected );
1068
1069 ok( my $response = request('http://localhost/action/chained/static_end'),
1070 "static paths are prefered over captures" );
1071 is( $response->header('X-Catalyst-Executed'),
1072 $expected, 'Executed actions' );
1073 }
ef5e5ed1 1074
1075 #
1076 # */search
1077 # doc/*
1078 #
1079 # request for doc/search should end up in doc/*
1080 {
1081 my @expected = qw[
1082 TestApp::Controller::Action::Chained->begin
1083 TestApp::Controller::Action::Chained->doc_star
1084 TestApp::Controller::Action::Chained->end
1085 ];
1086
1087 my $expected = join( ", ", @expected );
1088
1089 ok( my $response = request('http://localhost/chained/doc/search'),
1090 "we prefer static path parts earlier in the chain" );
fc38b056 1091 TODO: {
1092 local $TODO = 'gbjk never got off his ass and fixed this';
1093 is( $response->header('X-Catalyst-Executed'),
1094 $expected, 'Executed actions' );
1095 }
ef5e5ed1 1096 }
2c527b91 1097
1098 {
1099 ok( my $content =
06f97d3f 1100 get('http://localhost/chained/capture%2Farg%3B/return_arg/foo%2Fbar%3B'),
2c527b91 1101 'request with URI-encoded arg' );
634780e0 1102 like( $content, qr{foo/bar;\z}, 'args decoded' );
06f97d3f 1103 like( $content, qr{capture/arg;}, 'captureargs decoded' );
2c527b91 1104 }
372b0c1b 1105 {
1106 ok( my $content =
1107 get('http://localhost/chained/return_arg_decoded/foo%2Fbar%3B'),
1108 'request with URI-encoded arg' );
1109 like( $content, qr{foo/bar;\z}, 'args decoded' );
1110 }
60dadd31 1111
36c67dc1 1112 # Test round tripping, specifically the / character %2F in uri_for:
a76d2786 1113 # not being able to feed it back action + captureargs and args into uri for
1114 # and result in the original request uri is a major piece of suck ;)
36c67dc1 1115 foreach my $thing (
1116 ['foo', 'bar'],
1117 ['foo%2Fbar', 'baz'],
1118 ['foo', 'bar%2Fbaz'],
1119 ['foo%2Fbar', 'baz%2Fquux'],
1120 ['foo%2Fbar', 'baz%2Fquux', { foo => 'bar', 'baz' => 'quux%2Ffrood'}],
1121 ['foo%2Fbar', 'baz%2Fquux', { foo => 'bar', 'baz%2Ffnoo' => 'quux%2Ffrood'}],
7b346bc3 1122 ['h%C3%BCtte', 'h%C3%BCtte', { test => 'h%C3%BCtte' } ],
36c67dc1 1123 ) {
9b7d26c7 1124 my $path = '/chained/roundtrip_urifor/' .
a76d2786 1125 $thing->[0] . '/' . $thing->[1];
9b7d26c7 1126 $path .= '?' . join('&',
a76d2786 1127 map { $_ .'='. $thing->[2]->{$_}}
1128 sort keys %{$thing->[2]}) if $thing->[2];
36c67dc1 1129 ok( my $content =
9b7d26c7 1130 get('http://localhost/' . $path),
1131 'request ' . $path . ' ok');
3aea242a 1132 my $exp = URI->new('http://localhost:3000' . $path);
8c756ee1 1133 my ($want) = $content =~ m{/chained/(.*)};
1134 my $got = URI->new('http://localhost:3000/chained/' . $want);
9b7d26c7 1135 # Just check that the path matches, as who the hell knows or cares
1136 # where the app is based (live tests etc)
3aea242a 1137 is $got->path, $exp->path, "uri $path can round trip through uri_for (path)"
1138 or diag("Expected $path, got $content");
d527814d 1139 is_deeply $got->query_form_hash, $exp->query_form_hash, "uri $path can round trip through uri_for (query)"
2689f8a4 1140 or diag("Expected $path, got $content");
36c67dc1 1141 }
1279064a 1142
1143 #
1144 # match_captures
1145 #
1146 {
1147
1148 ok( my $response = request('http://localhost/chained/match_captures/foo/bar'), 'match_captures: falling through' );
1149 is($response->header('X-TestAppActionTestMatchCaptures'), 'fallthrough', 'match_captures: fell through');
1150
1151 ok($response = request('http://localhost/chained/match_captures/force/bar'), 'match_captures: *not* falling through' );
1152 is($response->header('X-TestAppActionTestMatchCaptures'), 'forcing', 'match_captures: forced');
1153 is($response->header('X-TestAppActionTestMatchCapturesHasRan'), 'yes', 'match_captures: actually ran');
1154 }
141459fa 1155}
372b0c1b 1156
36c67dc1 1157done_testing;
a76d2786 1158