feat: Renaming and moves some items around, listeners now manage reconnection events.
All checks were successful
CI / Run Tests (push) Successful in 4m16s

This commit is contained in:
2024-11-15 17:15:01 -05:00
parent 947472f62d
commit c84427a9b3
14 changed files with 649 additions and 725 deletions

View File

@@ -1,12 +1,11 @@
import Dependencies
import Logging
import Models
@_spi(Internal) import MQTTConnectionManager
@_spi(Internal) import MQTTManager
import MQTTNIO
import NIO
import PsychrometricClientLive
@_spi(Internal) import SensorsService
import TopicDependencies
import XCTest
final class SensorsClientTests: XCTestCase {
@@ -23,25 +22,24 @@ final class SensorsClientTests: XCTestCase {
let client = createClient(identifier: "\(Self.self)")
withDependencies {
$0.mqttConnectionManager = .live(client: client, logger: Self.logger)
$0.mqtt = .live(client: client, logger: Self.logger)
$0.psychrometricClient = PsychrometricClient.liveValue
$0.topicListener = .live(client: client)
$0.topicPublisher = .live(client: client)
} operation: {
super.invokeTest()
}
}
func testListeningResumesAfterDisconnectThenReconnect() async throws {
@Dependency(\.mqttConnectionManager) var manager
struct TimeoutError: Error {}
let sensor = TemperatureAndHumiditySensor(location: .return)
var results = [TopicPublisher.PublishRequest]()
let results = ResultContainer()
try await withDependencies {
$0.topicPublisher = .capturing { results.append($0) }
$0.mqtt.publish = results.append
} operation: {
@Dependency(\.mqtt) var manager
let sensorsService = SensorsService(sensors: [sensor], logger: Self.logger)
let task = Task { try await sensorsService.run() }
defer { task.cancel() }
@@ -58,9 +56,7 @@ final class SensorsClientTests: XCTestCase {
}
// Give time to re-subscribe.
while !(await sensorsService.isListening) {
try await Task.sleep(for: .milliseconds(100))
}
try await Task.sleep(for: .milliseconds(200))
try await client.publish(
to: sensor.topics.temperature,
@@ -77,7 +73,7 @@ final class SensorsClientTests: XCTestCase {
}
var timeoutCount = 0
while !(results.count == 2) {
while !(await results.count == 2) {
guard timeoutCount < 20 else {
throw TimeoutError()
}
@@ -85,6 +81,8 @@ final class SensorsClientTests: XCTestCase {
timeoutCount += 1
}
let results = await results.results()
XCTAssertEqual(results.count, 2)
XCTAssert(results.contains(where: { $0.topicName == sensor.topics.dewPoint }))
XCTAssert(results.contains(where: { $0.topicName == sensor.topics.enthalpy }))
@@ -122,63 +120,23 @@ final class SensorsClientTests: XCTestCase {
// MARK: Helpers for tests.
class PublishInfoContainer {
private(set) var info: [MQTTPublishInfo]
private var topicFilters: [String]?
init(topicFilters: [String]? = nil) {
self.info = []
self.topicFilters = topicFilters
}
func addPublishInfo(_ info: MQTTPublishInfo) async {
guard let topicFilters else {
self.info.append(info)
return
}
if topicFilters.contains(info.topicName) {
self.info.append(info)
}
}
}
extension TopicPublisher {
static func capturing(
_ callback: @escaping (PublishRequest) -> Void
) -> Self {
.init { callback($0) }
}
}
// extension SensorsClient {
//
// static func testing(
// yielding: [(value: Double, to: String)],
// capturePublishedValues: @escaping (Double, String) -> Void,
// captureShutdownEvent: @escaping (Bool) -> Void
// ) -> Self {
// let (stream, continuation) = AsyncStream.makeStream(of: PublishInfo.self)
// let logger = Logger(label: "\(Self.self).testing")
//
// return .init(
// listen: { topics in
// for (value, topic) in yielding where topics.contains(topic) {
// continuation.yield(
// (buffer: ByteBuffer(string: "\(value)"), topic: topic)
// )
// }
// return stream
// },
// logger: logger,
// publish: { value, topic in
// capturePublishedValues(value, topic)
// },
// shutdown: {
// captureShutdownEvent(true)
// continuation.finish()
// }
// )
// }
// }
struct TopicNotFoundError: Error {}
actor ResultContainer: Sendable {
private var storage = [MQTTManager.PublishRequest]()
init() {}
@Sendable func append(_ result: MQTTManager.PublishRequest) async {
storage.append(result)
}
var count: Int {
get async { storage.count }
}
func results() async -> [MQTTManager.PublishRequest] {
storage
}
}