/
60_net_server.t
349 lines (302 loc) · 10.6 KB
/
60_net_server.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#!/usr/bin/env perl
# Test the RPC::XML::Server class with Net::Server rather than HTTP::Daemon
# This is run after the test suite for RPC::XML::Client, so we will use that
# for the client-side of the tests.
## no critic(RequireCheckedClose)
## no critic(RequireInterpolationOfMetachars)
use strict;
use warnings;
use subs qw(start_server find_port);
use Carp qw(carp croak);
use File::Spec;
use Module::Load;
use Test::More;
use RPC::XML::Server;
use RPC::XML::Client;
my ($dir, $srv, $pid_file, $log_file, $port, $client, $res, @keys, $meth, $list,
$bucket, %seen, $srv_hostname);
if ($^O eq 'MSWin32')
{
# Can't run this (reliably) under Windows:
plan skip_all => 'Net::Server tests not reliable on Windows platform';
}
elsif (! eval { load Net::Server; 1; })
{
# If they do not have Net::Server, quietly skip
plan skip_all => 'Net::Server not available';
}
else
{
# otherwise...
plan tests => 30;
}
# Presently, there is a problem with Net::Server+IO::Socket::IP, when the IPv6
# entry for 'localhost' comes before the IPv4 entry in /etc/hosts. For now, to
# get through the tests, look for that combination and substitute 127.0.0.1 for
# 'localhost' (and hope they don't have a weird network configuration).
# See RT#105679.
if (eval { load IO::Socket::IP; 1; })
{
carp 'Working around an issue with Net::Server+IO::Socket::IP';
$srv_hostname = '127.0.0.1';
}
else
{
$srv_hostname = 'localhost';
}
(undef, $dir, undef) = File::Spec->splitpath(File::Spec->rel2abs($0));
require File::Spec->catfile($dir, 'util.pl');
$pid_file = File::Spec->catfile($dir, 'net_server.pid');
$log_file = File::Spec->catfile($dir, 'net_server.log');
if (($port = find_port) == -1)
{
croak 'No usable port found between 9000 and 11000, skipping';
}
unlink $log_file, $pid_file;
# All this, and we haven't even created a server object or run a test yet
$srv = RPC::XML::Server->new(no_http => 1);
# Technically, this is overkill. But if it fails everything else blows up:
isa_ok($srv, 'RPC::XML::Server');
if (! ref $srv)
{
croak "Server allocation failed, cannot continue. Message was: $srv";
}
# All of these parameters are passed to the run() method of
# Net::Server::MultiType
start_server($srv,
server_type => 'Single',
log_file => $log_file,
log_level => 4,
pid_file => $pid_file,
port => $port,
host => $srv_hostname,
background => 1);
sleep 1; # Allow time for server to spin up
# Unless we see "ok 2", we have a problem
ok(-e $pid_file, 'server started, PID file exists');
# After this point, we have the obligation of killing the server manually
$client = RPC::XML::Client->new("http://$srv_hostname:$port");
is($client->simple_request('system.identity'), $srv->product_tokens,
'system.identity matches $srv->product_tokens');
# At this point, most of this is copied from the first server test suite
# (40_server.t). We do want to verify the full introspection API under
# Net::Server, though.
$res = $client->simple_request('system.listMethods');
@keys = $srv->list_methods;
is(ref($res), 'ARRAY', 'system.listMethods returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 2;
}
is(scalar(@{$res}), scalar(@keys),
'system.listMethods returned correct number of names');
is(join(q{} => sort @{$res}), join(q{} => sort @keys),
'system.listMethods returned matching set of names');
}
# Test the substring-parameter calling of system.listMethods
$res = $client->simple_request('system.listMethods', 'method');
is(ref($res), 'ARRAY', 'system.listMethods returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 1;
}
is(join(q{,} => sort @{$res}), 'system.methodHelp,system.methodSignature',
'system.listMethods with pattern returned correct set of names');
}
# Again, with a pattern that will produce no matches
$res = $client->simple_request('system.listMethods', 'none_will_match');
is(ref($res), 'ARRAY', 'system.listMethods returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 1;
}
is(scalar(@{$res}), 0, 'system.listMethods with bad pattern returned none');
}
# system.status
$res = $client->simple_request('system.status');
@keys = qw(host port name version path date date_int started started_int
total_requests methods_known);
is(ref($res), 'HASH', 'system.status returned HASH ref');
SKIP: {
if (! ref $res)
{
skip 'server response not a HASH reference', 2;
}
my @seen_keys = grep { defined $res->{$_} } @keys;
ok(@keys == @seen_keys, 'system.status hash has correct keys');
is($res->{total_requests}, 5, 'system.status total_request count correct');
}
# system.methodHelp
$res = $client->simple_request('system.methodHelp', 'system.identity');
is($res, $srv->get_method('system.identity')->{help},
'system.methodHelp returned correct string');
# system.methodHelp with multiple arguments
$res = $client->simple_request('system.methodHelp',
[ 'system.identity', 'system.status' ]);
is(ref($res), 'ARRAY', 'system.methodHelp returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 1;
}
is(join(q{} => @{$res}),
$srv->get_method('system.identity')->{help} .
$srv->get_method('system.status')->{help},
'system.methodHelp with specific methods returns correctly');
}
# system.methodHelp with an invalid argument
$res = $client->send_request('system.methodHelp', 'system.bad');
isa_ok($res, 'RPC::XML::fault', 'system.methodHelp (bad arg) response');
SKIP: {
if (! ref $res)
{
skip 'server response not an RPC::XML data object', 1;
}
like($res->string(), qr/Method.*unknown/,
'system.methodHelp (bad arg) has correct faultString');
}
# system.methodSignature
$res = $client->simple_request('system.methodSignature', 'system.methodHelp');
is(ref($res), 'ARRAY', 'system.methodSignature returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 1;
}
my $return_sig = join q{} => sort map { join q{ } => @{$_} } @{$res};
my $method_sig =
join q{} => sort @{$srv->get_method('system.methodHelp')->{signature}};
is($return_sig, $method_sig,
'system.methodSignature return value correct');
}
# system.methodSignature, with an invalid request
$res = $client->send_request('system.methodSignature', 'system.bad');
isa_ok($res, 'RPC::XML::fault', 'system.methodSignature (bad arg) response');
SKIP: {
if (! ref $res)
{
skip 'server response not an RPC::XML data object', 1;
}
like($res->string(), qr/Method.*unknown/,
'system.methodSignature (bad arg) has correct faultString');
}
# system.introspection
$list = $client->simple_request('system.introspection');
$bucket = 0;
%seen = ();
SKIP: {
if (ref($list) ne 'ARRAY')
{
skip 'system.introspection call did not return ARRAY ref', 1;
}
for my $result (@{$list})
{
if ($seen{$result->{name}}++)
{
# If we somehow get the same name twice, that's a point off
$bucket++;
next;
}
$meth = $srv->get_method($result->{name});
if ($meth)
{
my $result_sig = join q{} => sort @{$result->{signature}};
my $method_sig = join q{} => sort @{$meth->{signature}};
# A point off unless all three of these match
if (($meth->{help} ne $result->{help}) ||
($meth->{version} ne $result->{version}) ||
($result_sig ne $method_sig))
{
$bucket++;
}
}
else
{
# That's a point
$bucket++;
}
}
ok(! $bucket, 'system.introspection return data is correct');
}
# system.multicall
$res = $client->simple_request('system.multicall',
[ { methodName => 'system.identity' },
{ methodName => 'system.listMethods',
params => [ 'intro' ] } ]);
is(ref($res), 'ARRAY', 'system.multicall returned ARRAY ref');
SKIP: {
if (! ref $res)
{
skip 'server response not an ARRAY reference', 2;
}
is($res->[0], $srv->product_tokens,
'system.multicall, first return value correct');
SKIP: {
if (ref($res->[1]) ne 'ARRAY')
{
skip 'system.multicall return value second index not ARRAY ref', 1;
}
is(scalar(@{$res->[1]}), 1,
'system.multicall, second return value correct length');
is($res->[1]->[0], 'system.introspection',
'system.multicall, second return value correct value');
}
}
# system.multicall, with an attempt at illegal recursion
$res = $client->send_request('system.multicall',
[ { methodName => 'system.identity' },
{ methodName => 'system.multicall',
params => [ 'intro' ] } ]);
SKIP: {
if (ref($res) ne 'RPC::XML::fault')
{
skip 'system.multicall (recursion) response error, cannot test', 1;
}
like($res->string, qr/Recursive/,
'system.multicall recursion attempt set correct faultString');
}
# system.multicall, with bad data on one of the call specifications
$res = $client->send_request('system.multicall',
[ { methodName => 'system.identity' },
{ methodName => 'system.listMethods',
params => 'intro' } ]);
SKIP: {
if (ref($res) ne 'RPC::XML::fault')
{
skip 'system.multicall (bad data) response error, cannot test', 1;
}
like($res->string, qr/value for.*params.*not an array/i,
'system.multicall bad param array set correct faultString');
}
# system.status, once more, to check the total_requests value
$res = $client->simple_request('system.status');
SKIP: {
if (ref($res) ne 'HASH')
{
skip 'system.status response not HASH ref', 1;
}
is($res->{total_requests}, 19,
'system.status total_request correct at end of suite');
}
# Now that we're done, kill the server and exit
if (open my $fh, '<', $pid_file)
{
chomp(my $pid = <$fh>);
close $fh;
if ($pid =~ /^(\d+)$/)
{
kill 'INT', $1;
}
else
{
carp "WARNING: $pid_file appears corrupt, zombie processes may remain!";
}
}
else
{
carp "WARNING: Opening $pid_file failed: $! (zombie processes may remain)";
}
exit;