14
14
15
15
'use strict' ;
16
16
17
- var spawn = require ( 'child_process' ) . spawn ,
18
- os = require ( 'os' ) ,
19
- path = require ( 'path' ) ,
17
+ var path = require ( 'path' ) ,
20
18
url = require ( 'url' ) ,
21
19
util = require ( 'util' ) ;
22
20
23
21
var promise = require ( '../' ) . promise ,
24
22
httpUtil = require ( '../http/util' ) ,
23
+ exec = require ( '../io/exec' ) ,
25
24
net = require ( '../net' ) ,
26
25
portprober = require ( '../net/portprober' ) ;
27
26
@@ -95,6 +94,21 @@ function DriverService(executable, options) {
95
94
96
95
/** @private {(string|!Array.<string|number|!Stream|null|undefined>)} */
97
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 ;
98
112
}
99
113
100
114
@@ -106,26 +120,6 @@ function DriverService(executable, options) {
106
120
DriverService . DEFAULT_START_TIMEOUT_MS = 30 * 1000 ;
107
121
108
122
109
- /** @private {child_process.ChildProcess} */
110
- DriverService . prototype . process_ = null ;
111
-
112
-
113
- /**
114
- * Promise that resolves to the server's address or null if the server has not
115
- * been started.
116
- * @private {webdriver.promise.Promise.<string>}
117
- */
118
- DriverService . prototype . address_ = null ;
119
-
120
-
121
- /**
122
- * Promise that tracks the status of shutting down the server, or null if the
123
- * server is not currently shutting down.
124
- * @private {webdriver.promise.Promise}
125
- */
126
- DriverService . prototype . shutdownHook_ = null ;
127
-
128
-
129
123
/**
130
124
* @return {!webdriver.promise.Promise.<string> } A promise that resolves to
131
125
* the server's address.
@@ -140,6 +134,8 @@ DriverService.prototype.address = function() {
140
134
141
135
142
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.
143
139
* @return {boolean } Whether the underlying service process is running.
144
140
*/
145
141
DriverService . prototype . isRunning = function ( ) {
@@ -151,7 +147,7 @@ DriverService.prototype.isRunning = function() {
151
147
* Starts the server if it is not already running.
152
148
* @param {number= } opt_timeoutMs How long to wait, in milliseconds, for the
153
149
* server to start accepting requests. Defaults to 30 seconds.
154
- * @return {!webdriver. promise.Promise.<string> } A promise that will resolve
150
+ * @return {!promise.Promise.<string> } A promise that will resolve
155
151
* to the server's base URL when it has started accepting requests. If the
156
152
* timeout expires before the server has started, the promise will be
157
153
* rejected.
@@ -164,21 +160,28 @@ DriverService.prototype.start = function(opt_timeoutMs) {
164
160
var timeout = opt_timeoutMs || DriverService . DEFAULT_START_TIMEOUT_MS ;
165
161
166
162
var self = this ;
163
+ this . command_ = promise . defer ( ) ;
167
164
this . address_ = promise . defer ( ) ;
168
165
this . address_ . fulfill ( promise . when ( this . port_ , function ( port ) {
169
166
if ( port <= 0 ) {
170
167
throw Error ( 'Port must be > 0: ' + port ) ;
171
168
}
172
169
return promise . when ( self . args_ , function ( args ) {
173
- self . process_ = spawn ( self . executable_ , args , {
170
+ var command = exec ( self . executable_ , {
171
+ args : args ,
174
172
env : self . env_ ,
175
173
stdio : self . stdio_
176
- } ) . once ( 'exit' , onServerExit ) ;
174
+ } ) ;
175
+
176
+ self . command_ . fulfill ( command ) ;
177
177
178
- // This process should not wait on the spawned child, however, we do
179
- // want to ensure the child is killed when this process exits.
180
- self . process_ . unref ( ) ;
181
- process . once ( 'exit' , killServer ) ;
178
+ command . result ( ) . then ( function ( result ) {
179
+ self . address_ . reject ( result . code == 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
+ } ) ;
182
185
183
186
var serverUrl = url . format ( {
184
187
protocol : 'http' ,
@@ -195,26 +198,6 @@ DriverService.prototype.start = function(opt_timeoutMs) {
195
198
} ) ) ;
196
199
197
200
return this . address_ ;
198
-
199
- function onServerExit ( code , signal ) {
200
- self . address_ . reject ( code == null ?
201
- Error ( 'Server was killed with ' + signal ) :
202
- Error ( 'Server exited with ' + code ) ) ;
203
-
204
- if ( self . shutdownHook_ ) {
205
- self . shutdownHook_ . fulfill ( ) ;
206
- }
207
-
208
- self . shutdownHook_ = null ;
209
- self . address_ = null ;
210
- self . process_ = null ;
211
- process . removeListener ( 'exit' , killServer ) ;
212
- }
213
-
214
- function killServer ( ) {
215
- process . removeListener ( 'exit' , killServer ) ;
216
- self . process_ && self . process_ . kill ( 'SIGTERM' ) ;
217
- }
218
201
} ;
219
202
220
203
@@ -226,26 +209,12 @@ DriverService.prototype.start = function(opt_timeoutMs) {
226
209
* the server has been stopped.
227
210
*/
228
211
DriverService . prototype . kill = function ( ) {
229
- if ( ! this . address_ ) {
212
+ if ( ! this . address_ || ! this . command_ ) {
230
213
return promise . fulfilled ( ) ; // Not currently running.
231
214
}
232
-
233
- if ( ! this . shutdownHook_ ) {
234
- // No process: still starting; wait on address.
235
- // Otherwise, kill the process now. Exit handler will resolve the
236
- // shutdown hook.
237
- if ( this . process_ ) {
238
- this . shutdownHook_ = promise . defer ( ) ;
239
- this . process_ . kill ( 'SIGTERM' ) ;
240
- } else {
241
- var self = this ;
242
- this . shutdownHook_ = this . address_ . thenFinally ( function ( ) {
243
- self . process_ && self . process_ . kill ( 'SIGTERM' ) ;
244
- } ) ;
245
- }
246
- }
247
-
248
- return this . shutdownHook_ ;
215
+ return this . command_ . then ( function ( command ) {
216
+ command . kill ( 'SIGTERM' ) ;
217
+ } ) ;
249
218
} ;
250
219
251
220
0 commit comments