Project updates from Template (#1)

This PR contains the latest updates from the generic Website template, which have been added while working on #loud-amsterdam.

Reviewed-on: #1
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-09-04 13:40:35 +00:00
committed by javier
parent 08b4d80064
commit 65b62681eb
60 changed files with 2347 additions and 326 deletions
@@ -0,0 +1,179 @@
import HTTPTypes
import Hummingbird
import HummingbirdTesting
import Testing
@testable import Infrastructure
@Suite(
"HTTPSRedirectMiddleware middleware",
.tags(.middleware)
)
struct HTTPSRedirectMiddlewareTests {
// MARK: Functional tests
@Test
func `redirects a request forwarded over plain http`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "http"]
) { response in
#expect(response.status == .movedPermanently)
#expect(response.headers[.location] == "https://example.com/hello")
}
}
}
@Test
func `preserves the path and the query of the redirected request`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello?utm_source=test&utm_medium=email",
method: .get,
headers: [.xForwardedProto: "http"]
) { response in
#expect(response.headers[.location] == "https://example.com/hello?utm_source=test&utm_medium=email")
}
}
}
@Test
func `matches the forwarded scheme regardless of its casing`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "HTTP"]
) { response in
#expect(response.status == .movedPermanently)
}
}
}
@Test
func `reads the leftmost entry of a proxy chain`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "http, https"]
) { response in
#expect(response.status == .movedPermanently)
}
}
}
@Test
func `passes a request forwarded over https through`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "https"]
) { response in
#expect(response.status == .ok)
#expect(response.headers[.location] == nil)
}
}
}
@Test
func `passes a request without the forwarded header through`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get
) { response in
#expect(response.status == .ok)
}
}
}
@Test
func `passes every request through when the header is not trusted`() async throws {
try await app(
configuration: .init(
origin: "https://example.com",
trustForwardedProto: false
)
).test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "http"]
) { response in
#expect(response.status == .ok)
}
}
}
@Test
func `leaves the well-known space on plain http`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/.well-known/acme-challenge/token",
method: .get,
headers: [.xForwardedProto: "http"]
) { response in
#expect(response.status == .ok)
#expect(response.headers[.location] == nil)
}
}
}
@Test
func `passes every request through when the origin is not itself https`() async throws {
try await app(
configuration: .init(
origin: "http://example.com",
trustForwardedProto: true
)
).test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get,
headers: [.xForwardedProto: "http"]
) { response in
#expect(response.status == .ok)
}
}
}
}
// MARK: - Helpers
private extension HTTPSRedirectMiddlewareTests {
// MARK: Methods
/// Builds an application whose router applies the HTTPS-redirect middleware ahead of a `/hello`
/// route returning a plain body and a `/.well-known/acme-challenge/token` route standing in for
/// a certificate authority's challenge file.
func app(
configuration: HTTPSRedirectMiddleware<BasicRequestContext>.Configuration = .init(
origin: "https://example.com",
trustForwardedProto: true
)
) -> some ApplicationProtocol {
let router = Router()
router.addMiddleware {
HTTPSRedirectMiddleware(configuration: configuration)
}
router.get("hello") { _, _ in
"Hello!"
}
router.get(".well-known/acme-challenge/token") { _, _ in
"token"
}
return Application(router: router)
}
}
@@ -25,6 +25,9 @@ struct LocalizationMiddlewareTests {
router.get("language") { _, context in
context.language
}
router.get("de/language") { _, context in
context.language
}
return router
}())
@@ -69,4 +72,44 @@ struct LocalizationMiddlewareTests {
}
}
@Test
func `honours a supported lang query parameter over the header`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/language?lang=de",
method: .get,
headers: [.acceptLanguage: "en"]
) { response in
#expect(String(buffer: response.body) == "de")
}
}
}
/// A language's whole URL prefix answers in its language, so its not-found page does too.
@Test
func `pins the language a leading path segment names over the header`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/de/language",
method: .get,
headers: [.acceptLanguage: "en"]
) { response in
#expect(String(buffer: response.body) == "de")
}
}
}
@Test
func `negotiates the header when the lang query parameter is unsupported`() async throws {
try await app.test(.router) { client in
try await client.execute(
uri: "/language?lang=fr",
method: .get,
headers: [.acceptLanguage: "de"]
) { response in
#expect(String(buffer: response.body) == "de")
}
}
}
}
@@ -0,0 +1,150 @@
import HTTPTypes
import Hummingbird
import HummingbirdTesting
import Testing
@testable import Infrastructure
@Suite(
"TrailingSlashRedirectMiddleware middleware",
.tags(.middleware)
)
struct TrailingSlashRedirectMiddlewareTests {
// MARK: Functional tests
@Test
func `redirects a path carrying a trailing slash`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello/",
method: .get
) { response in
#expect(response.status == .movedPermanently)
#expect(response.headers[.location] == "/hello")
}
}
}
@Test
func `preserves the query of the redirected request`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello/?utm_source=test&utm_medium=email",
method: .get
) { response in
#expect(response.headers[.location] == "/hello?utm_source=test&utm_medium=email")
}
}
}
@Test
func `collapses a path of nothing but slashes onto the root`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "//",
method: .get
) { response in
#expect(response.status == .movedPermanently)
#expect(response.headers[.location] == "/")
}
}
}
@Test
func `strips every trailing slash at once`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello///",
method: .get
) { response in
#expect(response.headers[.location] == "/hello")
}
}
}
@Test
func `passes the canonical path through`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello",
method: .get
) { response in
#expect(response.status == .ok)
#expect(response.headers[.location] == nil)
}
}
}
@Test
func `leaves the root path alone`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/",
method: .get
) { response in
#expect(response.status == .ok)
#expect(response.headers[.location] == nil)
}
}
}
@Test
func `redirects a head request as it does a get`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello/",
method: .head
) { response in
#expect(response.status == .movedPermanently)
#expect(response.headers[.location] == "/hello")
}
}
}
@Test
func `passes a post through so its body survives`() async throws {
try await app().test(.router) { client in
try await client.execute(
uri: "/hello/",
method: .post
) { response in
#expect(response.status == .ok)
#expect(response.headers[.location] == nil)
}
}
}
}
// MARK: - Helpers
private extension TrailingSlashRedirectMiddlewareTests {
// MARK: Methods
/// Builds an application whose router applies the trailing-slash middleware ahead of a `/hello`
/// route answering both `GET` and `POST`, and a root route standing in for the landing page.
func app() -> some ApplicationProtocol {
let router = Router()
router.addMiddleware {
TrailingSlashRedirectMiddleware()
}
router.get("hello") { _, _ in
"Hello!"
}
router.post("hello") { _, _ in
"Posted!"
}
router.get("/") { _, _ in
"Root!"
}
return Application(router: router)
}
}