line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RapidApp::Test::Client; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
24
|
use strict; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
102
|
|
4
|
4
|
|
|
4
|
|
21
|
use warnings; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
103
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# Object class for simulating RapidApp HTTP client sessions |
7
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
1647
|
use Moo; |
|
4
|
|
|
|
|
31080
|
|
|
4
|
|
|
|
|
16
|
|
9
|
4
|
|
|
4
|
|
17165
|
use Types::Standard qw(:all); |
|
4
|
|
|
|
|
243494
|
|
|
4
|
|
|
|
|
41
|
|
10
|
|
|
|
|
|
|
|
11
|
4
|
|
|
4
|
|
159248
|
use RapidApp; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
127
|
|
12
|
4
|
|
|
4
|
|
25
|
use Scalar::Util qw(blessed); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
229
|
|
13
|
4
|
|
|
4
|
|
23
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
26
|
|
14
|
4
|
|
|
4
|
|
9947
|
use LWP::UserAgent; |
|
4
|
|
|
|
|
73852
|
|
|
4
|
|
|
|
|
139
|
|
15
|
4
|
|
|
4
|
|
32
|
use HTTP::Request::Common; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
320
|
|
16
|
4
|
|
|
4
|
|
27
|
use JSON qw(decode_json); |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
32
|
|
17
|
4
|
|
|
4
|
|
417
|
use Try::Tiny; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
4982
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# shorthand aliases: |
20
|
0
|
|
|
0
|
0
|
0
|
sub lreq { (shift)->last_request } |
21
|
8
|
|
|
8
|
0
|
117
|
sub lres { (shift)->last_response } |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
has 'ajax_request_headers', is => 'ro', default => sub {{ |
24
|
|
|
|
|
|
|
'X-RapidApp-RequestContentType' => 'JSON', |
25
|
|
|
|
|
|
|
'X-RapidApp-VERSION' => $RapidApp::VERSION, |
26
|
|
|
|
|
|
|
'X-Requested-With' => 'XMLHttpRequest', |
27
|
|
|
|
|
|
|
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8', |
28
|
|
|
|
|
|
|
}}, isa => HashRef; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has 'request_num', is => 'rw', default => sub{0}, isa => Int; |
31
|
|
|
|
|
|
|
has 'last_request', is => 'rw', default => sub{undef}, isa => Maybe[InstanceOf['HTTP::Request']]; |
32
|
|
|
|
|
|
|
has 'last_response', is => 'rw', default => sub{undef}, isa => Maybe[InstanceOf['HTTP::Response']]; |
33
|
|
|
|
|
|
|
has 'last_request_started', is => 'rw', default => sub{undef}; |
34
|
|
|
|
|
|
|
has 'last_request_elapsed', is => 'rw', default => sub{undef}, isa => Maybe[Str]; |
35
|
|
|
|
|
|
|
has 'last_url', is => 'rw', default => sub{undef}, isa => Maybe[Str]; |
36
|
|
|
|
|
|
|
has 'cookie', is => 'rw', default => sub{undef}, isa => Maybe[Str]; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# i.e. http://localhost:3000 |
39
|
|
|
|
|
|
|
has 'base_url', is => 'ro', isa => Maybe[Str], default => sub {undef}; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
has 'agent_string', is => 'ro', lazy => 1, default => sub { |
42
|
|
|
|
|
|
|
my $self = shift; |
43
|
|
|
|
|
|
|
return (ref $self); |
44
|
|
|
|
|
|
|
}, isa => Str; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
has 'request_caller', is => 'ro', lazy => 1, default => sub { |
47
|
|
|
|
|
|
|
my $self = shift; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# create in a closure: |
50
|
|
|
|
|
|
|
my $ua = LWP::UserAgent->new; |
51
|
|
|
|
|
|
|
$ua->agent($self->agent_string); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
return sub { |
54
|
|
|
|
|
|
|
my $request = shift; |
55
|
|
|
|
|
|
|
return $ua->request($request); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
}, isa => CodeRef; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub make_request { |
60
|
26
|
|
|
26
|
0
|
101
|
my ($self, $req) = @_; |
61
|
|
|
|
|
|
|
|
62
|
26
|
|
|
|
|
553
|
$self->last_request(undef); |
63
|
26
|
|
|
|
|
1090
|
$self->last_response(undef); |
64
|
26
|
|
|
|
|
1198
|
$self->last_request_elapsed(undef); |
65
|
26
|
|
|
|
|
894
|
$self->request_num( $self->request_num + 1 ); |
66
|
|
|
|
|
|
|
|
67
|
26
|
|
|
|
|
938
|
$self->last_request_started([gettimeofday]); |
68
|
|
|
|
|
|
|
|
69
|
26
|
100
|
|
|
|
403
|
$req->header( Cookie => $self->cookie ) if ($self->cookie); |
70
|
|
|
|
|
|
|
|
71
|
26
|
|
|
|
|
1859
|
my $res = $self->request_caller->( $self->last_request($req) ); |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Record the response unless the request_caller already did: |
74
|
26
|
50
|
|
|
|
564
|
$self->record_response( $res ) unless ($self->last_response); |
75
|
|
|
|
|
|
|
|
76
|
26
|
|
|
|
|
253
|
return $res; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub record_response { |
80
|
26
|
|
|
26
|
0
|
41763
|
my ($self, $res) = @_; |
81
|
26
|
50
|
|
|
|
578
|
die "last_response already defined" if ($self->last_response); |
82
|
26
|
|
|
|
|
565
|
$self->last_response( $res ); |
83
|
26
|
|
|
|
|
980
|
$self->cookie( $res->header('Set-Cookie') ); |
84
|
26
|
|
|
|
|
2460
|
$self->last_request_elapsed(sprintf("%0.5f sec",tv_interval( |
85
|
|
|
|
|
|
|
$self->last_request_started |
86
|
|
|
|
|
|
|
))); |
87
|
26
|
|
|
|
|
2045
|
return $res; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub normalize_url { |
91
|
26
|
|
|
26
|
0
|
76
|
my ($self, $url) = @_; |
92
|
|
|
|
|
|
|
|
93
|
26
|
50
|
33
|
|
|
191
|
$url = join('',$self->base_url,$url) if ( |
94
|
|
|
|
|
|
|
$self->base_url && |
95
|
|
|
|
|
|
|
$url =~ /^\// #<-- starts with '/' |
96
|
|
|
|
|
|
|
); |
97
|
|
|
|
|
|
|
|
98
|
26
|
|
|
|
|
597
|
return $self->last_url($url); |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub get_request { |
103
|
8
|
|
|
8
|
0
|
29
|
my ($self, $url, $headers) = @_; |
104
|
8
|
|
|
|
|
28
|
$url = $self->normalize_url($url); |
105
|
8
|
|
|
|
|
362
|
my $req = GET($url); |
106
|
8
|
100
|
|
|
|
1107
|
$req->header( %$headers ) if ($headers); |
107
|
8
|
|
|
|
|
320
|
$self->make_request($req); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub post_request { |
111
|
18
|
|
|
18
|
0
|
74
|
my ($self, $url, $params, $headers) = @_; |
112
|
18
|
|
|
|
|
57
|
$url = $self->normalize_url($url); |
113
|
18
|
100
|
|
|
|
677
|
my $arr_arg = ref($params) eq 'HASH' ? [%$params] : $params; |
114
|
18
|
|
|
|
|
95
|
my $req = POST($url,$params); |
115
|
18
|
100
|
|
|
|
11930
|
$req->header( %$headers ) if ($headers); |
116
|
18
|
|
|
|
|
1909
|
$self->make_request($req); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub last_request_is_ajax { |
120
|
26
|
|
|
26
|
0
|
54
|
my $self = shift; |
121
|
26
|
50
|
|
|
|
334
|
my $req = $self->last_request or return 0; |
122
|
26
|
|
|
|
|
230
|
my $req_with = $req->header('X-Requested-With'); |
123
|
26
|
|
66
|
|
|
1540
|
return $req_with && $req_with eq 'XMLHttpRequest'; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub last_request_type { |
127
|
26
|
|
|
26
|
0
|
228
|
my $self = shift; |
128
|
26
|
50
|
|
|
|
333
|
return '(none)' unless ($self->last_request); |
129
|
26
|
100
|
|
|
|
199
|
return $self->last_request_is_ajax ? 'Ajax' : 'Browser'; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub last_response_set_cookie { |
133
|
26
|
|
|
26
|
0
|
63
|
my $self = shift; |
134
|
26
|
50
|
|
|
|
333
|
my $res = $self->last_response or return 0; |
135
|
26
|
|
|
|
|
211
|
return $res->header('Set-Cookie'); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub describe_request { |
139
|
26
|
|
|
26
|
0
|
57
|
my $self = shift; |
140
|
26
|
50
|
|
|
|
432
|
my $req = $self->last_request or return '(no request)'; |
141
|
|
|
|
|
|
|
|
142
|
26
|
|
|
|
|
589
|
my @list = ( |
143
|
|
|
|
|
|
|
' <r', $self->request_num,'> ', |
144
|
|
|
|
|
|
|
$self->last_request_type, |
145
|
|
|
|
|
|
|
'->', $req->method, '(\'',$req->uri->path,'\')', |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# If we already have the response, include the elapsed time: |
149
|
26
|
50
|
|
|
|
1394
|
push @list,(' [',$self->last_request_elapsed,']') |
150
|
|
|
|
|
|
|
if ($self->last_response); |
151
|
|
|
|
|
|
|
|
152
|
26
|
100
|
|
|
|
671
|
push @list, ' **set-cookie**' if ($self->last_response_set_cookie); |
153
|
|
|
|
|
|
|
|
154
|
26
|
|
|
|
|
1341
|
return join('',@list); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
##################### |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# Simulate an Ajax POST request as if it was generated by the |
161
|
|
|
|
|
|
|
# RapidApp/ExtJS JavaScript client/browser to a JSON-encoded |
162
|
|
|
|
|
|
|
# resource. Decodes and returns the JSON as perl ref |
163
|
|
|
|
|
|
|
sub ajax_post_decode { |
164
|
13
|
|
|
13
|
0
|
49
|
my ($self, $url, $params) = @_; |
165
|
13
|
|
|
|
|
78
|
my $res = $self->post_request($url, $params, $self->ajax_request_headers); |
166
|
13
|
|
66
|
13
|
|
120
|
return try{decode_json($res->decoded_content)} || $res->decoded_content; |
|
13
|
|
|
|
|
414
|
|
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub ajax_get_raw { |
171
|
2
|
|
|
2
|
0
|
8
|
my ($self, $url) = @_; |
172
|
2
|
|
|
|
|
16
|
my $res = $self->get_request($url, $self->ajax_request_headers); |
173
|
2
|
|
|
|
|
13
|
return $res->decoded_content; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub ajax_get_decode { |
178
|
0
|
|
|
0
|
0
|
0
|
my ($self, $url) = @_; |
179
|
0
|
|
|
|
|
0
|
my $content = $self->ajax_get_raw($url); |
180
|
0
|
|
0
|
0
|
|
0
|
return try{decode_json($content)} || $content; |
|
0
|
|
|
|
|
0
|
|
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub browser_get_raw { |
184
|
3
|
|
|
3
|
0
|
14
|
my ($self, $url) = @_; |
185
|
3
|
|
|
|
|
14
|
my $res = $self->get_request($url); |
186
|
3
|
|
|
|
|
19
|
return $res->decoded_content; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub browser_post_raw { |
190
|
0
|
|
|
0
|
0
|
|
my ($self, $url, $params) = @_; |
191
|
0
|
|
|
|
|
|
my $res = $self->post_request($url,$params); |
192
|
0
|
|
|
|
|
|
return $res->decoded_content; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
1; |