Files
fil/e2e/swift_e2e/Tests/KreuzbergE2ETests/TestHelpers.swift

128 lines
5.5 KiB
Swift
Raw Normal View History

2026-06-01 23:40:55 +02:00
// This file is auto-generated by alef DO NOT EDIT.
// alef:hash:4e15143f4af1ae8bafbdb1506ef057da924484c66a19483966333558ad437e75
// To regenerate: alef generate
// To verify freshness: alef verify --exit-code
// Issues & docs: https://github.com/kreuzberg-dev/alef
// swift-format-ignore-file
import Foundation
#if canImport(FoundationNetworking)
// URLSession, URLRequest, HTTPURLResponse, and URLSessionTaskDelegate live in
// the FoundationNetworking submodule on swift-corelibs-foundation (Linux). On
// Apple platforms these types remain in plain Foundation and this submodule
// does not exist; the canImport guard skips the import there.
import FoundationNetworking
#endif
import RustBridge
// Make `RustString` print its content in XCTest failure output. Without this,
// every error thrown from the swift-bridge layer surfaces as
// `caught error: "RustBridge.RustString"` with the actual message hidden
// inside the opaque class instance. The `@retroactive` keyword acknowledges
// that the conformed-to protocol (`CustomStringConvertible`) and the
// conforming type (`RustString`) both live outside this module required by
// Swift 6 to silence the retroactive-conformance warning. swift-bridge does
// not give `RustString` a `description` of its own, so there is no conflict.
extension RustString: @retroactive CustomStringConvertible {
public var description: String { self.toString() }
}
// Spawns the alef mock-server once per test process and exposes its base URL.
// SwiftPM/XCTest has no global "before all tests" hook that can inject environment
// variables (the JVM-style listener trick used by the Java/Kotlin backends), so the
// server is started lazily on first access of `baseURL` and kept alive for the
// lifetime of the process. A pre-set `MOCK_SERVER_URL` (e.g. exported by CI) wins.
enum AlefE2EMockServer {
static let baseURL: String = AlefE2EMockServer.start()
// Retain the child process so it is not reaped while tests run.
nonisolated(unsafe) private static var process: Process?
private static func start() -> String {
if let preset = ProcessInfo.processInfo.environment["MOCK_SERVER_URL"], !preset.isEmpty {
return preset
}
let fileManager = FileManager.default
var dir = URL(fileURLWithPath: fileManager.currentDirectoryPath)
var fixturesDir: URL?
for _ in 0..<16 {
let candidate = dir.appendingPathComponent("fixtures")
var isDir: ObjCBool = false
if fileManager.fileExists(atPath: candidate.path, isDirectory: &isDir), isDir.boolValue {
fixturesDir = candidate
break
}
let parent = dir.deletingLastPathComponent()
if parent.path == dir.path { break }
dir = parent
}
guard let fixtures = fixturesDir else {
fatalError("AlefE2EMockServer: could not locate fixtures/ above \(fileManager.currentDirectoryPath)")
}
let repoRoot = fixtures.deletingLastPathComponent()
let binary = repoRoot.appendingPathComponent("e2e/rust/target/release/mock-server")
guard fileManager.fileExists(atPath: binary.path) else {
fatalError("AlefE2EMockServer: mock-server binary not found at \(binary.path) — run: cargo build --manifest-path e2e/rust/Cargo.toml --bin mock-server --release")
}
let proc = Process()
proc.executableURL = binary
proc.arguments = [fixtures.path]
let stdoutPipe = Pipe()
proc.standardOutput = stdoutPipe
// Keep stdin open so the server does not see EOF and exit immediately.
proc.standardInput = Pipe()
do {
try proc.run()
} catch {
fatalError("AlefE2EMockServer: failed to start mock-server: \(error)")
}
process = proc
let handle = stdoutPipe.fileHandleForReading
var buffer = Data()
var resolved: String?
for _ in 0..<500 {
let chunk = handle.availableData
if chunk.isEmpty { break }
buffer.append(chunk)
if let text = String(data: buffer, encoding: .utf8) {
for line in text.split(separator: "\n") {
if line.hasPrefix("MOCK_SERVER_URL=") {
resolved = String(line.dropFirst("MOCK_SERVER_URL=".count)).trimmingCharacters(in: .whitespacesAndNewlines)
break
}
}
}
if resolved != nil { break }
}
guard let url = resolved else {
proc.terminate()
fatalError("AlefE2EMockServer: mock-server did not emit MOCK_SERVER_URL")
}
// Drain remaining stdout in the background so a full pipe never blocks the server.
DispatchQueue.global(qos: .background).async {
while !handle.availableData.isEmpty {}
}
return url
}
}
// URLSession that does not follow redirects, so tests can assert on 3xx status codes
// and Location headers instead of transparently chasing them to the final response.
final class AlefE2ENoRedirectDelegate: NSObject, URLSessionTaskDelegate {
func urlSession(
_ session: URLSession,
task: URLSessionTask,
willPerformHTTPRedirection response: HTTPURLResponse,
newRequest request: URLRequest,
completionHandler: @escaping (URLRequest?) -> Void
) {
completionHandler(nil)
}
}
let alefE2ESession = URLSession(
configuration: .ephemeral,
delegate: AlefE2ENoRedirectDelegate(),
delegateQueue: nil
)