import HTTPTypes import Hummingbird import HummingbirdTesting import Testing @testable import Infrastructure @Suite("VaryMiddleware middleware", .tags(.middleware)) struct VaryMiddlewareTests { // MARK: Functional tests @Test func `adds the default field to a response without a vary header`() async throws { try await app().test(.router) { client in try await client.execute( uri: "/plain", method: .get ) { response in #expect(response.status == .ok) #expect(response.headers[.vary] == "Accept-Encoding") } } } @Test func `appends to an existing vary header`() async throws { try await app().test(.router) { client in try await client.execute( uri: "/localized", method: .get ) { response in #expect(response.headers[.vary] == "Accept-Language, Accept-Encoding") } } } @Test func `does not duplicate a name already present`() async throws { try await app().test(.router) { client in try await client.execute( uri: "/encoded", method: .get ) { response in #expect(response.headers[.vary] == "Accept-Encoding") } } } @Test func `matches an existing name regardless of its casing`() async throws { try await app().test(.router) { client in try await client.execute( uri: "/lowercased", method: .get ) { response in #expect(response.headers[.vary] == "accept-encoding") } } } @Test func `normalizes the whitespace of an existing list`() async throws { try await app().test(.router) { client in try await client.execute( uri: "/spaced", method: .get ) { response in #expect(response.headers[.vary] == "Accept-Language, User-Agent, Accept-Encoding") } } } @Test func `appends every configured field`() async throws { try await app( fields: [.acceptEncoding, .acceptLanguage] ).test(.router) { client in try await client.execute( uri: "/plain", method: .get ) { response in #expect(response.headers[.vary] == "Accept-Encoding, Accept-Language") } } } } // MARK: - Helpers private extension VaryMiddlewareTests { // MARK: Methods /// Builds an application whose router applies the vary middleware ahead of routes whose /// responses carry different `Vary` starting points: `/plain` none, `/localized` an /// `Accept-Language`, `/encoded` an `Accept-Encoding` already, `/lowercased` a lowercase /// `accept-encoding`, and `/spaced` a list with irregular whitespace. func app( fields: [HTTPField.Name] = [.acceptEncoding] ) -> some ApplicationProtocol { let router = Router() router.addMiddleware { VaryMiddleware(fields: fields) } router.get("plain") { _, _ in "Hello!" } for (path, vary) in [ ("localized", "Accept-Language"), ("encoded", "Accept-Encoding"), ("lowercased", "accept-encoding"), ("spaced", "Accept-Language , User-Agent"), ] { router.get(RouterPath(path)) { _, _ -> Response in var response = Response(status: .ok) response.headers[.vary] = vary return response } } return Application(router: router) } }