diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64a283772..40ecaf3a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: SPM tests - run: swift test --enable-code-coverage + run: swift test - name: Convert coverage files run: | xcrun llvm-cov export -format "lcov" \ diff --git a/Sources/Hummingbird/Application.swift b/Sources/Hummingbird/Application.swift index 58429f78a..bb7bc8417 100644 --- a/Sources/Hummingbird/Application.swift +++ b/Sources/Hummingbird/Application.swift @@ -21,12 +21,33 @@ import NIOPosix import NIOTransportServices import ServiceLifecycle +/// Where should the application get its EventLoopGroup from +public enum EventLoopGroupProvider { + /// Use this EventLoopGroup + case shared(EventLoopGroup) + /// Use one of the singleton EventLoopGroups + case singleton + + public var eventLoopGroup: EventLoopGroup { + switch self { + case .singleton: + #if os(iOS) + return NIOTSEventLoopGroup.singleton + #else + return MultiThreadedEventLoopGroup.singleton + #endif + case .shared(let elg): + return elg + } + } +} + public final class HBApplicationContext: Sendable { /// thread pool used by application public let threadPool: NIOThreadPool /// Configuration public let configuration: HBApplicationConfiguration - /// Logger. Required to be a var by hummingbird-lambda + /// Logger public let logger: Logger /// Encoder used by router public let encoder: HBResponseEncoder @@ -48,60 +69,125 @@ public final class HBApplicationContext: Sendable { } } -public struct HBApplication: Sendable { +/// Application builder class. Brings together all the components of Hummingbird together +/// +/// Setup an HBApplicationBuilder, setup your application middleware, encoders, routes etc and then either +/// add call `build` to create an `HBApplication` which you add to your ServiceLifecycle `ServiceGroup` or +/// run separately with `buildAndRun`. +/// ``` +/// let app = HBApplicationBuilder() +/// app.middleware.add(MyMiddleware()) +/// app.router.get("hello") { _ in +/// return "hello" +/// } +/// try await app.buildAndRun() +/// ``` +/// Editing the application builder setup after calling `build` will produce undefined behaviour. +public struct HBApplication { + // MARK: Member variables + /// event loop group used by application - public let context: HBApplicationContext - // eventLoopGroup public let eventLoopGroup: EventLoopGroup - // server - public let server: HBHTTPServer - // date cache service - internal let dateCache: HBDateCache + /// thread pool used by application + public let threadPool: NIOThreadPool + /// routes requests to requestResponders based on URI + public let responder: Responder + /// Configuration + public var configuration: HBApplicationConfiguration + /// Logger + public var logger: Logger + /// Encoder used by router + public var encoder: HBResponseEncoder + /// decoder used by router + public var decoder: HBRequestDecoder + /// on server running + public var onServerRunning: @Sendable (Channel) async -> Void + /// additional channel handlers + var additionalChannelHandlers: [@Sendable () -> any RemovableChannelHandler] - init(builder: HBApplicationBuilder) { - self.eventLoopGroup = builder.eventLoopGroup - self.context = .init( - threadPool: builder.threadPool, - configuration: builder.configuration, - logger: builder.logger, - encoder: builder.encoder, - decoder: builder.decoder - ) - self.dateCache = .init() - let responder = Responder( - responder: builder.constructResponder(), - applicationContext: self.context, - dateCache: self.dateCache - ) - self.server = HBHTTPServer( - group: builder.eventLoopGroup, - configuration: builder.configuration.httpServer, - responder: responder, - additionalChannelHandlers: builder.additionalChannelHandlers.map { $0() }, - onServerRunning: builder.onServerRunning, - logger: builder.logger - ) + // MARK: Initialization + + /// Initialize new Application + public init( + responder: Responder, + configuration: HBApplicationConfiguration = HBApplicationConfiguration(), + threadPool: NIOThreadPool = .singleton, + eventLoopGroupProvider: EventLoopGroupProvider = .singleton + ) { + var logger = Logger(label: configuration.serverName ?? "HummingBird") + logger.logLevel = configuration.logLevel + self.logger = logger + + self.responder = responder + self.configuration = configuration + self.encoder = NullEncoder() + self.decoder = NullDecoder() + self.onServerRunning = { _ in } + // add idle read, write handlers + if let idleTimeoutConfiguration = configuration.idleTimeoutConfiguration { + self.additionalChannelHandlers = [{ + IdleStateHandler( + readTimeout: idleTimeoutConfiguration.readTimeout, + writeTimeout: idleTimeoutConfiguration.writeTimeout + ) + }] + } else { + self.additionalChannelHandlers = [] + } + + self.eventLoopGroup = eventLoopGroupProvider.eventLoopGroup + self.threadPool = threadPool } - /// shutdown eventloop, threadpool and any extensions attached to the Application - public func shutdownApplication() throws { - try self.context.threadPool.syncShutdownGracefully() + // MARK: Methods + + /// Helper function that runs application inside a ServiceGroup which will gracefully + /// shutdown on signals SIGINT, SIGTERM + public func runService() async throws { + let serviceGroup = ServiceGroup( + configuration: .init( + services: [self], + gracefulShutdownSignals: [.sigterm, .sigint], + logger: self.logger + ) + ) + try await serviceGroup.run() } } /// Conform to `Service` from `ServiceLifecycle`. extension HBApplication: Service { public func run() async throws { + let context = HBApplicationContext( + threadPool: self.threadPool, + configuration: self.configuration, + logger: self.logger, + encoder: self.encoder, + decoder: self.decoder + ) + let dateCache = HBDateCache() + let responder = HTTPResponder( + responder: self.responder, + applicationContext: context, + dateCache: dateCache + ) + let server = HBHTTPServer( + group: self.eventLoopGroup, + configuration: self.configuration.httpServer, + responder: responder, + additionalChannelHandlers: self.additionalChannelHandlers.map { $0() }, + onServerRunning: self.onServerRunning, + logger: self.logger + ) try await withGracefulShutdownHandler { - let services: [any Service] = [self.server, self.dateCache] + let services: [any Service] = [server, dateCache] let serviceGroup = ServiceGroup( - configuration: .init(services: services, logger: self.context.logger) + configuration: .init(services: services, logger: self.logger) ) try await serviceGroup.run() - try self.shutdownApplication() } onGracefulShutdown: { Task { - try await self.server.shutdownGracefully() + try await server.shutdownGracefully() } } } diff --git a/Sources/Hummingbird/ApplicationBuilder.swift b/Sources/Hummingbird/ApplicationBuilder.swift deleted file mode 100644 index bc4770c8a..000000000 --- a/Sources/Hummingbird/ApplicationBuilder.swift +++ /dev/null @@ -1,143 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Hummingbird server framework project -// -// Copyright (c) 2021-2023 the Hummingbird authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -import Dispatch -import HummingbirdCore -import Logging -import NIOCore -import NIOHTTP1 -import NIOPosix -import NIOTransportServices -import ServiceLifecycle - -/// Where should the application get its EventLoopGroup from -public enum EventLoopGroupProvider { - /// Use this EventLoopGroup - case shared(EventLoopGroup) - /// Use one of the singleton EventLoopGroups - case singleton -} - -/// Application builder class. Brings together all the components of Hummingbird together -/// -/// Setup an HBApplicationBuilder, setup your application middleware, encoders, routes etc and then either -/// add call `build` to create an `HBApplication` which you add to your ServiceLifecycle `ServiceGroup` or -/// run separately with `buildAndRun`. -/// ``` -/// let app = HBApplicationBuilder() -/// app.middleware.add(MyMiddleware()) -/// app.router.get("hello") { _ in -/// return "hello" -/// } -/// try await app.buildAndRun() -/// ``` -/// Editing the application builder setup after calling `build` will produce undefined behaviour. -public final class HBApplicationBuilder { - // MARK: Member variables - - /// event loop group used by application - public let eventLoopGroup: EventLoopGroup - /// thread pool used by application - public let threadPool: NIOThreadPool - /// routes requests to requestResponders based on URI - public let router: HBRouterBuilder - /// Configuration - public var configuration: HBApplicationConfiguration - /// Logger. Required to be a var by hummingbird-lambda - public var logger: Logger - /// Encoder used by router - public var encoder: HBResponseEncoder - /// decoder used by router - public var decoder: HBRequestDecoder - /// on server running - public var onServerRunning: @Sendable (Channel) async -> Void - /// additional channel handlers - var additionalChannelHandlers: [@Sendable () -> any RemovableChannelHandler] - - // MARK: Initialization - - /// Initialize new Application - public init( - requestContext: RequestContext.Type = HBBasicRequestContext.self, - configuration: HBApplicationConfiguration = HBApplicationConfiguration(), - eventLoopGroupProvider: EventLoopGroupProvider = .singleton - ) { - var logger = Logger(label: configuration.serverName ?? "HummingBird") - logger.logLevel = configuration.logLevel - self.logger = logger - - self.router = HBRouterBuilder(context: RequestContext.self) - self.configuration = configuration - self.encoder = NullEncoder() - self.decoder = NullDecoder() - self.onServerRunning = { _ in } - // add idle read, write handlers - if let idleTimeoutConfiguration = configuration.idleTimeoutConfiguration { - self.additionalChannelHandlers = [{ - IdleStateHandler( - readTimeout: idleTimeoutConfiguration.readTimeout, - writeTimeout: idleTimeoutConfiguration.writeTimeout - ) - }] - } else { - self.additionalChannelHandlers = [] - } - - // create eventLoopGroup - switch eventLoopGroupProvider { - case .singleton: - #if os(iOS) - self.eventLoopGroup = NIOTSEventLoopGroup.singleton - #else - self.eventLoopGroup = MultiThreadedEventLoopGroup.singleton - #endif - case .shared(let elg): - self.eventLoopGroup = elg - } - - self.threadPool = NIOThreadPool(numberOfThreads: configuration.threadPoolSize) - self.threadPool.start() - } - - // MARK: Methods - - public func build() -> HBApplication { - return .init(builder: self) - } - - /// Helper function that runs application inside a ServiceGroup which will gracefully - /// shutdown on signals SIGINT, SIGTERM - public func buildAndRun() async throws { - let serviceGroup = ServiceGroup( - configuration: .init( - services: [self.build()], - gracefulShutdownSignals: [.sigterm, .sigint], - logger: self.logger - ) - ) - try await serviceGroup.run() - } - - /// middleware applied to requests - public var middleware: HBMiddlewareGroup { return self.router.middlewares } - - /// Construct the RequestResponder from the middleware group and router - func constructResponder() -> any HBResponder { - return self.router.buildResponder() - } - - public func addChannelHandler(_ handler: @autoclosure @escaping @Sendable () -> any RemovableChannelHandler) { - self.additionalChannelHandlers.append(handler) - } -} diff --git a/Sources/Hummingbird/Server/Application+HTTPResponder.swift b/Sources/Hummingbird/Server/Application+HTTPResponder.swift index 4604dcb9a..bd7579715 100644 --- a/Sources/Hummingbird/Server/Application+HTTPResponder.swift +++ b/Sources/Hummingbird/Server/Application+HTTPResponder.swift @@ -19,8 +19,8 @@ import NIOCore import NIOHTTP1 extension HBApplication { - struct Responder: HBHTTPResponder { - let responder: any HBResponder + struct HTTPResponder: HBHTTPResponder { + let responder: Responder let applicationContext: HBApplicationContext let dateCache: HBDateCache @@ -34,7 +34,7 @@ extension HBApplication { head: request.head, body: request.body ) - let context = RequestContext( + let context = Responder.Context( applicationContext: self.applicationContext, channel: context.channel, logger: loggerWithRequestId(self.applicationContext.logger) diff --git a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift index b685e9d8f..c73b816f7 100644 --- a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift +++ b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift @@ -21,7 +21,8 @@ import NIOCore /// In memory driver for persist system for storing persistent cross request key/value pairs public final class HBMemoryPersistDriver: HBPersistDriver { - public init(eventLoopGroup: EventLoopGroup) { + public init(eventLoopGroupProvider: EventLoopGroupProvider = .singleton) { + let eventLoopGroup = eventLoopGroupProvider.eventLoopGroup self.eventLoop = eventLoopGroup.next() self.values = [:] self.task = self.eventLoop.scheduleRepeatedTask(initialDelay: .hours(1), delay: .hours(1)) { _ in diff --git a/Sources/HummingbirdFoundation/Files/FileMiddleware.swift b/Sources/HummingbirdFoundation/Files/FileMiddleware.swift index 82c9c81ae..0c585262e 100644 --- a/Sources/HummingbirdFoundation/Files/FileMiddleware.swift +++ b/Sources/HummingbirdFoundation/Files/FileMiddleware.swift @@ -48,7 +48,7 @@ public struct HBFileMiddleware: HBMiddleware { cacheControl: HBCacheControl = .init([]), searchForIndexHtml: Bool = false, threadPool: NIOThreadPool = NIOThreadPool.singleton, - logger: Logger + logger: Logger = Logger(label: "HBFileMiddleware") ) { self.rootFolder = URL(fileURLWithPath: rootFolder) self.threadPool = threadPool diff --git a/Sources/HummingbirdXCT/ApplicationBuilder+XCT.swift b/Sources/HummingbirdXCT/Application+XCT.swift similarity index 90% rename from Sources/HummingbirdXCT/ApplicationBuilder+XCT.swift rename to Sources/HummingbirdXCT/Application+XCT.swift index e3bf749e9..b659893ef 100644 --- a/Sources/HummingbirdXCT/ApplicationBuilder+XCT.swift +++ b/Sources/HummingbirdXCT/Application+XCT.swift @@ -48,7 +48,7 @@ public enum XCTRouterTestingSetup { /// } /// } /// ``` -extension HBApplicationBuilder { +extension HBApplication { // MARK: Initialization /// Creates a version of `HBApplication` that can be used for testing code @@ -56,17 +56,17 @@ extension HBApplicationBuilder { /// - Parameters: /// - testing: indicates which type of testing framework we want /// - configuration: configuration of application - public func buildAndTest( + public func test( _: XCTLiveTestingSetup, _ test: @escaping @Sendable (any HBXCTClientProtocol) async throws -> Value ) async throws -> Value { let app: any HBXCTApplication - app = HBXCTLive(builder: self) + app = HBXCTLive(app: self) return try await app.run(test) } } -extension HBApplicationBuilder where RequestContext: HBTestRouterContextProtocol { +extension HBApplication where Responder.Context: HBTestRouterContextProtocol { // MARK: Initialization /// Creates a version of `HBApplication` that can be used for testing code @@ -74,12 +74,12 @@ extension HBApplicationBuilder where RequestContext: HBTestRouterContextProtocol /// - Parameters: /// - testing: indicates which type of testing framework we want /// - configuration: configuration of application - public func buildAndTest( + public func test( _: XCTRouterTestingSetup, _ test: @escaping @Sendable (any HBXCTClientProtocol) async throws -> Value ) async throws -> Value { let app: any HBXCTApplication - app = HBXCTRouter(builder: self) + app = HBXCTRouter(app: self) return try await app.run(test) } } diff --git a/Sources/HummingbirdXCT/HBXCTLive.swift b/Sources/HummingbirdXCT/HBXCTLive.swift index 112c60598..c9afbd820 100644 --- a/Sources/HummingbirdXCT/HBXCTLive.swift +++ b/Sources/HummingbirdXCT/HBXCTLive.swift @@ -22,7 +22,7 @@ import ServiceLifecycle import XCTest /// Test using a live server -final class HBXCTLive: HBXCTApplication { +final class HBXCTLive: HBXCTApplication { struct Client: HBXCTClientProtocol { let client: HBXCTClient @@ -42,15 +42,16 @@ final class HBXCTLive: HBXCTApplication { } } - init(builder: HBApplicationBuilder) { - builder.configuration = builder.configuration.with(address: .hostname("localhost", port: 0)) + init(app: HBApplication) { + var app = app + app.configuration = app.configuration.with(address: .hostname("localhost", port: 0)) let promise = Promise() - builder.onServerRunning = { channel in + app.onServerRunning = { channel in await promise.complete(channel.localAddress!.port!) } self.timeout = .seconds(15) self.promise = promise - self.application = builder.build() + self.application = app } /// Start tests @@ -60,7 +61,7 @@ final class HBXCTLive: HBXCTApplication { configuration: .init( services: [self.application], gracefulShutdownSignals: [.sigterm, .sigint], - logger: self.application.context.logger + logger: self.application.logger ) ) group.addTask { @@ -85,7 +86,7 @@ final class HBXCTLive: HBXCTApplication { await self.promise.complete(channel.localAddress!.port!) } - let application: HBApplication + let application: HBApplication let promise: Promise let timeout: TimeAmount } diff --git a/Sources/HummingbirdXCT/HBXCTRouter.swift b/Sources/HummingbirdXCT/HBXCTRouter.swift index de961fe10..210289e14 100644 --- a/Sources/HummingbirdXCT/HBXCTRouter.swift +++ b/Sources/HummingbirdXCT/HBXCTRouter.swift @@ -52,32 +52,27 @@ public struct HBTestRouterContext: HBTestRouterContextProtocol, HBRemoteAddressR } /// Test sending values to requests to router. This does not setup a live server -struct HBXCTRouter: HBXCTApplication { +struct HBXCTRouter: HBXCTApplication where Responder.Context: HBTestRouterContextProtocol { let eventLoopGroup: EventLoopGroup let context: HBApplicationContext - let responder: any HBResponder + let responder: Responder - init(builder: HBApplicationBuilder) { - self.eventLoopGroup = builder.eventLoopGroup + init(app: HBApplication) { + self.eventLoopGroup = app.eventLoopGroup self.context = HBApplicationContext( - threadPool: builder.threadPool, - configuration: builder.configuration, - logger: builder.logger, - encoder: builder.encoder, - decoder: builder.decoder + threadPool: app.threadPool, + configuration: app.configuration, + logger: app.logger, + encoder: app.encoder, + decoder: app.decoder ) - self.responder = builder.router.buildResponder() - } - - func shutdown() async throws { - try await self.context.threadPool.shutdownGracefully() + self.responder = app.responder } /// Run test func run(_ test: @escaping @Sendable (HBXCTClientProtocol) async throws -> Value) async throws -> Value { let client = Client(eventLoopGroup: self.eventLoopGroup, responder: self.responder, applicationContext: self.context) let value = try await test(client) - try await self.shutdown() return value } @@ -85,7 +80,7 @@ struct HBXCTRouter: HBXCTApplicatio /// resulting response back to XCT response type struct Client: HBXCTClientProtocol { let eventLoopGroup: EventLoopGroup - let responder: any HBResponder + let responder: Responder let applicationContext: HBApplicationContext func execute(uri: String, method: HTTPMethod, headers: HTTPHeaders, body: ByteBuffer?) async throws -> HBXCTResponse { @@ -96,10 +91,10 @@ struct HBXCTRouter: HBXCTApplicatio head: .init(version: .http1_1, method: method, uri: uri, headers: headers), body: .byteBuffer(body) ) - let context = RequestContext( + let context = Responder.Context( applicationContext: self.applicationContext, eventLoop: eventLoop, - logger: HBApplication.loggerWithRequestId(self.applicationContext.logger) + logger: HBApplication.loggerWithRequestId(self.applicationContext.logger) ) return self.responder.respond(to: request, context: context) .flatMapErrorThrowing { error in diff --git a/Sources/PerformanceTest/main.swift b/Sources/PerformanceTest/main.swift index 0eb3016c7..ee6ee86fc 100644 --- a/Sources/PerformanceTest/main.swift +++ b/Sources/PerformanceTest/main.swift @@ -23,36 +23,38 @@ let port = HBEnvironment.shared.get("SERVER_PORT", as: Int.self) ?? 8080 // create app let elg = MultiThreadedEventLoopGroup(numberOfThreads: 2) defer { try? elg.syncShutdownGracefully() } -let app = HBApplicationBuilder( - configuration: .init( - address: .hostname(hostname, port: port), - serverName: "Hummingbird" - ), - eventLoopGroupProvider: .shared(elg) -) -app.logger.logLevel = .debug -app.encoder = JSONEncoder() -app.decoder = JSONDecoder() - -// configure app - +var router = HBRouterBuilder() // number of raw requests // ./wrk -c 128 -d 15s -t 8 http://localhost:8080 -app.router.get { _, _ in +router.get { _, _ in return "Hello, world" } // request with a body // ./wrk -c 128 -d 15s -t 8 -s scripts/post.lua http://localhost:8080 -app.router.post { request, _ in +router.post { request, _ in return request.body.buffer } // return JSON // ./wrk -c 128 -d 15s -t 8 http://localhost:8080/json -app.router.get("json") { _, _ in +router.get("json") { _, _ in return ["message": "Hello, world"] } +var app = HBApplication( + responder: router.buildResponder(), + configuration: .init( + address: .hostname(hostname, port: port), + serverName: "Hummingbird" + ), + eventLoopGroupProvider: .shared(elg) +) +app.logger.logLevel = .debug +app.encoder = JSONEncoder() +app.decoder = JSONDecoder() + +// configure app + // run app -try await app.buildAndRun() +try await app.runService() diff --git a/Tests/HummingbirdFoundationTests/CookiesTests.swift b/Tests/HummingbirdFoundationTests/CookiesTests.swift index 21c63c946..dcdeb7258 100644 --- a/Tests/HummingbirdFoundationTests/CookiesTests.swift +++ b/Tests/HummingbirdFoundationTests/CookiesTests.swift @@ -65,13 +65,14 @@ class CookieTests: XCTestCase { } func testSetCookie() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/") { _, _ -> HBResponse in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/") { _, _ -> HBResponse in var response = HBResponse(status: .ok, headers: [:], body: .empty) response.setCookie(.init(name: "test", value: "value")) return response } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .POST) { response in XCTAssertEqual(response.headers["Set-Cookie"].first, "test=value; HttpOnly") } @@ -79,11 +80,12 @@ class CookieTests: XCTestCase { } func testSetCookieViaRequest() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/") { _, _ in return HBEditedResponse(headers: ["Set-Cookie": HBCookie(name: "test", value: "value").description], response: "Hello") } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .POST) { response in XCTAssertEqual(response.headers["Set-Cookie"].first, "test=value; HttpOnly") } @@ -91,11 +93,12 @@ class CookieTests: XCTestCase { } func testReadCookieFromRequest() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/") { request, _ -> String? in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/") { request, _ -> String? in return request.cookies["test"]?.value } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .POST, headers: ["cookie": "test=value"]) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "value") diff --git a/Tests/HummingbirdFoundationTests/FileTests+async.swift b/Tests/HummingbirdFoundationTests/FileTests+async.swift index 0ce9815b8..60338ff71 100644 --- a/Tests/HummingbirdFoundationTests/FileTests+async.swift +++ b/Tests/HummingbirdFoundationTests/FileTests+async.swift @@ -27,19 +27,20 @@ class HummingbirdAsyncFilesTests: XCTestCase { } func testRead() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("test.jpg") { _, context -> HBResponse in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("test.jpg") { _, context -> HBResponse in let fileIO = HBFileIO(threadPool: context.applicationContext.threadPool) let body = try await fileIO.loadFile(path: "test.jpg", context: context, logger: context.logger) return .init(status: .ok, headers: [:], body: body) } + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 320_003) let data = Data(buffer: buffer) let fileURL = URL(fileURLWithPath: "test.jpg") XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test.jpg", method: .GET) { response in XCTAssertEqual(response.body, buffer) } @@ -48,8 +49,8 @@ class HummingbirdAsyncFilesTests: XCTestCase { func testWrite() async throws { let filename = "testWrite.txt" - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.put("store") { request, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("store") { request, context -> HTTPResponseStatus in let fileIO = HBFileIO(threadPool: context.applicationContext.threadPool) try await fileIO.writeFile( contents: request.body, @@ -59,8 +60,9 @@ class HummingbirdAsyncFilesTests: XCTestCase { ) return .ok } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = ByteBufferAllocator().buffer(string: "This is a test") try await client.XCTExecute(uri: "/store", method: .PUT, body: buffer) { response in XCTAssertEqual(response.status, .ok) diff --git a/Tests/HummingbirdFoundationTests/FilesTests.swift b/Tests/HummingbirdFoundationTests/FilesTests.swift index f2615edc7..947012d4a 100644 --- a/Tests/HummingbirdFoundationTests/FilesTests.swift +++ b/Tests/HummingbirdFoundationTests/FilesTests.swift @@ -34,8 +34,9 @@ class HummingbirdFilesTests: XCTestCase { } func testRead() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let text = "Test file contents" let data = Data(text.utf8) @@ -43,7 +44,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test.jpg", method: .GET) { response in var body = try XCTUnwrap(response.body) XCTAssertEqual(body.readString(length: body.readableBytes), text) @@ -53,8 +54,9 @@ class HummingbirdFilesTests: XCTestCase { } func testReadLargeFile() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 380_000) let data = Data(buffer: buffer) @@ -62,7 +64,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test.txt", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(body, buffer) @@ -71,8 +73,9 @@ class HummingbirdFilesTests: XCTestCase { } func testReadRange() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 326_000) let data = Data(buffer: buffer) @@ -80,7 +83,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test.txt", method: .GET, headers: ["Range": "bytes=100-3999"]) { response in let body = try XCTUnwrap(response.body) let slice = buffer.getSlice(at: 100, length: 3900) @@ -115,8 +118,9 @@ class HummingbirdFilesTests: XCTestCase { } func testIfRangeRead() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 10000) let data = Data(buffer: buffer) @@ -124,7 +128,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let (eTag, modificationDate) = try await client.XCTExecute(uri: "/test.txt", method: .GET, headers: ["Range": "bytes=-3999"]) { response -> (String, String) in let eTag = try XCTUnwrap(response.headers["eTag"].first) let modificationDate = try XCTUnwrap(response.headers["modified-date"].first) @@ -150,8 +154,9 @@ class HummingbirdFilesTests: XCTestCase { } func testHead() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let date = Date() let text = "Test file contents" @@ -160,7 +165,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/testHead.txt", method: .HEAD) { response in XCTAssertNil(response.body) XCTAssertEqual(response.headers["Content-Length"].first, text.utf8.count.description) @@ -173,8 +178,9 @@ class HummingbirdFilesTests: XCTestCase { } func testETag() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 16200) let data = Data(buffer: buffer) @@ -182,7 +188,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in var eTag: String? try await client.XCTExecute(uri: "/test.txt", method: .HEAD) { response in eTag = try XCTUnwrap(response.headers["eTag"].first) @@ -194,8 +200,9 @@ class HummingbirdFilesTests: XCTestCase { } func testIfNoneMatch() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 16200) let data = Data(buffer: buffer) @@ -203,7 +210,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let eTag = try await client.XCTExecute(uri: "/test.txt", method: .HEAD) { response in return try XCTUnwrap(response.headers["eTag"].first) } @@ -222,8 +229,9 @@ class HummingbirdFilesTests: XCTestCase { } func testIfModifiedSince() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".")) + let app = HBApplication(responder: router.buildResponder()) let buffer = self.randomBuffer(size: 16200) let data = Data(buffer: buffer) @@ -231,7 +239,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let modifiedDate = try await client.XCTExecute(uri: "/test.txt", method: .HEAD) { response in return try XCTUnwrap(response.headers["modified-date"].first) } @@ -247,12 +255,13 @@ class HummingbirdFilesTests: XCTestCase { } func testCacheControl() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) let cacheControl: HBCacheControl = .init([ (.text, [.maxAge(60 * 60 * 24 * 30)]), (.imageJpeg, [.maxAge(60 * 60 * 24 * 30), .private]), ]) - app.middleware.add(HBFileMiddleware(".", cacheControl: cacheControl, threadPool: app.threadPool, logger: app.logger)) + router.middlewares.add(HBFileMiddleware(".", cacheControl: cacheControl)) + let app = HBApplication(responder: router.buildResponder()) let text = "Test file contents" let data = Data(text.utf8) @@ -263,7 +272,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL2)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL2)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test.txt", method: .GET) { response in XCTAssertEqual(response.headers["cache-control"].first, "max-age=2592000") } @@ -274,8 +283,9 @@ class HummingbirdFilesTests: XCTestCase { } func testIndexHtml() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBFileMiddleware(".", searchForIndexHtml: true, threadPool: app.threadPool, logger: app.logger)) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBFileMiddleware(".", searchForIndexHtml: true)) + let app = HBApplication(responder: router.buildResponder()) let text = "Test file contents" let data = Data(text.utf8) @@ -283,7 +293,7 @@ class HummingbirdFilesTests: XCTestCase { XCTAssertNoThrow(try data.write(to: fileURL)) defer { XCTAssertNoThrow(try FileManager.default.removeItem(at: fileURL)) } - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in var body = try XCTUnwrap(response.body) XCTAssertEqual(body.readString(length: body.readableBytes), text) @@ -293,14 +303,15 @@ class HummingbirdFilesTests: XCTestCase { func testWrite() async throws { let filename = "testWrite.txt" - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.put("store") { request, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("store") { request, context -> EventLoopFuture in let fileIO = HBFileIO(threadPool: context.applicationContext.threadPool) return fileIO.writeFile(contents: request.body, path: filename, context: context, logger: context.logger) .map { .ok } } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = ByteBufferAllocator().buffer(string: "This is a test") try await client.XCTExecute(uri: "/store", method: .PUT, body: buffer) { response in XCTAssertEqual(response.status, .ok) @@ -315,14 +326,15 @@ class HummingbirdFilesTests: XCTestCase { func testWriteLargeFile() async throws { let filename = "testWriteLargeFile.txt" - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.put("store") { request, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("store") { request, context -> EventLoopFuture in let fileIO = HBFileIO(threadPool: context.applicationContext.threadPool) return fileIO.writeFile(contents: request.body, path: filename, context: context, logger: context.logger) .map { .ok } } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 400_000) try await client.XCTExecute(uri: "/store", method: .PUT, body: buffer) { response in XCTAssertEqual(response.status, .ok) diff --git a/Tests/HummingbirdFoundationTests/HummingBirdJSONTests.swift b/Tests/HummingbirdFoundationTests/HummingBirdJSONTests.swift index 839a0b369..a753d4427 100644 --- a/Tests/HummingbirdFoundationTests/HummingBirdJSONTests.swift +++ b/Tests/HummingbirdFoundationTests/HummingBirdJSONTests.swift @@ -27,16 +27,17 @@ class HummingbirdJSONTests: XCTestCase { struct Error: Swift.Error {} func testDecode() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.decoder = JSONDecoder() - app.router.put("/user") { request, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("/user") { request, context -> HTTPResponseStatus in guard let user = try? request.decode(as: User.self, using: context) else { throw HBHTTPError(.badRequest) } XCTAssertEqual(user.name, "John Smith") XCTAssertEqual(user.email, "john.smith@email.com") XCTAssertEqual(user.age, 25) return .ok } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.decoder = JSONDecoder() + try await app.test(.router) { client in let body = #"{"name": "John Smith", "email": "john.smith@email.com", "age": 25}"# try await client.XCTExecute(uri: "/user", method: .PUT, body: ByteBufferAllocator().buffer(string: body)) { XCTAssertEqual($0.status, .ok) @@ -45,12 +46,13 @@ class HummingbirdJSONTests: XCTestCase { } func testEncode() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.encoder = JSONEncoder() - app.router.get("/user") { _, _ -> User in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/user") { _, _ -> User in return User(name: "John Smith", email: "john.smith@email.com", age: 25) } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.encoder = JSONEncoder() + try await app.test(.router) { client in try await client.XCTExecute(uri: "/user", method: .GET) { response in let body = try XCTUnwrap(response.body) let user = try JSONDecoder().decode(User.self, from: body) @@ -62,12 +64,13 @@ class HummingbirdJSONTests: XCTestCase { } func testEncode2() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.encoder = JSONEncoder() - app.router.get("/json") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/json") { _, _ in return ["message": "Hello, world!"] } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.encoder = JSONEncoder() + try await app.test(.router) { client in try await client.XCTExecute(uri: "/json", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), #"{"message":"Hello, world!"}"#) diff --git a/Tests/HummingbirdFoundationTests/URLEncodedForm/Application+URLEncodedFormTests.swift b/Tests/HummingbirdFoundationTests/URLEncodedForm/Application+URLEncodedFormTests.swift index abc5c04d9..e5ca02208 100644 --- a/Tests/HummingbirdFoundationTests/URLEncodedForm/Application+URLEncodedFormTests.swift +++ b/Tests/HummingbirdFoundationTests/URLEncodedForm/Application+URLEncodedFormTests.swift @@ -27,16 +27,17 @@ class HummingBirdURLEncodedTests: XCTestCase { struct Error: Swift.Error {} func testDecode() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.decoder = URLEncodedFormDecoder() - app.router.put("/user") { request, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("/user") { request, context -> HTTPResponseStatus in guard let user = try? request.decode(as: User.self, using: context) else { throw HBHTTPError(.badRequest) } XCTAssertEqual(user.name, "John Smith") XCTAssertEqual(user.email, "john.smith@email.com") XCTAssertEqual(user.age, 25) return .ok } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.decoder = URLEncodedFormDecoder() + try await app.test(.router) { client in let body = "name=John%20Smith&email=john.smith%40email.com&age=25" try await client.XCTExecute(uri: "/user", method: .PUT, body: ByteBufferAllocator().buffer(string: body)) { XCTAssertEqual($0.status, .ok) @@ -45,12 +46,13 @@ class HummingBirdURLEncodedTests: XCTestCase { } func testEncode() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.encoder = URLEncodedFormEncoder() - app.router.get("/user") { _, _ -> User in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/user") { _, _ -> User in return User(name: "John Smith", email: "john.smith@email.com", age: 25) } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.encoder = URLEncodedFormEncoder() + try await app.test(.router) { client in try await client.XCTExecute(uri: "/user", method: .GET) { response in var body = try XCTUnwrap(response.body) let bodyString = try XCTUnwrap(body.readString(length: body.readableBytes)) diff --git a/Tests/HummingbirdTests/ApplicationTests.swift b/Tests/HummingbirdTests/ApplicationTests.swift index 3e8fe4f6e..7dad72ec0 100644 --- a/Tests/HummingbirdTests/ApplicationTests.swift +++ b/Tests/HummingbirdTests/ApplicationTests.swift @@ -26,12 +26,13 @@ final class ApplicationTests: XCTestCase { } func testGetRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("/hello") { _, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/hello") { _, context -> EventLoopFuture in let buffer = context.allocator.buffer(string: "GET: Hello") return context.eventLoop.makeSucceededFuture(buffer) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in var body = try XCTUnwrap(response.body) let string = body.readString(length: body.readableBytes) @@ -42,11 +43,12 @@ final class ApplicationTests: XCTestCase { } func testHTTPStatusRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("/accepted") { _, _ -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/accepted") { _, _ -> HTTPResponseStatus in return .accepted } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/accepted", method: .GET) { response in XCTAssertEqual(response.status, .accepted) } @@ -54,11 +56,12 @@ final class ApplicationTests: XCTestCase { } func testStandardHeaders() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("/hello") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/hello") { _, _ in return "Hello" } - try await app.buildAndTest(.live) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.live) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in XCTAssertEqual(response.headers["connection"].first, "keep-alive") XCTAssertEqual(response.headers["content-length"].first, "5") @@ -67,11 +70,12 @@ final class ApplicationTests: XCTestCase { } func testServerHeaders() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self, configuration: .init(serverName: "TestServer")) - app.router.get("/hello") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/hello") { _, _ in return "Hello" } - try await app.buildAndTest(.live) { client in + let app = HBApplication(responder: router.buildResponder(), configuration: .init(serverName: "TestServer")) + try await app.test(.live) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in XCTAssertEqual(response.headers["server"].first, "TestServer") } @@ -79,11 +83,12 @@ final class ApplicationTests: XCTestCase { } func testPostRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello") { _, _ -> String in return "POST: Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .POST) { response in var body = try XCTUnwrap(response.body) @@ -95,14 +100,15 @@ final class ApplicationTests: XCTestCase { } func testMultipleMethods() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello") { _, _ -> String in return "POST" } - app.router.get("/hello") { _, _ -> String in + router.get("/hello") { _, _ -> String in return "GET" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in let body = try XCTUnwrap(response.body) @@ -116,15 +122,16 @@ final class ApplicationTests: XCTestCase { } func testMultipleGroupMethods() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.group("hello") + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.group("hello") .post { _, _ -> String in return "POST" } .get { _, _ -> String in return "GET" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in let body = try XCTUnwrap(response.body) @@ -138,12 +145,13 @@ final class ApplicationTests: XCTestCase { } func testQueryRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/query") { request, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/query") { request, context -> EventLoopFuture in let buffer = context.allocator.buffer(string: request.uri.queryParameters["test"].map { String($0) } ?? "") return context.eventLoop.makeSucceededFuture(buffer) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/query?test=test%20data%C3%A9", method: .POST) { response in var body = try XCTUnwrap(response.body) @@ -155,11 +163,12 @@ final class ApplicationTests: XCTestCase { } func testMultipleQueriesRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/add") { request, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/add") { request, _ -> String in return request.uri.queryParameters.getAll("value", as: Int.self).reduce(0,+).description } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/add?value=3&value=45&value=7", method: .POST) { response in var body = try XCTUnwrap(response.body) @@ -171,11 +180,12 @@ final class ApplicationTests: XCTestCase { } func testArray() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("array") { _, _ -> [String] in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("array") { _, _ -> [String] in return ["yes", "no"] } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/array", method: .GET) { response in let body = try XCTUnwrap(response.body) @@ -185,11 +195,12 @@ final class ApplicationTests: XCTestCase { } func testEventLoopFutureArray() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.patch("array") { _, context -> EventLoopFuture<[String]> in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.patch("array") { _, context -> EventLoopFuture<[String]> in return context.success(["yes", "no"]) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/array", method: .PATCH) { response in let body = try XCTUnwrap(response.body) @@ -199,14 +210,15 @@ final class ApplicationTests: XCTestCase { } func testResponseBody() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/echo-body") .post { request, _ -> HBResponse in let body: HBResponseBody = request.body.buffer.map { .byteBuffer($0) } ?? .empty return .init(status: .ok, headers: [:], body: body) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 1_140_000) try await client.XCTExecute(uri: "/echo-body", method: .POST, body: buffer) { response in @@ -217,8 +229,8 @@ final class ApplicationTests: XCTestCase { /// Test streaming of requests and streaming of responses by streaming the request body into a response streamer func testStreaming() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("streaming", options: .streamBody) { request, _ -> HBResponse in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("streaming", options: .streamBody) { request, _ -> HBResponse in guard let stream = request.body.stream else { throw HBHTTPError(.badRequest) } struct RequestStreamer: HBResponseBodyStreamer { let stream: HBStreamerProtocol @@ -236,7 +248,7 @@ final class ApplicationTests: XCTestCase { } return HBResponse(status: .ok, headers: [:], body: .stream(RequestStreamer(stream: stream))) } - app.router.post("size", options: .streamBody) { request, context -> EventLoopFuture in + router.post("size", options: .streamBody) { request, context -> EventLoopFuture in guard let stream = request.body.stream else { return context.failure(.badRequest) } @@ -247,8 +259,9 @@ final class ApplicationTests: XCTestCase { } .map { _ in size.load(ordering: .relaxed).description } } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 640_001) try await client.XCTExecute(uri: "/streaming", method: .POST, body: buffer) { response in @@ -267,8 +280,8 @@ final class ApplicationTests: XCTestCase { /// Test streaming of requests and streaming of responses by streaming the request body into a response streamer func testStreamingSmallBuffer() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("streaming", options: .streamBody) { request, _ -> HBResponse in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("streaming", options: .streamBody) { request, _ -> HBResponse in guard let stream = request.body.stream else { throw HBHTTPError(.badRequest) } struct RequestStreamer: HBResponseBodyStreamer { let stream: HBStreamerProtocol @@ -286,7 +299,8 @@ final class ApplicationTests: XCTestCase { } return HBResponse(status: .ok, headers: [:], body: .stream(RequestStreamer(stream: stream))) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 64) try await client.XCTExecute(uri: "/streaming", method: .POST, body: buffer) { response in @@ -308,12 +322,13 @@ final class ApplicationTests: XCTestCase { } } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(CollateMiddleware()) - app.router.put("/hello") { _, _ -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(CollateMiddleware()) + router.put("/hello") { _, _ -> HTTPResponseStatus in return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 512_000) try await client.XCTExecute(uri: "/hello", method: .PUT, body: buffer) { response in @@ -323,13 +338,14 @@ final class ApplicationTests: XCTestCase { } func testOptional() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/echo-body") .post { request, _ -> ByteBuffer? in return request.body.buffer } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 64) try await client.XCTExecute(uri: "/echo-body", method: .POST, body: buffer) { response in @@ -343,13 +359,14 @@ final class ApplicationTests: XCTestCase { } func testELFOptional() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/echo-body") .post { request, context -> EventLoopFuture in return context.success(request.body.buffer) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 64) try await client.XCTExecute(uri: "/echo-body", method: .POST, body: buffer) { response in @@ -367,13 +384,14 @@ final class ApplicationTests: XCTestCase { let first: String let last: String } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/name") .patch { _, _ -> Name? in return Name(first: "john", last: "smith") } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/name", method: .PATCH) { response in let body = try XCTUnwrap(response.body) @@ -383,15 +401,16 @@ final class ApplicationTests: XCTestCase { } func testTypedResponse() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.delete("/hello") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.delete("/hello") { _, _ in return HBEditedResponse( status: .imATeapot, headers: ["test": "value", "content-type": "application/json"], response: "Hello" ) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .DELETE) { response in var body = try XCTUnwrap(response.body) @@ -409,16 +428,17 @@ final class ApplicationTests: XCTestCase { struct Result: HBResponseEncodable { let value: String } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.encoder = JSONEncoder() - app.router.patch("/hello") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.patch("/hello") { _, _ in return HBEditedResponse( status: .imATeapot, headers: ["test": "value", "content-type": "application/json"], response: Result(value: "true") ) } - try await app.buildAndTest(.router) { client in + var app = HBApplication(responder: router.buildResponder()) + app.encoder = JSONEncoder() + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .PATCH) { response in var body = try XCTUnwrap(response.body) @@ -433,8 +453,8 @@ final class ApplicationTests: XCTestCase { } func testTypedResponseFuture() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.delete("/hello") { _, context in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.delete("/hello") { _, context in return context.success( HBEditedResponse( status: .imATeapot, @@ -443,7 +463,8 @@ final class ApplicationTests: XCTestCase { ) ) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .DELETE) { response in var body = try XCTUnwrap(response.body) @@ -458,14 +479,15 @@ final class ApplicationTests: XCTestCase { } func testMaxUploadSize() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self, configuration: .init(maxUploadSize: 64 * 1024)) - app.router.post("upload") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("upload") { _, _ in "ok" } - app.router.post("stream", options: .streamBody) { _, _ in + router.post("stream", options: .streamBody) { _, _ in "ok" } - try await app.buildAndTest(.live) { client in + let app = HBApplication(responder: router.buildResponder(), configuration: .init(maxUploadSize: 64 * 1024)) + try await app.test(.live) { client in let buffer = self.randomBuffer(size: 128 * 1024) // check non streamed route throws an error try await client.XCTExecute(uri: "/upload", method: .POST, body: buffer) { response in @@ -479,8 +501,9 @@ final class ApplicationTests: XCTestCase { } /* func testRemoteAddress() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("/") { _, context -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + let app = HBApplication(responder: router.buildResponder()) + router.get("/") { _, context -> String in switch context.remoteAddress { case .v4(let address): return String(describing: address.host) @@ -490,7 +513,7 @@ final class ApplicationTests: XCTestCase { throw HBHTTPError(.internalServerError) } } - try await app.buildAndTest(.live) { client in + try await app.test(.live) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) diff --git a/Tests/HummingbirdTests/AsyncAwaitTests.swift b/Tests/HummingbirdTests/AsyncAwaitTests.swift index a9b1fbb45..61888f6f6 100644 --- a/Tests/HummingbirdTests/AsyncAwaitTests.swift +++ b/Tests/HummingbirdTests/AsyncAwaitTests.swift @@ -31,11 +31,12 @@ final class AsyncAwaitTests: XCTestCase { } func testAsyncRoute() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("/hello") { request, context -> ByteBuffer in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/hello") { request, context -> ByteBuffer in return await self.getBuffer(request: request, context: context) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in var body = try XCTUnwrap(response.body) let string = body.readString(length: body.readableBytes) @@ -46,11 +47,12 @@ final class AsyncAwaitTests: XCTestCase { } func testAsyncRouterGroup() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.group("test").get("/hello") { request, context -> ByteBuffer in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.group("test").get("/hello") { request, context -> ByteBuffer in return await self.getBuffer(request: request, context: context) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test/hello", method: .GET) { response in var body = try XCTUnwrap(response.body) let string = body.readString(length: body.readableBytes) @@ -68,12 +70,13 @@ final class AsyncAwaitTests: XCTestCase { return response } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(AsyncTestMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(AsyncTestMiddleware()) + router.get("/hello") { _, _ -> String in "hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in XCTAssertEqual(response.headers["async"].first, "true") } @@ -91,10 +94,11 @@ final class AsyncAwaitTests: XCTestCase { return try await context.success("Hello \(self.name)").get() } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("/hello/:name", use: AsyncTest.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello/:name", use: AsyncTest.self) + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello/Adam", method: .POST) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "Hello Adam") @@ -103,8 +107,8 @@ final class AsyncAwaitTests: XCTestCase { } func testCollatingRequestBody() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.patch("size") { request, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.patch("size") { request, _ -> String in guard let body = request.body.buffer else { throw HBHTTPError(.badRequest) } @@ -112,8 +116,9 @@ final class AsyncAwaitTests: XCTestCase { try await Task.sleep(nanoseconds: 1) return body.readableBytes.description } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 530_001) try await client.XCTExecute(uri: "/size", method: .PATCH, body: buffer) { response in let body = try XCTUnwrap(response.body) @@ -124,8 +129,8 @@ final class AsyncAwaitTests: XCTestCase { /// Test streaming of requests via AsyncSequence func testStreaming() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.post("size", options: .streamBody) { request, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("size", options: .streamBody) { request, _ -> String in guard let stream = request.body.stream else { throw HBHTTPError(.badRequest) } @@ -135,8 +140,9 @@ final class AsyncAwaitTests: XCTestCase { } return size.description } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 530_001) try await client.XCTExecute(uri: "/size", method: .POST, body: buffer) { response in let body = try XCTUnwrap(response.body) @@ -147,13 +153,14 @@ final class AsyncAwaitTests: XCTestCase { /// Test streaming of response via AsyncSequence func testResponseAsyncSequence() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("buffer", options: .streamBody) { request, _ -> HBRequestBodyStreamerSequence.ResponseGenerator in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("buffer", options: .streamBody) { request, _ -> HBRequestBodyStreamerSequence.ResponseGenerator in guard let stream = request.body.stream else { throw HBHTTPError(.badRequest) } return stream.sequence.responseGenerator } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 530_001) try await client.XCTExecute(uri: "/buffer", method: .GET, body: buffer) { response in XCTAssertEqual(response.status, .ok) @@ -164,8 +171,8 @@ final class AsyncAwaitTests: XCTestCase { /// Test streaming of response via AsyncSequence func testResponseAsyncStream() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("alphabet") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("alphabet") { _, _ in AsyncStream { cont in let alphabet = "abcdefghijklmnopqrstuvwxyz" var index = alphabet.startIndex @@ -178,8 +185,9 @@ final class AsyncAwaitTests: XCTestCase { cont.finish() } } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let buffer = self.randomBuffer(size: 530_001) try await client.XCTExecute(uri: "/alphabet", method: .GET, body: buffer) { response in let body = try XCTUnwrap(response.body) diff --git a/Tests/HummingbirdTests/DateCacheTests.swift b/Tests/HummingbirdTests/DateCacheTests.swift index 1ed8be9d5..1d011b8e1 100644 --- a/Tests/HummingbirdTests/DateCacheTests.swift +++ b/Tests/HummingbirdTests/DateCacheTests.swift @@ -31,12 +31,13 @@ class HummingbirdDateTests: XCTestCase { } func testDateHeader() async throws { - let app = HBApplicationBuilder() - app.router.get("date") { _, _ in + let router = HBRouterBuilder() + router.get("date") { _, _ in return "hello" } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.live) { client in + try await app.test(.live) { client in let date = try await client.XCTExecute(uri: "/date", method: .GET) { response in XCTAssertNotNil(response.headers["date"].first) return response.headers["date"].first diff --git a/Tests/HummingbirdTests/EnvironmentTests.swift b/Tests/HummingbirdTests/EnvironmentTests.swift index e4b398aa4..9de4975fc 100644 --- a/Tests/HummingbirdTests/EnvironmentTests.swift +++ b/Tests/HummingbirdTests/EnvironmentTests.swift @@ -43,7 +43,8 @@ final class EnvironmentTests: XCTestCase { func testLogLevel() { setenv("LOG_LEVEL", "trace", 1) - let app = HBApplicationBuilder() + let router = HBRouterBuilder() + let app = HBApplication(responder: router.buildResponder()) XCTAssertEqual(app.logger.logLevel, .trace) } diff --git a/Tests/HummingbirdTests/HandlerTests.swift b/Tests/HummingbirdTests/HandlerTests.swift index 350140b2e..ed2f97b20 100644 --- a/Tests/HummingbirdTests/HandlerTests.swift +++ b/Tests/HummingbirdTests/HandlerTests.swift @@ -28,11 +28,12 @@ final class HandlerTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.post("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let body = ByteBufferAllocator().buffer(string: #"{"foo": "bar"}"#) try await client.XCTExecute( @@ -57,11 +58,12 @@ final class HandlerTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.post("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let body = ByteBufferAllocator().buffer(string: #"{"value": "bar"}"#) try await client.XCTExecute( @@ -86,11 +88,12 @@ final class HandlerTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.post("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let body = ByteBufferAllocator().buffer(string: #"{"name": null}"#) try await client.XCTExecute( @@ -120,11 +123,12 @@ final class HandlerTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.post("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in let body = ByteBufferAllocator().buffer(string: #"{invalid}"#) try await client.XCTExecute( @@ -147,11 +151,12 @@ final class HandlerTests: XCTestCase { return "Hello \(self.name)" } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.post("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.post("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .POST, body: ByteBufferAllocator().buffer(string: #"{"name": "Adam"}"#)) { response in let body = try XCTUnwrap(response.body) @@ -167,11 +172,12 @@ final class HandlerTests: XCTestCase { return context.success("Hello \(self.name)") } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.put("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .PUT, body: ByteBufferAllocator().buffer(string: #"{"name": "Adam"}"#)) { response in let body = try XCTUnwrap(response.body) @@ -188,11 +194,12 @@ final class HandlerTests: XCTestCase { return .ok } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("/hello", use: DecodeTest.self) + var app = HBApplication(responder: router.buildResponder()) app.decoder = JSONDecoder() - app.router.get("/hello", use: DecodeTest.self) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET, body: ByteBufferAllocator().buffer(string: #"{"name2": "Adam"}"#)) { response in XCTAssertEqual(response.status, .badRequest) } @@ -211,10 +218,11 @@ final class HandlerTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.put("/:test", use: ParameterTest.self) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.put("/:test", use: ParameterTest.self) + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/23", method: .PUT) { response in let body = try XCTUnwrap(response.body) diff --git a/Tests/HummingbirdTests/MetricsTests.swift b/Tests/HummingbirdTests/MetricsTests.swift index 5e1d1f788..81ba433e7 100644 --- a/Tests/HummingbirdTests/MetricsTests.swift +++ b/Tests/HummingbirdTests/MetricsTests.swift @@ -184,12 +184,13 @@ final class MetricsTests: XCTestCase { } func testCounter() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBMetricsMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBMetricsMiddleware()) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { _ in } } @@ -202,12 +203,13 @@ final class MetricsTests: XCTestCase { } func testError() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBMetricsMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBMetricsMiddleware()) + router.get("/hello") { _, _ -> String in throw HBHTTPError(.badRequest) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { _ in } } @@ -221,12 +223,13 @@ final class MetricsTests: XCTestCase { } func testNotFoundError() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBMetricsMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBMetricsMiddleware()) + router.get("/hello") { _, _ -> String in return "hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello2", method: .GET) { _ in } } @@ -239,12 +242,13 @@ final class MetricsTests: XCTestCase { } func testParameterEndpoint() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBMetricsMiddleware()) - app.router.get("/user/:id") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBMetricsMiddleware()) + router.get("/user/:id") { _, _ -> String in throw HBHTTPError(.badRequest) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/user/765", method: .GET) { _ in } } diff --git a/Tests/HummingbirdTests/MiddlewareTests.swift b/Tests/HummingbirdTests/MiddlewareTests.swift index c99b07fda..f321ef043 100644 --- a/Tests/HummingbirdTests/MiddlewareTests.swift +++ b/Tests/HummingbirdTests/MiddlewareTests.swift @@ -27,12 +27,13 @@ final class MiddlewareTests: XCTestCase { } } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestMiddleware()) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in XCTAssertEqual(response.headers["middleware"].first, "TestMiddleware") } @@ -50,13 +51,14 @@ final class MiddlewareTests: XCTestCase { } } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestMiddleware(string: "first")) - app.middleware.add(TestMiddleware(string: "second")) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestMiddleware(string: "first")) + router.middlewares.add(TestMiddleware(string: "second")) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in // headers come back in opposite order as middleware is applied to responses in that order XCTAssertEqual(response.headers["middleware"].first, "second") @@ -76,12 +78,13 @@ final class MiddlewareTests: XCTestCase { } } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestMiddleware()) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { _ in } } @@ -98,10 +101,11 @@ final class MiddlewareTests: XCTestCase { } } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestMiddleware()) + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestMiddleware()) + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "Edited error") @@ -117,25 +121,27 @@ final class MiddlewareTests: XCTestCase { return next.respond(to: request, context: context) } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.group() + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.group() .add(middleware: TestMiddleware()) .get("test") { _, _ in return "test" } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test", method: .GET) { _ in } } } func testCORSUseOrigin() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBCORSMiddleware()) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBCORSMiddleware()) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET, headers: ["origin": "foo.com"]) { response in // headers come back in opposite order as middleware is applied to responses in that order XCTAssertEqual(response.headers["Access-Control-Allow-Origin"].first, "foo.com") @@ -144,12 +150,13 @@ final class MiddlewareTests: XCTestCase { } func testCORSUseAll() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBCORSMiddleware(allowOrigin: .all)) - app.router.get("/hello") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBCORSMiddleware(allowOrigin: .all)) + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .GET, headers: ["origin": "foo.com"]) { response in // headers come back in opposite order as middleware is applied to responses in that order XCTAssertEqual(response.headers["Access-Control-Allow-Origin"].first, "*") @@ -158,8 +165,8 @@ final class MiddlewareTests: XCTestCase { } func testCORSOptions() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBCORSMiddleware( + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBCORSMiddleware( allowOrigin: .all, allowHeaders: ["content-type", "authorization"], allowMethods: [.GET, .PUT, .DELETE, .OPTIONS], @@ -167,10 +174,11 @@ final class MiddlewareTests: XCTestCase { exposedHeaders: ["content-length"], maxAge: .seconds(3600) )) - app.router.get("/hello") { _, _ -> String in + router.get("/hello") { _, _ -> String in return "Hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .OPTIONS, headers: ["origin": "foo.com"]) { response in // headers come back in opposite order as middleware is applied to responses in that order XCTAssertEqual(response.headers["Access-Control-Allow-Origin"].first, "*") @@ -187,12 +195,13 @@ final class MiddlewareTests: XCTestCase { } func testRouteLoggingMiddleware() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBLogRequestsMiddleware(.debug)) - app.router.put("/hello") { _, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBLogRequestsMiddleware(.debug)) + router.put("/hello") { _, context -> EventLoopFuture in return context.failure(.badRequest) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/hello", method: .PUT) { _ in } } diff --git a/Tests/HummingbirdTests/PersistTests+async.swift b/Tests/HummingbirdTests/PersistTests+async.swift index 18881cc1a..a79d55270 100644 --- a/Tests/HummingbirdTests/PersistTests+async.swift +++ b/Tests/HummingbirdTests/PersistTests+async.swift @@ -17,42 +17,39 @@ import HummingbirdXCT import XCTest final class AsyncPersistTests: XCTestCase { - func createApplication() throws -> (HBApplicationBuilder, HBPersistDriver) { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - let persist: HBPersistDriver = HBMemoryPersistDriver(eventLoopGroup: app.eventLoopGroup) + func createRouter() throws -> (HBRouterBuilder, HBPersistDriver) { + let router = HBRouterBuilder(context: HBTestRouterContext.self) + let persist: HBPersistDriver = HBMemoryPersistDriver() - app.router.put("/persist/:tag") { request, context -> HTTPResponseStatus in + router.put("/persist/:tag") { request, context -> HTTPResponseStatus in guard let buffer = request.body.buffer else { throw HBHTTPError(.badRequest) } let tag = try context.parameters.require("tag") try await persist.set(key: tag, value: String(buffer: buffer), request: request) return .ok } - app.router.put("/persist/:tag/:time") { request, context -> HTTPResponseStatus in + router.put("/persist/:tag/:time") { request, context -> HTTPResponseStatus in guard let time = context.parameters.get("time", as: Int.self) else { throw HBHTTPError(.badRequest) } guard let buffer = request.body.buffer else { throw HBHTTPError(.badRequest) } let tag = try context.parameters.require("tag") try await persist.set(key: tag, value: String(buffer: buffer), expires: .seconds(numericCast(time)), request: request) return .ok } - app.router.get("/persist/:tag") { request, context -> String? in + router.get("/persist/:tag") { request, context -> String? in let tag = try context.parameters.require("tag") return try await persist.get(key: tag, as: String.self, request: request) } - app.router.delete("/persist/:tag") { request, context -> HTTPResponseStatus in + router.delete("/persist/:tag") { request, context -> HTTPResponseStatus in let tag = try context.parameters.require("tag") try await persist.remove(key: tag, request: request) return .noContent } - return (app, persist) + return (router, persist) } func testSetGet() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } try await client.XCTExecute(uri: "/persist/\(tag)", method: .GET) { response in @@ -63,18 +60,15 @@ final class AsyncPersistTests: XCTestCase { } func testCreateGet() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, persist) = try createApplication() - app.router.put("/create/:tag") { request, context -> HTTPResponseStatus in + let (router, persist) = try createRouter() + router.put("/create/:tag") { request, context -> HTTPResponseStatus in guard let buffer = request.body.buffer else { throw HBHTTPError(.badRequest) } let tag = try context.parameters.require("tag") try await persist.create(key: tag, value: String(buffer: buffer), request: request) return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/create/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } try await client.XCTExecute(uri: "/persist/\(tag)", method: .GET) { response in @@ -85,12 +79,8 @@ final class AsyncPersistTests: XCTestCase { } func testDoubleCreateFail() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, persist) = try createApplication() - app.router.put("/create/:tag") { request, context -> HTTPResponseStatus in + let (router, persist) = try createRouter() + router.put("/create/:tag") { request, context -> HTTPResponseStatus in guard let buffer = request.body.buffer else { throw HBHTTPError(.badRequest) } let tag = try context.parameters.require("tag") do { @@ -100,7 +90,8 @@ final class AsyncPersistTests: XCTestCase { } return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/create/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { response in XCTAssertEqual(response.status, .ok) @@ -112,12 +103,9 @@ final class AsyncPersistTests: XCTestCase { } func testSetTwice() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "test1")) { _ in } @@ -132,12 +120,9 @@ final class AsyncPersistTests: XCTestCase { } func testExpires() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag1 = UUID().uuidString let tag2 = UUID().uuidString @@ -156,27 +141,24 @@ final class AsyncPersistTests: XCTestCase { } func testCodable() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif struct TestCodable: Codable { let buffer: String } - let (app, persist) = try createApplication() - - app.router.put("/codable/:tag") { request, context -> HTTPResponseStatus in + let (router, persist) = try createRouter() + router.put("/codable/:tag") { request, context -> HTTPResponseStatus in guard let tag = context.parameters.get("tag") else { throw HBHTTPError(.badRequest) } guard let buffer = request.body.buffer else { throw HBHTTPError(.badRequest) } try await persist.set(key: tag, value: TestCodable(buffer: String(buffer: buffer)), request: request) return .ok } - app.router.get("/codable/:tag") { request, context -> String? in + router.get("/codable/:tag") { request, context -> String? in guard let tag = context.parameters.get("tag") else { throw HBHTTPError(.badRequest) } let value = try await persist.get(key: tag, as: TestCodable.self, request: request) return value?.buffer } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/codable/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } @@ -188,12 +170,9 @@ final class AsyncPersistTests: XCTestCase { } func testRemove() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "ThisIsTest1")) { _ in } @@ -205,12 +184,9 @@ final class AsyncPersistTests: XCTestCase { } func testExpireAndAdd() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard HBEnvironment().get("CI") != "true" else { throw XCTSkip() } - #endif - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)/0", method: .PUT, body: ByteBufferAllocator().buffer(string: "ThisIsTest1")) { _ in } diff --git a/Tests/HummingbirdTests/PersistTests.swift b/Tests/HummingbirdTests/PersistTests.swift index 8362d230d..9bdcdc796 100644 --- a/Tests/HummingbirdTests/PersistTests.swift +++ b/Tests/HummingbirdTests/PersistTests.swift @@ -19,38 +19,39 @@ import XCTest final class PersistTests: XCTestCase { static let redisHostname = HBEnvironment.shared.get("REDIS_HOSTNAME") ?? "localhost" - func createApplication() throws -> (HBApplicationBuilder, HBPersistDriver) { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - let persist = HBMemoryPersistDriver(eventLoopGroup: app.eventLoopGroup) + func createRouter() throws -> (HBRouterBuilder, HBPersistDriver) { + let router = HBRouterBuilder(context: HBTestRouterContext.self) + let persist = HBMemoryPersistDriver() - app.router.put("/persist/:tag") { request, context -> EventLoopFuture in + router.put("/persist/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } guard let buffer = request.body.buffer else { return context.failure(.badRequest) } return persist.set(key: tag, value: String(buffer: buffer), request: request) .map { _ in .ok } } - app.router.put("/persist/:tag/:time") { request, context -> EventLoopFuture in + router.put("/persist/:tag/:time") { request, context -> EventLoopFuture in guard let time = context.parameters.get("time", as: Int.self) else { return context.failure(.badRequest) } guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } guard let buffer = request.body.buffer else { return context.failure(.badRequest) } return persist.set(key: tag, value: String(buffer: buffer), expires: .seconds(numericCast(time)), request: request) .map { _ in .ok } } - app.router.get("/persist/:tag") { request, context -> EventLoopFuture in + router.get("/persist/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag", as: String.self) else { return context.failure(.badRequest) } return persist.get(key: tag, as: String.self, request: request) } - app.router.delete("/persist/:tag") { request, context -> EventLoopFuture in + router.delete("/persist/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag", as: String.self) else { return context.failure(.badRequest) } return persist.remove(key: tag, request: request) .map { _ in .noContent } } - return (app, persist) + return (router, persist) } func testSetGet() async throws { - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } try await client.XCTExecute(uri: "/persist/\(tag)", method: .GET) { response in @@ -61,14 +62,15 @@ final class PersistTests: XCTestCase { } func testCreateGet() async throws { - let (app, persist) = try createApplication() - app.router.put("/create/:tag") { request, context -> EventLoopFuture in + let (router, persist) = try createRouter() + router.put("/create/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } guard let buffer = request.body.buffer else { return context.failure(.badRequest) } return persist.create(key: tag, value: String(buffer: buffer), request: request) .map { _ in .ok } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/create/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } try await client.XCTExecute(uri: "/persist/\(tag)", method: .GET) { response in @@ -79,8 +81,8 @@ final class PersistTests: XCTestCase { } func testDoubleCreateFail() async throws { - let (app, persist) = try createApplication() - app.router.put("/create/:tag") { request, context -> EventLoopFuture in + let (router, persist) = try createRouter() + router.put("/create/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } guard let buffer = request.body.buffer else { return context.failure(.badRequest) } return persist.create(key: tag, value: String(buffer: buffer), request: request) @@ -90,7 +92,8 @@ final class PersistTests: XCTestCase { } .map { _ in .ok } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/create/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { response in XCTAssertEqual(response.status, .ok) @@ -102,8 +105,9 @@ final class PersistTests: XCTestCase { } func testSetTwice() async throws { - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "test1")) { _ in } @@ -118,8 +122,9 @@ final class PersistTests: XCTestCase { } func testExpires() async throws { - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag1 = UUID().uuidString let tag2 = UUID().uuidString @@ -141,19 +146,20 @@ final class PersistTests: XCTestCase { struct TestCodable: Codable { let buffer: String } - let (app, persist) = try createApplication() - - app.router.put("/codable/:tag") { request, context -> EventLoopFuture in + let (router, persist) = try createRouter() + router.put("/codable/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } guard let buffer = request.body.buffer else { return context.failure(.badRequest) } return persist.set(key: tag, value: TestCodable(buffer: String(buffer: buffer)), request: request) .map { _ in .ok } } - app.router.get("/codable/:tag") { request, context -> EventLoopFuture in + router.get("/codable/:tag") { request, context -> EventLoopFuture in guard let tag = context.parameters.get("tag") else { return context.failure(.badRequest) } return persist.get(key: tag, as: TestCodable.self, request: request).map { $0.map(\.buffer) } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/codable/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "Persist")) { _ in } @@ -165,8 +171,9 @@ final class PersistTests: XCTestCase { } func testRemove() async throws { - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)", method: .PUT, body: ByteBufferAllocator().buffer(string: "ThisIsTest1")) { _ in } @@ -178,8 +185,9 @@ final class PersistTests: XCTestCase { } func testExpireAndAdd() async throws { - let (app, _) = try createApplication() - try await app.buildAndTest(.router) { client in + let (router, _) = try createRouter() + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let tag = UUID().uuidString try await client.XCTExecute(uri: "/persist/\(tag)/0", method: .PUT, body: ByteBufferAllocator().buffer(string: "ThisIsTest1")) { _ in } diff --git a/Tests/HummingbirdTests/RouterTests.swift b/Tests/HummingbirdTests/RouterTests.swift index 4e4ce5dac..e9b051e40 100644 --- a/Tests/HummingbirdTests/RouterTests.swift +++ b/Tests/HummingbirdTests/RouterTests.swift @@ -45,11 +45,12 @@ final class RouterTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestEndpointMiddleware()) - app.router.get("/test/:number") { _, _ in return "xxx" } + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestEndpointMiddleware()) + router.get("/test/:number") { _, _ in return "xxx" } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test/1", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "/test/:number") @@ -66,19 +67,20 @@ final class RouterTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestEndpointMiddleware()) - app.router.get("test") { _, context in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestEndpointMiddleware()) + router.get("test") { _, context in return context.endpointPath } - app.router.get { _, context in + router.get { _, context in return context.endpointPath } - app.router.post("/test2") { _, context in + router.post("/test2") { _, context in return context.endpointPath } + let app = HBApplication(responder: router.buildResponder()) - try await app.buildAndTest(.router) { client in + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "/") @@ -103,25 +105,26 @@ final class RouterTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(TestEndpointMiddleware()) - app.router.get("test/") { _, context in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(TestEndpointMiddleware()) + router.get("test/") { _, context in return context.endpointPath } - app.router.post("test2") { _, context in + router.post("test2") { _, context in return context.endpointPath } - app.router + router .group("testGroup") .get { _, context in return context.endpointPath } - app.router + router .group("testGroup2") .get("/") { _, context in return context.endpointPath } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test/", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "/test") @@ -146,8 +149,8 @@ final class RouterTests: XCTestCase { /// Test correct endpoints are called from group func testMethodEndpoint() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/endpoint") .get { _, _ in return "GET" @@ -155,7 +158,8 @@ final class RouterTests: XCTestCase { .put { _, _ in return "PUT" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/endpoint", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "GET") @@ -171,17 +175,18 @@ final class RouterTests: XCTestCase { /// Test middle in group is applied to group but not to routes outside /// group func testGroupMiddleware() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group() .add(middleware: TestMiddleware()) .get("/group") { _, _ in return "hello" } - app.router.get("/not-group") { _, _ in + router.get("/not-group") { _, _ in return "hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/group", method: .GET) { response in XCTAssertEqual(response.headers["middleware"].first, "TestMiddleware") } @@ -193,14 +198,15 @@ final class RouterTests: XCTestCase { } func testEndpointMiddleware() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/group") .add(middleware: TestMiddleware()) .head { _, _ in return "hello" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/group", method: .HEAD) { response in XCTAssertEqual(response.headers["middleware"].first, "TestMiddleware") } @@ -209,15 +215,16 @@ final class RouterTests: XCTestCase { /// Test middleware in parent group is applied to routes in child group func testGroupGroupMiddleware() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .group("/test") .add(middleware: TestMiddleware()) .group("/group") .get { _, context in return context.success("hello") } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test/group", method: .GET) { response in XCTAssertEqual(response.headers["middleware"].first, "TestMiddleware") } @@ -236,8 +243,8 @@ final class RouterTests: XCTestCase { } } - let app = HBApplicationBuilder(requestContext: HBTestRouterContext2.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext2.self) + router .group("/test") .add(middleware: TestGroupMiddleware(output: "route1")) .get { _, context in @@ -248,7 +255,8 @@ final class RouterTests: XCTestCase { .get { _, context in return context.success(context.string) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/test/group", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "route2") @@ -261,12 +269,13 @@ final class RouterTests: XCTestCase { } func testParameters() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .delete("/user/:id") { _, context -> String? in return context.parameters.get("id", as: String.self) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/user/1234", method: .DELETE) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "1234") @@ -275,13 +284,14 @@ final class RouterTests: XCTestCase { } func testParameterCollection() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .delete("/user/:username/:id") { _, context -> String? in XCTAssertEqual(context.parameters.count, 2) return context.parameters.get("id", as: String.self) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/user/john/1234", method: .DELETE) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "1234") @@ -290,15 +300,16 @@ final class RouterTests: XCTestCase { } func testPartialCapture() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .get("/files/file.${ext}/${name}.jpg") { _, context -> String in XCTAssertEqual(context.parameters.count, 2) let ext = try context.parameters.require("ext") let name = try context.parameters.require("name") return "\(name).\(ext)" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/files/file.doc/test.jpg", method: .GET) { response in let body = try XCTUnwrap(response.body) XCTAssertEqual(String(buffer: body), "test.doc") @@ -307,12 +318,13 @@ final class RouterTests: XCTestCase { } func testPartialWildcard() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router .get("/files/file.*/*.jpg") { _, _ -> HTTPResponseStatus in return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/files/file.doc/test.jpg", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -324,11 +336,12 @@ final class RouterTests: XCTestCase { /// Test we have a request id and that it increments with each request func testRequestId() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("id") { _, context in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("id") { _, context in return context.id.description } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in let idString = try await client.XCTExecute(uri: "/id", method: .GET) { response -> String in let body = try XCTUnwrap(response.body) return String(buffer: body) @@ -344,11 +357,12 @@ final class RouterTests: XCTestCase { // Test redirect response func testRedirect() async throws { - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.router.get("redirect") { _, _ in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.get("redirect") { _, _ in return HBResponse.redirect(to: "/other") } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/redirect", method: .GET) { response in XCTAssertEqual(response.headers["location"].first, "/other") XCTAssertEqual(response.status, .seeOther) diff --git a/Tests/HummingbirdTests/TracingTests.swift b/Tests/HummingbirdTests/TracingTests.swift index e407180b8..bfcd27d3a 100644 --- a/Tests/HummingbirdTests/TracingTests.swift +++ b/Tests/HummingbirdTests/TracingTests.swift @@ -34,12 +34,13 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.get("users/:id") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.get("users/:id") { _, _ -> String in return "42" } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/users/42", method: .GET) { response in XCTAssertEqual(response.status, .ok) var responseBody = try XCTUnwrap(response.body) @@ -74,12 +75,13 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.post("users") { _, _ -> String in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.post("users") { _, _ -> String in throw HBHTTPError(.internalServerError) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/users", method: .POST, headers: ["content-length": "2"], body: ByteBuffer(string: "42")) { response in XCTAssertEqual(response.status, .internalServerError) } @@ -115,11 +117,11 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware(recordingHeaders: [ + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware(recordingHeaders: [ "accept", "content-type", "cache-control", "does-not-exist", ])) - app.router.get("users/:id") { _, _ -> HBResponse in + router.get("users/:id") { _, _ -> HBResponse in var headers = HTTPHeaders() headers.add(name: "cache-control", value: "86400") headers.add(name: "cache-control", value: "public") @@ -130,7 +132,8 @@ final class TracingTests: XCTestCase { body: .byteBuffer(ByteBuffer(string: "42")) ) } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in var requestHeaders = HTTPHeaders() requestHeaders.add(name: "Accept", value: "text/plain") requestHeaders.add(name: "Accept", value: "application/json") @@ -173,12 +176,13 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.post("/users") { _, _ -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.post("/users") { _, _ -> HTTPResponseStatus in return .noContent } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/users", method: .POST) { response in XCTAssertEqual(response.status, .noContent) } @@ -210,12 +214,13 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.get("/") { _, _ -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.get("/") { _, _ -> HTTPResponseStatus in return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -247,9 +252,10 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - try await app.buildAndTest(.router) { client in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .notFound) } @@ -285,16 +291,17 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.get("/") { _, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.get("/") { _, context -> HTTPResponseStatus in var serviceContext = context.serviceContext serviceContext.testID = "test" let span = InstrumentationSystem.legacyTracer.startAnySpan("testing", context: serviceContext, ofKind: .server) span.end() return .ok } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -318,9 +325,9 @@ final class TracingTests: XCTestCase { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.get("/") { _, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.get("/") { _, context -> HTTPResponseStatus in var serviceContext = context.serviceContext serviceContext.testID = "test" return context.withSpan("TestSpan", serviceContext: serviceContext, ofKind: .client) { _, span in @@ -328,7 +335,8 @@ final class TracingTests: XCTestCase { return .ok } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -367,13 +375,14 @@ final class TracingTests: XCTestCase { } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(SpanMiddleware()) - app.middleware.add(HBTracingMiddleware()) - app.router.get("/") { _, context -> EventLoopFuture in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(SpanMiddleware()) + router.middlewares.add(HBTracingMiddleware()) + router.get("/") { _, context -> EventLoopFuture in return context.eventLoop.scheduleTask(in: .milliseconds(2)) { return .ok }.futureResult } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -401,15 +410,16 @@ extension TracingTests { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.router.get("/") { _, _ -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.get("/") { _, _ -> HTTPResponseStatus in try await Task.sleep(nanoseconds: 1000) return InstrumentationSystem.tracer.withAnySpan("testing", ofKind: .server) { _ in return .ok } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) } @@ -444,16 +454,17 @@ extension TracingTests { tracer.onEndSpan = { _ in expectation.fulfill() } InstrumentationSystem.bootstrapInternal(tracer) - let app = HBApplicationBuilder(requestContext: HBTestRouterContext.self) - app.middleware.add(HBTracingMiddleware()) - app.middleware.add(AsyncSpanMiddleware()) - app.router.get("/") { _, context -> HTTPResponseStatus in + let router = HBRouterBuilder(context: HBTestRouterContext.self) + router.middlewares.add(HBTracingMiddleware()) + router.middlewares.add(AsyncSpanMiddleware()) + router.get("/") { _, context -> HTTPResponseStatus in try await Task.sleep(nanoseconds: 1000) return context.withSpan("testing", ofKind: .server) { _, _ in return .ok } } - try await app.buildAndTest(.router) { client in + let app = HBApplication(responder: router.buildResponder()) + try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .GET) { response in XCTAssertEqual(response.status, .ok) }