Skip to content

Commit

Permalink
run jest with --detectOpenHandles on CI to figure out what i… (#58543)
Browse files Browse the repository at this point in the history
* run jest with `--detectOpenHandles` on CI to figure out what is happening with pauses

* focus tests on jest integration

* force kill child processes in config reload test

* skip flaky suite

* increase timeout for looking for installed packages

* run all tests again
  • Loading branch information
Spencer authored Feb 27, 2020
1 parent a896515 commit 841e64e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 165 deletions.
318 changes: 156 additions & 162 deletions src/cli/serve/integration_tests/reload_logging_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,180 +84,174 @@ function createConfigManager(configPath: string) {
}

describe('Server logging configuration', function() {
let child: Child.ChildProcess;
let child: undefined | Child.ChildProcess;

beforeEach(() => {
Fs.mkdirSync(tempDir, { recursive: true });
});

afterEach(async () => {
if (child !== undefined) {
child.kill();
// wait for child to be killed otherwise jest complains that process not finished
await new Promise(res => setTimeout(res, 1000));
const exitPromise = new Promise(resolve => child?.once('exit', resolve));
child.kill('SIGKILL');
await exitPromise;
}

Del.sync(tempDir, { force: true });
});

const isWindows = /^win/.test(process.platform);
if (isWindows) {
if (process.platform.startsWith('win')) {
it('SIGHUP is not a feature of Windows.', () => {
// nothing to do for Windows
});
} else {
describe('legacy logging', () => {
it(
'should be reloadable via SIGHUP process signaling',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(legacyConfig, configFilePath);

child = Child.spawn(process.execPath, [
kibanaPath,
'--oss',
'--config',
configFilePath,
'--verbose',
]);

const message$ = Rx.fromEvent(child.stdout, 'data').pipe(
map(messages =>
String(messages)
.split('\n')
.filter(Boolean)
)
);

await message$
.pipe(
// We know the sighup handler will be registered before this message logged
filter(messages => messages.some(m => m.includes('setting up root'))),
take(1)
)
.toPromise();

const lastMessage = await message$.pipe(take(1)).toPromise();
expect(containsJsonOnly(lastMessage)).toBe(true);

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.json = false;
return oldConfig;
});

child.kill('SIGHUP');

await message$
.pipe(
filter(messages => !containsJsonOnly(messages)),
take(1)
)
.toPromise();
},
minute
);

it(
'should recreate file handle on SIGHUP',
async function() {
const logPath = Path.resolve(tempDir, 'kibana.log');
const logPathArchived = Path.resolve(tempDir, 'kibana_archive.log');

child = Child.spawn(process.execPath, [
kibanaPath,
'--oss',
'--config',
legacyConfig,
'--logging.dest',
logPath,
'--verbose',
]);

await watchFileUntil(logPath, /setting up root/, 30 * second);
// once the server is running, archive the log file and issue SIGHUP
Fs.renameSync(logPath, logPathArchived);
child.kill('SIGHUP');

await watchFileUntil(
logPath,
/Reloaded logging configuration due to SIGHUP/,
30 * second
);
},
minute
);
});

describe('platform logging', () => {
it(
'should be reloadable via SIGHUP process signaling',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(configFileLogConsole, configFilePath);

child = Child.spawn(process.execPath, [kibanaPath, '--oss', '--config', configFilePath]);

const message$ = Rx.fromEvent(child.stdout, 'data').pipe(
map(messages =>
String(messages)
.split('\n')
.filter(Boolean)
)
);

await message$
.pipe(
// We know the sighup handler will be registered before this message logged
filter(messages => messages.some(m => m.includes('setting up root'))),
take(1)
)
.toPromise();

const lastMessage = await message$.pipe(take(1)).toPromise();
expect(containsJsonOnly(lastMessage)).toBe(true);

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.appenders.console.layout.kind = 'pattern';
return oldConfig;
});
child.kill('SIGHUP');

await message$
.pipe(
filter(messages => !containsJsonOnly(messages)),
take(1)
)
.toPromise();
},
30 * second
);
it(
'should recreate file handle on SIGHUP',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(configFileLogFile, configFilePath);

const logPath = Path.resolve(tempDir, 'kibana.log');
const logPathArchived = Path.resolve(tempDir, 'kibana_archive.log');

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.appenders.file.path = logPath;
return oldConfig;
});

child = Child.spawn(process.execPath, [kibanaPath, '--oss', '--config', configFilePath]);

await watchFileUntil(logPath, /setting up root/, 30 * second);
// once the server is running, archive the log file and issue SIGHUP
Fs.renameSync(logPath, logPathArchived);
child.kill('SIGHUP');

await watchFileUntil(
logPath,
/Reloaded logging configuration due to SIGHUP/,
30 * second
);
},
minute
);
});
return;
}

describe('legacy logging', () => {
it(
'should be reloadable via SIGHUP process signaling',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(legacyConfig, configFilePath);

child = Child.spawn(process.execPath, [
kibanaPath,
'--oss',
'--config',
configFilePath,
'--verbose',
]);

const message$ = Rx.fromEvent(child.stdout, 'data').pipe(
map(messages =>
String(messages)
.split('\n')
.filter(Boolean)
)
);

await message$
.pipe(
// We know the sighup handler will be registered before this message logged
filter(messages => messages.some(m => m.includes('setting up root'))),
take(1)
)
.toPromise();

const lastMessage = await message$.pipe(take(1)).toPromise();
expect(containsJsonOnly(lastMessage)).toBe(true);

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.json = false;
return oldConfig;
});

child.kill('SIGHUP');

await message$
.pipe(
filter(messages => !containsJsonOnly(messages)),
take(1)
)
.toPromise();
},
minute
);

it(
'should recreate file handle on SIGHUP',
async function() {
const logPath = Path.resolve(tempDir, 'kibana.log');
const logPathArchived = Path.resolve(tempDir, 'kibana_archive.log');

child = Child.spawn(process.execPath, [
kibanaPath,
'--oss',
'--config',
legacyConfig,
'--logging.dest',
logPath,
'--verbose',
]);

await watchFileUntil(logPath, /setting up root/, 30 * second);
// once the server is running, archive the log file and issue SIGHUP
Fs.renameSync(logPath, logPathArchived);
child.kill('SIGHUP');

await watchFileUntil(logPath, /Reloaded logging configuration due to SIGHUP/, 30 * second);
},
minute
);
});

describe('platform logging', () => {
it(
'should be reloadable via SIGHUP process signaling',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(configFileLogConsole, configFilePath);

child = Child.spawn(process.execPath, [kibanaPath, '--oss', '--config', configFilePath]);

const message$ = Rx.fromEvent(child.stdout, 'data').pipe(
map(messages =>
String(messages)
.split('\n')
.filter(Boolean)
)
);

await message$
.pipe(
// We know the sighup handler will be registered before this message logged
filter(messages => messages.some(m => m.includes('setting up root'))),
take(1)
)
.toPromise();

const lastMessage = await message$.pipe(take(1)).toPromise();
expect(containsJsonOnly(lastMessage)).toBe(true);

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.appenders.console.layout.kind = 'pattern';
return oldConfig;
});
child.kill('SIGHUP');

await message$
.pipe(
filter(messages => !containsJsonOnly(messages)),
take(1)
)
.toPromise();
},
30 * second
);
it(
'should recreate file handle on SIGHUP',
async function() {
const configFilePath = Path.resolve(tempDir, 'kibana.yml');
Fs.copyFileSync(configFileLogFile, configFilePath);

const logPath = Path.resolve(tempDir, 'kibana.log');
const logPathArchived = Path.resolve(tempDir, 'kibana_archive.log');

createConfigManager(configFilePath).modify(oldConfig => {
oldConfig.logging.appenders.file.path = logPath;
return oldConfig;
});

child = Child.spawn(process.execPath, [kibanaPath, '--oss', '--config', configFilePath]);

await watchFileUntil(logPath, /setting up root/, 30 * second);
// once the server is running, archive the log file and issue SIGHUP
Fs.renameSync(logPath, logPathArchived);
child.kill('SIGHUP');

await watchFileUntil(logPath, /Reloaded logging configuration due to SIGHUP/, 30 * second);
},
minute
);
});
});
2 changes: 1 addition & 1 deletion src/dev/npm/integration_tests/installed_packages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('src/dev/npm/installed_packages', () => {
includeDev: true,
}),
]);
}, 60 * 1000);
}, 360 * 1000);

it('reads all installed packages of a module', () => {
expect(fixture1Packages).toEqual([
Expand Down
2 changes: 1 addition & 1 deletion tasks/test_jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module.exports = function(grunt) {
function runJest(jestScript) {
const serverCmd = {
cmd: 'node',
args: [jestScript, '--ci'],
args: [jestScript, '--ci', '--detectOpenHandles'],
opts: { stdio: 'inherit' },
};

Expand Down
2 changes: 1 addition & 1 deletion test/scripts/jenkins_xpack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if [[ -z "$CODE_COVERAGE" ]] ; then

echo " -> Running jest tests"
cd "$XPACK_DIR"
checks-reporter-with-killswitch "X-Pack Jest" node scripts/jest --ci --verbose
checks-reporter-with-killswitch "X-Pack Jest" node scripts/jest --ci --verbose --detectOpenHandles
echo ""
echo ""

Expand Down

0 comments on commit 841e64e

Please sign in to comment.