File Coverage

blib/lib/Test/ExtDirect.pm
Criterion Covered Total %
statement 70 91 76.9
branch 6 14 42.8
condition 4 6 66.6
subroutine 15 19 78.9
pod 7 7 100.0
total 102 137 74.4


line stmt bran cond sub pod time code
1             package Test::ExtDirect;
2              
3 4     4   288792 use strict;
  4         8  
  4         151  
4 4     4   22 use warnings;
  4         6  
  4         114  
5              
6 4     4   23 use Carp;
  4         16  
  4         322  
7 4     4   4379 use Data::Dumper; # for cloning
  4         43371  
  4         310  
8 4     4   48 use Exporter;
  4         8  
  4         131  
9              
10 4     4   20 use Test::More;
  4         8  
  4         1346  
11              
12 4     4   5122 use RPC::ExtDirect::Server;
  4         287809  
  4         214  
13 4     4   3980 use RPC::ExtDirect::Server::Util;
  4         22879  
  4         293  
14 4     4   3876 use RPC::ExtDirect::Client;
  4         28833  
  4         5055  
15              
16             our @ISA = qw(Exporter);
17              
18             our @EXPORT_OK = qw(
19             maybe_start_server
20             start_server
21             stop_server
22              
23             get_extdirect_api
24              
25             call_extdirect
26             submit_extdirect
27             poll_extdirect
28              
29             call_extdirect_ok
30             submit_extdirect_ok
31             poll_extdirect_ok
32              
33             call
34             submit
35             poll
36              
37             call_ok
38             submit_ok
39             poll_ok
40             );
41              
42             our %EXPORT_TAGS = (
43             DEFAULT => [qw/
44             start_server stop_server call_extdirect call_extdirect_ok
45             submit_extdirect submit_extdirect_ok poll_extdirect
46             poll_extdirect_ok get_extdirect_api maybe_start_server
47             /],
48              
49             all => [qw/
50             start_server stop_server call_extdirect call_extdirect_ok
51             submit_extdirect submit_extdirect_ok poll_extdirect
52             poll_extdirect_ok call submit poll call_ok submit_ok poll_ok
53             get_extdirect_api maybe_start_server
54             /],
55             );
56              
57             our @EXPORT = qw(
58             maybe_start_server
59             start_server
60             stop_server
61              
62             get_extdirect_api
63             call_extdirect
64             call_extdirect_ok
65             submit_extdirect
66             submit_extdirect_ok
67             poll_extdirect
68             poll_extdirect_ok
69             );
70              
71             our $VERSION = '1.01';
72              
73             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
74             #
75             # Starts testing HTTP server and returns the host and port
76             # the server is listening on.
77             #
78              
79             *start_server = *RPC::ExtDirect::Server::Util::start_server;
80              
81             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
82             #
83             # Stops the running HTTP server instance
84             #
85              
86             *stop_server = *RPC::ExtDirect::Server::Util::stop_server;
87              
88             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
89             #
90             # Potentially starts an instance of a Server.
91             #
92              
93             *maybe_start_server = *RPC::ExtDirect::Server::Util::maybe_start_server;
94              
95             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
96             #
97             # Return Ext.Direct API published by the server as RPC::ExtDirect::Client::API
98             # object
99             #
100              
101             sub get_extdirect_api {
102 1     1 1 546 my (%params) = @_;
103            
104             # We assume that users want remoting API by default
105 1   50     10 my $api_type = delete $params{type} || 'remoting';
106            
107 1         4 my $client = _get_client(%params);
108 1         16 my $api = $client->get_api($api_type);
109              
110 1         79 return $api;
111             }
112              
113             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
114             #
115             # Instantiate a new RPC::ExtDirect::Client and make a request call
116             # returning the data
117             #
118              
119             sub call_extdirect {
120 3     3 1 8637 my (%params) = @_;
121              
122 3         14 my $action_name = delete $params{action};
123 3         10 my $method_name = delete $params{method};
124 3         27 my $arg = _clone( delete $params{arg} );
125              
126 3         33 my $client = _get_client(%params);
127            
128             # This is a backward compatibility measure; until RPC::ExtDirect 3.0 the
129             # calling code wasn't required to pass any arg to the client when calling
130             # a method with ordered parameters. It is now an error to do so, and
131             # for a good reason: starting with version 3.0, it is possible to
132             # define a method with no strict argument checking, which defaults to
133             # using named parameters. To avoid possible problems stemming from this
134             # change, we strictly check the existence of arguments for both ordered
135             # and named conventions in RPC::ExtDirect::Client.
136             #
137             # Having said that, I don't think that this kind of strict checking is
138             # beneficial for Test::ExtDirect since the test code that calls
139             # Ext.Direct methods is probably focusing on other aspects than strict
140             # argument checking that happens in the transport layer.
141             #
142             # As a side benefit, we also get an early warning if something went awry
143             # and we can't even get a reference to the Action or Method in question.
144            
145 3 100       21 if ( !$arg ) {
146 2         11 my $api = $client->get_api('remoting');
147            
148 2 50       27 croak "Can't get remoting API from the client" unless $api;
149            
150 2         53 my $method = $api->get_method_by_name($action_name, $method_name);
151            
152 2 50       41 croak "Can't resolve ${action_name}->${method_name} method"
153             unless $method;
154            
155 2 50       73 if ( $method->is_ordered ) {
    0          
156 2         19 $arg = [];
157             }
158             elsif ( $method->is_named ) {
159 0         0 $arg = {};
160             }
161             }
162            
163 3         26 my $data = $client->call(
164             action => $action_name,
165             method => $method_name,
166             arg => $arg,
167             %params,
168             );
169              
170 3         126319 return $data;
171             }
172              
173             *call = \&call_extdirect;
174              
175             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
176             #
177             # Run call_extdirect wrapped in eval and fail the test if it dies
178             #
179              
180             sub call_extdirect_ok {
181 0     0 1 0 local $@;
182            
183 0         0 my $result = eval { call_extdirect(@_) };
  0         0  
184              
185 0         0 _pass_or_fail(my $err = $@);
186              
187 0         0 return $result;
188             }
189              
190             *call_ok = \&call_extdirect_ok;
191              
192             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
193             #
194             # Submit a form to Ext.Direct method
195             #
196              
197             sub submit_extdirect {
198 2     2 1 7444 my (%params) = @_;
199              
200 2         9 my $action = delete $params{action};
201 2         8 my $method = delete $params{method};
202 2         16 my $arg = _clone( delete $params{arg} );
203 2         26 my $upload = _clone( delete $params{upload} );
204              
205 2         23 my $client = _get_client(%params);
206 2         15 my $data = $client->submit(action => $action, method => $method,
207             arg => $arg, upload => $upload,
208             %params);
209              
210 2         31111 return $data;
211             }
212              
213             *submit = \&submit_extdirect;
214              
215             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
216             #
217             # Run submit_extdirect wrapped in eval, fail the test if it dies
218             #
219              
220             sub submit_extdirect_ok {
221 0     0 1 0 local $@;
222            
223 0         0 my $result = eval { submit_extdirect(@_) };
  0         0  
224              
225 0         0 _pass_or_fail(my $err = $@);
226              
227 0         0 return $result;
228             }
229              
230             *submit_ok = \&submit_extdirect_ok;
231              
232             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
233             #
234             # Poll Ext.Direct event provider and return data
235             #
236              
237             sub poll_extdirect {
238 2     2 1 3227 my (%params) = @_;
239              
240 2         13 my $client = _get_client(%params);
241 2         16 my $data = $client->poll(%params);
242              
243 2         45691 return $data;
244             }
245              
246             *poll = \&poll_extdirect;
247              
248             ### PUBLIC PACKAGE SUBROUTINE (EXPORT) ###
249             #
250             # Run poll_extdirect wrapped in eval, fail the test if it dies
251             #
252              
253             sub poll_extdirect_ok {
254 0     0 1 0 local $@;
255            
256 0         0 my $result = eval { poll_extdirect(@_) };
  0         0  
257              
258 0         0 _pass_or_fail(my $err = $@);
259              
260 0         0 return $result;
261             }
262              
263             *poll_ok = \&poll_extdirect_ok;
264              
265             ############## PRIVATE METHODS BELOW ##############
266              
267             ### PRIVATE PACKAGE SUBROUTINE ###
268             #
269             # Initializes RPC::ExtDirect::Client instance
270             #
271              
272             sub _get_client {
273 9     9   7214 my (%params) = @_;
274              
275 9   100     147 my $class = delete $params{client_class} || 'RPC::ExtDirect::Client';
276              
277 9 50       1508 eval "require $class" or croak "Can't load package $class";
278              
279 9   50     480 $params{static_dir} ||= '/tmp';
280              
281 9         69 my ($host, $port) = maybe_start_server(%params);
282              
283 9         24233 my $client = $class->new(host => $host, port => $port, %params);
284              
285 9         670909 return $client;
286             }
287              
288             ### PRIVATE PACKAGE SUBROUTINE ###
289             #
290             # Pass or fail a test depending on $@
291             #
292              
293             sub _pass_or_fail {
294 0     0   0 my ($err) = @_;
295              
296 0         0 my ($calling_sub) = (caller 0)[3];
297              
298 0 0       0 if ( $err ) {
299 0         0 fail "$calling_sub failed: $err";
300             }
301             else {
302 0         0 pass "$calling_sub successful";
303             };
304             }
305              
306             ### PRIVATE PACKAGE SUBROUTINE ###
307             #
308             # Create a deep copy (clone) of the passed data structure.
309             # We're not much concerned with performance here, and this
310             # custom implementation allows to avoid a depedency like
311             # Clone or Storable, which is overkill here.
312             #
313              
314             sub _clone {
315 7     7   82 my $data = shift;
316            
317             # Faster than calling instance methods
318 7         32 local $Data::Dumper::Purity = 1;
319 7         57 local $Data::Dumper::Terse = 1;
320 7         47 local $Data::Dumper::Deepcopy = 1;
321            
322 7         80 return eval Dumper($data);
323             }
324              
325             1;