test: run tests under asan on linux-x64 (#23570)

This commit is contained in:
Jeremy Rose 2021-02-22 16:16:17 -08:00 committed by GitHub
parent b181dae146
commit 7f8e34fa3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 50 deletions

View file

@ -680,28 +680,34 @@ step-electron-dist-unzip: &step-electron-dist-unzip
cd src/out/Default cd src/out/Default
# -o overwrite files WITHOUT prompting # -o overwrite files WITHOUT prompting
# TODO(alexeykuzmin): Remove '-o' when it's no longer needed. # TODO(alexeykuzmin): Remove '-o' when it's no longer needed.
unzip -o dist.zip # -: allows to extract archive members into locations outside
# of the current ``extraction root folder''.
# ASan builds have the llvm-symbolizer binaries listed as
# runtime_deps, with their paths as `../../third_party/...`
# unzip exits with non-zero code on such zip files unless -: is
# passed.
unzip -:o dist.zip
step-ffmpeg-unzip: &step-ffmpeg-unzip step-ffmpeg-unzip: &step-ffmpeg-unzip
run: run:
name: Unzip ffmpeg.zip name: Unzip ffmpeg.zip
command: | command: |
cd src/out/ffmpeg cd src/out/ffmpeg
unzip -o ffmpeg.zip unzip -:o ffmpeg.zip
step-mksnapshot-unzip: &step-mksnapshot-unzip step-mksnapshot-unzip: &step-mksnapshot-unzip
run: run:
name: Unzip mksnapshot.zip name: Unzip mksnapshot.zip
command: | command: |
cd src/out/Default cd src/out/Default
unzip -o mksnapshot.zip unzip -:o mksnapshot.zip
step-chromedriver-unzip: &step-chromedriver-unzip step-chromedriver-unzip: &step-chromedriver-unzip
run: run:
name: Unzip chromedriver.zip name: Unzip chromedriver.zip
command: | command: |
cd src/out/Default cd src/out/Default
unzip -o chromedriver.zip unzip -:o chromedriver.zip
step-ffmpeg-gn-gen: &step-ffmpeg-gn-gen step-ffmpeg-gn-gen: &step-ffmpeg-gn-gen
run: run:
@ -733,19 +739,23 @@ step-verify-mksnapshot: &step-verify-mksnapshot
run: run:
name: Verify mksnapshot name: Verify mksnapshot
command: | command: |
if [ "$IS_ASAN" != "1" ]; then
cd src cd src
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
else else
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
fi fi
fi
step-verify-chromedriver: &step-verify-chromedriver step-verify-chromedriver: &step-verify-chromedriver
run: run:
name: Verify ChromeDriver name: Verify ChromeDriver
command: | command: |
if [ "$IS_ASAN" != "1" ]; then
cd src cd src
python electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default python electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default
fi
step-setup-linux-for-headless-testing: &step-setup-linux-for-headless-testing step-setup-linux-for-headless-testing: &step-setup-linux-for-headless-testing
run: run:
@ -1266,18 +1276,6 @@ steps-verify-ffmpeg: &steps-verify-ffmpeg
- *step-verify-ffmpeg - *step-verify-ffmpeg
- *step-maybe-notify-slack-failure - *step-maybe-notify-slack-failure
steps-verify-chromedriver: &steps-verify-chromedriver
steps:
- attach_workspace:
at: .
- *step-depot-tools-add-to-path
- *step-electron-dist-unzip
- *step-chromedriver-unzip
- *step-setup-linux-for-headless-testing
- *step-verify-chromedriver
- *step-maybe-notify-slack-failure
steps-tests: &steps-tests steps-tests: &steps-tests
steps: steps:
- attach_workspace: - attach_workspace:
@ -1301,6 +1299,18 @@ steps-tests: &steps-tests
ELECTRON_DISABLE_SECURITY_WARNINGS: 1 ELECTRON_DISABLE_SECURITY_WARNINGS: 1
command: | command: |
cd src cd src
if [ "$IS_ASAN" == "1" ]; then
ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron"
export ASAN_OPTIONS="symbolize=0 handle_abort=1"
export G_SLICE=always-malloc
export NSS_DISABLE_ARENA_FREE_LIST=1
export NSS_DISABLE_UNLOAD=1
export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer
export MOCHA_TIMEOUT=180000
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
else
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging) (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
@ -1309,6 +1319,7 @@ steps-tests: &steps-tests
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split))
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split))
fi fi
fi
- run: - run:
name: Check test results existence name: Check test results existence
command: | command: |
@ -1443,6 +1454,9 @@ commands:
restore-src-cache: restore-src-cache:
type: boolean type: boolean
default: true default: true
build-nonproprietary-ffmpeg:
type: boolean
default: true
steps: steps:
- when: - when:
condition: << parameters.attach >> condition: << parameters.attach >>
@ -1541,6 +1555,9 @@ commands:
- *step-electron-chromedriver-build - *step-electron-chromedriver-build
- *step-electron-chromedriver-store - *step-electron-chromedriver-store
- when:
condition: << parameters.build-nonproprietary-ffmpeg >>
steps:
# ffmpeg # ffmpeg
- *step-ffmpeg-gn-gen - *step-ffmpeg-gn-gen
- *step-ffmpeg-build - *step-ffmpeg-build
@ -1784,6 +1801,22 @@ jobs:
checkout: true checkout: true
use-out-cache: false use-out-cache: false
linux-x64-testing-asan:
<<: *machine-linux-2xlarge
environment:
<<: *env-global
<<: *env-testing-build
<<: *env-ninja-status
CHECK_DIST_MANIFEST: '0'
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
GN_EXTRA_ARGS: 'is_asan = true'
steps:
- electron-build:
persist: true
checkout: true
use-out-cache: false
build-nonproprietary-ffmpeg: false
linux-x64-testing-no-run-as-node: linux-x64-testing-no-run-as-node:
<<: *machine-linux-2xlarge <<: *machine-linux-2xlarge
environment: environment:
@ -2277,6 +2310,17 @@ jobs:
parallelism: 3 parallelism: 3
<<: *steps-tests <<: *steps-tests
linux-x64-testing-asan-tests:
<<: *machine-linux-medium
environment:
<<: *env-linux-medium
<<: *env-headless-testing
<<: *env-stack-dumping
IS_ASAN: '1'
DISABLE_CRASH_REPORTER_TESTS: '1'
parallelism: 3
<<: *steps-tests
linux-x64-testing-nan: linux-x64-testing-nan:
<<: *machine-linux-medium <<: *machine-linux-medium
environment: environment:
@ -2573,6 +2617,7 @@ workflows:
- linux-checkout-and-save-cache - linux-checkout-and-save-cache
- linux-x64-testing - linux-x64-testing
- linux-x64-testing-asan
- linux-x64-testing-no-run-as-node - linux-x64-testing-no-run-as-node
- linux-x64-testing-gn-check: - linux-x64-testing-gn-check:
requires: requires:
@ -2580,6 +2625,9 @@ workflows:
- linux-x64-testing-tests: - linux-x64-testing-tests:
requires: requires:
- linux-x64-testing - linux-x64-testing
- linux-x64-testing-asan-tests:
requires:
- linux-x64-testing-asan
- linux-x64-testing-nan: - linux-x64-testing-nan:
requires: requires:
- linux-x64-testing - linux-x64-testing

View file

@ -209,7 +209,8 @@ describe('app module', () => {
}); });
}); });
describe('app.requestSingleInstanceLock', () => { // TODO(jeremy): figure out why these tests time out under ASan
ifdescribe(!process.env.IS_ASAN)('app.requestSingleInstanceLock', () => {
it('prevents the second launch of app', async function () { it('prevents the second launch of app', async function () {
this.timeout(120000); this.timeout(120000);
const appPath = path.join(fixturesPath, 'api', 'singleton'); const appPath = path.join(fixturesPath, 'api', 'singleton');
@ -1454,7 +1455,8 @@ describe('app module', () => {
}); });
describe('when app.enableSandbox() is called', () => { describe('when app.enableSandbox() is called', () => {
it('adds --enable-sandbox to all renderer processes', done => { // TODO(jeremy): figure out why this times out under ASan
ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app'); const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']); appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']);
@ -1479,7 +1481,8 @@ describe('app module', () => {
}); });
describe('when the app is launched with --enable-sandbox', () => { describe('when the app is launched with --enable-sandbox', () => {
it('adds --enable-sandbox to all renderer processes', done => { // TODO(jeremy): figure out why this times out under ASan
ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app'); const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
appProcess = cp.spawn(process.execPath, [appPath, '--enable-sandbox']); appProcess = cp.spawn(process.execPath, [appPath, '--enable-sandbox']);

View file

@ -11,7 +11,7 @@ import { EventEmitter } from 'events';
import { closeWindow } from './window-helpers'; import { closeWindow } from './window-helpers';
import { emittedOnce } from './events-helpers'; import { emittedOnce } from './events-helpers';
import { WebmGenerator } from './video-helpers'; import { WebmGenerator } from './video-helpers';
import { delay } from './spec-helpers'; import { delay, ifit } from './spec-helpers';
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures'); const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures');
@ -704,13 +704,14 @@ describe('protocol module', () => {
}); });
describe('protocol.registerSchemeAsPrivileged', () => { describe('protocol.registerSchemeAsPrivileged', () => {
it('does not crash on exit', async () => { // TODO(jeremy): figure out why this times out under ASan
ifit(!process.env.IS_ASAN)('does not crash on exit', async () => {
const appPath = path.join(__dirname, 'fixtures', 'api', 'custom-protocol-shutdown.js'); const appPath = path.join(__dirname, 'fixtures', 'api', 'custom-protocol-shutdown.js');
const appProcess = ChildProcess.spawn(process.execPath, ['--enable-logging', appPath]); const appProcess = ChildProcess.spawn(process.execPath, ['--enable-logging', appPath]);
let stdout = ''; let stdout = '';
let stderr = ''; let stderr = '';
appProcess.stdout.on('data', data => { stdout += data; }); appProcess.stdout.on('data', data => { process.stdout.write(data); stdout += data; });
appProcess.stderr.on('data', data => { stderr += data; }); appProcess.stderr.on('data', data => { process.stderr.write(data); stderr += data; });
const [code] = await emittedOnce(appProcess, 'exit'); const [code] = await emittedOnce(appProcess, 'exit');
if (code !== 0) { if (code !== 0) {
console.log('Exit code : ', code); console.log('Exit code : ', code);

View file

@ -18,6 +18,8 @@ const features = process._linkedBinding('electron_common_features');
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures'); const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures');
const isAsan = process.env.IS_ASAN;
describe('reporting api', () => { describe('reporting api', () => {
// TODO(nornagon): this started failing a lot on CI. Figure out why and fix // TODO(nornagon): this started failing a lot on CI. Figure out why and fix
// it. // it.
@ -329,17 +331,19 @@ describe('command line switches', () => {
// The LC_ALL env should not be set to DOM locale string. // The LC_ALL env should not be set to DOM locale string.
expect(lcAll).to.not.equal(app.getLocale()); expect(lcAll).to.not.equal(app.getLocale());
}); });
ifit(process.platform === 'linux')('should not change LC_ALL', async () => testLocale('fr', lcAll, true)); // TODO(jeremy): figure out why this times out under ASan
ifit(process.platform === 'linux' && !process.env.IS_ASAN)('should not change LC_ALL', async () => testLocale('fr', lcAll, true));
ifit(process.platform === 'linux')('should not change LC_ALL when setting invalid locale', async () => testLocale('asdfkl', lcAll, true)); ifit(process.platform === 'linux')('should not change LC_ALL when setting invalid locale', async () => testLocale('asdfkl', lcAll, true));
ifit(process.platform === 'linux')('should not change LC_ALL when --lang is not set', async () => testLocale('', lcAll, true)); ifit(process.platform === 'linux')('should not change LC_ALL when --lang is not set', async () => testLocale('', lcAll, true));
}); });
describe('--remote-debugging-pipe switch', () => { // TODO(nornagon): figure out why these tests fail under ASan.
ifdescribe(!isAsan)('--remote-debugging-pipe switch', () => {
it('should expose CDP via pipe', async () => { it('should expose CDP via pipe', async () => {
const electronPath = process.execPath; const electronPath = process.execPath;
appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], { appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], {
stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'] stdio: ['inherit', 'inherit', 'inherit', 'pipe', 'pipe']
}); }) as ChildProcess.ChildProcessWithoutNullStreams;
const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
const pipe = new PipeTransport(stdio[3], stdio[4]); const pipe = new PipeTransport(stdio[3], stdio[4]);
const versionPromise = new Promise(resolve => { pipe.onmessage = resolve; }); const versionPromise = new Promise(resolve => { pipe.onmessage = resolve; });
@ -352,8 +356,8 @@ describe('command line switches', () => {
it('should override --remote-debugging-port switch', async () => { it('should override --remote-debugging-port switch', async () => {
const electronPath = process.execPath; const electronPath = process.execPath;
appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe', '--remote-debugging-port=0'], { appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe', '--remote-debugging-port=0'], {
stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'] stdio: ['inherit', 'inherit', 'pipe', 'pipe', 'pipe']
}); }) as ChildProcess.ChildProcessWithoutNullStreams;
let stderr = ''; let stderr = '';
appProcess.stderr.on('data', (data: string) => { stderr += data; }); appProcess.stderr.on('data', (data: string) => { stderr += data; });
const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
@ -367,8 +371,8 @@ describe('command line switches', () => {
it('should shut down Electron upon Browser.close CDP command', async () => { it('should shut down Electron upon Browser.close CDP command', async () => {
const electronPath = process.execPath; const electronPath = process.execPath;
appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], { appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], {
stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'] stdio: ['inherit', 'inherit', 'inherit', 'pipe', 'pipe']
}); }) as ChildProcess.ChildProcessWithoutNullStreams;
const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
const pipe = new PipeTransport(stdio[3], stdio[4]); const pipe = new PipeTransport(stdio[3], stdio[4]);
pipe.send({ id: 1, method: 'Browser.close', params: {} }); pipe.send({ id: 1, method: 'Browser.close', params: {} });
@ -376,13 +380,18 @@ describe('command line switches', () => {
}); });
}); });
describe('--remote-debugging-port switch', () => { // TODO(nornagon): figure out why these tests fail under ASan.
ifdescribe(!isAsan)('--remote-debugging-port switch', () => {
it('should display the discovery page', (done) => { it('should display the discovery page', (done) => {
const electronPath = process.execPath; const electronPath = process.execPath;
let output = ''; let output = '';
appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-port=']); appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-port=']);
appProcess.stdout.on('data', (data) => {
console.log(data);
});
appProcess.stderr.on('data', (data) => { appProcess.stderr.on('data', (data) => {
console.log(data);
output += data; output += data;
const m = /DevTools listening on ws:\/\/127.0.0.1:(\d+)\//.exec(output); const m = /DevTools listening on ws:\/\/127.0.0.1:(\d+)\//.exec(output);
if (m) { if (m) {

View file

@ -243,7 +243,8 @@ describe('node feature', () => {
}); });
// IPC Electron child process not supported on Windows // IPC Electron child process not supported on Windows
ifit(process.platform !== 'win32')('does not crash when quitting with the inspector connected', function (done) { // TODO(jeremy): figure out why this times out under ASan
ifit(process.platform !== 'win32' && !process.env.IS_ASAN)('does not crash when quitting with the inspector connected', function (done) {
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], { child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], {
stdio: ['ipc'] stdio: ['ipc']
}) as childProcess.ChildProcessWithoutNullStreams; }) as childProcess.ChildProcessWithoutNullStreams;