diff --git a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift index 4faabb2b..e128e97d 100644 --- a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift +++ b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift @@ -35,9 +35,11 @@ public actor MemoryPersistDriver: PersistDriver where C.Duration == Du public func get(key: String, as: Object.Type) async throws -> Object? { guard let item = self.values[key] else { return nil } - guard let expires = item.expires else { return item.value as? Object } - guard self.clock.now <= expires else { return nil } - return item.value as? Object + if let expires = item.expires { + guard self.clock.now <= expires else { return nil } + } + guard let object = item.value as? Object else { throw PersistError.invalidConversion } + return object } public func remove(key: String) async throws { diff --git a/Sources/Hummingbird/Storage/PersistError.swift b/Sources/Hummingbird/Storage/PersistError.swift index 7731df64..bd488fa9 100644 --- a/Sources/Hummingbird/Storage/PersistError.swift +++ b/Sources/Hummingbird/Storage/PersistError.swift @@ -16,6 +16,7 @@ public struct PersistError: Error, Equatable { private enum Internal { case duplicate + case invalidConversion } private let value: Internal @@ -23,5 +24,8 @@ public struct PersistError: Error, Equatable { self.value = value } + /// Failed to creating a persist entry as it already exists public static var duplicate: Self { .init(value: .duplicate) } + /// Failed to convert a persist value to the requested type + public static var invalidConversion: Self { .init(value: .invalidConversion) } } diff --git a/Tests/HummingbirdTests/PersistTests.swift b/Tests/HummingbirdTests/PersistTests.swift index e84b1cd6..f600233d 100644 --- a/Tests/HummingbirdTests/PersistTests.swift +++ b/Tests/HummingbirdTests/PersistTests.swift @@ -140,10 +140,6 @@ final class PersistTests: XCTestCase { } func testCodable() async throws { - #if os(macOS) - // disable macOS tests in CI. GH Actions are currently running this when they shouldn't - guard Environment().get("CI") != "true" else { throw XCTSkip() } - #endif struct TestCodable: Codable { let buffer: String } @@ -171,6 +167,31 @@ final class PersistTests: XCTestCase { } } + func testInvalidGetAs() async throws { + struct TestCodable: Codable { + let buffer: String + } + let (router, persist) = try createRouter() + router.put("/invalid") { _, _ -> HTTPResponse.Status in + try await persist.set(key: "test", value: TestCodable(buffer: "hello")) + return .ok + } + router.get("/invalid") { _, _ -> String? in + do { + return try await persist.get(key: "test", as: String.self) + } catch let error as PersistError where error == .invalidConversion { + throw HTTPError(.badRequest) + } + } + let app = Application(router: router) + try await app.test(.router) { client in + try await client.execute(uri: "/invalid", method: .put) + try await client.execute(uri: "/invalid", method: .get) { response in + XCTAssertEqual(response.status, .badRequest) + } + } + } + func testRemove() async throws { let (router, _) = try createRouter() let app = Application(responder: router.buildResponder())