node_modules/selenium-webdriver/remote/index.js

Maintainability

73.46

Lines of code

287

Created with Raphaël 2.1.002550751002014-12-3

2014-12-4
Maintainability: 73.46

Created with Raphaël 2.1.00751502253002014-12-3

2014-12-4
Lines of Code: 287

Difficulty

31.03

Estimated Errors

1.28

Function weight

By Complexity

Created with Raphaël 2.1.0DriverService4

By SLOC

Created with Raphaël 2.1.0<anonymous>.start47
1
// Copyright 2013 Software Freedom Conservancy
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
//     You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
'use strict';
Column: 1 "Use the function form of "use strict"."
16
 
17
var path = require('path'),
Column: 12 "'require' is not defined."
18
    url = require('url'),
Column: 11 "'require' is not defined."
19
    util = require('util');
Column: 12 "'require' is not defined."
20
 
21
var promise = require('../').promise,
Column: 15 "'require' is not defined."
22
    httpUtil = require('../http/util'),
Column: 16 "'require' is not defined."
23
    exec = require('../io/exec'),
Column: 12 "'require' is not defined."
24
    net = require('../net'),
Column: 11 "'require' is not defined."
25
    portprober = require('../net/portprober');
Column: 18 "'require' is not defined."
26
 
27
 
28
 
29
/**
30
 * Configuration options for a DriverService instance.
31
 * <ul>
32
 * <li>
33
 * <li>{@code loopback} - Whether the service should only be accessed on this
34
 *     host's loopback address.
35
 * <li>{@code port} - The port to start the server on (must be > 0). If the
36
 *     port is provided as a promise, the service will wait for the promise to
37
 *     resolve before starting.
38
 * <li>{@code args} - The arguments to pass to the service. If a promise is
39
 *     provided, the service will wait for it to resolve before starting.
40
 * <li>{@code path} - The base path on the server for the WebDriver wire
41
 *     protocol (e.g. '/wd/hub'). Defaults to '/'.
42
 * <li>{@code env} - The environment variables that should be visible to the
43
 *     server process. Defaults to inheriting the current process's
44
 *     environment.
45
 * <li>{@code stdio} - IO configuration for the spawned server process. For
46
 *     more information, refer to the documentation of
47
 *     {@code child_process.spawn}.
48
 * </ul>
49
 *
50
 * @typedef {{
51
 *   port: (number|!webdriver.promise.Promise.<number>),
52
 *   args: !(Array.<string>|webdriver.promise.Promise.<!Array.<string>>),
53
 *   path: (string|undefined),
54
 *   env: (!Object.<string, string>|undefined),
55
 *   stdio: (string|!Array.<string|number|!Stream|null|undefined>|undefined)
56
 * }}
57
 */
58
var ServiceOptions;
59
 
60
 
61
/**
62
 * Manages the life and death of a native executable WebDriver server.
63
 *
64
 * <p>It is expected that the driver server implements the
65
 * <a href="http://code.google.com/p/selenium/wiki/JsonWireProtocol">WebDriver
66
 * Wire Protocol</a>. Furthermore, the managed server should support multiple
67
 * concurrent sessions, so that this class may be reused for multiple clients.
68
 *
69
 * @param {string} executable Path to the executable to run.
70
 * @param {!ServiceOptions} options Configuration options for the service.
71
 * @constructor
72
 */
73
function DriverService(executable, options) {
74
 
75
  /** @private {string} */
76
  this.executable_ = executable;
77
 
78
  /** @private {boolean} */
79
  this.loopbackOnly_ = !!options.loopback;
80
 
81
  /** @private {(number|!webdriver.promise.Promise.<number>)} */
82
  this.port_ = options.port;
83
 
84
  /**
85
   * @private {!(Array.<string>|webdriver.promise.Promise.<!Array.<string>>)}
86
   */
87
  this.args_ = options.args;
88
 
89
  /** @private {string} */
90
  this.path_ = options.path || '/';
91
 
92
  /** @private {!Object.<string, string>} */
93
  this.env_ = options.env || process.env;
Column: 30 "'process' is not defined."
94
 
95
  /** @private {(string|!Array.<string|number|!Stream|null|undefined>)} */
96
  this.stdio_ = options.stdio || 'ignore';
97
 
98
  /**
99
   * A promise for the managed subprocess, or null if the server has not been
100
   * started yet. This promise will never be rejected.
101
   * @private {promise.Promise.<!exec.Command>}
102
   */
103
  this.command_ = null;
104
 
105
  /**
106
   * Promise that resolves to the server's address or null if the server has
107
   * not been started. This promise will be rejected if the server terminates
108
   * before it starts accepting WebDriver requests.
109
   * @private {promise.Promise.<string>}
110
   */
111
  this.address_ = null;
112
}
113
 
114
 
115
/**
116
 * The default amount of time, in milliseconds, to wait for the server to
117
 * start.
118
 * @type {number}
119
 */
120
DriverService.DEFAULT_START_TIMEOUT_MS = 30 * 1000;
121
 
122
 
123
/**
124
 * @return {!webdriver.promise.Promise.<string>} A promise that resolves to
125
 *    the server's address.
126
 * @throws {Error} If the server has not been started.
127
 */
128
DriverService.prototype.address = function() {
129
  if (this.address_) {
130
    return this.address_;
131
  }
132
  throw Error('Server has not been started.');
133
};
134
 
135
 
136
/**
137
 * Returns whether the underlying process is still running. This does not take
138
 * into account whether the process is in the process of shutting down.
139
 * @return {boolean} Whether the underlying service process is running.
140
 */
141
DriverService.prototype.isRunning = function() {
142
  return !!this.address_;
143
};
144
 
145
 
146
/**
147
 * Starts the server if it is not already running.
148
 * @param {number=} opt_timeoutMs How long to wait, in milliseconds, for the
149
 *     server to start accepting requests. Defaults to 30 seconds.
150
 * @return {!promise.Promise.<string>} A promise that will resolve
151
 *     to the server's base URL when it has started accepting requests. If the
152
 *     timeout expires before the server has started, the promise will be
153
 *     rejected.
154
 */
155
DriverService.prototype.start = function(opt_timeoutMs) {
156
  if (this.address_) {
157
    return this.address_;
158
  }
159
 
160
  var timeout = opt_timeoutMs || DriverService.DEFAULT_START_TIMEOUT_MS;
161
 
162
  var self = this;
163
  this.command_ = promise.defer();
164
  this.address_ = promise.defer();
165
  this.address_.fulfill(promise.when(this.port_, function(port) {
166
    if (port <= 0) {
167
      throw Error('Port must be > 0: ' + port);
168
    }
169
    return promise.when(self.args_, function(args) {
170
      var command = exec(self.executable_, {
171
        args: args,
172
        env: self.env_,
173
        stdio: self.stdio_
174
      });
175
 
176
      self.command_.fulfill(command);
177
 
178
      command.result().then(function(result) {
179
        self.address_.reject(result.code == null ?
Column: 42 "Use '===' to compare with 'null'."
180
            Error('Server was killed with ' + result.signal) :
181
            Error('Server exited with ' + result.code));
182
        self.address_ = null;
183
        self.command_ = null;
184
      });
185
 
186
      var serverUrl = url.format({
187
        protocol: 'http',
188
        hostname: !self.loopbackOnly_ && net.getAddress() ||
189
            net.getLoopbackAddress(),
190
        port: port,
191
        pathname: self.path_
192
      });
193
 
194
      return httpUtil.waitForServer(serverUrl, timeout).then(function() {
195
        return serverUrl;
196
      });
197
    });
198
  }));
199
 
200
  return this.address_;
201
};
202
 
203
 
204
/**
205
 * Stops the service if it is not currently running. This function will kill
206
 * the server immediately. To synchronize with the active control flow, use
207
 * {@link #stop()}.
208
 * @return {!webdriver.promise.Promise} A promise that will be resolved when
209
 *     the server has been stopped.
210
 */
211
DriverService.prototype.kill = function() {
212
  if (!this.address_ || !this.command_) {
213
    return promise.fulfilled();  // Not currently running.
214
  }
215
  return this.command_.then(function(command) {
216
    command.kill('SIGTERM');
217
  });
218
};
219
 
220
 
221
/**
222
 * Schedules a task in the current control flow to stop the server if it is
223
 * currently running.
224
 * @return {!webdriver.promise.Promise} A promise that will be resolved when
225
 *     the server has been stopped.
226
 */
227
DriverService.prototype.stop = function() {
228
  return promise.controlFlow().execute(this.kill.bind(this));
229
};
230
 
231
 
232
 
233
/**
234
 * Manages the life and death of the Selenium standalone server. The server
235
 * may be obtained from http://selenium-release.storage.googleapis.com/index.html.
236
 * @param {string} jar Path to the Selenium server jar.
237
 * @param {!SeleniumServer.Options} options Configuration options for the
238
 *     server.
239
 * @throws {Error} If an invalid port is specified.
240
 * @constructor
241
 * @extends {DriverService}
242
 */
243
function SeleniumServer(jar, options) {
244
  if (options.port < 0)
245
    throw Error('Port must be >= 0: ' + options.port);
246
 
247
  var port = options.port || portprober.findFreePort();
248
  var args = promise.when(options.jvmArgs || [], function(jvmArgs) {
249
    return promise.when(options.args || [], function(args) {
250
      return promise.when(port, function(port) {
251
        return jvmArgs.concat(['-jar', jar, '-port', port]).concat(args);
252
      });
253
    });
254
  });
255
 
256
  DriverService.call(this, 'java', {
257
    port: port,
258
    args: args,
259
    path: '/wd/hub',
260
    env: options.env,
261
    stdio: options.stdio
262
  });
263
}
264
util.inherits(SeleniumServer, DriverService);
265
 
266
 
267
/**
268
 * Options for the Selenium server:
269
 * <ul>
270
 * <li>{@code port} - The port to start the server on (must be > 0). If the
271
 *     port is provided as a promise, the service will wait for the promise to
272
 *     resolve before starting.
273
 * <li>{@code args} - The arguments to pass to the service. If a promise is
274
 *     provided, the service will wait for it to resolve before starting.
275
 * <li>{@code jvmArgs} - The arguments to pass to the JVM. If a promise is
276
 *     provided, the service will wait for it to resolve before starting.
277
 * <li>{@code env} - The environment variables that should be visible to the
278
 *     server process. Defaults to inheriting the current process's
279
 *     environment.
280
 * <li>{@code stdio} - IO configuration for the spawned server process. For
281
 *     more information, refer to the documentation of
282
 *     {@code child_process.spawn}.
283
 * </ul>
284
 *
285
 * @typedef {{
286
 *   port: (number|!webdriver.promise.Promise.<number>),
287
 *   args: !(Array.<string>|webdriver.promise.Promise.<!Array.<string>>),
288
 *   jvmArgs: (!Array.<string>|
289
 *             !webdriver.promise.Promise.<!Array.<string>>|
290
 *             undefined),
291
 *   env: (!Object.<string, string>|undefined),
292
 *   stdio: (string|!Array.<string|number|!Stream|null|undefined>|undefined)
293
 * }}
294
 */
295
SeleniumServer.Options;
Column: 16 "Expected an assignment or function call and instead saw an expression."
296
 
297
 
298
// PUBLIC API
299
 
300
exports.DriverService = DriverService;
Column: 1 "'exports' is not defined."
301
exports.SeleniumServer = SeleniumServer;
Column: 1 "'exports' is not defined."