Skip to content

Commit

Permalink
refactor: migrate Browser class to ES2015
Browse files Browse the repository at this point in the history
  • Loading branch information
devoto13 committed Mar 15, 2018
1 parent 6c92019 commit bb012e2
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 166 deletions.
254 changes: 134 additions & 120 deletions lib/browser.js
@@ -1,139 +1,115 @@
var helper = require('./helper')
var logger = require('./logger')
'use strict'

var Result = require('./browser_result')
const Result = require('./browser_result')
const helper = require('./helper')
const logger = require('./logger')

// The browser is ready to execute tests.
var READY = 1
const READY = 1

// The browser is executing the tests.
var EXECUTING = 2
const EXECUTING = 2

// The browser is not executing, but temporarily disconnected (waiting for reconnecting).
var READY_DISCONNECTED = 3
const READY_DISCONNECTED = 3

// The browser is executing the tests, but temporarily disconnect (waiting for reconnecting).
var EXECUTING_DISCONNECTED = 4
const EXECUTING_DISCONNECTED = 4

// The browser got permanently disconnected (being removed from the collection and destroyed).
var DISCONNECTED = 5
const DISCONNECTED = 5

var Browser = function (id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
/* config.browserDisconnectTimeout */ disconnectDelay,
/* config.browserNoActivityTimeout */ noActivityTimeout) {
var name = helper.browserFullNameToShort(fullName)
var log = logger.create(name)
var activeSockets = [socket]
var activeSocketsIds = function () {
return activeSockets.map(function (s) {
return s.id
}).join(', ')
}

var self = this
var pendingDisconnect
var disconnect = function (reason) {
self.state = DISCONNECTED
self.disconnectsCount++
log.warn('Disconnected (%d times)' + (reason || ''), self.disconnectsCount)
emitter.emit('browser_error', self, 'Disconnected' + (reason || ''))
collection.remove(self)
class Browser {
constructor (id, fullName, collection, emitter, socket, timer, disconnectDelay, noActivityTimeout) {
this.id = id
this.fullName = fullName
this.name = helper.browserFullNameToShort(fullName)
this.state = READY
this.lastResult = new Result()
this.disconnectsCount = 0
this.activeSockets = [socket]
this.noActivityTimeout = noActivityTimeout
this.collection = collection
this.emitter = emitter
this.socket = socket
this.timer = timer
this.disconnectDelay = disconnectDelay

this.log = logger.create(this.name)

this.noActivityTimeoutId = null
this.pendingDisconnect = null
}

var noActivityTimeoutId
var refreshNoActivityTimeout = noActivityTimeout ? function () {
clearNoActivityTimeout()
noActivityTimeoutId = timer.setTimeout(function () {
self.lastResult.totalTimeEnd()
self.lastResult.disconnected = true
disconnect(', because no message in ' + noActivityTimeout + ' ms.')
emitter.emit('browser_complete', self)
}, noActivityTimeout)
} : function () {}

var clearNoActivityTimeout = noActivityTimeout ? function () {
if (noActivityTimeoutId) {
timer.clearTimeout(noActivityTimeoutId)
noActivityTimeoutId = null
}
} : function () {}
init () {
this.collection.add(this)

this.id = id
this.fullName = fullName
this.name = name
this.state = READY
this.lastResult = new Result()
this.disconnectsCount = 0
this.bindSocketEvents(this.socket)

this.init = function () {
collection.add(this)

this.bindSocketEvents(socket)

log.info('Connected on socket %s with id %s', socket.id, id)
this.log.info('Connected on socket %s with id %s', this.socket.id, this.id)

// TODO(vojta): move to collection
emitter.emit('browsers_change', collection)
this.emitter.emit('browsers_change', this.collection)

emitter.emit('browser_register', this)
this.emitter.emit('browser_register', this)
}

this.isReady = function () {
isReady () {
return this.state === READY
}

this.toString = function () {
toString () {
return this.name
}

this.onKarmaError = function (error) {
onKarmaError (error) {
if (this.isReady()) {
return
}

this.lastResult.error = true
emitter.emit('browser_error', this, error)
this.emitter.emit('browser_error', this, error)

refreshNoActivityTimeout()
this.refreshNoActivityTimeout()
}

this.onInfo = function (info) {
onInfo (info) {
if (this.isReady()) {
return
}

// TODO(vojta): remove
if (helper.isDefined(info.dump)) {
emitter.emit('browser_log', this, info.dump, 'dump')
this.emitter.emit('browser_log', this, info.dump, 'dump')
}

if (helper.isDefined(info.log)) {
emitter.emit('browser_log', this, info.log, info.type)
this.emitter.emit('browser_log', this, info.log, info.type)
}

if (
!helper.isDefined(info.log) &&
!helper.isDefined(info.dump)
) {
emitter.emit('browser_info', this, info)
this.emitter.emit('browser_info', this, info)
}

refreshNoActivityTimeout()
this.refreshNoActivityTimeout()
}

this.onStart = function (info) {
onStart (info) {
this.lastResult = new Result()
this.lastResult.total = info.total

if (info.total === null) {
log.warn('Adapter did not report total number of specs.')
this.log.warn('Adapter did not report total number of specs.')
}

emitter.emit('browser_start', this, info)
refreshNoActivityTimeout()
this.emitter.emit('browser_start', this, info)
this.refreshNoActivityTimeout()
}

this.onComplete = function (result) {
onComplete (result) {
if (this.isReady()) {
return
}
Expand All @@ -145,70 +121,68 @@ var Browser = function (id, fullName, /* capturedBrowsers */ collection, emitter
this.lastResult.error = true
}

emitter.emit('browsers_change', collection)
emitter.emit('browser_complete', this, result)
this.emitter.emit('browsers_change', this.collection)
this.emitter.emit('browser_complete', this, result)

clearNoActivityTimeout()
this.clearNoActivityTimeout()
}

this.onDisconnect = function (disconnectedSocket) {
activeSockets.splice(activeSockets.indexOf(disconnectedSocket), 1)
onDisconnect (disconnectedSocket) {
this.activeSockets.splice(this.activeSockets.indexOf(disconnectedSocket), 1)

if (activeSockets.length) {
log.debug('Disconnected %s, still have %s', disconnectedSocket.id, activeSocketsIds())
if (this.activeSockets.length) {
this.log.debug('Disconnected %s, still have %s', disconnectedSocket.id, this.getActiveSocketsIds())
return
}

if (this.state === READY) {
disconnect()
this.disconnect()
} else if (this.state === EXECUTING) {
log.debug('Disconnected during run, waiting %sms for reconnecting.', disconnectDelay)
this.log.debug('Disconnected during run, waiting %sms for reconnecting.', this.disconnectDelay)
this.state = EXECUTING_DISCONNECTED

pendingDisconnect = timer.setTimeout(function () {
self.lastResult.totalTimeEnd()
self.lastResult.disconnected = true
disconnect()
emitter.emit('browser_complete', self)
}, disconnectDelay)
this.pendingDisconnect = this.timer.setTimeout(() => {
this.lastResult.totalTimeEnd()
this.lastResult.disconnected = true
this.disconnect()
this.emitter.emit('browser_complete', this)
}, this.disconnectDelay)

clearNoActivityTimeout()
this.clearNoActivityTimeout()
}
}

this.reconnect = function (newSocket) {
reconnect (newSocket) {
if (this.state === EXECUTING_DISCONNECTED) {
this.state = EXECUTING
log.debug('Reconnected on %s.', newSocket.id)
this.log.debug('Reconnected on %s.', newSocket.id)
} else if (this.state === EXECUTING || this.state === READY) {
log.debug('New connection %s (already have %s)', newSocket.id, activeSocketsIds())
this.log.debug('New connection %s (already have %s)', newSocket.id, this.getActiveSocketsIds())
} else if (this.state === DISCONNECTED) {
this.state = READY
log.info('Connected on socket %s with id %s', newSocket.id, this.id)
collection.add(this)
this.log.info('Connected on socket %s with id %s', newSocket.id, this.id)
this.collection.add(this)

// TODO(vojta): move to collection
emitter.emit('browsers_change', collection)
this.emitter.emit('browsers_change', this.collection)

emitter.emit('browser_register', this)
this.emitter.emit('browser_register', this)
}

var exists = activeSockets.some(function (s) {
return s.id === newSocket.id
})
const exists = this.activeSockets.some((s) => s.id === newSocket.id)
if (!exists) {
activeSockets.push(newSocket)
this.activeSockets.push(newSocket)
this.bindSocketEvents(newSocket)
}

if (pendingDisconnect) {
timer.clearTimeout(pendingDisconnect)
if (this.pendingDisconnect) {
this.timer.clearTimeout(this.pendingDisconnect)
}

refreshNoActivityTimeout()
this.refreshNoActivityTimeout()
}

this.onResult = function (result) {
onResult (result) {
if (result.length) {
return result.forEach(this.onResult, this)
}
Expand All @@ -220,38 +194,78 @@ var Browser = function (id, fullName, /* capturedBrowsers */ collection, emitter

this.lastResult.add(result)

emitter.emit('spec_complete', this, result)
refreshNoActivityTimeout()
this.emitter.emit('spec_complete', this, result)
this.refreshNoActivityTimeout()
}

this.serialize = function () {
serialize () {
return {
id: this.id,
name: this.name,
isReady: this.state === READY
}
}

this.execute = function (config) {
activeSockets.forEach(function (socket) {
socket.emit('execute', config)
})
execute (config) {
this.activeSockets.forEach((socket) => socket.emit('execute', config))

this.state = EXECUTING
refreshNoActivityTimeout()
this.refreshNoActivityTimeout()
}

getActiveSocketsIds () {
return this.activeSockets.map((s) => s.id).join(', ')
}

disconnect (reason) {
this.state = DISCONNECTED
this.disconnectsCount++
this.log.warn('Disconnected (%d times)' + (reason || ''), this.disconnectsCount)
this.emitter.emit('browser_error', this, 'Disconnected' + (reason || ''))
this.collection.remove(this)
}

refreshNoActivityTimeout () {
if (this.noActivityTimeout) {
this.clearNoActivityTimeout()

this.noActivityTimeoutId = this.timer.setTimeout(() => {
this.lastResult.totalTimeEnd()
this.lastResult.disconnected = true
this.disconnect(', because no message in ' + this.noActivityTimeout + ' ms.')
this.emitter.emit('browser_complete', this)
}, this.noActivityTimeout)
}
}

this.bindSocketEvents = function (socket) {
clearNoActivityTimeout () {
if (this.noActivityTimeout) {
if (this.noActivityTimeoutId) {
this.timer.clearTimeout(this.noActivityTimeoutId)
this.noActivityTimeoutId = null
}
}
}

bindSocketEvents (socket) {
// TODO: check which of these events are actually emitted by socket
socket.on('disconnect', function () { self.onDisconnect(socket) })
socket.on('start', function (info) { self.onStart(info) })
socket.on('karma_error', function (error) { self.onKarmaError(error) })
socket.on('complete', function (result) { self.onComplete(result) })
socket.on('info', function (info) { self.onInfo(info) })
socket.on('result', function (result) { self.onResult(result) })
socket.on('disconnect', () => this.onDisconnect(socket))
socket.on('start', (info) => this.onStart(info))
socket.on('karma_error', (error) => this.onKarmaError(error))
socket.on('complete', (result) => this.onComplete(result))
socket.on('info', (info) => this.onInfo(info))
socket.on('result', (result) => this.onResult(result))
}
}

Browser.factory = function (
id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
/* config.browserDisconnectTimeout */ disconnectDelay,
/* config.browserNoActivityTimeout */ noActivityTimeout
) {
return new Browser(id, fullName, collection, emitter, socket, timer, disconnectDelay, noActivityTimeout)
}

Browser.STATE_READY = READY
Browser.STATE_EXECUTING = EXECUTING
Browser.STATE_READY_DISCONNECTED = READY_DISCONNECTED
Expand Down
2 changes: 1 addition & 1 deletion lib/server.js
Expand Up @@ -307,7 +307,7 @@ Server.prototype._start = function (config, launcher, preprocess, fileList,
id: ['value', info.id || null],
fullName: ['value', (helper.isDefined(info.displayName) ? info.displayName : info.name)],
socket: ['value', socket]
}]).instantiate(Browser)
}]).invoke(Browser.factory)

newBrowser.init()

Expand Down

0 comments on commit bb012e2

Please sign in to comment.