diff --git a/.gitignore b/.gitignore index acb159a..bb9d983 100755 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ DerivedData/ mqtt_password.txt .env .smbdelete* +buildServer.json +.nvim/* diff --git a/.swiftpm/dewpoint-controller-Package.xctestplan b/.swiftpm/dewpoint-controller-Package.xctestplan new file mode 100644 index 0000000..5e8bdf3 --- /dev/null +++ b/.swiftpm/dewpoint-controller-Package.xctestplan @@ -0,0 +1,35 @@ +{ + "configurations" : [ + { + "id" : "AFB1047B-4742-43D2-AFB9-680C1CB2D273", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "targetForVariableExpansion" : { + "containerPath" : "container:", + "identifier" : "dewpoint-controller", + "name" : "dewpoint-controller" + } + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "MQTTConnectionServiceTests", + "name" : "MQTTConnectionServiceTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "SensorsServiceTests", + "name" : "SensorsServiceTests" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/DewPointEnvironment.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/DewPointEnvironment.xcscheme deleted file mode 100755 index 1a3b0b2..0000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/DewPointEnvironment.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/EnvVars.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/EnvVars.xcscheme deleted file mode 100755 index 1983919..0000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/EnvVars.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ClientLive.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/MQTTConnectionService.xcscheme old mode 100755 new mode 100644 similarity index 77% rename from .swiftpm/xcode/xcshareddata/xcschemes/ClientLive.xcscheme rename to .swiftpm/xcode/xcshareddata/xcschemes/MQTTConnectionService.xcscheme index 3327fe3..45f5e1a --- a/.swiftpm/xcode/xcshareddata/xcschemes/ClientLive.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/MQTTConnectionService.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1610" + version = "1.7"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> @@ -26,9 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Bootstrap.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/MQTTManager.xcscheme old mode 100755 new mode 100644 similarity index 79% rename from .swiftpm/xcode/xcshareddata/xcschemes/Bootstrap.xcscheme rename to .swiftpm/xcode/xcshareddata/xcschemes/MQTTManager.xcscheme index fc5f894..a9416cb --- a/.swiftpm/xcode/xcshareddata/xcschemes/Bootstrap.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/MQTTManager.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1610" + version = "1.7"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> @@ -26,9 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Client.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SensorsService.xcscheme old mode 100755 new mode 100644 similarity index 78% rename from .swiftpm/xcode/xcshareddata/xcschemes/Client.xcscheme rename to .swiftpm/xcode/xcshareddata/xcschemes/SensorsService.xcscheme index 543cd43..f4e1101 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Client.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SensorsService.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1610" + version = "1.7"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> @@ -26,9 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller-Package.xcscheme old mode 100755 new mode 100644 index 8f82c6f..62a0843 --- a/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller-Package.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1610" + version = "1.7"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> @@ -28,51 +29,9 @@ buildForAnalyzing = "YES"> - - - - - - - - - - - - @@ -90,62 +49,6 @@ ReferencedContainer = "container:"> - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - @@ -239,9 +142,9 @@ diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller.xcscheme old mode 100755 new mode 100644 index 7e9546e..2ccaeb1 --- a/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/dewPoint-controller.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1610" + version = "1.7"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> - - - - - - - - @@ -54,29 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - - - - - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> @@ -109,9 +61,9 @@ runnableDebuggingMode = "0"> diff --git a/Makefile b/Makefile index 3ff79d4..9ec2468 100755 --- a/Makefile +++ b/Makefile @@ -20,3 +20,10 @@ test-docker: @docker compose --file docker/docker-compose-test.yaml \ run --build --remove-orphans -i --rm test @docker compose --file docker/docker-compose-test.yaml down + +start-mosquitto: + @docker compose --file docker/docker-compose.yaml \ + up -d mosquitto + +test-swift: start-mosquitto + @swift test --enable-code-coverage diff --git a/Package.swift b/Package.swift index 92bb0a8..86e17da 100755 --- a/Package.swift +++ b/Package.swift @@ -73,6 +73,7 @@ let package = Package( dependencies: [ "MQTTConnectionService", "MQTTManager", + .product(name: "PsychrometricClientLive", package: "swift-psychrometrics"), .product(name: "ServiceLifecycleTestKit", package: "swift-service-lifecycle") ] ), @@ -84,6 +85,7 @@ let package = Package( .product(name: "Dependencies", package: "swift-dependencies"), .product(name: "DependenciesMacros", package: "swift-dependencies"), .product(name: "MQTTNIO", package: "mqtt-nio"), + .product(name: "PsychrometricClient", package: "swift-psychrometrics"), .product(name: "ServiceLifecycle", package: "swift-service-lifecycle") ], swiftSettings: swiftSettings diff --git a/Sources/MQTTConnectionService/MQTTConnectionService.swift b/Sources/MQTTConnectionService/MQTTConnectionService.swift index 438316c..fd5e85f 100644 --- a/Sources/MQTTConnectionService/MQTTConnectionService.swift +++ b/Sources/MQTTConnectionService/MQTTConnectionService.swift @@ -19,19 +19,22 @@ public struct MQTTConnectionService: Service { /// to the MQTT broker and handles graceful shutdown of the /// connection. public func run() async throws { + try await mqtt.connect() + try await withGracefulShutdownHandler { - try await mqtt.connect() for await event in try mqtt.connectionStream().cancelOnGracefulShutdown() { // We don't really need to do anything with the events, so just logging // for now. But we need to iterate on an async stream for the service to // continue to run and handle graceful shutdowns. logger?.trace("Received connection event: \(event)") } - // when we reach here we are shutting down, so we shutdown - // the manager. - mqtt.shutdown() } onGracefulShutdown: { self.logger?.trace("Received graceful shutdown.") + shutdown() } } + + public func shutdown() { + mqtt.shutdown() + } } diff --git a/Sources/MQTTManager/Interface.swift b/Sources/MQTTManager/Interface.swift index 2307aa1..c618782 100644 --- a/Sources/MQTTManager/Interface.swift +++ b/Sources/MQTTManager/Interface.swift @@ -183,6 +183,7 @@ public extension MQTTManager { ) }, shutdown: { + Task { try await client.shutdown() } manager.shutdown() }, _withClient: { callback in diff --git a/Tests/MQTTConnectionServiceTests/MQTTConnectionServiceTests.swift b/Tests/MQTTConnectionServiceTests/MQTTConnectionServiceTests.swift index bcd9651..8940623 100644 --- a/Tests/MQTTConnectionServiceTests/MQTTConnectionServiceTests.swift +++ b/Tests/MQTTConnectionServiceTests/MQTTConnectionServiceTests.swift @@ -1,24 +1,60 @@ -import AsyncAlgorithms +import Dependencies import Logging import Models import MQTTConnectionService @_spi(Internal) import MQTTManager import MQTTNIO import NIO +import PsychrometricClientLive import ServiceLifecycle import ServiceLifecycleTestKit import XCTest +// TODO: Rename to integration test when other tests are moved. final class MQTTConnectionServiceTests: XCTestCase { static let hostname = ProcessInfo.processInfo.environment["MOSQUITTO_SERVER"] ?? "localhost" static let logger: Logger = { var logger = Logger(label: "MQTTConnectionServiceTests") - logger.logLevel = .trace + logger.logLevel = .info return logger }() + override func invokeTest() { + let client = createClient(identifier: "\(Self.self)") + + withDependencies { + $0.mqtt = .live(client: client, logger: Self.logger) + $0.psychrometricClient = PsychrometricClient.liveValue + } operation: { + super.invokeTest() + } + } + + func testConnectionServiceShutdown() async throws { + @Dependency(\.mqtt) var mqtt + + let service = MQTTConnectionService(logger: Self.logger) + let task = Task { try await service.run() } + defer { task.cancel() } + + try await Task.sleep(for: .milliseconds(200)) + + // check the connection is active here. + try await mqtt.withClient { client in + XCTAssert(client.isActive()) + } + service.shutdown() + + try await Task.sleep(for: .milliseconds(500)) + + // check the connection is active here. + try await mqtt.withClient { client in + XCTAssertFalse(client.isActive()) + } + } + // TODO: Move to integration tests. func testMQTTConnectionStream() async throws { let client = createClient(identifier: "testNonManagedStream") @@ -43,11 +79,10 @@ final class MQTTConnectionServiceTests: XCTestCase { try await Task.sleep(for: .milliseconds(100)) } try await Task.sleep(for: .milliseconds(200)) - manager.shutdown() try await client.disconnect() - try await Task.sleep(for: .seconds(1)) - try await client.shutdown() - try await Task.sleep(for: .seconds(1)) + try await Task.sleep(for: .milliseconds(500)) + manager.shutdown() + try await Task.sleep(for: .milliseconds(500)) connectionStream1.stop() connectionStream2.stop() }