b9367a21e8c8469b1d68762455c300d78b6d21fd
[catagits/Catalyst-Runtime.git] / t / live_component_controller_action_chained.t
1 #!perl
2
3 use strict;
4 use warnings;
5
6 use FindBin;
7 use lib "$FindBin::Bin/lib";
8
9 our $iters;
10
11 BEGIN { $iters = $ENV{CAT_BENCH_ITERS} || 2; }
12
13 use Test::More tests => 99*$iters;
14 use Catalyst::Test 'TestApp';
15
16 if ( $ENV{CAT_BENCHMARK} ) {
17     require Benchmark;
18     Benchmark::timethis( $iters, \&run_tests );
19 }
20 else {
21     for ( 1 .. $iters ) {
22         run_tests();
23     }
24 }
25
26 sub run_tests {
27
28     #
29     #   This is a simple test where the parent and child actions are
30     #   within the same controller.
31     #
32     {
33         my @expected = qw[
34           TestApp::Controller::Action::Chained->begin
35           TestApp::Controller::Action::Chained->foo
36           TestApp::Controller::Action::Chained->endpoint
37           TestApp::Controller::Action::Chained->end
38         ];
39
40         my $expected = join( ", ", @expected );
41
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' );
46     }
47
48     #
49     #   This makes sure the above isn't found if the argument for the
50     #   end action isn't supplied.
51     #
52     {
53         my $expected = undef;
54
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' );
60     }
61
62     #
63     #   Tests the case when the child action is placed in a subcontroller.
64     #
65     {
66         my @expected = qw[
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
71         ];
72
73         my $expected = join( ", ", @expected );
74
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' );
79     }
80
81     #
82     #   Tests if the relative specification (e.g.: Chained('bar') ) works
83     #   as expected.
84     #
85     {
86         my @expected = qw[
87           TestApp::Controller::Action::Chained->begin
88           TestApp::Controller::Action::Chained->bar
89           TestApp::Controller::Action::Chained->finale
90           TestApp::Controller::Action::Chained->end
91         ];
92
93         my $expected = join( ", ", @expected );
94
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' );
99     }
100
101     #
102     #   Just a test for multiple arguments.
103     #
104     {
105         my @expected = qw[
106           TestApp::Controller::Action::Chained->begin
107           TestApp::Controller::Action::Chained->foo2
108           TestApp::Controller::Action::Chained->endpoint2
109           TestApp::Controller::Action::Chained->end
110         ];
111
112         my $expected = join( ", ", @expected );
113
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' );
119     }
120
121     #
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.
125     #
126     {
127         my @expected = qw[
128           TestApp::Controller::Action::Chained->begin
129           TestApp::Controller::Action::Chained->one_end
130           TestApp::Controller::Action::Chained->end
131         ];
132
133         my $expected = join( ", ", @expected );
134
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' );
140     }
141
142     #
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).
146     #
147     {
148         my @expected = qw[
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
153         ];
154
155         my $expected = join( ", ", @expected );
156
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' );
162     }
163
164     #
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.
168     #
169     {
170         my @expected = qw[
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
176         ];
177
178         my $expected = join( ", ", @expected );
179
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' );
185     }
186
187     #
188     #   Tests dispatching on number of arguments for :Args. This should be
189     #   dispatched to the action expecting one argument.
190     #
191     {
192         my @expected = qw[
193           TestApp::Controller::Action::Chained->begin
194           TestApp::Controller::Action::Chained->multi1
195           TestApp::Controller::Action::Chained->end
196         ];
197
198         my $expected = join( ", ", @expected );
199
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' );
205     }
206
207     #
208     #   Belongs to the former test and goes for the action expecting two arguments.
209     #
210     {
211         my @expected = qw[
212           TestApp::Controller::Action::Chained->begin
213           TestApp::Controller::Action::Chained->multi2
214           TestApp::Controller::Action::Chained->end
215         ];
216
217         my $expected = join( ", ", @expected );
218
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' );
224     }
225
226     #
227     #   Dispatching on argument count again, this time we provide too many
228     #   arguments, so dispatching should fail.
229     #
230     {
231         my $expected = undef;
232
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' );
238     }
239
240     #
241     #   This tests the case when an action says it's the child of an action in
242     #   a subcontroller.
243     #
244     {
245         my @expected = qw[
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
250         ];
251
252         my $expected = join( ", ", @expected );
253
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' );
259     }
260
261     #
262     #   Just a more complex version of the former test. It tests if a controller ->
263     #   subcontroller -> controller dispatch works.
264     #
265     {
266         my @expected = qw[
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
272         ];
273
274         my $expected = join( ", ", @expected );
275
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' );
281     }
282
283     #
284     #   Tests dispatch on capture number. This test is for a one capture action.
285     #
286     {
287         my @expected = qw[
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
292         ];
293
294         my $expected = join( ", ", @expected );
295
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' );
301     }
302
303     #
304     #   Belongs to the former test. This one goes for the action expecting two
305     #   captures.
306     #
307     {
308         my @expected = qw[
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
313         ];
314
315         my $expected = join( ", ", @expected );
316
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' );
322     }
323
324     #
325     #   Tests the priority of a slurpy arguments action (with :Args) against
326     #   two actions chained together. The two actions should win.
327     #
328     {
329         my @expected = qw[
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
334         ];
335
336         my $expected = join( ", ", @expected );
337
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' );
343     }
344
345     #
346     #   This belongs to the former test but tests if two chained actions have
347     #   priority over an action with the exact arguments.
348     #
349     {
350         my @expected = qw[
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
355         ];
356
357         my $expected = join( ", ", @expected );
358
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' );
364     }
365
366     #
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.
369     #
370     {
371         my @expected = qw[
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
376         ];
377
378         my $expected = join( ", ", @expected );
379
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' );
385     }
386
387     #
388     #   Test dispatching between two controllers that are on the same level and
389     #   therefor have no parent/child relationship.
390     #
391     {
392         my @expected = qw[
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
397         ];
398
399         my $expected = join( ", ", @expected );
400
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' );
406     }
407
408     #
409     #   This is for testing if the arguments got passed to the actions 
410     #   correctly.
411     #
412     {
413         my @expected = qw[
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
419         ];
420
421         my $expected = join( ", ", @expected );
422
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' );
428     }
429
430     #
431     #   The :Args attribute is optional, we check the action not specifying
432     #   it with these tests.
433     #
434     {
435         my @expected = qw[
436           TestApp::Controller::Action::Chained->begin
437           TestApp::Controller::Action::Chained->opt_args
438           TestApp::Controller::Action::Chained->end
439         ];
440
441         my $expected = join( ", ", @expected );
442
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' );
448     }
449
450     #
451     #   Tests for optional PathPart attribute.
452     #
453     {
454         my @expected = qw[
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
459         ];
460
461         my $expected = join( ", ", @expected );
462
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' );
468     }
469
470     #
471     #   Tests for optional PathPart *and* Args attributes.
472     #
473     {
474         my @expected = qw[
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
479         ];
480
481         my $expected = join( ", ", @expected );
482
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' );
488     }
489
490     #
491     #   Test if :Chained is the same as :Chained('/')
492     #
493     {
494         my @expected = qw[
495           TestApp::Controller::Action::Chained->begin
496           TestApp::Controller::Action::Chained->rootdef
497           TestApp::Controller::Action::Chained->end
498         ];
499
500         my $expected = join( ", ", @expected );
501
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' );
507     }
508
509     #
510     #   Test if :Chained('.') is working
511     #
512     {
513         my @expected = qw[
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
518         ];
519
520         my $expected = join( ", ", @expected );
521
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' );
527     }
528
529     #
530     #   Test behaviour of auto actions returning '1' for the chain.
531     #
532     {
533         my @expected = qw[
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
540         ];
541
542         my $expected = join( ", ", @expected );
543
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' );
549     }
550
551     #
552     #   Test behaviour of auto actions returning '0' for the chain.
553     #
554     {
555         my @expected = qw[
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
560         ];
561
562         my $expected = join( ", ", @expected );
563
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' );
569     }
570
571     #
572     #   Test what auto actions are run when namespaces are changed
573     #   horizontally.
574     #
575     {
576         my @expected = qw[
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
583         ];
584
585         my $expected = join( ", ", @expected );
586
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' );
592     }
593
594     #
595     #   Test forwarding from auto action in chain dispatch.
596     #
597     {
598         my @expected = qw[
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
606         ];
607
608         my $expected = join( ", ", @expected );
609
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' );
615     }
616
617     #
618     #   Detaching out of the auto action of a chain.
619     #
620     {
621         my @expected = qw[
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
627         ];
628
629         my $expected = join( ", ", @expected );
630
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' );
636     }
637
638     #
639     #   Test forwarding from auto action in chain dispatch.
640     #
641     {
642         my $expected = undef;
643
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' );
649     }
650
651     #
652     #   Test forwarding out of a chain.
653     #
654     {
655         my @expected = qw[
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
661         ];
662
663         my $expected = join( ", ", @expected );
664
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' );
670     }
671
672     #
673     #   Test detaching out of a chain.
674     #
675     {
676         my @expected = qw[
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
681         ];
682
683         my $expected = join( ", ", @expected );
684
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' );
690     }
691 }