1 | // Licensed to the Software Freedom Conservancy (SFC) under one
|
2 | // or more contributor license agreements. See the NOTICE file
|
3 | // distributed with this work for additional information
|
4 | // regarding copyright ownership. The SFC licenses this file
|
5 | // to you under the Apache License, Version 2.0 (the
|
6 | // "License"); you may not use this file except in compliance
|
7 | // with the License. You may obtain a copy of the License at
|
8 | //
|
9 | // http://www.apache.org/licenses/LICENSE-2.0
|
10 | //
|
11 | // Unless required by applicable law or agreed to in writing,
|
12 | // software distributed under the License is distributed on an
|
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14 | // KIND, either express or implied. See the License for the
|
15 | // specific language governing permissions and limitations
|
16 | // under the License.
|
17 |
|
18 | /**
|
19 | * @fileoverview Various HTTP utilities.
|
20 | */
|
21 |
|
22 |
|
23 |
|
24 | const Executor = require('./index').Executor,
|
25 | HttpClient = require('./index').HttpClient,
|
26 | HttpRequest = require('./index').Request,
|
27 | Command = require('../lib/command').Command,
|
28 | CommandName = require('../lib/command').Name,
|
29 | error = require('../lib/error')
|
30 |
|
31 | /**
|
32 | * Queries a WebDriver server for its current status.
|
33 | * @param {string} url Base URL of the server to query.
|
34 | * @return {!Promise<!Object>} A promise that resolves with
|
35 | * a hash of the server status.
|
36 | */
|
37 | function getStatus(url) {
|
38 | const client = new HttpClient(url)
|
39 | const executor = new Executor(client)
|
40 | const command = new Command(CommandName.GET_SERVER_STATUS)
|
41 | return executor.execute(command)
|
42 | }
|
43 |
|
44 | class CancellationError {}
|
45 |
|
46 | // PUBLIC API
|
47 |
|
48 | /**
|
49 | * Queries a WebDriver server for its current status.
|
50 | * @param {string} url Base URL of the server to query.
|
51 | * @return {!Promise<!Object>} A promise that resolves with
|
52 | * a hash of the server status.
|
53 | */
|
54 | exports.getStatus = getStatus
|
55 |
|
56 | exports.CancellationError = CancellationError
|
57 |
|
58 | /**
|
59 | * Waits for a WebDriver server to be healthy and accepting requests.
|
60 | * @param {string} url Base URL of the server to query.
|
61 | * @param {number} timeout How long to wait for the server.
|
62 | * @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
|
63 | * if resolved before the server is ready, the wait will be terminated
|
64 | * early with a {@link CancellationError}.
|
65 | * @return {!Promise} A promise that will resolve when the server is ready, or
|
66 | * if the wait is cancelled.
|
67 | */
|
68 | exports.waitForServer = function (url, timeout, opt_cancelToken) {
|
69 | return new Promise((onResolve, onReject) => {
|
70 | let start = Date.now()
|
71 |
|
72 | let done = false
|
73 | let resolve = (status) => {
|
74 | done = true
|
75 | onResolve(status)
|
76 | }
|
77 | let reject = (err) => {
|
78 | done = true
|
79 | onReject(err)
|
80 | }
|
81 |
|
82 | if (opt_cancelToken) {
|
83 | opt_cancelToken.then((_) => reject(new CancellationError()))
|
84 | }
|
85 |
|
86 | checkServerStatus()
|
87 | function checkServerStatus() {
|
88 | return getStatus(url).then((status) => resolve(status), onError)
|
89 | }
|
90 |
|
91 | function onError(e) {
|
92 | // Some servers don't support the status command. If they are able to
|
93 | // response with an error, then can consider the server ready.
|
94 | if (e instanceof error.UnsupportedOperationError) {
|
95 | resolve({})
|
96 | return
|
97 | }
|
98 |
|
99 | if (Date.now() - start > timeout) {
|
100 | reject(Error('Timed out waiting for the WebDriver server at ' + url))
|
101 | } else {
|
102 | setTimeout(function () {
|
103 | if (!done) {
|
104 | checkServerStatus()
|
105 | }
|
106 | }, 50)
|
107 | }
|
108 | }
|
109 | })
|
110 | }
|
111 |
|
112 | /**
|
113 | * Polls a URL with GET requests until it returns a 2xx response or the
|
114 | * timeout expires.
|
115 | * @param {string} url The URL to poll.
|
116 | * @param {number} timeout How long to wait, in milliseconds.
|
117 | * @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
|
118 | * if resolved before the a 2xx response is received, the wait will be
|
119 | * terminated early with a {@link CancellationError}.
|
120 | * @return {!Promise} A promise that will resolve when a 2xx is received from
|
121 | * the given URL, or if the wait is cancelled.
|
122 | */
|
123 | exports.waitForUrl = function (url, timeout, opt_cancelToken) {
|
124 | return new Promise((onResolve, onReject) => {
|
125 | let client = new HttpClient(url)
|
126 | let request = new HttpRequest('GET', '')
|
127 | let start = Date.now()
|
128 |
|
129 | let done = false
|
130 | let resolve = () => {
|
131 | done = true
|
132 | onResolve()
|
133 | }
|
134 | let reject = (err) => {
|
135 | done = true
|
136 | onReject(err)
|
137 | }
|
138 |
|
139 | if (opt_cancelToken) {
|
140 | opt_cancelToken.then((_) => reject(new CancellationError()))
|
141 | }
|
142 |
|
143 | testUrl()
|
144 |
|
145 | function testUrl() {
|
146 | client.send(request).then(onResponse, onError)
|
147 | }
|
148 |
|
149 | function onError() {
|
150 | if (Date.now() - start > timeout) {
|
151 | reject(Error('Timed out waiting for the URL to return 2xx: ' + url))
|
152 | } else {
|
153 | setTimeout(function () {
|
154 | if (!done) {
|
155 | testUrl()
|
156 | }
|
157 | }, 50)
|
158 | }
|
159 | }
|
160 |
|
161 | function onResponse(response) {
|
162 | if (done) {
|
163 | return
|
164 | }
|
165 | if (response.status > 199 && response.status < 300) {
|
166 | resolve()
|
167 | return
|
168 | }
|
169 | onError()
|
170 | }
|
171 | })
|
172 | }
|