Files
ccn/Services/Website/Tests/Library/Cases/Public/Controllers/HealthControllerTests.swift
T
javier 65b62681eb 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>
2026-09-04 13:40:35 +00:00

151 lines
4.4 KiB
Swift

import Hummingbird
import HummingbirdTesting
import Infrastructure
import Logging
import NIOCore
import Persistence
import Testing
@testable import WebsiteLibrary
@Suite(
"HealthController controller",
.tags(.controller)
)
struct HealthControllerTests {
// MARK: Functional tests
@Test
func `serves the status payload at the health path`() async throws {
try await app(
probe: nil
).test(.router) { client in
try await client.execute(
uri: "/health",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(response.status == .ok)
#expect(response.headers[.contentType] == "application/json")
#expect(body == #"{"status":"ok"}"#)
#expect(response.headers[.robotsTag] == "noindex")
}
}
}
@Test
func `serves ready at the readiness path when the database is reachable`() async throws {
let service = try Service(
driver: .inMemory,
logger: Logger(label: "test")
)
let fluent = service()
do {
try await app(
probe: Probe(fluent: fluent)
).test(.router) { client in
try await client.execute(
uri: "/health/ready",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(response.status == .ok)
#expect(response.headers[.contentType] == "application/json")
#expect(body == #"{"status":"ready"}"#)
#expect(response.headers[.robotsTag] == "noindex")
}
}
} catch {
try? await fluent.shutdown()
throw error
}
try await fluent.shutdown()
}
@Test
func `serves unavailable at the readiness path when the database is unreachable`() async throws {
// Port 1 on the loopback interface has nothing listening, so the probe's connection is refused
// immediately instead of timing out.
let service = try Service(
driver: .postgres(
.init(
host: "127.0.0.1",
port: 1,
name: "unreachable",
username: "nobody",
password: "nothing",
tls: .off,
maxConnectionsPerEventLoop: 1,
poolTimeout: .seconds(10)
)
),
logger: Logger(label: "test")
)
let fluent = service()
do {
try await app(
probe: Probe(fluent: fluent)
).test(.router) { client in
try await client.execute(
uri: "/health/ready",
method: .get
) { response in
let body = String(buffer: response.body)
#expect(response.status == .serviceUnavailable)
#expect(response.headers[.contentType] == "application/json")
#expect(body == #"{"status":"unavailable"}"#)
#expect(response.headers[.robotsTag] == "noindex")
}
}
} catch {
try? await fluent.shutdown()
throw error
}
try await fluent.shutdown()
}
@Test
func `does not serve the readiness path without a probe`() async throws {
try await app(probe: nil).test(.router) { client in
try await client.execute(
uri: "/health/ready",
method: .get
) { response in
#expect(response.status == .notFound)
}
}
}
}
// MARK: - Helpers
private extension HealthControllerTests {
/// Builds a test application serving the ``HealthController`` routes for the given probe.
/// - Parameter probe: the probe supplied to the controller, or `nil` for liveness only.
/// - Returns: the configured test application.
func app(
probe: Probe?
) -> some ApplicationProtocol {
Application(router: {
let router = Router()
router.addRoutes(HealthController<BasicRequestContext>(probe: probe).routes)
return router
}())
}
}