Skip to content

Instantly share code, notes, and snippets.

@notmessenger
Last active June 20, 2018 19:43
Show Gist options
  • Save notmessenger/fe373e4aa37a986d083490b45d082251 to your computer and use it in GitHub Desktop.
Save notmessenger/fe373e4aa37a986d083490b45d082251 to your computer and use it in GitHub Desktop.
Async execution of multiple "ember exam" calls to facilitate split test parallelization

https://github.com/trentmwillis/ember-exam#split-test-parallelization

Inspired by https://stackoverflow.com/questions/49039442/firefox-browser-disconnect-issue-when-running-tests-via-testem

This coding works though needs to be more robust.

Regarding split test parallelization overall found that Chrome 67 worked better than Firefox 60 but was still an interesting experience regardless of which used. Also, without having actual different containers to run the parallelization in everything is running within the same resource pool so isn't practically any more performant.

To use this save the script into a file named whatever (run-tests.js for example) and then modify your package.json from

"coverage": "rm -rf coverage_* && COVERAGE=true ember exam --split 5 --parallel"

to

"coverage": "rm -rf coverage_* && COVERAGE=true node ./run-tests.js"

Be sure to also make the file executable before committing it via chmod ugo+x run-tests.js

run-tests.js

#!/usr/bin/env node

/**
 *
 *
 * Inspired by https://stackoverflow.com/questions/49039442/firefox-browser-disconnect-issue-when-running-tests-via-testem
 */

const util = require('util')
const exec = util.promisify(require('child_process').exec)

/**
 * Total number of partitions to split the tests into
 *
 * @see {@link https://github.com/trentmwillis/ember-exam#splitting}
 * @type {Number}
 */
const numberOfPartitions = 100

/**
 * Total number of partitions to run in parallel at one time
 *
 * @see {@link https://github.com/trentmwillis/ember-exam#splitting}
 * @type {Number}
 */
const numberOfPartitionsInParallel = 4

/**
 * Promise requests of exec() calls
 *
 * @type {exec[]}
 */
let processess = []

/**
 * Which partition entry
 *
 * @type {Number}
 */
let whichPartition = 0

/**
 * How many spawn() calls to prepare
 *
 * @type {Number}
 */
const howManyprocessessNeeded = Math.ceil(numberOfPartitions/numberOfPartitionsInParallel)



// @TODO RUN AN EMBER BUILD FIRST


// Prepare exec() calls
for (let i = 0; i < howManyprocessessNeeded; i++) {
    let partitions = ''

    for (let k = 0; k < numberOfPartitionsInParallel; k++) {
        ++whichPartition
        partitions += `,${whichPartition}`
    }

    const cmd = `./node_modules/.bin/ember exam --test-port=0 --path=./dist --split=${numberOfPartitions} --partition=${partitions.substring(1)} --parallel`

    processess.push(exec(cmd, {maxBuffer: 1024 * 1500}))

//console.log(cmd)
}


let output

Promise
    .all(processess)
    .then(responses => {
        responses.forEach(response => {

const { stdout, stderr } = response

console.log('STDOUT', stdout)
console.log('STDERR', stderr)

            // response.stdout.on('data', (data) => {
            //     output += data.toString('ascii')
            // })
        })
    })
    .catch(err => {
        console.log(err)
    })
    .then(function() {
        console.log('THEN()')
    })



/*

let totalTests = 0

function parseTestProgress(data) {


// # tests 96
// # pass  96
// # skip  0
// # fail  0


    const output = data.toString('ascii')

    const totalTestsMatch = output.match(/# tests \d+/i)

    let totalTestsJeremy = 0
    if (totalTestsMatch) {
        totalTestsJeremy = parseInt(totalTestsMatch[0].replace('# tests ', ''), 10)
    }

    totalTests += totalTestsJeremy

    console.log('JEREMY', totalTests)
}

function runSplitTests(whichPartition) {
    if (whichPartition >= numberOfPartitions) {
        return
    }

    let spawnArguments = [
        'exam',
    ]

    // this path does not exist on the very first run of ember exam
    if (whichPartition > 0) {
        spawnArguments.push('--path=./dist')
    }

    spawnArguments.push(`--split=${numberOfPartitions}`)

    for (let i = 0; i < numberOfPartitionsInParallel; i++) {
        ++whichPartition
        spawnArguments.push(`--partition=${whichPartition}`)
    }

    spawnArguments.push('--parallel')

    console.log(
        '\n================================================ RUNNING COMMAND ================================================\n',
        './node_modules/.bin/ember', spawnArguments.join(' '),
        '\n=================================================================================================================\n'
    )

//    const emberExam = spawn('./node_modules/.bin/ember', spawnArguments)
    const emberExam = spawn('pwd')

    emberExam.stdout.on('data', (data) => {
        console.log(data.toString('ascii'))
        parseTestProgress(data)
    })

    emberExam.on('close', (code) => {
        runSplitTests(whichPartition)
    })

    emberExam.on('disconnect', (code) => {
        console.log('DISCONNECTED - NOT WORKING')
    })

    emberExam.on('error', (err) => {
      console.log(err)
    })
}

runSplitTests(0)
*/

If you run into these errors

message: >
  Error: Browser disconnected
  Stderr:
  *** You are running in headless mode.
  [Parent 7353, Gecko_IOThread] WARNING: pipe error: Broken pipe: file /build/firefox-d34xn2/firefox-60.0.2+build1/ipc/chromium/src/chrome/common/ipc_channel_posix.cc, line 709

  ###!!! [Parent][MessageChannel] Error: (msgtype=0x15007F,name=PBrowser::Msg_Destroy) Channel error: cannot send/recv

  ###!!! [Parent][MessageChannel] Error: (msgtype=0x15007F,name=PBrowser::Msg_Destroy) Channel error: cannot send/recv

with Firefox you may need/want to try:

user_pref('browser.tabs.remote.autostart', false)
user_pref('browser.tabs.remote.autostart.2', false)
user_pref('browser.tabs.remote.force-enable', false)

from https://support.mozilla.org/en-US/questions/1167673 https://stackoverflow.com/questions/49039442/firefox-browser-disconnect-issue-when-running-tests-via-testem

though have not had any success with them yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment