File Coverage

blib/lib/Selenium/Remote/RemoteConnection.pm
Criterion Covered Total %
statement 107 118 90.6
branch 36 42 85.7
condition 14 24 58.3
subroutine 18 19 94.7
pod 2 2 100.0
total 177 205 86.3


line stmt bran cond sub pod time code
1             package Selenium::Remote::RemoteConnection;
2             $Selenium::Remote::RemoteConnection::VERSION = '1.50';
3 29     29   616840 use strict;
  29         64  
  29         1137  
4 29     29   180 use warnings;
  29         55  
  29         1810  
5              
6             #ABSTRACT: Connect to a selenium server
7              
8 29     29   1040 use Moo;
  29         15897  
  29         252  
9 29     29   14561 use Try::Tiny;
  29         1325  
  29         2283  
10 29     29   19811 use LWP::UserAgent;
  29         1357827  
  29         1385  
11 29     29   298 use HTTP::Headers;
  29         82  
  29         852  
12 29     29   149 use HTTP::Request;
  29         63  
  29         902  
13 29     29   172 use Carp qw(croak);
  29         59  
  29         1829  
14 29     29   11279 use JSON;
  29         202339  
  29         307  
15 29     29   22381 use Data::Dumper;
  29         238695  
  29         2262  
16 29     29   16616 use Selenium::Remote::ErrorHandler;
  29         129  
  29         1378  
17 29     29   307 use Scalar::Util qw{looks_like_number};
  29         66  
  29         42858  
18              
19             has 'remote_server_addr' => ( is => 'rw', );
20              
21             has 'port' => ( is => 'rw', );
22              
23             has 'debug' => (
24             is => 'rw',
25             default => sub { 0 }
26             );
27              
28             has 'ua' => (
29             is => 'lazy',
30 1     1   18 builder => sub { return LWP::UserAgent->new; }
31             );
32              
33             has 'error_handler' => (
34             is => 'lazy',
35 4     4   88 builder => sub { return Selenium::Remote::ErrorHandler->new; }
36             );
37              
38             with 'Selenium::Remote::Driver::CanSetWebdriverContext';
39              
40              
41             sub check_status {
42 10     10 1 146 my $self = shift;
43 10         20 my $status;
44              
45             try {
46 10     10   576 $status = $self->request( { method => 'GET', url => 'status' } );
47             }
48             catch {
49 0     0   0 croak "Could not connect to SeleniumWebDriver: $_";
50 10         101 };
51              
52 10   50     267 my $cmdOut = $status->{cmd_status} || '';
53 10 100       36 if ( $cmdOut ne 'OK' ) {
54              
55             # Could be grid, see if we can talk to it
56 1         4 $status = undef;
57 1         7 $status =
58             $self->request( { method => 'GET', url => 'grid/api/hub/status' } );
59             }
60              
61 10 100       55 unless ( $cmdOut eq 'OK' ) {
62 1   50     7 my $cr = $status->{cmd_return} // '';
63 1         320 croak "Selenium server did not return proper status: $cmdOut: $cr";
64             }
65             }
66              
67              
68             sub request {
69 30     30 1 885 my ( $self, $resource, $params, $dont_process_response ) = @_;
70 30         72 my $method = $resource->{method};
71 30         119 my $url = $resource->{url};
72 30   100     156 my $no_content_success = $resource->{no_content_success} // 0;
73              
74 30         102 my $content = '';
75 30         60 my $fullurl = '';
76              
77             # Construct full url.
78 30 100       245 if ( $url =~ m/^http/g ) {
    100          
    100          
79 3         8 $fullurl = $url;
80             }
81             elsif ( $url =~ m/^\// ) {
82              
83             # This is used when we get a 302 Redirect with a Location header.
84 1         9 $fullurl =
85             "http://" . $self->remote_server_addr . ":" . $self->port . $url;
86             }
87             elsif ( $url =~ m/grid/g ) {
88 2         19 $fullurl =
89             "http://" . $self->remote_server_addr . ":" . $self->port . "/$url";
90             }
91             else {
92 24         672 $fullurl =
93             "http://"
94             . $self->remote_server_addr . ":"
95             . $self->port
96             . $self->wd_context_prefix . "/$url";
97             }
98              
99 30 100 66     321 if ( ( defined $params ) && $params ne '' ) {
100              
101             #WebDriver 3 shims
102 16 100       80 if ( $resource->{payload} ) {
103 1         1 foreach my $key ( keys( %{ $resource->{payload} } ) ) {
  1         3  
104 1         3 $params->{$key} = $resource->{payload}->{$key};
105             }
106             }
107              
108 16         112 my $json = JSON->new;
109 16         88 $json->allow_blessed;
110 16         246 $content = $json->allow_nonref->utf8->encode($params);
111             }
112              
113 30 50       110 print "REQ: $method, $fullurl, $content\n" if $self->debug;
114              
115             # HTTP request
116 30         153 my $header =
117             HTTP::Headers->new( Content_Type => 'application/json; charset=utf-8' );
118 30         1707 $header->header( 'Accept' => 'application/json' );
119 30         1210 my $request = HTTP::Request->new( $method, $fullurl, $header, $content );
120 30         55459 my $response = $self->ua->request($request);
121 30 100       87738 if ($dont_process_response) {
122 1         5 return $response;
123             }
124 29         174 return $self->_process_response( $response, $no_content_success );
125             }
126              
127             sub _process_response {
128 230     230   535 my ( $self, $response, $no_content_success ) = @_;
129 230         370 my $data; # server response 'value' that'll be returned to the user
130 230         1052 my $json = JSON->new;
131              
132 230 100       660 if ( $response->is_redirect ) {
133 2         70 my $redirect = {
134             method => 'GET',
135             url => $response->header('location')
136             };
137 2         136 return $self->request($redirect);
138             }
139             else {
140 228         1992 my $decoded_json = undef;
141 228 100       1022 print "RES: " . $response->decoded_content . "\n\n" if $self->debug;
142              
143 228 100 66     13748 if ( ( $response->message ne 'No Content' )
144             && ( $response->content ne '' ) )
145             {
146 217 100       5384 if ( $response->content_type !~ m/json/i ) {
147 2         90 $data->{'cmd_status'} = 'NOTOK';
148             $data->{'cmd_return'}->{message} =
149 2         8 'Server returned error message '
150             . $response->content
151             . ' instead of data';
152 2         127 return $data;
153             }
154             $decoded_json =
155 215         8688 $json->allow_nonref(1)->utf8(1)->decode( $response->content );
156 215         19678 $data->{'sessionId'} = $decoded_json->{'sessionId'};
157             }
158              
159 226 100       1028 if ( $response->is_error ) {
    50          
160 18         219 $data->{'cmd_status'} = 'NOTOK';
161 18 100       62 if ( defined $decoded_json ) {
162 17         751 $data->{'cmd_return'} =
163             $self->error_handler->process_error($decoded_json);
164             }
165             else {
166 1         3 $data->{'cmd_return'} =
167             'Server returned error code '
168             . $response->code
169             . ' and no data';
170             }
171 18         492 return $data;
172             }
173             elsif ( $response->is_success ) {
174 208         2960 $data->{'cmd_status'} = 'OK';
175 208 100       423 if ( defined $decoded_json ) {
176              
177             #XXX MS edge doesn't follow spec here either
178 198 0 66     1441 if ( looks_like_number( $decoded_json->{status} )
      33        
179             && $decoded_json->{status} > 0
180             && $decoded_json->{value}{message} )
181             {
182 0         0 $data->{cmd_status} = 'NOT OK';
183 0         0 $data->{cmd_return} = $decoded_json->{value};
184 0         0 return $data;
185             }
186              
187             #XXX shockingly, neither does InternetExplorerDriver
188 198 50 33     912 if ( ref $decoded_json eq 'HASH' && $decoded_json->{error} ) {
189 0         0 $data->{cmd_status} = 'NOT OK';
190 0         0 $data->{cmd_return} = $decoded_json;
191 0         0 return $data;
192             }
193              
194 198 100       400 if ($no_content_success) {
195 71         196 $data->{'cmd_return'} = 1;
196             }
197             else {
198 127         1860 $data->{'cmd_return'} = $decoded_json->{'value'};
199 127 50 66     2537 if ( ref( $data->{cmd_return} ) eq 'HASH'
200             && exists $data->{cmd_return}->{sessionId} )
201             {
202 0         0 $data->{sessionId} = $data->{cmd_return}->{sessionId};
203             }
204             }
205             }
206             else {
207 10         33 $data->{'cmd_return'} =
208             'Server returned status code '
209             . $response->code
210             . ' but no data';
211             }
212 208         3533 return $data;
213             }
214             else {
215             # No idea what the server is telling me, must be high
216 0           $data->{'cmd_status'} = 'NOTOK';
217 0           $data->{'cmd_return'} =
218             'Server returned status code '
219             . $response->code
220             . ' which I don\'t understand';
221 0           return $data;
222             }
223             }
224             }
225              
226             1;
227              
228             __END__