@@ -20,6 +20,7 @@ var Log = require('../lib/logger'),
20
20
logger = new Log ( global . logLevel ) ,
21
21
BrowserStack = require ( 'browserstack' ) ,
22
22
fs = require ( 'fs' ) ,
23
+ qs = require ( 'querystring' ) ,
23
24
chalk = require ( 'chalk' ) ,
24
25
config = require ( '../lib/config' ) ,
25
26
utils = require ( '../lib/utils' ) ,
@@ -32,6 +33,7 @@ var Log = require('../lib/logger'),
32
33
server ,
33
34
timeout ,
34
35
activityTimeout ,
36
+ ackTimeout ,
35
37
workers = { } ,
36
38
workerKeys = { } ,
37
39
tunnelingAgent ,
@@ -43,6 +45,7 @@ function terminateAllWorkers(callback) {
43
45
var worker = workers [ key ] ;
44
46
if ( worker ) {
45
47
logger . debug ( '[%s] Terminated' , worker . string ) ;
48
+ clearTimeout ( worker . ackTimeout ) ;
46
49
clearTimeout ( worker . activityTimeout ) ;
47
50
clearTimeout ( worker . testActivityTimeout ) ;
48
51
delete workers [ key ] ;
@@ -109,9 +112,24 @@ function getTestBrowserInfo(browserString, path) {
109
112
if ( config . multipleTest ) {
110
113
info += ', ' + path ;
111
114
}
115
+
112
116
return info ;
113
117
}
114
118
119
+
120
+ function buildTestUrl ( test_path , worker_key , browser_string ) {
121
+ var url = 'http://localhost:' + serverPort + '/' + test_path ;
122
+
123
+ var querystring = qs . stringify ( {
124
+ _worker_key : worker_key ,
125
+ _browser_string : browser_string
126
+ } ) ;
127
+
128
+ url += ( ( url . indexOf ( '?' ) > 0 ) ? '&' : '?' ) + querystring ;
129
+ return url ;
130
+ }
131
+
132
+
115
133
function launchServer ( ) {
116
134
logger . debug ( 'Launching server on port:' , serverPort ) ;
117
135
@@ -120,20 +138,12 @@ function launchServer() {
120
138
}
121
139
122
140
function launchBrowser ( browser , path ) {
123
- var url = 'http://localhost:' + serverPort . toString ( ) + '/' + path . replace ( / \\ / g, '/' ) ;
124
- var browserString = utils . browserString ( browser ) ;
125
- logger . debug ( '[%s] Launching' , getTestBrowserInfo ( browserString , path ) ) ;
126
-
127
141
var key = utils . uuid ( ) ;
142
+ var browserString = utils . browserString ( browser ) ;
143
+ var browserInfo = getTestBrowserInfo ( browserString , path ) ;
144
+ logger . debug ( '[%s] Launching' , browserInfo ) ;
128
145
129
- if ( url . indexOf ( '?' ) > 0 ) {
130
- url += '&' ;
131
- } else {
132
- url += '?' ;
133
- }
134
-
135
- url += '_worker_key=' + key + '&_browser_string=' + browserString ;
136
- browser [ 'url' ] = url ;
146
+ browser . url = buildTestUrl ( path . replace ( / \\ / g, '/' ) , key , browserString ) ;
137
147
138
148
if ( config . project ) {
139
149
browser . project = config . project ;
@@ -153,6 +163,7 @@ function launchBrowser(browser, path) {
153
163
timeout = 300 ;
154
164
}
155
165
activityTimeout = timeout - 10 ;
166
+ ackTimeout = parseInt ( config . ackTimeout ) || 60 ;
156
167
157
168
client . createWorker ( browser , function ( err , worker ) {
158
169
if ( err || typeof worker !== 'object' ) {
@@ -169,10 +180,13 @@ function launchBrowser(browser, path) {
169
180
worker . string = browserString ;
170
181
worker . test_path = path ;
171
182
worker . path_index = 0 ;
183
+
184
+ // attach helper methods to manage worker state
185
+ attachWorkerHelpers ( worker ) ;
186
+
172
187
workers [ key ] = worker ;
173
188
workerKeys [ worker . id ] = { key : key , marked : false } ;
174
189
} ) ;
175
-
176
190
}
177
191
178
192
function launchBrowsers ( config , browser ) {
@@ -187,6 +201,63 @@ function launchBrowsers(config, browser) {
187
201
} , 100 ) ;
188
202
}
189
203
204
+
205
+ function attachWorkerHelpers ( worker ) {
206
+ // TODO: Consider creating instances of a proper 'Worker' class
207
+
208
+ worker . buildUrl = function buildUrl ( test_path ) {
209
+ return buildTestUrl ( test_path || this . test_path , this . _worker_key , this . getTestBrowserInfo ( ) ) ;
210
+ } ;
211
+
212
+ worker . getTestBrowserInfo = function getTestBrowserInfo ( test_path ) {
213
+ var info = this . string ;
214
+ if ( config . multipleTest ) {
215
+ info += ', ' + ( test_path || this . test_path ) ;
216
+ }
217
+ return info ;
218
+ } ;
219
+
220
+ worker . awaitAck = function awaitAck ( ) {
221
+ var self = this ;
222
+
223
+ if ( this . ackTimeout ) {
224
+ // Already awaiting ack, or awaited ack once and failed
225
+ return ;
226
+ }
227
+
228
+ this . ackTimeout = setTimeout ( function ( ) {
229
+ if ( self . isAckd ) {
230
+ // Already ack'd
231
+ return ;
232
+ }
233
+
234
+ // worker has not acknowledged itself in 60 sec, reopen url
235
+ client . changeUrl ( self . id , { url : self . buildUrl ( ) } , function ( ) {
236
+ logger . debug ( "[%s] Sent Request to reload url" , self . getTestBrowserInfo ( ) ) ;
237
+ } ) ;
238
+
239
+ } , ackTimeout * 1000 ) ;
240
+
241
+ logger . debug ( '[%s] Awaiting ack' , this . getTestBrowserInfo ( ) ) ;
242
+ } ;
243
+
244
+ worker . markAckd = function markAckd ( ) {
245
+ this . resetAck ( ) ;
246
+ this . isAckd = true ;
247
+
248
+ logger . debug ( '[%s] Received ack' , this . getTestBrowserInfo ( ) ) ;
249
+ } ;
250
+
251
+ worker . resetAck = function resetAck ( ) {
252
+ clearTimeout ( this . ackTimeout ) ;
253
+ this . ackTimeout = null ;
254
+ this . isAckd = false ;
255
+ } ;
256
+
257
+ return worker ;
258
+ }
259
+
260
+
190
261
var statusPoller = {
191
262
poller : null ,
192
263
@@ -208,10 +279,13 @@ var statusPoller = {
208
279
209
280
if ( _worker . status === 'running' ) {
210
281
//clearInterval(statusPoller);
211
- logger . debug ( '[%s] Launched' , getTestBrowserInfo ( worker . string , worker . test_path ) ) ;
282
+ logger . debug ( '[%s] Launched' , worker . getTestBrowserInfo ( ) ) ;
212
283
worker . launched = true ;
213
284
workerData . marked = true ;
214
285
286
+ // Await ack from browser-worker
287
+ worker . awaitAck ( ) ;
288
+
215
289
worker . activityTimeout = setTimeout ( function ( ) {
216
290
if ( ! worker . acknowledged ) {
217
291
var subject = 'Worker inactive for too long: ' + worker . string ;
0 commit comments