// // AuthenticationMiddlewareTests.swift // // Copyright 2026 Brendan Szymanski // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // SPDX-License-Identifier: GPL-3.0-or-later // import Foundation import HTTPTypes import OpenAPIRuntime import Testing @testable import LuminateServices /// Records the request a middleware forwarded, so a test can inspect it after the fact. private actor RequestRecorder { /// The last forwarded request. private(set) var request: HTTPRequest? /// Stores a forwarded request. /// /// - Parameter request: The request the middleware passed down the chain. func record(_ request: HTTPRequest) { self.request = request } } /// Pins the exact `Authorization` header Jellyfin expects. /// /// Jellyfin rejects the request outright if this string is malformed, and the failure surfaces as a /// bare 401 with no explanation, so the format is asserted literally rather than by parsing. @Suite struct AuthenticationMiddlewareTests { /// Runs `middleware` over a throwaway request and returns the `Authorization` header it set. /// /// - Parameter middleware: The middleware under test. /// - Returns: The forwarded request's `Authorization` header, if it set one. private func authorizationHeader(from middleware: AuthenticationMiddleware) async throws -> String? { let recorder = RequestRecorder() let request = HTTPRequest(method: .get, scheme: "http", authority: "localhost", path: "/System/Info/Public") _ = try await middleware.intercept( request, body: nil, baseURL: URL(string: "http://localhost")!, operationID: "GetPublicSystemInfo" ) { forwarded, _, _ in await recorder.record(forwarded) return (HTTPResponse(status: .ok), nil) } return await recorder.request?.headerFields[.authorization] } @Test("Builds the MediaBrowser credential string with the token") func authenticatedHeader() async throws { let middleware = AuthenticationMiddleware( clientName: "Luminate", deviceName: "test-device", deviceID: "test-device-id", version: "0.1.0", token: "test-token" ) let header = try await authorizationHeader(from: middleware) #expect( header == #"MediaBrowser Client="Luminate", Device="test-device", DeviceId="test-device-id", Version="0.1.0", Token="test-token""# ) } @Test("Sends an empty token before sign-in rather than omitting the header") func unauthenticatedHeader() async throws { let middleware = AuthenticationMiddleware( clientName: "Luminate", deviceName: "test-device", deviceID: "test-device-id", version: "0.1.0", token: nil ) let header = try await authorizationHeader(from: middleware) #expect( header == #"MediaBrowser Client="Luminate", Device="test-device", DeviceId="test-device-id", Version="0.1.0", Token="""# ) } }