Make UVU tests time out (#265)

This commit is contained in:
Drew Powers 2021-05-27 14:06:54 -06:00 committed by GitHub
parent c711681cb6
commit 5292b08028
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 107 deletions

View file

@ -3,8 +3,17 @@ import * as assert from 'uvu/assert';
import { runDevServer } from './helpers.js';
const ConfigPath = suite('Config path');
const MAX_TEST_TIME = 10000; // max time this test suite may take
const root = new URL('./fixtures/config-path/', import.meta.url);
const timers = {};
ConfigPath.before.each(({ __test__ }) => {
timers[__test__] = setTimeout(() => {
throw new Error(`Test "${__test__}" did not finish within allowed time`);
}, MAX_TEST_TIME);
});
ConfigPath('can be passed via --config', async (context) => {
const configPath = new URL('./config/my-config.mjs', root).pathname;
const args = ['--config', configPath];
@ -21,4 +30,8 @@ ConfigPath('can be passed via --config', async (context) => {
assert.ok(true, 'Server started');
});
ConfigPath.after.each(({ __test__ }) => {
clearTimeout(timers[__test__]);
});
ConfigPath.run();

View file

@ -5,8 +5,16 @@ import { runDevServer } from './helpers.js';
import { loadConfig } from '#astro/config';
const ConfigPort = suite('Config path');
const MAX_TEST_TIME = 10000; // max time this test suite may take
const root = new URL('./fixtures/config-port/', import.meta.url);
const timers = {};
ConfigPort.before.each(({ __test__ }) => {
timers[__test__] = setTimeout(() => {
throw new Error(`Test "${__test__}" did not finish within allowed time`);
}, MAX_TEST_TIME);
});
ConfigPort('can be specified in the astro config', async (context) => {
const astroConfig = await loadConfig(fileURLToPath(root));
@ -15,17 +23,21 @@ ConfigPort('can be specified in the astro config', async (context) => {
ConfigPort('can be specified via --port flag', async (context) => {
const args = ['--port', '3002'];
const process = runDevServer(root, args);
const proc = runDevServer(root, args);
process.stdout.setEncoding('utf8');
for await (const chunk of process.stdout) {
proc.stdout.setEncoding('utf8');
for await (const chunk of proc.stdout) {
if (/Local:/.test(chunk)) {
assert.ok(/:3002/.test(chunk), 'Using the right port');
break;
}
}
process.kill();
proc.kill();
});
ConfigPort.after.each(({ __test__ }) => {
clearTimeout(timers[__test__]);
});
ConfigPort.run();

View file

@ -3,65 +3,87 @@ import { build as astroBuild } from '#astro/build';
import { readFile } from 'fs/promises';
import { createRuntime } from '#astro/runtime';
import { loadConfig } from '#astro/config';
import * as assert from 'uvu/assert';
import execa from 'execa';
const MAX_STARTUP_TIME = 7000; // max time startup may take
const MAX_TEST_TIME = 10000; // max time an individual test may take
const MAX_SHUTDOWN_TIME = 3000; // max time shutdown() may take
/** setup fixtures for tests */
export function setup(Suite, fixturePath) {
let runtime, setupError;
let runtime;
const timers = {};
Suite.before(async (context) => {
let timeout = setTimeout(() => {
throw new Error('Startup did not complete within allowed time');
}, MAX_STARTUP_TIME);
const astroConfig = await loadConfig(fileURLToPath(new URL(fixturePath, import.meta.url)));
const logging = {
level: 'error',
dest: process.stderr,
};
try {
runtime = await createRuntime(astroConfig, { logging });
} catch (err) {
console.error(err);
setupError = err;
}
runtime = await createRuntime(astroConfig, {
logging: { level: 'error', dest: process.stderr },
});
context.runtime = runtime;
clearTimeout(timeout);
});
Suite.before.each(({ __test__ }) => {
if (timers[__test__]) throw new Error(`Test "${__test__}" already declared`);
timers[__test__] = setTimeout(() => {
throw new Error(`"${__test__}" did not finish within allowed time`);
}, MAX_TEST_TIME);
});
Suite.after(async () => {
let timeout = setTimeout(() => {
throw new Error('Shutdown did not complete within allowed time');
}, MAX_SHUTDOWN_TIME);
(await runtime) && runtime.shutdown();
clearTimeout(timeout);
});
Suite('No errors creating a runtime', () => {
assert.equal(setupError, undefined);
Suite.after.each(({ __test__ }) => {
clearTimeout(timers[__test__]);
});
}
export function setupBuild(Suite, fixturePath) {
let build, setupError;
const timers = {};
Suite.before(async (context) => {
let timeout = setTimeout(() => {
throw new Error('Startup did not complete within allowed time');
}, MAX_STARTUP_TIME);
const astroConfig = await loadConfig(fileURLToPath(new URL(fixturePath, import.meta.url)));
const logging = {
level: 'error',
dest: process.stderr,
};
build = () => astroBuild(astroConfig, logging);
context.build = build;
context.build = () => astroBuild(astroConfig, { level: 'error', dest: process.stderr });
context.readFile = async (path) => {
const resolved = fileURLToPath(new URL(`${fixturePath}/${astroConfig.dist}${path}`, import.meta.url));
return readFile(resolved).then((r) => r.toString('utf8'));
};
clearTimeout(timeout);
});
Suite.before.each(({ __test__ }) => {
if (timers[__test__]) throw new Error(`Test "${__test__}" already declared`);
timers[__test__] = setTimeout(() => {
throw new Error(`"${__test__}" did not finish within allowed time`);
}, MAX_TEST_TIME);
});
Suite.after(async () => {
// Shutdown i guess.
});
Suite('No errors creating a runtime', () => {
assert.equal(setupError, undefined);
Suite.after.each(({ __test__ }) => {
clearTimeout(timers[__test__]);
});
}

View file

@ -1,91 +1,37 @@
import path from 'path';
import glob from 'tiny-glob/sync.js';
import { fileURLToPath } from 'url';
import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import { createRuntime } from '#astro/runtime';
import { loadConfig } from '#astro/config';
import { promises as fsPromises } from 'fs';
import { relative as pathRelative } from 'path';
const { readdir, stat } = fsPromises;
import { setup } from './helpers.js';
const SnowpackDev = suite('snowpack.dev');
setup(SnowpackDev, '../../../examples/snowpack');
const snowpackDir = new URL('../../../examples/snowpack/', import.meta.url);
let runtime, cwd, setupError;
SnowpackDev.before(async () => {
// Bug: Snowpack config is still loaded relative to the current working directory.
cwd = process.cwd();
process.chdir(fileURLToPath(snowpackDir));
const astroConfig = await loadConfig(fileURLToPath(snowpackDir));
const logging = {
level: 'error',
dest: process.stderr,
};
try {
runtime = await createRuntime(astroConfig, { logging });
} catch (err) {
console.error(err);
setupError = err;
}
});
SnowpackDev.after(async () => {
process.chdir(cwd);
(await runtime) && runtime.shutdown();
});
/** create an iterator for all page files */
async function* allPageFiles(root) {
for (const filename of await readdir(root)) {
const fullpath = new URL(filename, root);
const info = await stat(fullpath);
if (info.isDirectory()) {
yield* allPageFiles(new URL(fullpath + '/'));
} else {
yield fullpath;
}
}
}
/** create an iterator for all pages and yield the relative paths */
async function* allPages(root) {
for await (let fileURL of allPageFiles(root)) {
let bare = fileURLToPath(fileURL)
.replace(/\.(astro|md)$/, '')
.replace(/index$/, '');
yield '/' + pathRelative(fileURLToPath(root), bare);
}
// convert file path to its final url
function formatURL(filepath) {
return filepath
.replace(/^\/?/, '/') // add / to beginning, if missing
.replace(/(index)?\.(astro|md)$/, '') // remove .astro and .md extensions
.replace(/\/$/, ''); // remove trailing slash, if any
}
SnowpackDev('No error creating the runtime', () => {
assert.equal(setupError, undefined);
// declaring routes individually helps us run many quick tests rather than one giant slow test
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../examples/snowpack/src/pages');
let pages = glob('**/*.{astro,md}', { cwd: root, onlyFiles: true })
.filter((page) => !page.includes('proof-of-concept-dynamic'))
.map(formatURL);
SnowpackDev('Pages successfully scanned', () => {
assert.ok(pages.length > 0);
});
SnowpackDev('Can load every page', async () => {
const failed = [];
const pageRoot = new URL('./src/pages/', snowpackDir);
for await (let pathname of allPages(pageRoot)) {
if (pathname.includes('proof-of-concept-dynamic')) {
continue;
}
for (const pathname of pages) {
SnowpackDev(`Loads "${pathname}"`, async ({ runtime }) => {
const result = await runtime.load(pathname);
if (result.statusCode === 500) {
failed.push({ ...result, pathname });
continue;
}
assert.equal(result.statusCode, 200, `Loading ${pathname}`);
}
if (failed.length > 0) {
console.error(failed);
}
assert.equal(failed.length, 0, 'Failed pages');
});
assert.equal(result.statusCode, 200);
return;
});
}
SnowpackDev.run();