Skip to content

Split functional tests into per file so they don't run out of memory during failures #13534

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 18 commits into from
Aug 20, 2020
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ obj/**
tmp/**
.python-version
.vs/
test-results.xml
test-results*.xml
xunit-test-results.xml
build/ci/performance/performance-results.json
!build/
Expand Down
147 changes: 47 additions & 100 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@
{
Copy link
Author

Choose a reason for hiding this comment

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

THis file didn't change as much as it looks. I just formatted it.

"version": "0.1.0",
"configurations": [
{
"name": "Node: Current File",
"program": "${file}",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
},
{
"name": "Python: Current File",
"type": "python",
"justMyCode": true,
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}"
},
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"stopOnEntry": false,
"smartStep": true,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
],
"skipFiles": ["<node_internals>/**"],
"env": {
// Enable this to turn on redux logging during debugging
"XVSC_PYTHON_FORCE_LOGGING": "1",
Expand All @@ -37,40 +48,27 @@
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"stopOnEntry": false,
"smartStep": true,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Inject DS WebBrowser UI",
"env": {
"VSC_PYTHON_DS_UI_PROMPT": "1"
},
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Extension inside container",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}/data"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "${workspaceFolder}/data"],
"stopOnEntry": false,
"smartStep": true,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile"
},
{
Expand All @@ -79,9 +77,7 @@
"request": "launch",
"module": "IPython",
"console": "integratedTerminal",
"args": [
"${file}"
] // Additional args should be prefixed with a '--' first.
"args": ["${file}"] // Additional args should be prefixed with a '--' first.
},
{
"name": "Python: Current File",
Expand All @@ -104,17 +100,12 @@
"stopOnEntry": false,
"sourceMaps": true,
"smartStep": true,
"outFiles": [
"${workspaceFolder}/out/**/*",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"env": {
"IS_CI_SERVER_TEST_DEBUGGER": "1"
},
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
// Note, for the smoke test you want to debug, you may need to copy the file,
Expand All @@ -134,14 +125,9 @@
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Tests (Single Workspace, VS Code, *.test.ts)",
Expand All @@ -159,14 +145,9 @@
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Tests (DataScience, *.ds.test.ts)",
Expand All @@ -189,14 +170,9 @@
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Tests (Multiroot, VS Code, *.test.ts)",
Expand All @@ -212,14 +188,9 @@
"stopOnEntry": false,
"sourceMaps": true,
"smartStep": true,
"outFiles": [
"${workspaceFolder}/out/**/*",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Unit Tests (without VS Code, *.unit.test.ts)",
Expand All @@ -237,14 +208,9 @@
//"--grep", "<suite name>",
"--timeout=300000"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Unit Tests (fast, without VS Code and without react/monaco, *.unit.test.ts)",
Expand All @@ -263,14 +229,9 @@
"--timeout=300000",
"--fast"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Functional Tests (without VS Code, *.functional.test.ts)",
Expand Down Expand Up @@ -301,14 +262,9 @@
// Remove 'X' prefix to dump output for debugger. Directory has to exist prior to launch
"XDEBUGPY_LOG_DIR": "${workspaceRoot}/tmp/Debug_Output"
},
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Functional DS UI Tests (without VS Code, *.ui.functional.test.ts)",
Expand Down Expand Up @@ -337,26 +293,17 @@
// Remove `X` prefix and update path to test with real python interpreter (for DS functional tests).
"XCI_PYTHON_PATH": "<Python Path>"
},
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"!${workspaceFolder}/**/node_modules**/*"
],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"preLaunchTask": "Compile",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"type": "node",
"request": "launch",
"name": "Gulp tasks (helpful for debugging gulpfile.js)",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"args": [
"watch"
],
"skipFiles": [
"<node_internals>/**"
]
"args": ["watch"],
"skipFiles": ["<node_internals>/**"]
}
]
}
82 changes: 82 additions & 0 deletions build/ci/scripts/runFunctionalTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// This script will run all of the functional tests for each functional test file in sequence
// This prevents mocha from running out of memory when running all of the tests
//
// This could potentially be improved to run tests in parallel (try that later)
//
// Additionally this was written in python at first but running python on an azure
// machine may pick up an invalid environment for the subprocess. Node doesn't have this problem
var path = require('path');
var glob = require('glob');
var child_process = require('child_process');

// Create a base for the output file
var originalMochaFile = process.env['MOCHA_FILE'];
var mochaFile = originalMochaFile || './test-results.xml';
var mochaBaseFile = path.join(path.dirname(mochaFile), path.basename(mochaFile, '.xml'));
var mochaFileExt = '.xml';

// Wrap async code in a function so can wait till done
async function main() {
console.log('Globbing files for functional tests');

// Glob all of the files that we usually send to mocha as a group (see mocha.functional.opts.xml)
var files = await new Promise((resolve, reject) => {
glob('./out/test/**/*.functional.test.js', (ex, res) => {
if (ex) {
reject(ex);
} else {
resolve(res);
}
});
});

// Iterate over them, running mocha on each
var returnCode = 0;

// Go through each one at a time
try {
for (var index = 0; index < files.length; index += 1) {
// Each run with a file will expect a $MOCHA_FILE$ variable. Generate one for each
// Note: this index is used as a pattern when setting mocha file in the test_phases.yml
var subMochaFile = `${mochaBaseFile}_${index}_${path.basename(files[index])}${mochaFileExt}`;
process.env['MOCHA_FILE'] = subMochaFile;
var exitCode = await new Promise((resolve) => {
// Spawn the sub node process
var proc = child_process.fork('./node_modules/mocha/bin/_mocha', [
files[index],
'--require=out/test/unittests.js',
'--exclude=out/**/*.jsx',
'--reporter=mocha-multi-reporters',
'--reporter-option=configFile=build/.mocha-multi-reporters.config',
'--ui=tdd',
'--recursive',
'--colors',
'--exit',
'--timeout=180000'
]);
proc.on('exit', resolve);
});

// If failed keep track
if (exitCode !== 0) {
console.log(`Functional tests for ${files[index]} failed.`);
returnCode = exitCode;
}
}
} catch (ex) {
console.log(`Functional tests run failure: ${ex}.`);
returnCode = -1;
}

// Reset the mocha file variable
if (originalMochaFile) {
process.env['MOCHA_FILE'] = originalMochaFile;
}

// Indicate error code
console.log(`Functional test run result: ${returnCode}`);
process.exit(returnCode);
}

// Call the main function. It will exit when promise is finished.
main();
Loading