Repository: ktorio/ktor
File: ktor-server/ktor-server-tests/jvm/test/io/ktor/server/plugins/StaticContentTest.kt (Kotlin)

Code before:

        testCustomEtagAndLastModified("staticFiles/plugins/PartialContentTest.kt", etag, date)
        testCustomEtagAndLastModified("staticResources/nested/file-nested.txt", etag, date)
        testCustomEtagAndLastModified("staticFileSystem/nested/file-nested.txt", etag, date)
        testCustomEtagAndLastModified("staticZip/nested/file-nested.txt", etag, date)

        // precompressed
        testCustomEtagAndLastModified("staticFilesPrecompressed/file.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticResources/nested/file-nested.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticFileSystem/nested/file-nested.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticZip/nested/file-nested.txt", etag, date, "br")
    }

    private suspend fun ApplicationTestBuilder.testCustomEtagAndLastModified(
        url: String,
        expectedEtag: String,
        expectedDate: GMTDate,
        acceptEncoding: String? = null
    ) {
        val response = client.get(url) {
            headers {
                acceptEncoding?.let { append(HttpHeaders.AcceptEncoding, acceptEncoding) }
            }
        }
        assertEquals(HttpStatusCode.OK, response.status)
        val etag = response.headers[HttpHeaders.ETag] ?: error("no ETag")
        assertEquals(expectedEtag.quote(), etag)
        assertEquals(expectedDate.toHttpDate(), response.headers[HttpHeaders.LastModified])
    }

    private fun StaticContentConfig<*>.configure(etag: String, date: GMTDate) {
        preCompressed(CompressedFileType.BROTLI)
        etag { EntityTagVersion(etag) }
        lastModified { date }
    }

    @Test
    fun `test strong etag`() = testApplication {
        val filesDir = Files.createTempDirectory("etag-strong").toFile()
        File(filesDir, "test.txt").apply { writeText("test.txt") }
        File(filesDir, "test.txt.br").apply { writeText("test.txt.br") }
        File(filesDir, "test.txt.gz").apply { writeText("test.txt.gz") }

        install(ConditionalHeaders)
        routing {
            staticFiles("/static", filesDir) {
                preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP)
                etag(EntityTagMode.StrongSha256)
            }
        }


Review comment (bug):
In tests it's better to use `fail`. The test will be marked as "Failed" instead of "Exited exceptionally" in the IDE
```suggestion
        val etag = response.headers[HttpHeaders.ETag] ?: fail("no ETag")
```

Code after:

        testCustomEtagAndLastModified("staticFiles/plugins/PartialContentTest.kt", etag, date)
        testCustomEtagAndLastModified("staticResources/nested/file-nested.txt", etag, date)
        testCustomEtagAndLastModified("staticFileSystem/nested/file-nested.txt", etag, date)
        testCustomEtagAndLastModified("staticZip/nested/file-nested.txt", etag, date)

        // precompressed
        testCustomEtagAndLastModified("staticFilesPrecompressed/file.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticResources/nested/file-nested.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticFileSystem/nested/file-nested.txt", etag, date, "br")
        testCustomEtagAndLastModified("staticZip/nested/file-nested.txt", etag, date, "br")
    }

    private suspend fun ApplicationTestBuilder.testCustomEtagAndLastModified(
        url: String,
        expectedEtag: String,
        expectedDate: GMTDate,
        acceptEncoding: String? = null
    ) {
        val response = client.get(url) {
            headers {
                acceptEncoding?.let { append(HttpHeaders.AcceptEncoding, acceptEncoding) }
            }
        }
        assertEquals(HttpStatusCode.OK, response.status)
        val etag = response.headers[HttpHeaders.ETag] ?: fail("no ETag")
        assertEquals(expectedEtag.quote(), etag)
        assertEquals(expectedDate.toHttpDate(), response.headers[HttpHeaders.LastModified])
    }

    private fun StaticContentConfig<*>.configure(etag: String, date: GMTDate) {
        preCompressed(CompressedFileType.BROTLI)
        etag { EntityTagVersion(etag) }
        lastModified { date }
    }

    @Test
    fun `test strong etag`() = testApplication {
        val filesDir = Files.createTempDirectory("etag-strong").toFile()
        File(filesDir, "test.txt").apply { writeText("test.txt") }
        File(filesDir, "test.txt.br").apply { writeText("test.txt.br") }
        File(filesDir, "test.txt.gz").apply { writeText("test.txt.gz") }

        install(ConditionalHeaders)
        routing {
            staticFiles("/static", filesDir) {
                preCompressed(CompressedFileType.BROTLI, CompressedFileType.GZIP)
                etag(ETagProvider.StrongSha256)
            }
        }