Skip to content

Commit ade5ca1

Browse files
author
Andrea Scuderi
committed
Improve Unit Tests
1 parent a3f75ba commit ade5ca1

File tree

5 files changed

+266
-189
lines changed

5 files changed

+266
-189
lines changed

Sources/BreezeLambdaWebHook/HandlerContext.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,25 @@ import Foundation
2323
import ServiceLifecycle
2424
import Logging
2525

26+
///
27+
/// `HandlerContext` provides a context for Lambda handlers, encapsulating an HTTP client and configuration.
28+
///
29+
/// This struct is responsible for managing the lifecycle of the HTTP client used for outbound requests,
30+
/// including graceful and synchronous shutdown procedures. It also provides logging for lifecycle events.
31+
///
32+
/// - Parameters:
33+
/// - httpClient: The HTTP client used for making outbound HTTP requests.
34+
/// - config: The configuration for the HTTP client, including timeout and logger.
35+
///
36+
/// - Conforms to: `Service`
2637
public struct HandlerContext: Service {
38+
/// The HTTP client used for outbound requests.
2739
public let httpClient: HTTPClient
40+
/// The configuration for the HTTP client.
2841
private let config: BreezeHTTPClientConfig
2942

43+
/// Initializes a new `HandlerContext` with the provided configuration.
44+
/// - Parameter config: The configuration for the HTTP client.
3045
public init(config: BreezeHTTPClientConfig) {
3146
let timeout = HTTPClient.Configuration.Timeout(
3247
connect: config.timeout,
@@ -40,18 +55,21 @@ public struct HandlerContext: Service {
4055
self.config = config
4156
}
4257

58+
/// Runs the `HandlerContext` and waits for a graceful shutdown.
4359
public func run() async throws {
4460
config.logger.info("BreezeHTTPClientProvider started")
4561
try await gracefulShutdown()
4662
config.logger.info("BreezeHTTPClientProvider is gracefully shutting down ...")
4763
try await onGracefulShutdown()
4864
}
4965

66+
/// Handles graceful shutdown of the HTTP client.
5067
public func onGracefulShutdown() async throws {
5168
try await httpClient.shutdown()
5269
config.logger.info("BreezeHTTPClientProvider: HTTPClient shutdown is completed.")
5370
}
5471

72+
/// Synchronously shuts down the HTTP client.
5573
public func syncShutdown() throws {
5674
try httpClient.syncShutdown()
5775
config.logger.info("BreezeHTTPClientProvider: HTTPClient syncShutdown is completed.")

Tests/BreezeLambdaWebHookTests/BreezeLambdaWebHookService.swift

Lines changed: 0 additions & 126 deletions
This file was deleted.
Lines changed: 57 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 (c) Andrea Scuderi - https://github.com/swift-serverless
1+
// Copyright 2024 (c) Andrea Scuderi - https://github.com/swift-serverless
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -13,79 +13,73 @@
1313
// limitations under the License.
1414

1515
import Testing
16+
@testable import AsyncHTTPClient
1617
import AWSLambdaEvents
17-
import AWSLambdaRuntime
18-
import AsyncHTTPClient
18+
@testable import AWSLambdaRuntime
19+
@testable import ServiceLifecycle
20+
import ServiceLifecycleTestKit
1921
@testable import BreezeLambdaWebHook
2022
import Logging
23+
#if canImport(FoundationEssentials)
24+
import FoundationEssentials
25+
#else
2126
import Foundation
27+
#endif
28+
import NIOCore
2229

23-
@Suite("BreezeLambdaWebHookSuite")
24-
struct BreezeLambdaWebHookTests: ~Copyable {
2530

26-
let decoder = JSONDecoder()
27-
let config = BreezeHTTPClientConfig(
28-
timeout: .seconds(1),
29-
logger: Logger(label: "test")
30-
)
31-
32-
init() {
33-
setEnvironmentVar(name: "_HANDLER", value: "build/webhook", overwrite: true)
34-
setEnvironmentVar(name: "LOCAL_LAMBDA_SERVER_ENABLED", value: "true", overwrite: true)
35-
}
36-
37-
deinit {
38-
unsetenv("LOCAL_LAMBDA_SERVER_ENABLED")
39-
unsetenv("_HANDLER")
40-
}
31+
@Suite(.serialized)
32+
struct BreezeLambdaWebHookTests {
4133

42-
@Test("PostWhenMissingBody_ThenError")
43-
func postWhenMissingBody_thenError() async throws {
44-
let createRequest = try Fixtures.fixture(name: Fixtures.getWebHook, type: "json")
45-
let request = try decoder.decode(APIGatewayV2Request.self, from: createRequest)
46-
let apiResponse: APIGatewayV2Response = try await Lambda.test(MyPostWebHook.self, config: config, with: request)
47-
let response: APIGatewayV2Response.BodyError = try apiResponse.decodeBody()
48-
49-
#expect(apiResponse.statusCode == .badRequest)
50-
#expect(apiResponse.headers == [ "Content-Type": "application/json" ])
51-
#expect(response.error == "invalidRequest")
52-
}
34+
let decoder = JSONDecoder()
5335

54-
@Test("PostWhenBody_ThenValue")
55-
func postWhenBody_thenValue() async throws {
56-
let createRequest = try Fixtures.fixture(name: Fixtures.postWebHook, type: "json")
57-
let request = try decoder.decode(APIGatewayV2Request.self, from: createRequest)
58-
let apiResponse: APIGatewayV2Response = try await Lambda.test(MyPostWebHook.self, config: config, with: request)
59-
let response: MyPostResponse = try apiResponse.decodeBody()
60-
let body: MyPostRequest = try request.bodyObject()
61-
62-
#expect(apiResponse.statusCode == .ok)
63-
#expect(apiResponse.headers == [ "Content-Type": "application/json" ])
64-
#expect(response.body == body.value)
65-
#expect(response.handler == "build/webhook")
36+
@Test("BreezeLambdaWebHook can be shutdown gracefully")
37+
func breezeLambdaWebHookCanBeShutdownGracefully() async throws {
38+
await testGracefulShutdown { gracefulShutdownTestTrigger in
39+
let (gracefulStream, continuation) = AsyncStream<Void>.makeStream()
40+
await withThrowingTaskGroup(of: Void.self) { group in
41+
let logger = Logger(label: "test")
42+
let config = BreezeHTTPClientConfig(timeout: .seconds(30), logger: logger)
43+
let sut = BreezeLambdaWebHook<MockHandler>.init(name: "Test", config: config)
44+
group.addTask {
45+
try await Task.sleep(nanoseconds: 1_000_000_000)
46+
gracefulShutdownTestTrigger.triggerGracefulShutdown()
47+
}
48+
group.addTask {
49+
await withGracefulShutdownHandler {
50+
do {
51+
try await sut.run()
52+
} catch {
53+
Issue.record("Error running BreezeLambdaWebHook: \(error.localizedDescription)")
54+
}
55+
} onGracefulShutdown: {
56+
logger.info("On Graceful Shutdown")
57+
continuation.yield()
58+
}
59+
}
60+
for await _ in gracefulStream {
61+
#expect(sut.name == "Test")
62+
#expect(sut.config.timeout == .seconds(30))
63+
continuation.finish()
64+
logger.info("Graceful shutdown stream received")
65+
group.cancelAll()
66+
}
67+
}
68+
}
6669
}
70+
}
71+
72+
struct MockHandler: BreezeLambdaWebHookHandler {
73+
let handlerContext: HandlerContext
6774

68-
@Test("GetWhenMissingQuery_ThenError")
69-
func getWhenMissingQuery_thenError() async throws {
70-
let createRequest = try Fixtures.fixture(name: Fixtures.postWebHook, type: "json")
71-
let request = try decoder.decode(APIGatewayV2Request.self, from: createRequest)
72-
let apiResponse: APIGatewayV2Response = try await Lambda.test(MyGetWebHook.self, config: config, with: request)
73-
let response: APIGatewayV2Response.BodyError = try apiResponse.decodeBody()
74-
75-
#expect(apiResponse.statusCode == .badRequest)
76-
#expect(apiResponse.headers == [ "Content-Type": "application/json" ])
77-
#expect(response.error == "invalidRequest")
75+
init(handlerContext: HandlerContext) {
76+
self.handlerContext = handlerContext
7877
}
7978

80-
@Test("GetWhenQuery_ThenValue")
81-
func getWhenQuery_thenValue() async throws {
82-
let createRequest = try Fixtures.fixture(name: Fixtures.getWebHook, type: "json")
83-
let request = try decoder.decode(APIGatewayV2Request.self, from: createRequest)
84-
let apiResponse: APIGatewayV2Response = try await Lambda.test(MyGetWebHook.self, config: config, with: request)
85-
let response: [String: String] = try apiResponse.decodeBody()
86-
87-
#expect(apiResponse.statusCode == .ok)
88-
#expect(apiResponse.headers == [ "Content-Type": "application/json" ])
89-
#expect(response.count == 2)
79+
func handle(_ event: APIGatewayV2Request, context: LambdaContext) async throws -> APIGatewayV2Response {
80+
return APIGatewayV2Response(
81+
statusCode: .ok,
82+
body: "Mock response"
83+
)
9084
}
9185
}

0 commit comments

Comments
 (0)