From 229579336c53d2fa7158dce51b71c642bce4ad4f Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Oct 2023 13:37:30 -0400 Subject: [PATCH] Add Swift versions of a few more MTRDevice tests. (#29914) --- .../CHIPTests/MTRSwiftDeviceTests.swift | 153 +++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift b/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift index 5d963fb51176fd..b800588e55cd03 100644 --- a/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift +++ b/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift @@ -7,8 +7,8 @@ struct DeviceConstants { static let testVendorID = 0xFFF1 static let onboardingPayload = "MT:-24J0AFN00KA0648G00" static let deviceID = 0x12344321 - static let timeoutInSeconds : UInt16 = 3 - static let pairingTimeoutInSeconds : UInt16 = 10 + static let timeoutInSeconds : Double = 3 + static let pairingTimeoutInSeconds : Double = 10 } var sConnectedDevice: MTRBaseDevice? = nil @@ -191,7 +191,7 @@ class MTRSwiftDeviceTests : XCTestCase { XCTFail("Could not start setting up PASE session: \(error)") return } - wait(for: [expectation], timeout: TimeInterval(DeviceConstants.pairingTimeoutInSeconds)) + wait(for: [expectation], timeout: DeviceConstants.pairingTimeoutInSeconds) } static func shutdownStack() @@ -396,12 +396,157 @@ class MTRSwiftDeviceTests : XCTestCase { XCTAssertEqual(eventReportsReceived, 0); } + func test018_SubscriptionErrorWhenNotResubscribing() + { + let device = sConnectedDevice! + let queue = DispatchQueue.main + + let firstSubscribeExpectation = expectation(description: "First subscription complete") + let errorExpectation = expectation(description: "First subscription errored out") + + // Subscribe + let params = MTRSubscribeParams(minInterval: 1, maxInterval: 10) + params.shouldResubscribeAutomatically = false + params.shouldReplaceExistingSubscriptions = true // Not strictly needed, but checking that doing this does not + // affect this subscription erroring out correctly. + var subscriptionEstablished = false + device.subscribeToAttributes(withEndpointID: 1, + clusterID: 6, + attributeID: 0, + params: params, + queue: queue, + reportHandler: { values, error in + if (subscriptionEstablished) { + // We should only get an error here. + XCTAssertNil(values) + XCTAssertNotNil(error) + errorExpectation.fulfill() + } else { + XCTAssertNotNil(values) + XCTAssertNil(error) + } + }, + subscriptionEstablished: { + NSLog("subscribe attribute: OnOff established") + XCTAssertFalse(subscriptionEstablished) + subscriptionEstablished = true + firstSubscribeExpectation.fulfill() + }) + + // Wait till establishment + wait(for: [ firstSubscribeExpectation ], timeout: DeviceConstants.timeoutInSeconds) + + // Create second subscription which will cancel the first subscription. We + // can use a non-existent path here to cut down on the work that gets done. + params.shouldReplaceExistingSubscriptions = true + + device.subscribeToAttributes(withEndpointID: 10000, + clusterID: 6, + attributeID: 0, + params: params, + queue: queue, + reportHandler: { _, _ in + }) + wait(for: [ errorExpectation ], timeout: 60) + } + + func test019_MTRDeviceMultipleCommands() async + { + let device = MTRDevice(nodeID: DeviceConstants.deviceID as NSNumber, controller:sController!) + let queue = DispatchQueue.main + + let opcredsCluster = MTRClusterOperationalCredentials(device: device, endpointID: 0, queue: queue)! + let onOffCluster = MTRClusterOnOff(device: device, endpointID: 1, queue: queue)! + let badOnOffCluster = MTRClusterOnOff(device: device, endpointID: 0, queue: queue)! + + // Ensure our existing fabric label is not "Test". This uses a "base" + // cluster to ensure read-through to the other side. + let baseOpCredsCluster = MTRBaseClusterOperationalCredentials(device: sConnectedDevice!, endpointID: 0, queue: queue)! + var fabricList = try! await baseOpCredsCluster.readAttributeFabrics(with: nil) + XCTAssertEqual(fabricList.count, 1) + var entry = fabricList[0] as! MTROperationalCredentialsClusterFabricDescriptorStruct + XCTAssertNotEqual(entry.label, "Test") + + let currentFabricIndex = try! await baseOpCredsCluster.readAttributeCurrentFabricIndex() + + // NOTE: The command invocations do not use "await", because we actually want + // to do them all sort of in parallel, or at least queue them all on the MTRDevice + // before we get a chance to finish the first one. + let onExpectation = expectation(description: "On command executed") + onOffCluster.on(withExpectedValues: nil, expectedValueInterval: nil) { error in + XCTAssertNil(error) + onExpectation.fulfill() + } + + let offFailedExpectation = expectation(description: "Off command failed") + badOnOffCluster.off(withExpectedValues: nil, expectedValueInterval: nil) { error in + XCTAssertNotNil(error) + offFailedExpectation.fulfill() + } + + let updateLabelExpectation = expectation(description: "Fabric label updated") + let params = MTROperationalCredentialsClusterUpdateFabricLabelParams() + params.label = "Test" + opcredsCluster.updateFabricLabel(with: params, expectedValues: nil, expectedValueInterval: nil) { data, error in + XCTAssertNil(error) + XCTAssertNotNil(data) + XCTAssertEqual(data?.statusCode, 0) + XCTAssertEqual(data?.fabricIndex, currentFabricIndex) + updateLabelExpectation.fulfill() + } + + let offExpectation = expectation(description: "Off command executed") + // Send this one via MTRDevice, to test that codepath + device.invokeCommand(withEndpointID: 1, + clusterID: NSNumber(value: MTRClusterIDType.onOffID.rawValue), + commandID: NSNumber(value: MTRCommandIDType.clusterOnOffCommandOffID.rawValue), + commandFields: nil, + expectedValues: nil, + expectedValueInterval: nil, + queue: queue) { data, error in + XCTAssertNil(error) + offExpectation.fulfill() + } + + let onFailedExpectation = expectation(description: "On command failed") + badOnOffCluster.on(withExpectedValues: nil, expectedValueInterval: nil) { error in + XCTAssertNotNil(error) + onFailedExpectation.fulfill() + } + + let updateLabelFailedExpectation = expectation(description: "Fabric label update failed") + params.label = "12345678901234567890123445678901234567890" // Too long + opcredsCluster.updateFabricLabel(with: params, + expectedValues: nil, + expectedValueInterval: nil) { data, error in + XCTAssertNotNil(error) + XCTAssertNil(data) + updateLabelFailedExpectation.fulfill() + } + + wait(for: [ onExpectation, + offFailedExpectation, + updateLabelExpectation, + offExpectation, + onFailedExpectation, + updateLabelFailedExpectation ], + timeout: 60, + enforceOrder: true) + + // Now make sure our fabric label got updated. + fabricList = try! await baseOpCredsCluster.readAttributeFabrics(with: nil) + XCTAssertNotNil(fabricList) + XCTAssertEqual(fabricList.count, 1) + entry = fabricList[0] as! MTROperationalCredentialsClusterFabricDescriptorStruct + XCTAssertEqual(entry.label, "Test") + } + // Note: test027_AttestationChallenge is not implementable in Swift so far, // because the attestationChallenge property is internal-only func test999_TearDown() { - ResetCommissionee(sConnectedDevice, DispatchQueue.main, self, DeviceConstants.timeoutInSeconds) + ResetCommissionee(sConnectedDevice, DispatchQueue.main, self, UInt16(DeviceConstants.timeoutInSeconds)) type(of: self).shutdownStack() } }