UNPKG

5.22 kBJavaScriptView Raw
1var Promise = require('bluebird')
2var Batch = require('batch')
3
4var helper = require('./helper')
5var log = require('./logger').create('launcher')
6
7var baseDecorator = require('./launchers/base').decoratorFactory
8var captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
9var retryDecorator = require('./launchers/retry').decoratorFactory
10var processDecorator = require('./launchers/process').decoratorFactory
11
12// TODO(vojta): remove once nobody uses it
13var baseBrowserDecoratorFactory = function (baseLauncherDecorator, captureTimeoutLauncherDecorator,
14 retryLauncherDecorator, processLauncherDecorator) {
15 return function (launcher) {
16 baseLauncherDecorator(launcher)
17 captureTimeoutLauncherDecorator(launcher)
18 retryLauncherDecorator(launcher)
19 processLauncherDecorator(launcher)
20 }
21}
22
23var Launcher = function (emitter, injector) {
24 var browsers = []
25 var lastStartTime
26
27 var getBrowserById = function (id) {
28 for (var i = 0; i < browsers.length; i++) {
29 if (browsers[i].id === id) {
30 return browsers[i]
31 }
32 }
33
34 return null
35 }
36
37 this.launch = function (names, protocol, hostname, port, urlRoot, concurrency) {
38 var url = protocol + '//' + hostname + ':' + port + urlRoot
39 var batch = new Batch()
40 batch.concurrency(concurrency)
41
42 lastStartTime = Date.now()
43
44 names.forEach(function (name) {
45 var locals = {
46 id: ['value', Launcher.generateId()],
47 name: ['value', name],
48 baseLauncherDecorator: ['factory', baseDecorator],
49 captureTimeoutLauncherDecorator: ['factory', captureTimeoutDecorator],
50 retryLauncherDecorator: ['factory', retryDecorator],
51 processLauncherDecorator: ['factory', processDecorator],
52 baseBrowserDecorator: ['factory', baseBrowserDecoratorFactory]
53 }
54
55 // TODO(vojta): determine script from name
56 if (name.indexOf('/') !== -1) {
57 name = 'Script'
58 }
59
60 try {
61 var browser = injector.createChild([locals], ['launcher:' + name]).get('launcher:' + name)
62 } catch (e) {
63 if (e.message.indexOf('No provider for "launcher:' + name + '"') !== -1) {
64 log.warn('Can not load "%s", it is not registered!\n ' +
65 'Perhaps you are missing some plugin?', name)
66 } else {
67 log.warn('Can not load "%s"!\n ' + e.stack, name)
68 }
69
70 return
71 }
72
73 // TODO(vojta): remove in v1.0 (BC for old launchers)
74 if (!browser.forceKill) {
75 browser.forceKill = function () {
76 var self = this
77
78 return new Promise(function (resolve) {
79 self.kill(resolve)
80 })
81 }
82
83 browser.restart = function () {
84 var self = this
85 this.kill(function () {
86 self.start(url)
87 })
88 }
89 }
90
91 batch.push(function (done) {
92 log.info('Starting browser %s', helper.isDefined(browser.displayName) ? browser.displayName : browser.name)
93
94 browser.start(url)
95 browser.on('browser_process_failure', function () {
96 done(browser.error)
97 })
98
99 browser.on('done', function () {
100 // We are not done if there was an error as first the retry takes
101 // place which we catch with `browser_process_failure` if it fails
102 if (browser.error) return
103
104 done(null, browser)
105 })
106 })
107
108 browsers.push(browser)
109 })
110
111 batch.end(function (err) {
112 log.debug('Finished all browsers')
113
114 if (err) {
115 log.error(err)
116 }
117 })
118
119 return browsers
120 }
121
122 this.launch.$inject = [
123 'config.browsers',
124 'config.protocol',
125 'config.hostname',
126 'config.port',
127 'config.urlRoot',
128 'config.concurrency'
129 ]
130
131 this.kill = function (id, callback) {
132 var browser = getBrowserById(id)
133 callback = callback || function () {}
134
135 if (!browser) {
136 process.nextTick(callback)
137 return false
138 }
139
140 browser.forceKill().then(callback)
141 return true
142 }
143
144 this.restart = function (id) {
145 var browser = getBrowserById(id)
146
147 if (!browser) {
148 return false
149 }
150
151 browser.restart()
152 return true
153 }
154
155 this.killAll = function (callback) {
156 log.debug('Disconnecting all browsers')
157
158 var remaining = 0
159 var finish = function () {
160 remaining--
161 if (!remaining && callback) {
162 callback()
163 }
164 }
165
166 if (!browsers.length) {
167 return process.nextTick(callback)
168 }
169
170 browsers.forEach(function (browser) {
171 remaining++
172 browser.forceKill().then(finish)
173 })
174 }
175
176 this.areAllCaptured = function () {
177 return !browsers.some(function (browser) {
178 return !browser.isCaptured()
179 })
180 }
181
182 this.markCaptured = function (id) {
183 browsers.forEach(function (browser) {
184 if (browser.id === id) {
185 browser.markCaptured()
186 log.debug('%s (id %s) captured in %d secs', browser.name, browser.id,
187 (Date.now() - lastStartTime) / 1000)
188 }
189 })
190 }
191
192 // register events
193 emitter.on('exit', this.killAll)
194}
195
196Launcher.$inject = ['emitter', 'injector']
197
198Launcher.generateId = function () {
199 return '' + Math.floor(Math.random() * 100000000)
200}
201
202// PUBLISH
203exports.Launcher = Launcher