-
Notifications
You must be signed in to change notification settings - Fork 400
Show Docker logs again in functional tests #2727
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
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
abbfd8e
Show Docker logs again in functional tests
kumar303 0dafec4
bonkers script to start UI test server
kumar303 a021241
Wait for assets to be built
kumar303 e0ef0bd
cleanup
kumar303 1607c8e
quiet down the stat command
kumar303 dcee256
Merge branch 'master' into fix-travis-iss2704
kumar303 2e1e106
fix if statement
kumar303 49d3ea3
Fix up UI test docs
kumar303 f378ac0
Document new yarn command
kumar303 4eea134
Cleanup
kumar303 8264a9f
renamed variable
kumar303 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ npm-debug.log* | |
flow/logs/*log* | ||
|
||
# Runtime data | ||
docker-container-id.txt | ||
pids | ||
*.pid | ||
*.seed | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* @flow */ | ||
/* eslint-disable no-console */ | ||
// This starts a docker server for functional tests to access. | ||
// The script waits for the server to start and prints some logs | ||
// to help with debugging. | ||
|
||
const fs = require('fs'); | ||
const path = require('path'); | ||
const childProcess = require('child_process'); | ||
|
||
const root = path.join(__dirname, '..'); | ||
console.log(`Working directory: ${root}`); | ||
const containerIdFile = path.join(root, 'docker-container-id.txt'); | ||
|
||
// TODO: make these configurable when we need to start | ||
// servers for multiple apps. | ||
const appInstance = 'disco'; | ||
const nodeEnv = 'uitests'; | ||
|
||
function logDivider(heading) { | ||
console.log(`${'='.repeat(35)} ${heading} ${'='.repeat(35)}`); | ||
} | ||
|
||
function shell(cmd, args) { | ||
// Execs a command as if it were part of the parent shell | ||
// (i.e. the output is unbuffered and is displayed in the console). | ||
logDivider('BEGIN shell'); | ||
const cmdString = `${cmd} ${args.join(' ')}`; | ||
console.log(`Shell: ${cmdString}`); | ||
return new Promise((resolve, reject) => { | ||
const child = childProcess.spawn(cmd, args, { | ||
cwd: root, | ||
}); | ||
|
||
child.stdout.on('data', (data) => { | ||
process.stdout.write(data.toString()); | ||
}); | ||
child.stdout.on('error', (error) => reject(error)); | ||
|
||
child.stderr.on('data', (data) => { | ||
process.stderr.write(data.toString()); | ||
}); | ||
child.stderr.on('error', (error) => reject(error)); | ||
|
||
child.on('error', (error) => reject(error)); | ||
child.on('exit', (exitCode) => { | ||
logDivider('END shell'); | ||
if (exitCode !== 0) { | ||
reject(new Error( | ||
`shell command failed: ${cmdString} (exit: ${exitCode || '[empty]'})`)); | ||
} | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
function exec(cmd, argParts, { quiet = false } = {}) { | ||
const cmdString = `${cmd} ${argParts.join(' ')}`; | ||
if (!quiet) { | ||
logDivider('BEGIN exec'); | ||
console.log(`Exec: ${cmdString}`); | ||
} | ||
return new Promise((resolve, reject) => { | ||
childProcess.exec(cmdString, { cwd: root }, (error, stdout, stderr) => { | ||
let hasOutput = false; | ||
if (stdout) { | ||
hasOutput = true; | ||
if (!quiet) { | ||
logDivider('BEGIN stdout'); | ||
process.stdout.write(stdout.toString()); | ||
logDivider('END stdout'); | ||
} | ||
} | ||
if (stderr) { | ||
hasOutput = true; | ||
if (!quiet) { | ||
logDivider('BEGIN stderr'); | ||
process.stderr.write(stderr.toString()); | ||
logDivider('END stderr'); | ||
} | ||
} | ||
if (error) { | ||
if (!hasOutput) { | ||
console.warn('The command did not return any output'); | ||
} | ||
if (!quiet) { | ||
// Don't log all of the error because it includes all of stderr. | ||
console.error(`Snippet of exec error: ${error.toString().slice(0, 60)}...`); | ||
} | ||
reject(new Error(`exec command failed: ${cmdString}`)); | ||
} | ||
resolve(stdout.toString()); | ||
}); | ||
}); | ||
} | ||
|
||
function fileExistsSync(file) { | ||
try { | ||
return Boolean(fs.statSync(file)); | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
|
||
new Promise((resolve) => { | ||
if (fileExistsSync(containerIdFile)) { | ||
console.warn(`Removing existing container ID file: ${containerIdFile}`); | ||
fs.unlinkSync(containerIdFile); | ||
} | ||
resolve(); | ||
}) | ||
.then(() => exec('docker', ['build', '-q', '.'])) | ||
.then((imageIdOutput) => imageIdOutput.trim()) | ||
.then((imageId) => { | ||
// Start the server. | ||
const runArgs = [ | ||
'run', | ||
'-d', | ||
'-p=4000:4000', | ||
'-e', | ||
`NODE_APP_INSTANCE=${appInstance}`, | ||
'-e', | ||
`NODE_ENV=${nodeEnv}`, | ||
`--cidfile=${containerIdFile}`, | ||
// This will make sure we can read the logs. | ||
'--log-driver=json-file', | ||
imageId, | ||
'/bin/sh -c "npm run build && npm run start"', | ||
]; | ||
return exec('docker', runArgs); | ||
}) | ||
.then(() => { | ||
return fs.readFileSync(containerIdFile).toString(); | ||
}) | ||
.then((containerId) => { | ||
// Wait for the server to start and build assets. | ||
|
||
// This is the subresource integrity file, one of several asset files | ||
// built when the server starts. | ||
const sampleAssetFile = '/srv/code/dist/sri.json'; | ||
|
||
return new Promise((resolve, reject) => { | ||
// All time is in milleseconds. | ||
const interval = 1000; | ||
const timeOut = 1000 * 60 * 5; // 5 minutes | ||
let timeElapsed = 0; | ||
console.log(`Waiting for assets to build (looking for ${sampleAssetFile})`); | ||
|
||
const waitForAssets = () => { | ||
if (timeElapsed >= timeOut) { | ||
reject(new Error( | ||
`Timed out waiting for assets file to appear at | ||
${sampleAssetFile}`)); | ||
return; | ||
} | ||
timeElapsed += interval; | ||
|
||
exec('docker', | ||
['exec', containerId, 'ls', sampleAssetFile], { quiet: true } | ||
) | ||
.then(() => { | ||
// The file exists, the server has finished building assets. | ||
resolve(containerId); | ||
}) | ||
.catch(() => { | ||
// The file does not exist yet. Try again. | ||
setTimeout(waitForAssets, interval); | ||
}); | ||
}; | ||
|
||
waitForAssets(); | ||
}); | ||
}) | ||
.then((containerId) => { | ||
// Since the asset we just checked for isn't the final asset built, | ||
// wait just a bit before capturing the logs. | ||
return new Promise( | ||
(resolve) => setTimeout(() => resolve(containerId), 2000)); | ||
}) | ||
.then((containerId) => { | ||
// Show all of the server logs. | ||
return shell('docker', ['logs', '--tail=all', containerId]); | ||
}) | ||
.then(() => { | ||
console.log('The server is ready 🦄 ✨'); | ||
}) | ||
.catch((error) => { | ||
console.log(''); // Pad with a blank line | ||
console.error(error.stack); | ||
process.exit(1); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
process.env.NODE_APP_INSTANCE
would be a pretty easy fix here I think and buy us most of that. I think it's already passed to the tests on travis... if not you could easily add it to the env vars.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, I thought so too but passing env vars to commands in .travis.yml is not straight forward. I think it's best to deal with it later. I think we may have to create an
amo
and adisco
package.json
script.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, no problem.