Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(launcher): Update launcher to ES6 #3014

Merged
merged 1 commit into from
May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 69 additions & 131 deletions lib/launcher.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
var Promise = require('bluebird')
var Jobs = require('qjobs')
'use strict'

var helper = require('./helper')
var log = require('./logger').create('launcher')
const Promise = require('bluebird')
const Jobs = require('qjobs')

var baseDecorator = require('./launchers/base').decoratorFactory
var captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
var retryDecorator = require('./launchers/retry').decoratorFactory
var processDecorator = require('./launchers/process').decoratorFactory
const log = require('./logger').create('launcher')

const baseDecorator = require('./launchers/base').decoratorFactory
const captureTimeoutDecorator = require('./launchers/capture_timeout').decoratorFactory
const retryDecorator = require('./launchers/retry').decoratorFactory
const processDecorator = require('./launchers/process').decoratorFactory

// TODO(vojta): remove once nobody uses it
var baseBrowserDecoratorFactory = function (
const baseBrowserDecoratorFactory = function (
baseLauncherDecorator,
captureTimeoutLauncherDecorator,
retryLauncherDecorator,
Expand All @@ -25,34 +26,22 @@ var baseBrowserDecoratorFactory = function (
}
}

var Launcher = function (server, emitter, injector) {
function Launcher (server, emitter, injector) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not update it to be real class?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Actually I prefer small refactoring steps, so doing this next is my pref).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey, I see.

this._browsers = []
var lastStartTime
var self = this

var getBrowserById = function (id) {
for (var i = 0; i < self._browsers.length; i++) {
if (self._browsers[i].id === id) {
return self._browsers[i]
}
}
let lastStartTime

return null
}
const getBrowserById = (id) => this._browsers.find((browser) => browser.id === id)

this.launchSingle = function (protocol, hostname, port, urlRoot, upstreamProxy, processKillTimeout) {
var self = this
return function (name) {
name = (name + '').trim()
if (upstreamProxy) {
protocol = upstreamProxy.protocol
hostname = upstreamProxy.hostname
port = upstreamProxy.port
urlRoot = upstreamProxy.path + urlRoot.substr(1)
}
var url = protocol + '//' + hostname + ':' + port + urlRoot
this.launchSingle = (protocol, hostname, port, urlRoot, upstreamProxy, processKillTimeout) => {
if (upstreamProxy) {
protocol = upstreamProxy.protocol
hostname = upstreamProxy.hostname
port = upstreamProxy.port
urlRoot = upstreamProxy.path + urlRoot.substr(1)
}

var locals = {
return (name) => {
const locals = {
id: ['value', Launcher.generateId()],
name: ['value', name],
processKillTimeout: ['value', processKillTimeout],
Expand All @@ -71,81 +60,53 @@ var Launcher = function (server, emitter, injector) {
try {
var browser = injector.createChild([locals], ['launcher:' + name]).get('launcher:' + name)
} catch (e) {
if (e.message.indexOf('No provider for "launcher:' + name + '"') !== -1) {
log.error('Cannot load browser "%s": it is not registered! ' +
'Perhaps you are missing some plugin?', name)
if (e.message.indexOf(`No provider for "launcher:${name}"`) !== -1) {
log.error(`Cannot load browser "${name}": it is not registered! Perhaps you are missing some plugin?`)
} else {
log.error('Cannot load browser "%s"!\n ' + e.stack, name)
log.error(`Cannot load browser "${name}"!\n ` + e.stack)
}

emitter.emit('load_error', 'launcher', name)
return
}

// TODO(vojta): remove in v1.0 (BC for old launchers)
if (!browser.forceKill) {
browser.forceKill = function () {
var me = this
return new Promise(function (resolve) {
me.kill(resolve)
})
}
this.jobs.add((args, done) => {
log.info(`Starting browser ${browser.displayName || browser.name}`)

browser.restart = function () {
var me = this
this.kill(function () {
me.start(url)
})
}
}
browser.on('browser_process_failure', () => done(browser.error))

self.jobs.add(function (args, done) {
log.info('Starting browser %s', helper.isDefined(browser.displayName) ? browser.displayName : browser.name)

browser.on('browser_process_failure', function () {
done(browser.error)
browser.on('done', () => {
if (!browser.error && browser.state !== browser.STATE_RESTARTING) {
done(null, browser)
}
})

browser.on('done', function () {
// We are not done if there was an error as first the retry takes
// place which we catch with `browser_process_failure` if it fails
if (browser.error || browser.state === browser.STATE_RESTARTING) return

done(null, browser)
})

browser.start(url)
browser.start(`${protocol}//${hostname}:${port}${urlRoot}`)
}, [])

self.jobs.run()
self._browsers.push(browser)
this.jobs.run()
this._browsers.push(browser)
}
}

this.launch = function (names, concurrency) {
this.launch = (names, concurrency) => {
log.info(
'Launching browser%s %s with %s',
names.length > 1 ? 's' : '',
names.join(', '),
concurrency === Infinity ? 'unlimited concurrency' : 'concurrency ' + concurrency
concurrency === Infinity ? 'unlimited concurrency' : `concurrency ${concurrency}`
)
this.jobs = new Jobs({maxConcurrency: concurrency})
this.jobs = new Jobs({ maxConcurrency: concurrency })

var self = this
lastStartTime = Date.now()

if (server.loadErrors.length === 0) {
names.forEach(function (name) {
injector.invoke(self.launchSingle, self)(name)
})
if (server.loadErrors.length) {
this.jobs.add((args, done) => done(), [])
} else {
// Empty task to ensure `end` is emitted
this.jobs.add(function (args, done) {
done()
}, [])
names.forEach((name) => injector.invoke(this.launchSingle, this)(name))
}

this.jobs.on('end', function (err) {
this.jobs.on('end', (err) => {
log.debug('Finished all browsers')

if (err) {
Expand All @@ -155,7 +116,7 @@ var Launcher = function (server, emitter, injector) {

this.jobs.run()

return self._browsers
return this._browsers
}

this.launch.$inject = [
Expand All @@ -173,76 +134,53 @@ var Launcher = function (server, emitter, injector) {
'config.processKillTimeout'
]

this.kill = function (id, callback) {
var browser = getBrowserById(id)
this.kill = (id, callback) => {
callback = callback || function () {}
const browser = getBrowserById(id)

if (!browser) {
process.nextTick(callback)
return false
if (browser) {
browser.forceKill().then(callback)
return true
}

browser.forceKill().then(callback)
return true
process.nextTick(callback)
return false
}

this.restart = function (id) {
var browser = getBrowserById(id)

if (!browser) {
return false
this.restart = (id) => {
const browser = getBrowserById(id)
if (browser) {
browser.restart()
return true
}

browser.restart()
return true
return false
}

this.killAll = function (callback) {
this.killAll = (callback) => {
callback = callback || function () {}
log.debug('Disconnecting all browsers')

var remaining = 0
var finish = function () {
remaining--
if (!remaining && callback) {
callback()
}
}

if (!self._browsers.length) {
if (!this._browsers.length) {
return process.nextTick(callback)
}

self._browsers.forEach(function (browser) {
remaining++
browser.forceKill().then(finish)
})
Promise.all(
this._browsers
.map((browser) => browser.forceKill())
).then(callback)
}

this.areAllCaptured = function () {
return !self._browsers.some(function (browser) {
return !browser.isCaptured()
})
}
this.areAllCaptured = () => this._browsers.every((browser) => browser.isCaptured())

this.markCaptured = function (id) {
self._browsers.forEach(function (browser) {
if (browser.id === id) {
browser.markCaptured()
log.debug('%s (id %s) captured in %d secs', browser.name, browser.id,
(Date.now() - lastStartTime) / 1000)
}
})
this.markCaptured = (id) => {
const browser = getBrowserById(id)
browser.markCaptured()
log.debug(`${browser.name} (id ${browser.id}) captured in ${(Date.now() - lastStartTime) / 1000} secs`)
}

// register events
emitter.on('exit', this.killAll)
}

Launcher.$inject = ['server', 'emitter', 'injector']
Launcher.generateId = () => Math.floor(Math.random() * 100000000).toString()

Launcher.generateId = function () {
return '' + Math.floor(Math.random() * 100000000)
}

// PUBLISH
exports.Launcher = Launcher
6 changes: 3 additions & 3 deletions test/unit/launcher.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

var Promise = require('bluebird')
var di = require('di')

Expand Down Expand Up @@ -61,9 +63,7 @@ function ScriptBrowser (id, name, baseBrowserDecorator) {
describe('launcher', () => {
// mock out id generator
var lastGeneratedId = null
launcher.Launcher.generateId = () => {
return ++lastGeneratedId
}
launcher.Launcher.generateId = () => ++lastGeneratedId

before(() => {
Promise.setScheduler((fn) => fn())
Expand Down