1 | var Promise = require('bluebird')
|
2 | var Batch = require('batch')
|
3 |
|
4 | var helper = require('./helper')
|
5 | var log = require('./logger').create('launcher')
|
6 |
|
7 | var baseDecorator = require('./launchers/base').decoratorFactory
|
8 | var captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
|
9 | var retryDecorator = require('./launchers/retry').decoratorFactory
|
10 | var processDecorator = require('./launchers/process').decoratorFactory
|
11 |
|
12 |
|
13 | var 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 |
|
23 | var 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 |
|
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 |
|
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 |
|
101 |
|
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 |
|
193 | emitter.on('exit', this.killAll)
|
194 | }
|
195 |
|
196 | Launcher.$inject = ['emitter', 'injector']
|
197 |
|
198 | Launcher.generateId = function () {
|
199 | return '' + Math.floor(Math.random() * 100000000)
|
200 | }
|
201 |
|
202 |
|
203 | exports.Launcher = Launcher
|