test: add unit + integration tests for tf-docs (8 passing)
This commit is contained in:
@@ -125,6 +125,17 @@ const server = http.createServer((req, res) => {
|
|||||||
</html>`);
|
</html>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
if (require.main === module) {
|
||||||
|
server.listen(PORT, () => {
|
||||||
console.log(`[${SERVICE}] listening on :${PORT} (version ${VERSION})`);
|
console.log(`[${SERVICE}] listening on :${PORT} (version ${VERSION})`);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getDocsCandidates,
|
||||||
|
contentTypeFor,
|
||||||
|
health,
|
||||||
|
docsHandler,
|
||||||
|
server,
|
||||||
|
s3,
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
process.env.S3_BUCKET = process.env.S3_BUCKET || 'terraform-registry';
|
||||||
|
|
||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert');
|
||||||
|
const { Readable } = require('node:stream');
|
||||||
|
|
||||||
|
const { getDocsCandidates, contentTypeFor, server, s3 } = require('../server.js');
|
||||||
|
|
||||||
|
async function withServer(fn) {
|
||||||
|
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
||||||
|
const base = `http://127.0.0.1:${server.address().port}`;
|
||||||
|
try {
|
||||||
|
await fn(base);
|
||||||
|
} finally {
|
||||||
|
await new Promise((resolve) => server.close(resolve));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getDocsCandidates (URL -> S3 keys) ---
|
||||||
|
|
||||||
|
test('candidates: trailing slash -> index.html', () => {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
getDocsCandidates('/docs/nubes/nubes/1.0.0/'),
|
||||||
|
['docs/nubes/nubes/1.0.0/index.html']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('candidates: file with extension -> exact + root index fallback', () => {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
getDocsCandidates('/docs/nubes/nubes/1.0.0/page.html'),
|
||||||
|
['docs/nubes/nubes/1.0.0/page.html', 'docs/nubes/nubes/1.0.0/index.html']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('candidates: directory-style path -> exact + index.html + root index', () => {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
getDocsCandidates('/docs/nubes/nubes/1.0.0/guides/getting-started'),
|
||||||
|
[
|
||||||
|
'docs/nubes/nubes/1.0.0/guides/getting-started',
|
||||||
|
'docs/nubes/nubes/1.0.0/guides/getting-started/index.html',
|
||||||
|
'docs/nubes/nubes/1.0.0/index.html',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- contentTypeFor ---
|
||||||
|
|
||||||
|
test('contentTypeFor: known and unknown extensions', () => {
|
||||||
|
assert.strictEqual(contentTypeFor('index.html'), 'text/html; charset=utf-8');
|
||||||
|
assert.strictEqual(contentTypeFor('style.css'), 'text/css; charset=utf-8');
|
||||||
|
assert.strictEqual(contentTypeFor('app.js'), 'application/javascript; charset=utf-8');
|
||||||
|
assert.strictEqual(contentTypeFor('logo.png'), 'image/png');
|
||||||
|
assert.strictEqual(contentTypeFor('data.json'), 'application/json; charset=utf-8');
|
||||||
|
assert.strictEqual(contentTypeFor('file.unknown'), 'application/octet-stream');
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- /health ---
|
||||||
|
|
||||||
|
test('GET /health -> 200 ok when S3 available', async () => {
|
||||||
|
const originalSend = s3.send;
|
||||||
|
s3.send = async () => ({ $metadata: { httpStatusCode: 200 } });
|
||||||
|
await withServer(async (base) => {
|
||||||
|
const res = await fetch(`${base}/health`);
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(await res.text(), 'ok');
|
||||||
|
});
|
||||||
|
s3.send = originalSend;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('GET /health -> 503 when S3 unreachable', async () => {
|
||||||
|
const originalSend = s3.send;
|
||||||
|
s3.send = async () => { throw new Error('boom'); };
|
||||||
|
await withServer(async (base) => {
|
||||||
|
const res = await fetch(`${base}/health`);
|
||||||
|
assert.strictEqual(res.status, 503);
|
||||||
|
assert.match(await res.text(), /s3 unreachable/);
|
||||||
|
});
|
||||||
|
s3.send = originalSend;
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- /docs ---
|
||||||
|
|
||||||
|
test('GET /docs/... -> 200 streams body with content-type', async () => {
|
||||||
|
const originalSend = s3.send;
|
||||||
|
s3.send = async (cmd) => {
|
||||||
|
if (cmd.input && cmd.input.Key) {
|
||||||
|
return { Body: Readable.from(['<html>ok</html>']), ContentType: 'text/html' };
|
||||||
|
}
|
||||||
|
return { $metadata: { httpStatusCode: 200 } };
|
||||||
|
};
|
||||||
|
await withServer(async (base) => {
|
||||||
|
const res = await fetch(`${base}/docs/nubes/nubes/1.0.0/`);
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.match(res.headers.get('content-type') || '', /text\/html/);
|
||||||
|
assert.strictEqual(await res.text(), '<html>ok</html>');
|
||||||
|
});
|
||||||
|
s3.send = originalSend;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('GET /docs/... -> 404 when no key found', async () => {
|
||||||
|
const originalSend = s3.send;
|
||||||
|
s3.send = async (cmd) => {
|
||||||
|
if (cmd.input && cmd.input.Key) {
|
||||||
|
const err = new Error('Not Found');
|
||||||
|
err.name = 'NoSuchKey';
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return { $metadata: { httpStatusCode: 200 } };
|
||||||
|
};
|
||||||
|
await withServer(async (base) => {
|
||||||
|
const res = await fetch(`${base}/docs/nubes/nubes/1.0.0/missing`);
|
||||||
|
assert.strictEqual(res.status, 404);
|
||||||
|
});
|
||||||
|
s3.send = originalSend;
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user