Skip to content

Commit

Permalink
Use tree-kill to kill firefox
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig committed Jun 5, 2020
1 parent 593bc91 commit 32b6b9c
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 100 deletions.
41 changes: 3 additions & 38 deletions packages/server/lib/browsers/firefox-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,19 +233,7 @@ export default {
tries: 1, // marionette-client has its own retry logic which we want to avoid
})

let willDisconnect = false

// GeckoDriver commands:
// @see https://searchfox.org/mozilla-central/rev/0688ffdef223dac527c2fcdb25560118c4e4df51/testing/marionette/driver.js#3906
const sendMarionette = async (data) => {
if (willDisconnect) {
debug('received marionette command after disconnect, discarding silently %o', data)

return
}

debug('sending marionette command %o', data)

const sendMarionette = (data) => {
return driver.send(new Command(data))
}

Expand Down Expand Up @@ -298,30 +286,7 @@ export default {
.catch(_onError('commands'))
})

// on win32, firefox is not linked to the parent cmd.exe process, so we must use marionette
// to force close firefox
// @see https://github.com/cypress-io/cypress/issues/6392
return {
marionetteQuit: () => {
willDisconnect = true

const { tcp } = driver

tcp.socket.removeAllListeners()
tcp.client.removeAllEventListeners('error')

return sendMarionette({
name: 'Marionette:Quit',
parameters: {
// "Force all windows to close, then quit."
// @see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIAppStartup
flags: 'eForceQuit',
},
})
},
}

// NOTE: Marionette must run for the entirety of the browser session, or else `acceptInsecureCerts`
// will cease to apply and SSL validation prompts will appear
// even though Marionette is not used past this point, we have to keep the session open
// or else `acceptInsecureCerts` will cease to apply and SSL validation prompts will appear.
},
}
61 changes: 10 additions & 51 deletions packages/server/lib/browsers/firefox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Bluebird from 'bluebird'
import fs from 'fs-extra'
import Debug from 'debug'
import getPort from 'get-port'
import os from 'os'
import path from 'path'
import urlUtil from 'url'
import FirefoxProfile from 'firefox-profile'
Expand All @@ -12,7 +11,8 @@ import utils from './utils'
import * as launcherDebug from '@packages/launcher/lib/log'
import { Browser, BrowserInstance } from './types'
import { EventEmitter } from 'events'

import os from 'os'
import treeKill from 'tree-kill'
const errors = require('../errors')

const debug = Debug('cypress:server:browsers:firefox')
Expand Down Expand Up @@ -290,16 +290,13 @@ const defaultPreferences = {
'marionette.log.level': launcherDebug.log.enabled ? 'Debug' : undefined,
}

export function _createDetachedInstance (quitFn: () => Promise<void>): BrowserInstance {
export function _createDetachedInstance (browserInstance: BrowserInstance): BrowserInstance {
const detachedInstance: BrowserInstance = new EventEmitter() as BrowserInstance

detachedInstance.kill = () => {
quitFn()
.catch((err) => {
debug('error thrown while force-exiting detached instance, continuing %o', { err })
})
.then(() => {
debug('force-exit of detached instance completed')
// kill the entire process tree, from the spawned instance up
detachedInstance.kill = (): void => {
treeKill(browserInstance.pid, (err?, result?) => {
debug('force-exit of process tree complete %o', { err, result })
detachedInstance.emit('exit')
})
}
Expand Down Expand Up @@ -439,49 +436,11 @@ export async function open (browser: Browser, url, options: any = {}): Bluebird<
errors.throw('FIREFOX_COULD_NOT_CONNECT', err)
})

// Override the .kill method for Windows so that the Browsers closes b/w specs
if (os.platform() === 'win32') {
browserInstance.kill = async (...args) => {
debug('closing firefox on Windows')

killFirefoxInstanceWin32(browserInstance)
}
}

const [, { marionetteQuit }] = await firefoxUtil.setup({ extensions: launchOptions.extensions, url, foxdriverPort, marionettePort })
.tapCatch((err) => {
errors.throw('FIREFOX_COULD_NOT_CONNECT', err)
})

if (os.platform() === 'win32') {
return _createDetachedInstance(marionetteQuit)
// override the .kill method for Windows so that the detached Firefox process closes between specs
// @see https://github.com/cypress-io/cypress/issues/6392
return _createDetachedInstance(browserInstance)
}

return browserInstance
}

const killFirefoxInstanceWin32 = (browserInstance) => {
let instanceKill = `TASKKILL /T /PID ${browserInstance.pid}`

let parentPidFile = browserInstance.spawnargs[browserInstance.spawnargs.length - 1].split('\\')
let parentPidWithFilename = parentPidFile[parentPidFile.length - 1].split('-')
let parentPid = parentPidWithFilename[parentPidWithFilename.length - 1]

let parentKill = `TASKKILL /T /PID ${parentPid}`

const exec = _.noop

exec(instanceKill, { shell: 'cmd.exe' }, (error, stdout, stderr) => {
debug('killed child process in exec')
debug('instance/child process kill error:', error)
debug('instance/child process kill stdout', stdout)
debug('instance/child process kill stderr', stderr)

exec(parentKill, { shell: 'cmd.exe' }, (error, stdout, stderr) => {
debug('killed parent process in exec')
debug('parent process kill error:', error)
debug('parent process kill stdout', stdout)
debug('parent process kill stderr', stderr)
})
})
}
1 change: 1 addition & 0 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"term-size": "2.1.0",
"tough-cookie": "4.0.0",
"trash": "5.2.0",
"tree-kill": "1.2.2",
"ts-node": "8.5.4",
"underscore": "1.9.1",
"underscore.string": "3.3.5",
Expand Down
13 changes: 2 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13851,16 +13851,7 @@ http-proxy-agent@^2.1.0:
agent-base "4"
debug "3.1.0"

http-proxy@^1.17.0:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"

http-proxy@cypress-io/node-http-proxy#9322b4b69b34f13a6f3874e660a35df3305179c6:
http-proxy@^1.17.0, http-proxy@cypress-io/node-http-proxy#9322b4b69b34f13a6f3874e660a35df3305179c6:
version "1.18.0"
resolved "https://codeload.github.com/cypress-io/node-http-proxy/tar.gz/9322b4b69b34f13a6f3874e660a35df3305179c6"
dependencies:
Expand Down Expand Up @@ -24312,7 +24303,7 @@ traverse-chain@~0.1.0:
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=

tree-kill@^1.1.0:
tree-kill@1.2.2, tree-kill@^1.1.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
Expand Down

0 comments on commit 32b6b9c

Please sign in to comment.