line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
use strict; |
3
|
126
|
|
|
169
|
|
5317345
|
use warnings; |
|
126
|
|
|
|
|
1105
|
|
|
126
|
|
|
|
|
3243
|
|
4
|
126
|
|
|
126
|
|
613
|
use Test::More (); |
|
126
|
|
|
|
|
210
|
|
|
126
|
|
|
|
|
2772
|
|
5
|
126
|
|
|
126
|
|
3133
|
|
|
126
|
|
|
|
|
266691
|
|
|
126
|
|
|
|
|
2067
|
|
6
|
|
|
|
|
|
|
use Plack::Test; |
7
|
126
|
|
|
126
|
|
46847
|
use Catalyst::Exception; |
|
126
|
|
|
|
|
110855
|
|
|
126
|
|
|
|
|
5650
|
|
8
|
126
|
|
|
126
|
|
31310
|
use Catalyst::Utils; |
|
126
|
|
|
|
|
467
|
|
|
126
|
|
|
|
|
4112
|
|
9
|
126
|
|
|
126
|
|
45067
|
use Class::Load qw(load_class is_class_loaded); |
|
126
|
|
|
|
|
394
|
|
|
126
|
|
|
|
|
3796
|
|
10
|
126
|
|
|
126
|
|
711
|
use Sub::Exporter; |
|
126
|
|
|
|
|
216
|
|
|
126
|
|
|
|
|
5308
|
|
11
|
126
|
|
|
126
|
|
710
|
use Moose::Util 'find_meta'; |
|
126
|
|
|
|
|
223
|
|
|
126
|
|
|
|
|
884
|
|
12
|
126
|
|
|
126
|
|
22966
|
use Carp 'croak', 'carp'; |
|
126
|
|
|
|
|
279
|
|
|
126
|
|
|
|
|
663
|
|
13
|
126
|
|
|
126
|
|
25591
|
|
|
126
|
|
|
|
|
260
|
|
|
126
|
|
|
|
|
205713
|
|
14
|
|
|
|
|
|
|
my ($self, $args) = @_; |
15
|
|
|
|
|
|
|
|
16
|
127
|
|
|
127
|
|
261
|
return sub { _remote_request(@_) } |
17
|
|
|
|
|
|
|
if $args->{remote}; |
18
|
0
|
|
|
0
|
|
0
|
|
19
|
127
|
50
|
|
|
|
379
|
my $class = $args->{class}; |
20
|
|
|
|
|
|
|
|
21
|
127
|
|
|
|
|
303
|
# Here we should be failing right away, but for some stupid backcompat thing |
22
|
|
|
|
|
|
|
# I don't quite remember we fail lazily here. Needs a proper deprecation and |
23
|
|
|
|
|
|
|
# then removal. |
24
|
|
|
|
|
|
|
return sub { croak "Must specify a test app: use Catalyst::Test 'TestApp'" } |
25
|
|
|
|
|
|
|
unless $class; |
26
|
2
|
|
|
2
|
|
1179
|
|
27
|
127
|
100
|
|
|
|
357
|
load_class($class) unless is_class_loaded($class); |
28
|
|
|
|
|
|
|
$class->import; |
29
|
125
|
100
|
|
|
|
3124
|
|
30
|
125
|
|
|
|
|
9908
|
return sub { _local_request( $class, @_ ) }; |
31
|
|
|
|
|
|
|
} |
32
|
125
|
|
|
905
|
|
1035
|
|
|
905
|
|
|
|
|
705790
|
|
33
|
|
|
|
|
|
|
my ($self, $args) = @_; |
34
|
|
|
|
|
|
|
my $request = $args->{request}; |
35
|
|
|
|
|
|
|
|
36
|
127
|
|
|
127
|
|
397
|
return sub { $request->(@_)->content }; |
37
|
127
|
|
|
|
|
330
|
} |
38
|
|
|
|
|
|
|
my ($self, $args) = @_; |
39
|
127
|
|
|
43
|
|
496
|
my ($class, $request) = @{ $args }{qw(class request)}; |
|
43
|
|
|
|
|
36584
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
return sub { |
42
|
127
|
|
|
127
|
|
388
|
my $me = ref $self || $self; |
43
|
127
|
|
|
|
|
319
|
|
|
127
|
|
|
|
|
397
|
|
44
|
|
|
|
|
|
|
# fail if ctx_request is being used against a remote server |
45
|
|
|
|
|
|
|
Catalyst::Exception->throw("$me only works with local requests, not remote") |
46
|
79
|
|
33
|
79
|
|
87408
|
if $ENV{CATALYST_SERVER}; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# check explicitly for the class here, or the Cat->meta call will blow |
49
|
|
|
|
|
|
|
# up in our face |
50
|
79
|
50
|
|
|
|
277
|
Catalyst::Exception->throw("Must specify a test app: use Catalyst::Test 'TestApp'") unless $class; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# place holder for $c after the request finishes; reset every time |
53
|
|
|
|
|
|
|
# requests are done. |
54
|
79
|
100
|
|
|
|
205
|
my $ctx_closed_over; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# hook into 'dispatch' -- the function gets called after all plugins |
57
|
|
|
|
|
|
|
# have done their work, and it's an easy place to capture $c. |
58
|
78
|
|
|
|
|
115
|
my $meta = find_meta($class); |
59
|
|
|
|
|
|
|
$meta->make_mutable; |
60
|
|
|
|
|
|
|
$meta->add_after_method_modifier( "dispatch", sub { |
61
|
|
|
|
|
|
|
$ctx_closed_over = shift; |
62
|
78
|
|
|
|
|
250
|
}); |
63
|
78
|
|
|
|
|
1226
|
$meta->make_immutable( replace_constructor => 1 ); |
64
|
|
|
|
|
|
|
Class::C3::reinitialize(); # Fixes RT#46459, I've failed to write a test for how/why, but it does. |
65
|
954
|
|
|
954
|
|
5317
|
|
66
|
78
|
|
|
|
|
13577
|
# do the request; C::T::request will know about the class name, and |
67
|
78
|
|
|
|
|
38259
|
# we've already stopped it from doing remote requests above. |
68
|
78
|
|
|
|
|
26567
|
my $res = $args->{request}->( @_ ); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Make sure not to leave a reference $ctx hanging around. |
71
|
|
|
|
|
|
|
# This means that the context will go out of scope as soon as the |
72
|
78
|
|
|
|
|
381
|
# caller disposes of it, rather than waiting till the next time |
73
|
|
|
|
|
|
|
# that ctx_request is called. This can be important if your $ctx |
74
|
|
|
|
|
|
|
# ends up with a reference to a shared resource or lock (for example) |
75
|
|
|
|
|
|
|
# which you want to clean up in test teardown - if the $ctx is still |
76
|
|
|
|
|
|
|
# closed over then you're stuffed... |
77
|
|
|
|
|
|
|
my $ctx = $ctx_closed_over; |
78
|
|
|
|
|
|
|
undef $ctx_closed_over; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
return ( $res, $ctx ); |
81
|
78
|
|
|
|
|
137
|
}; |
82
|
78
|
|
|
|
|
140
|
} |
83
|
|
|
|
|
|
|
|
84
|
78
|
|
|
|
|
337
|
my $build_exports = sub { |
85
|
127
|
|
|
|
|
750
|
my ($self, $meth, $args, $defaults) = @_; |
86
|
|
|
|
|
|
|
my $class = $args->{class}; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my $request = $self->_build_request_export({ |
89
|
|
|
|
|
|
|
class => $class, |
90
|
|
|
|
|
|
|
remote => $ENV{CATALYST_SERVER}, |
91
|
|
|
|
|
|
|
}); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
my $get = $self->_build_get_export({ request => $request }); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $ctx_request = $self->_build_ctx_request_export({ |
96
|
|
|
|
|
|
|
class => $class, |
97
|
|
|
|
|
|
|
request => $request, |
98
|
|
|
|
|
|
|
}); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
return { |
101
|
|
|
|
|
|
|
request => $request, |
102
|
|
|
|
|
|
|
get => $get, |
103
|
|
|
|
|
|
|
ctx_request => $ctx_request, |
104
|
|
|
|
|
|
|
content_like => sub { |
105
|
|
|
|
|
|
|
my $action = shift; |
106
|
|
|
|
|
|
|
return Test::More->builder->like($get->($action),@_); |
107
|
|
|
|
|
|
|
}, |
108
|
|
|
|
|
|
|
action_ok => sub { |
109
|
9
|
|
|
9
|
|
4648
|
my $action = shift; |
110
|
9
|
|
|
|
|
70
|
my $meth = $request->($action)->request->method; |
111
|
|
|
|
|
|
|
my @args = @_ ? @_ : ("$meth $action returns successfully"); |
112
|
|
|
|
|
|
|
return Test::More->builder->ok($request->($action)->is_success,@args); |
113
|
3
|
|
|
3
|
|
1462
|
}, |
114
|
3
|
|
|
|
|
9
|
action_redirect => sub { |
115
|
3
|
100
|
|
|
|
87
|
my $action = shift; |
116
|
3
|
|
|
|
|
25
|
my $meth = $request->($action)->request->method; |
117
|
|
|
|
|
|
|
my @args = @_ ? @_ : ("$meth $action returns a redirect"); |
118
|
|
|
|
|
|
|
return Test::More->builder->ok($request->($action)->is_redirect,@args); |
119
|
1
|
|
|
1
|
|
284
|
}, |
120
|
1
|
|
|
|
|
4
|
action_notfound => sub { |
121
|
1
|
50
|
|
|
|
29
|
my $action = shift; |
122
|
1
|
|
|
|
|
7
|
my $meth = $request->($action)->request->method; |
123
|
|
|
|
|
|
|
my @args = @_ ? @_ : ("$meth $action returns a 404"); |
124
|
|
|
|
|
|
|
return Test::More->builder->is_eq($request->($action)->code,404,@args); |
125
|
2
|
|
|
2
|
|
973
|
}, |
126
|
2
|
|
|
|
|
10
|
contenttype_is => sub { |
127
|
2
|
100
|
|
|
|
61
|
my $action = shift; |
128
|
2
|
|
|
|
|
15
|
my $res = $request->($action); |
129
|
|
|
|
|
|
|
return Test::More->builder->is_eq(scalar($res->content_type),@_); |
130
|
|
|
|
|
|
|
}, |
131
|
1
|
|
|
1
|
|
294
|
}; |
132
|
1
|
|
|
|
|
5
|
}; |
133
|
1
|
|
|
|
|
9
|
|
134
|
|
|
|
|
|
|
our $default_host; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
{ |
137
|
|
|
|
|
|
|
my $import = Sub::Exporter::build_exporter({ |
138
|
|
|
|
|
|
|
groups => [ all => $build_exports ], |
139
|
|
|
|
|
|
|
into_level => 1, |
140
|
|
|
|
|
|
|
}); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my ($self, $class, $opts) = @_; |
144
|
|
|
|
|
|
|
Carp::carp( |
145
|
|
|
|
|
|
|
qq{Importing Catalyst::Test without an application name is deprecated:\n |
146
|
|
|
|
|
|
|
Instead of saying: use Catalyst::Test; |
147
|
|
|
|
|
|
|
say: use Catalyst::Test (); # If you don't want to import a test app right now. |
148
|
127
|
|
|
127
|
|
2292
|
or say: use Catalyst::Test 'MyApp'; # If you do want to import a test app.\n\n}) |
149
|
127
|
100
|
|
|
|
952
|
unless $class; |
150
|
|
|
|
|
|
|
$import->($self, '-all' => { class => $class }); |
151
|
|
|
|
|
|
|
$opts = {} unless ref $opts eq 'HASH'; |
152
|
|
|
|
|
|
|
$default_host = $opts->{default_host} if exists $opts->{default_host}; |
153
|
|
|
|
|
|
|
return 1; |
154
|
|
|
|
|
|
|
} |
155
|
127
|
|
|
|
|
503
|
} |
156
|
127
|
100
|
|
|
|
84439
|
|
157
|
127
|
100
|
|
|
|
633
|
=head1 NAME |
158
|
127
|
|
|
|
|
385546
|
|
159
|
|
|
|
|
|
|
Catalyst::Test - Test Catalyst Applications |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head1 SYNOPSIS |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# Helper |
164
|
|
|
|
|
|
|
script/test.pl |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Tests |
167
|
|
|
|
|
|
|
use Catalyst::Test 'TestApp'; |
168
|
|
|
|
|
|
|
my $content = get('index.html'); # Content as string |
169
|
|
|
|
|
|
|
my $response = request('index.html'); # HTTP::Response object |
170
|
|
|
|
|
|
|
my($res, $c) = ctx_request('index.html'); # HTTP::Response & context object |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
use HTTP::Request::Common; |
173
|
|
|
|
|
|
|
my $response = request POST '/foo', [ |
174
|
|
|
|
|
|
|
bar => 'baz', |
175
|
|
|
|
|
|
|
something => 'else' |
176
|
|
|
|
|
|
|
]; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Run tests against a remote server |
179
|
|
|
|
|
|
|
CATALYST_SERVER='http://localhost:3000/' prove -r -l lib/ t/ |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
use Catalyst::Test 'TestApp'; |
182
|
|
|
|
|
|
|
use Test::More tests => 1; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
ok( get('/foo') =~ /bar/ ); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# mock virtual hosts |
187
|
|
|
|
|
|
|
use Catalyst::Test 'MyApp', { default_host => 'myapp.com' }; |
188
|
|
|
|
|
|
|
like( get('/whichhost'), qr/served by myapp.com/ ); |
189
|
|
|
|
|
|
|
like( get( '/whichhost', { host => 'yourapp.com' } ), qr/served by yourapp.com/ ); |
190
|
|
|
|
|
|
|
{ |
191
|
|
|
|
|
|
|
local $Catalyst::Test::default_host = 'otherapp.com'; |
192
|
|
|
|
|
|
|
like( get('/whichhost'), qr/served by otherapp.com/ ); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head1 DESCRIPTION |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
This module allows you to make requests to a Catalyst application either without |
198
|
|
|
|
|
|
|
a server, by simulating the environment of an HTTP request using |
199
|
|
|
|
|
|
|
L<HTTP::Request::AsCGI> or remotely if you define the CATALYST_SERVER |
200
|
|
|
|
|
|
|
environment variable. This module also adds a few Catalyst-specific |
201
|
|
|
|
|
|
|
testing methods as displayed in the method section. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
The L<get|/"$content = get( ... )"> and L<request|/"$res = request( ... );"> |
204
|
|
|
|
|
|
|
functions take either a URI or an L<HTTP::Request> object. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 INLINE TESTS WILL NO LONGER WORK |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
While it used to be possible to inline a whole test app into a C<.t> file for |
209
|
|
|
|
|
|
|
a distribution, this will no longer work. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
The convention is to place your L<Catalyst> test apps into C<t/lib> in your |
212
|
|
|
|
|
|
|
distribution. E.g.: C<t/lib/TestApp.pm>, C<t/lib/TestApp/Controller/Root.pm>, |
213
|
|
|
|
|
|
|
etc.. Multiple test apps can be used in this way. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Then write your C<.t> files like so: |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
use strict; |
218
|
|
|
|
|
|
|
use warnings; |
219
|
|
|
|
|
|
|
use FindBin '$Bin'; |
220
|
|
|
|
|
|
|
use lib "$Bin/lib"; |
221
|
|
|
|
|
|
|
use Test::More tests => 6; |
222
|
|
|
|
|
|
|
use Catalyst::Test 'TestApp'; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head1 METHODS |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 $content = get( ... ) |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Returns the content. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
my $content = get('foo/bar?test=1'); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Note that this method doesn't follow redirects, so to test for a |
233
|
|
|
|
|
|
|
correctly redirecting page you'll need to use a combination of this |
234
|
|
|
|
|
|
|
method and the L<request|/"$res = request( ... );"> method below: |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
my $res = request('/'); # redirects to /y |
237
|
|
|
|
|
|
|
warn $res->header('location'); |
238
|
|
|
|
|
|
|
use URI; |
239
|
|
|
|
|
|
|
my $uri = URI->new($res->header('location')); |
240
|
|
|
|
|
|
|
is ( $uri->path , '/y'); |
241
|
|
|
|
|
|
|
my $content = get($uri->path); |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Note also that the content is returned as raw bytes, without any attempt |
244
|
|
|
|
|
|
|
to decode it into characters. |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head2 $res = request( ... ); |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Returns an L<HTTP::Response> object. Accepts an optional hashref for request |
249
|
|
|
|
|
|
|
header configuration; currently only supports setting 'host' value. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
my $res = request('foo/bar?test=1'); |
252
|
|
|
|
|
|
|
my $virtual_res = request('foo/bar?test=1', {host => 'virtualhost.com'}); |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
Alternately, you can pass in an L<HTTP::Request::Common> object to set arbitrary |
255
|
|
|
|
|
|
|
request headers. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
my $res = request(GET '/foo/bar', |
258
|
|
|
|
|
|
|
X-Foo => 'Bar', |
259
|
|
|
|
|
|
|
Authorization => 'Bearer JWT_HERE', |
260
|
|
|
|
|
|
|
... |
261
|
|
|
|
|
|
|
); |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 ($res, $c) = ctx_request( ... ); |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Works exactly like L<request|/"$res = request( ... );">, except it also returns the Catalyst context object, |
266
|
|
|
|
|
|
|
C<$c>. Note that this only works for local requests. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=cut |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
my $args = shift; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
my $request = Catalyst::Utils::request(shift); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
my %extra_env; |
275
|
|
|
|
|
|
|
_customize_request($request, \%extra_env, @_); |
276
|
906
|
|
|
906
|
|
1796
|
$args->{mangle_request}->($request) if $args->{mangle_request}; |
277
|
|
|
|
|
|
|
|
278
|
906
|
|
|
|
|
3212
|
my $ret; |
279
|
|
|
|
|
|
|
test_psgi |
280
|
906
|
|
|
|
|
1654
|
%{ $args }, |
281
|
906
|
|
|
|
|
3048
|
app => sub { $args->{app}->({ %{ $_[0] }, %extra_env }) }, |
282
|
906
|
50
|
|
|
|
2238
|
client => sub { |
283
|
|
|
|
|
|
|
my ($psgi_app) = @_; |
284
|
906
|
|
|
|
|
1352
|
my $resp = $psgi_app->($request); |
285
|
|
|
|
|
|
|
$args->{mangle_response}->($resp) if $args->{mangle_response}; |
286
|
906
|
|
|
|
|
7700
|
$ret = $resp; |
287
|
906
|
|
|
906
|
|
691152
|
}; |
|
906
|
|
|
|
|
12543
|
|
288
|
|
|
|
|
|
|
|
289
|
906
|
|
|
906
|
|
693475
|
return $ret; |
290
|
906
|
|
|
|
|
2108
|
} |
291
|
905
|
50
|
|
|
|
90448
|
|
292
|
905
|
|
|
|
|
56120
|
my $class = shift; |
293
|
906
|
|
|
|
|
1407
|
|
294
|
|
|
|
|
|
|
return _request({ |
295
|
905
|
|
|
|
|
15947
|
app => ref($class) eq "CODE" ? $class : $class->_finalized_psgi_app, |
296
|
|
|
|
|
|
|
mangle_response => sub { |
297
|
|
|
|
|
|
|
my ($resp) = @_; |
298
|
|
|
|
|
|
|
|
299
|
906
|
|
|
906
|
|
1875
|
# HTML head parsing based on LWP::UserAgent |
300
|
|
|
|
|
|
|
# |
301
|
|
|
|
|
|
|
# This is because if you make a remote request with LWP, then the |
302
|
|
|
|
|
|
|
# <BASE HREF="..."> from the returned HTML document will be used |
303
|
|
|
|
|
|
|
# to fill in $res->base, as documented in HTTP::Response. We need |
304
|
905
|
|
|
905
|
|
1985
|
# to support this in local test requests so that they work 'the same'. |
305
|
|
|
|
|
|
|
# |
306
|
|
|
|
|
|
|
# This is not just horrible and possibly broken, but also really |
307
|
|
|
|
|
|
|
# doesn't belong here. Whoever wants this should be working on |
308
|
|
|
|
|
|
|
# getting it into Plack::Test, or make a middleware out of it, or |
309
|
|
|
|
|
|
|
# whatever. Seriously - horrible. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
if (!$resp->content_type || $resp->content_is_html) { |
312
|
|
|
|
|
|
|
require HTML::HeadParser; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
my $parser = HTML::HeadParser->new(); |
315
|
|
|
|
|
|
|
$parser->xml_mode(1) if $resp->content_is_xhtml; |
316
|
|
|
|
|
|
|
$parser->utf8_mode(1) if $] >= 5.008 && $HTML::Parser::VERSION >= 3.40; |
317
|
|
|
|
|
|
|
|
318
|
905
|
100
|
100
|
|
|
3184
|
$parser->parse( $resp->content ); |
319
|
702
|
|
|
|
|
60758
|
my $h = $parser->header; |
320
|
|
|
|
|
|
|
for my $f ( $h->header_field_names ) { |
321
|
702
|
|
|
|
|
110108
|
$resp->init_header( $f, [ $h->header($f) ] ); |
322
|
702
|
50
|
|
|
|
61691
|
} |
323
|
702
|
50
|
33
|
|
|
22215
|
} |
324
|
|
|
|
|
|
|
# Another horrible hack to make the response headers have a |
325
|
702
|
|
|
|
|
1758
|
# 'status' field. This is for back-compat, but you should |
326
|
702
|
|
|
|
|
23167
|
# call $resp->code instead! |
327
|
702
|
|
|
|
|
4134
|
$resp->init_header('status', [ $resp->code ]); |
328
|
26
|
|
|
|
|
1030
|
}, |
329
|
|
|
|
|
|
|
}, @_); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
my $agent; |
333
|
|
|
|
|
|
|
|
334
|
905
|
|
|
|
|
29979
|
require LWP::UserAgent; |
335
|
|
|
|
|
|
|
local $Plack::Test::Impl = 'ExternalServer'; |
336
|
906
|
50
|
|
|
|
6717
|
|
337
|
|
|
|
|
|
|
unless ($agent) { |
338
|
|
|
|
|
|
|
$agent = LWP::UserAgent->new( |
339
|
|
|
|
|
|
|
keep_alive => 1, |
340
|
|
|
|
|
|
|
max_redirect => 0, |
341
|
|
|
|
|
|
|
timeout => 60, |
342
|
0
|
|
|
0
|
|
0
|
|
343
|
0
|
|
|
|
|
0
|
# work around newer LWP max_redirect 0 bug |
344
|
|
|
|
|
|
|
# http://rt.cpan.org/Ticket/Display.html?id=40260 |
345
|
0
|
0
|
|
|
|
0
|
requests_redirectable => [], |
346
|
0
|
|
|
|
|
0
|
); |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
$agent->env_proxy; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
my $server = URI->new($ENV{CATALYST_SERVER}); |
353
|
|
|
|
|
|
|
if ( $server->path =~ m|^(.+)?/$| ) { |
354
|
|
|
|
|
|
|
my $path = $1; |
355
|
|
|
|
|
|
|
$server->path("$path") if $path; # need to be quoted |
356
|
0
|
|
|
|
|
0
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
return _request({ |
359
|
|
|
|
|
|
|
ua => $agent, |
360
|
0
|
|
|
|
|
0
|
uri => $server, |
361
|
0
|
0
|
|
|
|
0
|
mangle_request => sub { |
362
|
0
|
|
|
|
|
0
|
my ($request) = @_; |
363
|
0
|
0
|
|
|
|
0
|
|
364
|
|
|
|
|
|
|
# the request path needs to be sanitised if $server is using a |
365
|
|
|
|
|
|
|
# non-root path due to potential overlap between request path and |
366
|
|
|
|
|
|
|
# response path. |
367
|
|
|
|
|
|
|
if ($server->path) { |
368
|
|
|
|
|
|
|
# If request path is '/', we have to add a trailing slash to the |
369
|
|
|
|
|
|
|
# final request URI |
370
|
0
|
|
|
0
|
|
0
|
my $add_trailing = ($request->uri->path eq '/' || $request->uri->path eq '') ? 1 : 0; |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
my @sp = split '/', $server->path; |
373
|
|
|
|
|
|
|
my @rp = split '/', $request->uri->path; |
374
|
|
|
|
|
|
|
shift @sp; shift @rp; # leading / |
375
|
0
|
0
|
|
|
|
0
|
if (@rp) { |
376
|
|
|
|
|
|
|
foreach my $sp (@sp) { |
377
|
|
|
|
|
|
|
$sp eq $rp[0] ? shift @rp : last |
378
|
0
|
0
|
0
|
|
|
0
|
} |
379
|
|
|
|
|
|
|
} |
380
|
0
|
|
|
|
|
0
|
$request->uri->path(join '/', @rp); |
381
|
0
|
|
|
|
|
0
|
|
382
|
0
|
|
|
|
|
0
|
if ( $add_trailing ) { |
|
0
|
|
|
|
|
0
|
|
383
|
0
|
0
|
|
|
|
0
|
$request->uri->path( $request->uri->path . '/' ); |
384
|
0
|
|
|
|
|
0
|
} |
385
|
0
|
0
|
|
|
|
0
|
} |
386
|
|
|
|
|
|
|
}, |
387
|
|
|
|
|
|
|
}, @_); |
388
|
0
|
|
|
|
|
0
|
} |
389
|
|
|
|
|
|
|
|
390
|
0
|
0
|
|
|
|
0
|
for my $name (qw(local_request remote_request)) { |
391
|
0
|
|
|
|
|
0
|
my $fun = sub { |
392
|
|
|
|
|
|
|
carp <<"EOW"; |
393
|
|
|
|
|
|
|
Calling Catalyst::Test::${name}() directly is deprecated. |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
0
|
Please import Catalyst::Test into your namespace and use the provided request() |
396
|
|
|
|
|
|
|
function instead. |
397
|
|
|
|
|
|
|
EOW |
398
|
|
|
|
|
|
|
return __PACKAGE__->can("_${name}")->(@_); |
399
|
|
|
|
|
|
|
}; |
400
|
1
|
|
|
1
|
|
237
|
|
401
|
|
|
|
|
|
|
no strict 'refs'; |
402
|
|
|
|
|
|
|
*$name = $fun; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
my $request = shift; |
406
|
1
|
|
|
|
|
17
|
my $extra_env = shift; |
407
|
|
|
|
|
|
|
my $opts = pop(@_) || {}; |
408
|
|
|
|
|
|
|
$opts = {} unless ref($opts) eq 'HASH'; |
409
|
126
|
|
|
126
|
|
965
|
if ( my $host = exists $opts->{host} ? $opts->{host} : $default_host ) { |
|
126
|
|
|
|
|
274
|
|
|
126
|
|
|
|
|
20282
|
|
410
|
|
|
|
|
|
|
$request->header( 'Host' => $host ); |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
if (my $extra = $opts->{extra_env}) { |
414
|
911
|
|
|
911
|
|
1571
|
@{ $extra_env }{keys %{ $extra }} = values %{ $extra }; |
415
|
911
|
|
|
|
|
1348
|
} |
416
|
911
|
|
100
|
|
|
4085
|
} |
417
|
911
|
100
|
|
|
|
2683
|
|
418
|
911
|
100
|
|
|
|
3284
|
=head2 action_ok($url [, $test_name ]) |
|
|
100
|
|
|
|
|
|
419
|
27
|
|
|
|
|
90
|
|
420
|
|
|
|
|
|
|
Fetches the given URL and checks that the request was successful. An optional |
421
|
|
|
|
|
|
|
second argument can be given to specify the name of the test. |
422
|
911
|
100
|
|
|
|
4367
|
|
423
|
2
|
|
|
|
|
3
|
=head2 action_redirect($url [, $test_name ]) |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
6
|
|
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Fetches the given URL and checks that the request was a redirect. An optional |
426
|
|
|
|
|
|
|
second argument can be given to specify the name of the test. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head2 action_notfound($url [, $test_name ]) |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Fetches the given URL and checks that the request was not found. An optional |
431
|
|
|
|
|
|
|
second argument can be given to specify the name of the test. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head2 content_like( $url, $regexp [, $test_name ] ) |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Fetches the given URL and returns whether the content matches the regexp. An |
436
|
|
|
|
|
|
|
optional third argument can be given to specify the name of the test. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head2 contenttype_is($url, $type [, $test_name ]) |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Verify the given URL has a content type of $type and optionally specify a test name. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head1 SEE ALSO |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
L<Catalyst>, L<Test::WWW::Mechanize::Catalyst>, |
445
|
|
|
|
|
|
|
L<Test::WWW::Selenium::Catalyst>, L<Test::More>, L<HTTP::Request::Common> |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head1 AUTHORS |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Catalyst Contributors, see Catalyst.pm |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head1 COPYRIGHT |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
This library is free software. You can redistribute it and/or modify it under |
454
|
|
|
|
|
|
|
the same terms as Perl itself. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=begin Pod::Coverage |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
local_request |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
remote_request |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=end Pod::Coverage |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=cut |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
1; |