-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Additional Test Helpers #10
Merged
+368
−37
Merged
Changes from 6 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
0eb092f
Add mocked functions
mgacy 484d432
Add Logger.mock member
mgacy 041eaf3
Fix duplicated implementation
mgacy e0e6ae6
Add Runtime.getRemainingTime()
mgacy 5035895
Improve ergonomics of MockContext creation
mgacy 3935c54
Add context provider
mgacy 569b39f
E -> EnvironmentVariable
mgacy f576960
Merge branch 'main' into feature/additional-test-support
mgacy fa5e0f0
Other Es -> EnvironmentVariable
mgacy 4d4204b
Fix type
mgacy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// | ||
// ContextProvider.swift | ||
// LambdaExtras | ||
// | ||
// Created by Mathew Gacy on 1/7/24. | ||
// | ||
|
||
import Foundation | ||
import Logging | ||
import NIOCore | ||
import NIO | ||
|
||
/// A helper to create and manage mock initialization and runtime contexts for testing. | ||
/// | ||
/// Example usage: | ||
/// | ||
/// ```swift | ||
/// final class MyHandlerTests: XCTestCase { | ||
/// var contextProvider: ContextProvider<MyEnvironment> | ||
/// | ||
/// override func setUp() { | ||
/// contextProvider.setUp() | ||
/// } | ||
/// | ||
/// override func tearDown() { | ||
/// XCTAssertNoThrow(try contextProvider.shutdown()) | ||
/// } | ||
/// | ||
/// func testMyHandler() async throws { | ||
/// let sut = try await MyHandler(context: contextProvider.makeInitializationContext()) | ||
/// let actual = try await sut.handle(MockEvent(), context: contextProvider.makeContext()) | ||
/// ... | ||
/// } | ||
/// } | ||
/// ``` | ||
public struct ContextProvider<E> { | ||
/// The event loop group used to provide the contexts' event loops. | ||
public private(set) var eventLoopGroup: EventLoopGroup! | ||
|
||
/// The event loop for the contexts. | ||
public private(set) var eventLoop: EventLoop! | ||
|
||
/// The logger for the contexts. | ||
public var logger: Logger | ||
|
||
/// A closure returning the value of the given environment variable. | ||
public var environmentValueProvider: @Sendable (E) throws -> String | ||
|
||
/// Creates an instance. | ||
/// | ||
/// - Parameter environmentValueProvider: A closure returning the value of the given | ||
/// environment variable. | ||
public init( | ||
logger: Logger = .mock, | ||
environmentValueProvider: @escaping @Sendable (E) throws -> String | ||
) { | ||
self.logger = logger | ||
self.environmentValueProvider = environmentValueProvider | ||
} | ||
|
||
/// Sets up the event loop used for the provided initialization and runtime contexts. | ||
/// | ||
/// Call this in your test class's `setUp()` method: | ||
/// | ||
/// ```swift | ||
/// final class MyHandlerTests: XCTestCase { | ||
/// var contextProvider: ContextProvider<MyEnvironment> | ||
/// ... | ||
/// override func setUp() { | ||
/// contextProvider.setUp() | ||
/// ... | ||
/// } | ||
/// } | ||
/// ``` | ||
public mutating func setUp() { | ||
eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) | ||
eventLoop = eventLoopGroup.next() | ||
} | ||
|
||
/// Shuts the event loop group down. | ||
/// | ||
/// Call this in your test class's `.tearDown()` method: | ||
/// | ||
/// ```swift | ||
/// final class MyHandlerTests: XCTestCase { | ||
/// var contextProvider: ContextProvider<MyEnvironment> | ||
/// ... | ||
/// override func tearDown() { | ||
/// XCTAssertNoThrow(try contextProvider.shutdown()) | ||
/// ... | ||
/// } | ||
/// } | ||
/// ``` | ||
public mutating func shutdown() throws { | ||
defer { | ||
eventLoop = nil | ||
eventLoopGroup = nil | ||
} | ||
try eventLoopGroup.syncShutdownGracefully() | ||
} | ||
|
||
/// Returns the mocked initialization context. | ||
public func makeInitializationContext() -> MockInitializationContext<E> { | ||
.init( | ||
logger: logger, | ||
eventLoop: eventLoop, | ||
allocator: .init(), | ||
environmentValueProvider: environmentValueProvider) | ||
} | ||
|
||
/// Returns the mocked runtime context. | ||
/// | ||
/// - Parameter configuration: The configuration for the mocked runtime context. | ||
public func makeContext( | ||
configuration: MockContext<E>.Configuration = .init() | ||
) -> MockContext<E> { | ||
.init( | ||
eventLoop: eventLoop, | ||
configuration: configuration, | ||
environmentValueProvider: environmentValueProvider) | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// Dispatch+Utils.swift | ||
// LambdaExtras | ||
// | ||
// Created by Mathew Gacy on 1/19/24. | ||
// | ||
|
||
import Dispatch | ||
|
||
extension DispatchWallTime { | ||
/// The interval between the point and its reference point. | ||
var millisecondsSinceEpoch: Int64 { | ||
Int64(bitPattern: self.rawValue) / -1_000_000 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// Logger+Utils.swift | ||
// LambdaExtras | ||
// | ||
// Created by Mathew Gacy on 1/7/24. | ||
// | ||
|
||
import Foundation | ||
import Logging | ||
|
||
public extension Logger { | ||
/// A logger for use in ``MockContext`` and ``MockInitializationContext``. | ||
static let mock = Logger( | ||
label: "mock-logger", | ||
factory: { _ in StreamLogHandler.standardOutput(label: "mock-logger") }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a nit that
E
may be too concise for a "environment variable".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, especially when I have used
EnvironmentVariable
elsewhereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it is
E
onMockContext
as well 🤷♂️There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
MockContext
andMockInitializationContext
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does bring up some confusion on my part around why these types are generic. I realize this relates to code that is already approved/merged, however
Lambda.env(_:)
takes a concreteString
type. Could you clarify the added flexibility?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The basic idea is types > strings
Let's say I define 2 environment variables for my Lambda in my SAM template:
bar
baz
Using
Lambda.env(_:)
the compiler would allow:With this I can do:
While I do offer a
LambdaExtras.DefaultEnvironment
type, in most cases there will be a project-specificEnvironment
type defined in a target using this package that represents the additional variables that are defined in the template or through the AWS console. The generics allow the contexts and other types to support those externally-defined types.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is supported by:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, there are other ways to get around the issues I pointed to above, but more generally, this setup means that instead of:
You can do:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, I'm tracking better now. Thanks!