File Coverage

blib/lib/Selenium/Remote/RemoteConnection.pm
Criterion Covered Total %
statement 106 117 90.6
branch 36 42 85.7
condition 13 22 59.0
subroutine 18 19 94.7
pod 2 2 100.0
total 175 202 86.6


line stmt bran cond sub pod time code
1             package Selenium::Remote::RemoteConnection;
2             $Selenium::Remote::RemoteConnection::VERSION = '1.49';
3 15     15   1581 use strict;
  15         73  
  15         486  
4 15     15   110 use warnings;
  15         52  
  15         466  
5              
6             #ABSTRACT: Connect to a selenium server
7              
8 15     15   717 use Moo;
  15         6959  
  15         143  
9 15     15   7018 use Try::Tiny;
  15         51  
  15         1076  
10 15     15   8551 use LWP::UserAgent;
  15         498561  
  15         548  
11 15     15   133 use HTTP::Headers;
  15         34  
  15         387  
12 15     15   94 use HTTP::Request;
  15         48  
  15         413  
13 15     15   93 use Carp qw(croak);
  15         50  
  15         876  
14 15     15   7776 use JSON;
  15         118854  
  15         129  
15 15     15   11418 use Data::Dumper;
  15         88140  
  15         963  
16 15     15   7361 use Selenium::Remote::ErrorHandler;
  15         94  
  15         673  
17 15     15   120 use Scalar::Util qw{looks_like_number};
  15         36  
  15         18059  
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   26 builder => sub { return LWP::UserAgent->new; }
31             );
32              
33             has 'error_handler' => (
34             is => 'lazy',
35 4     4   86 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 134 my $self = shift;
43 10         22 my $status;
44              
45             try {
46 10     10   577 $status = $self->request( { method => 'GET', url => 'status' } );
47             }
48             catch {
49 0     0   0 croak "Could not connect to SeleniumWebDriver: $_";
50 10         91 };
51              
52 10   50     210 my $cmdOut = $status->{cmd_status} || '';
53 10 100       40 if ( $cmdOut ne 'OK' ) {
54              
55             # Could be grid, see if we can talk to it
56 1         3 $status = undef;
57 1         5 $status =
58             $self->request( { method => 'GET', url => 'grid/api/hub/status' } );
59             }
60              
61 10 100       51 unless ( $cmdOut eq 'OK' ) {
62 1         141 croak "Selenium server did not return proper status";
63             }
64             }
65              
66              
67             sub request {
68 30     30 1 981 my ( $self, $resource, $params, $dont_process_response ) = @_;
69 30         64 my $method = $resource->{method};
70 30         66 my $url = $resource->{url};
71 30   100     128 my $no_content_success = $resource->{no_content_success} // 0;
72              
73 30         58 my $content = '';
74 30         114 my $fullurl = '';
75              
76             # Construct full url.
77 30 100       157 if ( $url =~ m/^http/g ) {
    100          
    100          
78 3         7 $fullurl = $url;
79             }
80             elsif ( $url =~ m/^\// ) {
81              
82             # This is used when we get a 302 Redirect with a Location header.
83 1         8 $fullurl =
84             "http://" . $self->remote_server_addr . ":" . $self->port . $url;
85             }
86             elsif ( $url =~ m/grid/g ) {
87 2         21 $fullurl =
88             "http://" . $self->remote_server_addr . ":" . $self->port . "/$url";
89             }
90             else {
91 24         529 $fullurl =
92             "http://"
93             . $self->remote_server_addr . ":"
94             . $self->port
95             . $self->wd_context_prefix . "/$url";
96             }
97              
98 30 100 66     326 if ( ( defined $params ) && $params ne '' ) {
99              
100             #WebDriver 3 shims
101 16 100       80 if ( $resource->{payload} ) {
102 1         2 foreach my $key ( keys( %{ $resource->{payload} } ) ) {
  1         6  
103 1         52 $params->{$key} = $resource->{payload}->{$key};
104             }
105             }
106              
107 16         114 my $json = JSON->new;
108 16         82 $json->allow_blessed;
109 16         254 $content = $json->allow_nonref->utf8->encode($params);
110             }
111              
112 30 50       111 print "REQ: $method, $fullurl, $content\n" if $self->debug;
113              
114             # HTTP request
115 30         131 my $header =
116             HTTP::Headers->new( Content_Type => 'application/json; charset=utf-8' );
117 30         1671 $header->header( 'Accept' => 'application/json' );
118 30         1274 my $request = HTTP::Request->new( $method, $fullurl, $header, $content );
119 30         41827 my $response = $self->ua->request($request);
120 30 100       67992 if ($dont_process_response) {
121 1         6 return $response;
122             }
123 29         106 return $self->_process_response( $response, $no_content_success );
124             }
125              
126             sub _process_response {
127 230     230   573 my ( $self, $response, $no_content_success ) = @_;
128 230         370 my $data; # server response 'value' that'll be returned to the user
129 230         989 my $json = JSON->new;
130              
131 230 100       741 if ( $response->is_redirect ) {
132 2         25 my $redirect = {
133             method => 'GET',
134             url => $response->header('location')
135             };
136 2         114 return $self->request($redirect);
137             }
138             else {
139 228         2020 my $decoded_json = undef;
140 228 100       986 print "RES: " . $response->decoded_content . "\n\n" if $self->debug;
141              
142 228 100 66     19641 if ( ( $response->message ne 'No Content' )
143             && ( $response->content ne '' ) )
144             {
145 217 100       5921 if ( $response->content_type !~ m/json/i ) {
146 2         70 $data->{'cmd_status'} = 'NOTOK';
147             $data->{'cmd_return'}->{message} =
148 2         6 'Server returned error message '
149             . $response->content
150             . ' instead of data';
151 2         53 return $data;
152             }
153             $decoded_json =
154 215         8844 $json->allow_nonref(1)->utf8(1)->decode( $response->content );
155 215         19624 $data->{'sessionId'} = $decoded_json->{'sessionId'};
156             }
157              
158 226 100       1014 if ( $response->is_error ) {
    50          
159 18         199 $data->{'cmd_status'} = 'NOTOK';
160 18 100       66 if ( defined $decoded_json ) {
161 17         508 $data->{'cmd_return'} =
162             $self->error_handler->process_error($decoded_json);
163             }
164             else {
165 1         6 $data->{'cmd_return'} =
166             'Server returned error code '
167             . $response->code
168             . ' and no data';
169             }
170 18         363 return $data;
171             }
172             elsif ( $response->is_success ) {
173 208         2843 $data->{'cmd_status'} = 'OK';
174 208 100       469 if ( defined $decoded_json ) {
175              
176             #XXX MS edge doesn't follow spec here either
177 198 0 66     1222 if ( looks_like_number( $decoded_json->{status} )
      33        
178             && $decoded_json->{status} > 0
179             && $decoded_json->{value}{message} )
180             {
181 0         0 $data->{cmd_status} = 'NOT OK';
182 0         0 $data->{cmd_return} = $decoded_json->{value};
183 0         0 return $data;
184             }
185              
186             #XXX shockingly, neither does InternetExplorerDriver
187 198 50 33     969 if ( ref $decoded_json eq 'HASH' && $decoded_json->{error} ) {
188 0         0 $data->{cmd_status} = 'NOT OK';
189 0         0 $data->{cmd_return} = $decoded_json;
190 0         0 return $data;
191             }
192              
193 198 100       422 if ($no_content_success) {
194 71         183 $data->{'cmd_return'} = 1;
195             }
196             else {
197 127         282 $data->{'cmd_return'} = $decoded_json->{'value'};
198 127 50 66     467 if ( ref( $data->{cmd_return} ) eq 'HASH'
199             && exists $data->{cmd_return}->{sessionId} )
200             {
201 0         0 $data->{sessionId} = $data->{cmd_return}->{sessionId};
202             }
203             }
204             }
205             else {
206 10         40 $data->{'cmd_return'} =
207             'Server returned status code '
208             . $response->code
209             . ' but no data';
210             }
211 208         2781 return $data;
212             }
213             else {
214             # No idea what the server is telling me, must be high
215 0           $data->{'cmd_status'} = 'NOTOK';
216 0           $data->{'cmd_return'} =
217             'Server returned status code '
218             . $response->code
219             . ' which I don\'t understand';
220 0           return $data;
221             }
222             }
223             }
224              
225             1;
226              
227             __END__