From a5dc4f93f3f1cc426a9019ef40d4e8bd5a4b9746 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 17 Jul 2024 15:07:16 -0400 Subject: [PATCH] Depend less on precise all-clusters-app endpoints layout in Darwin tests. (#34378) * Depend less on precise all-clusters-app endpoints layout in Darwin tests. * test020_ReadMultipleAttributes and test021_ReadMultipleWildcardPathsIncludeUnsupportedAttribute were assuming three endpoints numbered 0, 1, 2. The fix is to just read the PartsList from the device instead of making assumptions. * test033_TestMTRDeviceDeviceConfigurationChanged was assuming various things about which clusters are on which endpoints, as well as assuming that the PartsList of EP0 is _not_ [1, 2, 3]. Fix things so that we track which endpoint things are actually on, and make sure we take the PartsList from the device and add an entry that's not in it already to it instead of assuming its value. * testDataStorageUpdatesWhenRemovingEndpoints was comparing arrays of endpoints, but some of those arrays come from enumerating dictionary keys. Changing the set of keys can change their order. The fix is to compare sets of endpoints instead. Also, add asserts that the endpoint we are removing (2) is actually in the list, so that if that ever stops being true the test failure will be more understandable. * Apply suggestions from code review Co-authored-by: Kiel Oleson --------- Co-authored-by: Kiel Oleson --- .../Framework/CHIPTests/MTRDeviceTests.m | 145 ++++++++++++------ .../CHIPTests/MTRPerControllerStorageTests.m | 28 ++-- 2 files changed, 112 insertions(+), 61 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index 132ab263cf30f6..da059fc505de8c 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -1898,6 +1898,20 @@ - (void)test020_ReadMultipleAttributes MTRBaseDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); + // Get the list of endpoints from the device. Endpoint 0 we have to add explicitly, since it's + // not in its own PartsList. + XCTestExpectation * descriptorReadExpectation = [self expectationWithDescription:@"read PartsList from endpoint 0"]; + __auto_type * descriptorCluster = [[MTRBaseClusterDescriptor alloc] initWithDevice:device endpointID:@(0) queue:queue]; + __block NSMutableArray * endpointList = [NSMutableArray arrayWithObject:@0]; + [descriptorCluster readAttributePartsListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + XCTAssertNil(error); + XCTAssertNotNil(value); + [endpointList addObjectsFromArray:value]; + [descriptorReadExpectation fulfill]; + }]; + + [self waitForExpectations:@[ descriptorReadExpectation ] timeout:kTimeoutInSeconds]; + NSArray * attributePaths = @[ [MTRAttributeRequestPath requestPathWithEndpointID:nil clusterID:@29 attributeID:@0], [MTRAttributeRequestPath requestPathWithEndpointID:nil clusterID:@29 attributeID:@1], @@ -2028,8 +2042,7 @@ - (void)test020_ReadMultipleAttributes MTRAttributePath * path = result[@"attributePath"]; if ([path.attribute unsignedIntegerValue] < 4) { XCTAssertEqualObjects(path.cluster, @29); - __auto_type endpoint = [path.endpoint unsignedShortValue]; - XCTAssertTrue(endpoint == 0 || endpoint == 1 || endpoint == 2); + XCTAssertTrue([endpointList containsObject:path.endpoint]); } else { XCTAssertEqualObjects(path.cluster, @40); XCTAssertEqualObjects(path.endpoint, @0); @@ -2041,10 +2054,10 @@ - (void)test020_ReadMultipleAttributes XCTFail("Unexpected result dictionary %@", result); } } - // Our test application has 3 endpoints. We have a descriptor on each one, - // so that's 4 results per endpoint, and we only have Basic Information on - // endpoint 0, so that's 4 more results. - XCTAssertEqual(attributeResultCount, 3 * 4 + 4); + // We have a descriptor on each endpoint, so that's 4 results per endpoint, + // and we only have Basic Information on endpoint 0, so that's 4 more + // results. + XCTAssertEqual(attributeResultCount, endpointList.count * 4 + 4); XCTAssertEqual(eventResultCount, [eventPaths count]); [expectation fulfill]; @@ -2061,11 +2074,11 @@ - (void)test021_ReadMultipleWildcardPathsIncludeUnsupportedAttribute // Read the PartList of descriptor on endpoint 0 to find out how many endpoints there are. XCTestExpectation * descriptorReadExpectation = [self expectationWithDescription:@"read PartsList from endpoint 0"]; __auto_type * descriptorCluster = [[MTRBaseClusterDescriptor alloc] initWithDevice:device endpointID:@(0) queue:queue]; - __block size_t endpointCount = 0; + __block NSMutableArray * endpointList = [NSMutableArray arrayWithObject:@0]; [descriptorCluster readAttributePartsListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { XCTAssertNil(error); XCTAssertNotNil(value); - endpointCount = value.count + 1; // Include endpoint 0 + [endpointList addObjectsFromArray:value]; [descriptorReadExpectation fulfill]; }]; @@ -2103,14 +2116,13 @@ - (void)test021_ReadMultipleWildcardPathsIncludeUnsupportedAttribute // and we only have Basic Information on endpoint 0, so that's 4 more // results. Note that there are no results for failAttributeID, because we // used a wildcard path and hence it got ignored. - XCTAssertEqual(resultArray.count, endpointCount * 4 + 4); + XCTAssertEqual(resultArray.count, endpointList.count * 4 + 4); for (NSDictionary * result in resultArray) { MTRAttributePath * path = result[@"attributePath"]; if ([path.attribute unsignedIntegerValue] < 4) { XCTAssertEqualObjects(path.cluster, @29); - __auto_type endpoint = [path.endpoint unsignedShortValue]; - XCTAssertTrue(endpoint == 0 || endpoint == 1 || endpoint == 2); + XCTAssertTrue([endpointList containsObject:path.endpoint]); } else { XCTAssertEqualObjects(path.cluster, @40); XCTAssertEqualObjects(path.endpoint, @0); @@ -3171,7 +3183,7 @@ + (void)checkAttributeReportTriggersConfigurationChanged:(MTRAttributeIDType)att XCTestExpectation * gotAttributeReportExpectation = [testcase expectationWithDescription:@"Attribute report has been received"]; XCTestExpectation * gotAttributeReportEndExpectation = [testcase expectationWithDescription:@"Attribute report has ended"]; - XCTestExpectation * deviceConfigurationChangedExpectation = [testcase expectationWithDescription:@"Device configuration changed was receieved"]; + XCTestExpectation * deviceConfigurationChangedExpectation = [testcase expectationWithDescription:@"Device configuration changed was received"]; deviceConfigurationChangedExpectation.inverted = !expectConfigurationChanged; __block unsigned attributeReportsReceived = 0; @@ -3252,13 +3264,22 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged // attribute list and cluster revision for the Identify cluster, accepted commands list for oven cavity operational state ID cluster and // feature map for groups ID cluster. __block NSNumber * dataVersionForPartsList; + __block NSMutableArray *> * valueForPartsList; + __block NSNumber * endpointForPartsList; __block NSNumber * dataVersionForDeviceTypesList; + __block NSNumber * endpointForDeviceTypeList; __block NSNumber * dataVersionForServerList; + __block NSNumber * endpointForServerList; __block NSNumber * dataVersionForAcceptedCommandList; + __block NSNumber * endpointForAcceptedCommandList; __block NSNumber * dataVersionForAttributeList; + __block NSNumber * endpointForAttributeList; __block NSNumber * dataVersionForClusterRevision; + __block NSNumber * endpointForClusterRevision; __block NSNumber * dataVersionForFeatureMap; + __block NSNumber * endpointForFeatureMap; __block NSNumber * dataVersionForPowerConfigurationSources; + __block NSNumber * endpointForPowerConfigurationSources; delegate.onAttributeDataReceived = ^(NSArray *> * attributeReport) { attributeReportsReceived += attributeReport.count; @@ -3268,20 +3289,24 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged MTRAttributePath * attributePath = attributeDict[MTRAttributePathKey]; XCTAssertNotNil(attributePath); - if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypeDescriptorID) { + if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypeDescriptorID && attributePath.endpoint.unsignedLongValue == 0) { NSDictionary * data = attributeDict[MTRDataKey]; XCTAssertNotNil(data); switch (attributePath.attribute.unsignedLongValue) { case MTRAttributeIDTypeClusterDescriptorAttributePartsListID: { dataVersionForPartsList = data[MTRDataVersionKey]; + valueForPartsList = [data[MTRValueKey] mutableCopy]; + endpointForPartsList = attributePath.endpoint; break; } case MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID: { dataVersionForDeviceTypesList = data[MTRDataVersionKey]; + endpointForDeviceTypeList = attributePath.endpoint; break; } case MTRAttributeIDTypeClusterDescriptorAttributeServerListID: { dataVersionForServerList = data[MTRDataVersionKey]; + endpointForServerList = attributePath.endpoint; break; } } @@ -3291,10 +3316,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged switch (attributePath.attribute.unsignedLongValue) { case MTRAttributeIDTypeGlobalAttributeAttributeListID: { dataVersionForAttributeList = data[MTRDataVersionKey]; + endpointForAttributeList = attributePath.endpoint; break; } case MTRAttributeIDTypeGlobalAttributeClusterRevisionID: { dataVersionForClusterRevision = data[MTRDataVersionKey]; + endpointForClusterRevision = attributePath.endpoint; break; } } @@ -3302,14 +3329,17 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged NSDictionary * data = attributeDict[MTRDataKey]; XCTAssertNotNil(data); dataVersionForAcceptedCommandList = data[MTRDataVersionKey]; + endpointForAcceptedCommandList = attributePath.endpoint; } else if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypeGroupsID && attributePath.attribute.unsignedLongValue == MTRAttributeIDTypeGlobalAttributeFeatureMapID) { NSDictionary * data = attributeDict[MTRDataKey]; XCTAssertNotNil(data); dataVersionForFeatureMap = data[MTRDataVersionKey]; + endpointForFeatureMap = attributePath.endpoint; } else if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypePowerSourceConfigurationID && attributePath.attribute.unsignedLongValue == MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID) { NSDictionary * data = attributeDict[MTRDataKey]; XCTAssertNotNil(data); dataVersionForPowerConfigurationSources = data[MTRDataVersionKey]; + endpointForPowerConfigurationSources = attributePath.endpoint; } } }; @@ -3342,37 +3372,30 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged // Test attribute path - endpointId = 0, clusterId = descriptor, attributeId = parts list. dataVersionForPartsList = [NSNumber numberWithUnsignedLongLong:(dataVersionForPartsList.unsignedLongLongValue + 1)]; - NSArray *> * unsignedIntegerArrayValue = @[ - @{ + // Figure out an endpoint ID (not 0) we can add to PartsList. + for (unsigned i = 1; true; ++i) { + __auto_type unsignedIntegerValue = @{ MTRDataKey : @ { MTRTypeKey : MTRUnsignedIntegerValueType, - MTRValueKey : @1, - } - }, - @{ - MTRDataKey : @ { - MTRTypeKey : MTRUnsignedIntegerValueType, - MTRValueKey : @2, + MTRValueKey : @(i), } - }, - @{ - MTRDataKey : @ { - MTRTypeKey : MTRUnsignedIntegerValueType, - MTRValueKey : @3, - } - }, - ]; + }; + if (![valueForPartsList containsObject:unsignedIntegerValue]) { + [valueForPartsList addObject:unsignedIntegerValue]; + break; + } + } NSArray *> * attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributePartsListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForPartsList clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributePartsListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForPartsList, MTRTypeKey : MTRArrayValueType, - MTRValueKey : unsignedIntegerArrayValue, + MTRValueKey : valueForPartsList, } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributePartsListID clusterId:MTRClusterIDTypeDescriptorID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForPartsList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributePartsListID clusterId:MTRClusterIDTypeDescriptorID endpointId:endpointForPartsList device:device delegate:delegate dataVersion:dataVersionForPartsList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 0, clusterId = descriptor, attributeId = device types list. dataVersionForDeviceTypesList = [NSNumber numberWithUnsignedLongLong:(dataVersionForDeviceTypesList.unsignedLongLongValue + 1)]; @@ -3401,7 +3424,7 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged ]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForDeviceTypeList clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForDeviceTypesList, MTRTypeKey : MTRArrayValueType, @@ -3409,12 +3432,34 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID clusterId:MTRClusterIDTypeDescriptorID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForDeviceTypesList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + // unsignedIntegerArrayValue is used for a variety of tests below. + NSArray *> * unsignedIntegerArrayValue = @[ + @{ + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @1, + } + }, + @{ + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @2, + } + }, + @{ + MTRDataKey : @ { + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @3, + } + }, + ]; + + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID clusterId:MTRClusterIDTypeDescriptorID endpointId:endpointForDeviceTypeList device:device delegate:delegate dataVersion:dataVersionForDeviceTypesList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 0, clusterId = descriptor, attributeId = server list. dataVersionForServerList = [NSNumber numberWithUnsignedLongLong:(dataVersionForServerList.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeServerListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForServerList clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeServerListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForServerList, MTRTypeKey : MTRArrayValueType, @@ -3422,12 +3467,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributeServerListID clusterId:MTRClusterIDTypeDescriptorID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForServerList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterDescriptorAttributeServerListID clusterId:MTRClusterIDTypeDescriptorID endpointId:endpointForServerList device:device delegate:delegate dataVersion:dataVersionForServerList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 1, clusterId = ovencavityoperationalstateID, attributeId = accepted command list. dataVersionForAcceptedCommandList = [NSNumber numberWithUnsignedLongLong:(dataVersionForAcceptedCommandList.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(1) clusterID:@(MTRClusterIDTypeOvenCavityOperationalStateID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForAcceptedCommandList clusterID:@(MTRClusterIDTypeOvenCavityOperationalStateID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForAcceptedCommandList, MTRTypeKey : MTRArrayValueType, @@ -3435,12 +3480,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID clusterId:MTRClusterIDTypeOvenCavityOperationalStateID endpointId:@(1) device:device delegate:delegate dataVersion:dataVersionForAcceptedCommandList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID clusterId:MTRClusterIDTypeOvenCavityOperationalStateID endpointId:endpointForAcceptedCommandList device:device delegate:delegate dataVersion:dataVersionForAcceptedCommandList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 0, clusterId = identify, attributeId = attribute list. dataVersionForAttributeList = [NSNumber numberWithUnsignedLongLong:(dataVersionForAttributeList.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAttributeListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForAttributeList clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAttributeListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForAttributeList, MTRTypeKey : MTRArrayValueType, @@ -3448,12 +3493,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeAttributeListID clusterId:MTRClusterIDTypeIdentifyID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForAttributeList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeAttributeListID clusterId:MTRClusterIDTypeIdentifyID endpointId:endpointForAttributeList device:device delegate:delegate dataVersion:dataVersionForAttributeList attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 0, clusterId = identify, attributeId = cluster revision. dataVersionForClusterRevision = [NSNumber numberWithUnsignedLongLong:(dataVersionForClusterRevision.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeClusterRevisionID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForClusterRevision clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeClusterRevisionID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForClusterRevision, MTRTypeKey : MTRUnsignedIntegerValueType, @@ -3461,12 +3506,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeClusterRevisionID clusterId:MTRClusterIDTypeIdentifyID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForClusterRevision attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeClusterRevisionID clusterId:MTRClusterIDTypeIdentifyID endpointId:endpointForClusterRevision device:device delegate:delegate dataVersion:dataVersionForClusterRevision attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path - endpointId = 0, clusterId = groupsID, attributeId = feature map. dataVersionForFeatureMap = [NSNumber numberWithUnsignedLongLong:(dataVersionForFeatureMap.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeGroupsID) attributeID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForFeatureMap clusterID:@(MTRClusterIDTypeGroupsID) attributeID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForFeatureMap, MTRTypeKey : MTRUnsignedIntegerValueType, @@ -3474,12 +3519,12 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeFeatureMapID clusterId:MTRClusterIDTypeGroupsID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForFeatureMap attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeGlobalAttributeFeatureMapID clusterId:MTRClusterIDTypeGroupsID endpointId:endpointForFeatureMap device:device delegate:delegate dataVersion:dataVersionForFeatureMap attributeReport:attributeReport testcase:self expectConfigurationChanged:YES]; // Test attribute path that doesn't cause a device configuration changed - endpointId = 1, clusterId = power source configuration, attributeId = sources. dataVersionForPowerConfigurationSources = [NSNumber numberWithUnsignedLongLong:(dataVersionForPowerConfigurationSources.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypePowerSourceConfigurationID) attributeID:@(MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForPowerConfigurationSources clusterID:@(MTRClusterIDTypePowerSourceConfigurationID) attributeID:@(MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForPowerConfigurationSources, MTRTypeKey : MTRArrayValueType, @@ -3487,7 +3532,7 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } } ]; - [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID clusterId:MTRClusterIDTypePowerSourceConfigurationID endpointId:@(0) device:device delegate:delegate dataVersion:dataVersionForPowerConfigurationSources attributeReport:attributeReport testcase:self expectConfigurationChanged:NO]; + [MTRDeviceTests checkAttributeReportTriggersConfigurationChanged:MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID clusterId:MTRClusterIDTypePowerSourceConfigurationID endpointId:endpointForPowerConfigurationSources device:device delegate:delegate dataVersion:dataVersionForPowerConfigurationSources attributeReport:attributeReport testcase:self expectConfigurationChanged:NO]; NSArray *> * newUnsignedIntegerArrayValue = @[ @{ @@ -3510,7 +3555,7 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged dataVersionForPowerConfigurationSources = [NSNumber numberWithUnsignedLongLong:(dataVersionForPowerConfigurationSources.unsignedLongLongValue + 1)]; attributeReport = @[ @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAttributeListID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForAttributeList clusterID:@(MTRClusterIDTypeIdentifyID) attributeID:@(MTRAttributeIDTypeGlobalAttributeAttributeListID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForAttributeList, MTRTypeKey : MTRArrayValueType, @@ -3518,7 +3563,7 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } }, @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeGroupsID) attributeID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForFeatureMap clusterID:@(MTRClusterIDTypeGroupsID) attributeID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForFeatureMap, MTRTypeKey : MTRUnsignedIntegerValueType, @@ -3526,7 +3571,7 @@ - (void)test033_TestMTRDeviceDeviceConfigurationChanged } }, @{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypePowerSourceConfigurationID) attributeID:@(MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID)], + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:endpointForPowerConfigurationSources clusterID:@(MTRClusterIDTypePowerSourceConfigurationID) attributeID:@(MTRAttributeIDTypeClusterPowerSourceConfigurationAttributeSourcesID)], MTRDataKey : @ { MTRDataVersionKey : dataVersionForPowerConfigurationSources, MTRTypeKey : MTRArrayValueType, diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m index ced79aadb78b82..4c7375c45dd06b 100644 --- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m @@ -2508,11 +2508,12 @@ - (void)testDataStorageUpdatesWhenRemovingEndpoints __block NSNumber * rootEndpoint = @0; // This test will do the following - - // 1. Get the data version and attribute value of the parts list for endpoint 0 to inject a fake report. The attribute report will delete endpoint 2. + // 1. Get the data version and attribute value of the parts list for endpoint 0 to inject a fake report. + // The injected attribute report will delete endpoint 2. // That should cause the endpoint and its corresponding clusters to be removed from data storage. - // 2. The data store is populated with cluster index and cluster data for endpoints 0, 1 and 2 initially. + // 2. The data store is populated with cluster index and cluster data for the set of endpoints in our test app initially. // 3. After the fake attribute report is injected with deleted endpoint 2, make sure the data store is still populated with cluster index and cluster data - // for endpoints 0 and 1 but not 2. + // for all the other endpoints. __block MTRDeviceDataValueDictionary testDataForPartsList; __block id testClusterDataValueForPartsList; delegate.onAttributeDataReceived = ^(NSArray *> * attributeReport) { @@ -2534,18 +2535,21 @@ - (void)testDataStorageUpdatesWhenRemovingEndpoints }; __block NSMutableDictionary *> * initialClusterIndex = [[NSMutableDictionary alloc] init]; - __block NSMutableArray * testEndpoints; + // Some of the places we get endpoint lists get them from enumerating dictionary keys, which + // means order is not guaranteed. Make sure we compare sets of endpoints, not arrays, to + // account for that. + __block NSSet * testEndpoints; delegate.onReportEnd = ^{ XCTAssertNotNil(dataVersionForPartsList); XCTAssertNotNil(testClusterDataValueForPartsList); - testEndpoints = [self getEndpointArrayFromPartsList:testDataForPartsList forDevice:device]; + testEndpoints = [NSSet setWithArray:[self getEndpointArrayFromPartsList:testDataForPartsList forDevice:device]]; - // Make sure that the cluster data in the data storage is populated with cluster index and cluster data for endpoints 0, 1 and 2. + // Make sure that the cluster data in the data storage is populated with cluster index and cluster data for our endpoints. // We do not need to check _persistedClusterData here. _persistedClusterData will be paged in from storage when needed so // just checking data storage should suffice here. dispatch_sync(self->_storageQueue, ^{ - XCTAssertTrue([[controller.controllerDataStore _fetchEndpointIndexForNodeID:deviceID] isEqualToArray:testEndpoints]); + XCTAssertEqualObjects([NSSet setWithArray:[controller.controllerDataStore _fetchEndpointIndexForNodeID:deviceID]], testEndpoints); // Populate the initialClusterIndex to use as a reference for all cluster paths later. for (NSNumber * endpoint in testEndpoints) { @@ -2568,8 +2572,9 @@ - (void)testDataStorageUpdatesWhenRemovingEndpoints // Inject a fake attribute report deleting endpoint 2 from the parts list at the root endpoint. dataVersionForPartsList = [NSNumber numberWithUnsignedLongLong:(dataVersionForPartsList.unsignedLongLongValue + 1)]; - // Delete endpoint 2 from the attribute value in parts list. + // Delete our to-be-deleted endpoint from the attribute value in parts list. Make sure it's in the list to start with. NSNumber * toBeDeletedEndpoint = @2; + XCTAssertTrue([testEndpoints containsObject:toBeDeletedEndpoint]); id endpointData = @{ MTRDataKey : @ { @@ -2578,6 +2583,7 @@ - (void)testDataStorageUpdatesWhenRemovingEndpoints } }; + XCTAssertTrue([testClusterDataValueForPartsList containsObject:endpointData]); [testClusterDataValueForPartsList removeObject:endpointData]; NSArray *> * attributeReport = @[ @{ @@ -2612,13 +2618,13 @@ - (void)testDataStorageUpdatesWhenRemovingEndpoints delegate.onReportEnd = ^{ XCTAssertNotNil(testClusterDataValueForPartsList); - testEndpoints = [self getEndpointArrayFromPartsList:testDataForPartsList forDevice:device]; + testEndpoints = [NSSet setWithArray:[self getEndpointArrayFromPartsList:testDataForPartsList forDevice:device]]; - // Make sure that the cluster data in the data storage for endpoints 0 and 1 are present but not for endpoint 2. + // Make sure that the cluster data is removed from the data storage for the endpoint we deleted, but still there for the others. // We do not need to check _persistedClusterData here. _persistedClusterData will be paged in from storage when needed so // just checking data storage should suffice here. dispatch_sync(self->_storageQueue, ^{ - XCTAssertTrue([[controller.controllerDataStore _fetchEndpointIndexForNodeID:deviceID] isEqualToArray:testEndpoints]); + XCTAssertEqualObjects([NSSet setWithArray:[controller.controllerDataStore _fetchEndpointIndexForNodeID:deviceID]], testEndpoints); for (NSNumber * endpoint in testEndpoints) { XCTAssertNotNil(initialClusterIndex); for (NSNumber * cluster in [initialClusterIndex objectForKey:endpoint]) {