From d5d21e70ff94ea5d133b23793164de77e0bd024a Mon Sep 17 00:00:00 2001 From: Jacopo Date: Fri, 3 Jan 2025 17:58:12 +0100 Subject: [PATCH 1/9] Added support to logLevel plugin option --- index.js | 1 + test/static.test.js | 172 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/index.js b/index.js index 5b3e65e5..6a94b64f 100644 --- a/index.js +++ b/index.js @@ -64,6 +64,7 @@ async function fastifyStatic (fastify, opts) { schema: { hide: opts.schemaHide !== undefined ? opts.schemaHide : true }, + logLevel: opts.logLevel, errorHandler (error, request, reply) { if (error?.code === 'ERR_STREAM_PREMATURE_CLOSE') { reply.request.raw.destroy() diff --git a/test/static.test.js b/test/static.test.js index feab2212..3fed91b7 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -4102,3 +4102,175 @@ t.test('respect the .type when using with sendFile with contentType disabled', t }) }) }) + +t.test('register /static/ with custom log level', t => { + t.plan(12) + + const pluginOptions = { + root: path.join(__dirname, '/static'), + prefix: '/static/', + logLevel: 'debug' + } + const fastify = Fastify() + fastify.register(fastifyStatic, pluginOptions) + + t.teardown(fastify.close.bind(fastify)) + + fastify.listen({ port: 0 }, (err) => { + t.error(err) + + fastify.server.unref() + + t.test('/static/index.html', (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(body.toString(), indexContent) + genericResponseChecks(t, response) + }) + }) + + t.test('/static/index.html', t => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'HEAD', + url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(body.toString(), '') + genericResponseChecks(t, response) + }) + }) + + t.test('/static/index.css', (t) => { + t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/index.css' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + genericResponseChecks(t, response) + }) + }) + + t.test('/static/', (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(body.toString(), indexContent) + genericResponseChecks(t, response) + }) + }) + + t.test('/static', (t) => { + t.plan(2) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 404) + }) + }) + + t.test('/static/deep/path/for/test/purpose/foo.html', (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/purpose/foo.html' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(body.toString(), deepContent) + genericResponseChecks(t, response) + }) + }) + + t.test('/static/deep/path/for/test/', (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/' + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 200) + t.equal(body.toString(), innerIndex) + genericResponseChecks(t, response) + }) + }) + + t.test('/static/this/path/for/test', (t) => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/this/path/for/test', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 404) + genericErrorResponseChecks(t, response) + }) + }) + + t.test('/static/this/path/doesnt/exist.html', (t) => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/this/path/doesnt/exist.html', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 404) + genericErrorResponseChecks(t, response) + }) + }) + + t.test('/static/../index.js', (t) => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/../index.js', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 403) + genericErrorResponseChecks(t, response) + }) + }) + + t.test('304', t => { + t.plan(5 + GENERIC_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' + }, (err, response, body) => { + t.error(err) + const etag = response.headers.etag + t.equal(response.statusCode, 200) + t.equal(body.toString(), indexContent) + genericResponseChecks(t, response) + + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/static/index.html', + headers: { + 'if-none-match': etag + } + }, (err, response, body) => { + t.error(err) + t.equal(response.statusCode, 304) + }) + }) + }) + }) +}) From 2fa37d92da205875aeb27a66cbb15711770391a9 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 6 Jan 2025 17:26:47 +0100 Subject: [PATCH 2/9] Checking that with an higher log level logs are not generated --- test/static.test.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/test/static.test.js b/test/static.test.js index 3fed91b7..7c03b3b9 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -4104,14 +4104,30 @@ t.test('respect the .type when using with sendFile with contentType disabled', t }) t.test('register /static/ with custom log level', t => { - t.plan(12) + t.plan(11) const pluginOptions = { root: path.join(__dirname, '/static'), prefix: '/static/', - logLevel: 'debug' + logLevel: 'warn' } - const fastify = Fastify() + const fastify = Fastify({ + logger: { + stream: { + write: (logLine) => { + const log = JSON.parse(logLine) + + /* + Do not expecting any request to be log since an higher log level then info has been set for the plugin. + Fails the test otherwise. + */ + if (log.reqId) { + t.fail() + } + }, + }, + }, + }) fastify.register(fastifyStatic, pluginOptions) t.teardown(fastify.close.bind(fastify)) @@ -4172,17 +4188,6 @@ t.test('register /static/ with custom log level', t => { }) }) - t.test('/static', (t) => { - t.plan(2) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 404) - }) - }) - t.test('/static/deep/path/for/test/purpose/foo.html', (t) => { t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) simple.concat({ From 0bb421fad8be3085ff9d8efed17b7902b2631699 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 6 Jan 2025 18:55:07 +0100 Subject: [PATCH 3/9] Using .fail message to add more details to the test's scenario --- test/static.test.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/static.test.js b/test/static.test.js index 7c03b3b9..13a54111 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -4117,12 +4117,8 @@ t.test('register /static/ with custom log level', t => { write: (logLine) => { const log = JSON.parse(logLine) - /* - Do not expecting any request to be log since an higher log level then info has been set for the plugin. - Fails the test otherwise. - */ if (log.reqId) { - t.fail() + t.fail('Not expecting any log since plugin\'s log level is set at WARN') } }, }, From 55f44eaeb26ae4024e1d86e0ce3075d131efb1a3 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 9 Jan 2025 18:31:46 +0100 Subject: [PATCH 4/9] Added types for logLevel --- types/index.d.ts | 1 + types/index.test-d.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 4fddd485..1f12e40c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -114,6 +114,7 @@ declare namespace fastifyStatic { lastModified?: boolean; maxAge?: string | number; constraints?: RouteOptions['constraints']; + logLevel?: RouteOptions['logLevel']; } export const fastifyStatic: FastifyStaticPlugin diff --git a/types/index.test-d.ts b/types/index.test-d.ts index b91705da..a8a9903a 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -68,7 +68,8 @@ const options: FastifyStaticOptions = { constraints: { host: /.*\.example\.com/, version: '1.0.2' - } + }, + logLevel: 'warn' } expectError({ From 6eb90b8fafbbbf4accb2d153fff382411de2c516 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 9 Jan 2025 18:35:56 +0100 Subject: [PATCH 5/9] Updated readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 271e1ea9..aed53de4 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,12 @@ Default: `{}` Constraints that will be added to registered routes. See Fastify's documentation for [route constraints](https://fastify.dev/docs/latest/Reference/Routes/#constraints). +#### `logLevel` + +Default: `info` + +Set log level for this route. + #### `prefixAvoidTrailingSlash` Default: `false` From acf05ab740f943443a5168187e7287631d191527 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 9 Jan 2025 18:37:34 +0100 Subject: [PATCH 6/9] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aed53de4..e7e17936 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Constraints that will be added to registered routes. See Fastify's documentation Default: `info` -Set log level for this route. +Set log level to registered routes. #### `prefixAvoidTrailingSlash` From 835c6f43f06304fa456de20f5336e680c03c865a Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Mon, 13 Jan 2025 12:29:17 +0000 Subject: [PATCH 7/9] Update README.md Signed-off-by: Frazer Smith --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7e17936..53b108de 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Constraints that will be added to registered routes. See Fastify's documentation Default: `info` -Set log level to registered routes. +Set log level for registered routes. #### `prefixAvoidTrailingSlash` From 36e081441ddfaa40bcf6afd4b6ea04ddeb292d17 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 13 Jan 2025 14:02:20 +0100 Subject: [PATCH 8/9] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7e17936..53b108de 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Constraints that will be added to registered routes. See Fastify's documentation Default: `info` -Set log level to registered routes. +Set log level for registered routes. #### `prefixAvoidTrailingSlash` From 2bc290396650f085a74aca6e0439afa69e274d5a Mon Sep 17 00:00:00 2001 From: Jacopo Date: Sun, 2 Feb 2025 18:33:12 +0100 Subject: [PATCH 9/9] Adjusted test for node test runner --- test/static.test.js | 228 +++++++++++++++++--------------------------- 1 file changed, 88 insertions(+), 140 deletions(-) diff --git a/test/static.test.js b/test/static.test.js index 4d155451..6082e891 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -3493,8 +3493,8 @@ test('respect the .type when using with sendFile with contentType disabled', asy t.assert.deepStrictEqual(await response.text(), fooContent) }) -t.test('register /static/ with custom log level', t => { - t.plan(11) +test('register /static/ with custom log level', async t => { + t.plan(9) const pluginOptions = { root: path.join(__dirname, '/static'), @@ -3505,10 +3505,9 @@ t.test('register /static/ with custom log level', t => { logger: { stream: { write: (logLine) => { - const log = JSON.parse(logLine) - - if (log.reqId) { - t.fail('Not expecting any log since plugin\'s log level is set at WARN') + if (logLine.includes('"msg":"incoming request"')) { + console.warn(logLine) + throw new Error('Should never reach this point since log level is set at WARN!! Unexpected log line: ' + logLine) } }, }, @@ -3516,152 +3515,101 @@ t.test('register /static/ with custom log level', t => { }) fastify.register(fastifyStatic, pluginOptions) - t.teardown(fastify.close.bind(fastify)) + t.after(() => fastify.close()) - fastify.listen({ port: 0 }, (err) => { - t.error(err) + await fastify.listen({ port: 0 }) + fastify.server.unref() - fastify.server.unref() + await t.test('/static/index.html', async (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - t.test('/static/index.html', (t) => { - t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - t.equal(body.toString(), indexContent) - genericResponseChecks(t, response) - }) - }) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html') + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), indexContent) + genericResponseChecks(t, response) + }) - t.test('/static/index.html', t => { - t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'HEAD', - url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - t.equal(body.toString(), '') - genericResponseChecks(t, response) - }) - }) + await t.test('/static/index.html', async t => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html', { method: 'HEAD' }) + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), '') + genericResponseChecks(t, response) + }) - t.test('/static/index.css', (t) => { - t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/index.css' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - genericResponseChecks(t, response) - }) - }) + await t.test('/static/index.css', async (t) => { + t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.css') + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + genericResponseChecks(t, response) + }) - t.test('/static/', (t) => { - t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - t.equal(body.toString(), indexContent) - genericResponseChecks(t, response) - }) - }) + await t.test('/static/', async (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/') - t.test('/static/deep/path/for/test/purpose/foo.html', (t) => { - t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/purpose/foo.html' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - t.equal(body.toString(), deepContent) - genericResponseChecks(t, response) - }) - }) + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), indexContent) + genericResponseChecks(t, response) + }) - t.test('/static/deep/path/for/test/', (t) => { - t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/' - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 200) - t.equal(body.toString(), innerIndex) - genericResponseChecks(t, response) - }) - }) + await t.test('/static/deep/path/for/test/purpose/foo.html', async (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/purpose/foo.html') - t.test('/static/this/path/for/test', (t) => { - t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/this/path/for/test', - followRedirect: false - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 404) - genericErrorResponseChecks(t, response) - }) - }) + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), deepContent) + genericResponseChecks(t, response) + }) + await t.test('/static/deep/path/for/test/', async (t) => { + t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/') - t.test('/static/this/path/doesnt/exist.html', (t) => { - t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/this/path/doesnt/exist.html', - followRedirect: false - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 404) - genericErrorResponseChecks(t, response) - }) - }) + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), innerIndex) + genericResponseChecks(t, response) + }) - t.test('/static/../index.js', (t) => { - t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/../index.js', - followRedirect: false - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 403) - genericErrorResponseChecks(t, response) - }) - }) + await t.test('/static/this/path/for/test', async (t) => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/this/path/for/test') - t.test('304', t => { - t.plan(5 + GENERIC_RESPONSE_CHECK_COUNT) - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/index.html' - }, (err, response, body) => { - t.error(err) - const etag = response.headers.etag - t.equal(response.statusCode, 200) - t.equal(body.toString(), indexContent) - genericResponseChecks(t, response) - - simple.concat({ - method: 'GET', - url: 'http://localhost:' + fastify.server.address().port + '/static/index.html', - headers: { - 'if-none-match': etag - } - }, (err, response, body) => { - t.error(err) - t.equal(response.statusCode, 304) - }) - }) + t.assert.ok(!response.ok) + t.assert.deepStrictEqual(response.status, 404) + genericErrorResponseChecks(t, response) + }) + + await t.test('/static/this/path/doesnt/exist.html', async (t) => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/this/path/doesnt/exist.html') + + t.assert.ok(!response.ok) + t.assert.deepStrictEqual(response.status, 404) + genericErrorResponseChecks(t, response) + }) + + await t.test('304', async t => { + t.plan(5 + GENERIC_RESPONSE_CHECK_COUNT) + const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html') + + t.assert.ok(response.ok) + t.assert.deepStrictEqual(response.status, 200) + t.assert.deepStrictEqual(await response.text(), indexContent) + genericResponseChecks(t, response) + + const response2 = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html', { + headers: { + 'if-none-match': response.headers.get('etag') + }, + cache: 'no-cache' }) + t.assert.ok(!response2.ok) + t.assert.deepStrictEqual(response2.status, 304) }) })