From d8f14fa4c44796fe1c8b7c8c73cde7df50355772 Mon Sep 17 00:00:00 2001 From: Jeff Tung <100387939+jtung-apple@users.noreply.github.com> Date: Thu, 23 May 2024 16:34:44 -0700 Subject: [PATCH] Fix TSAN issue with test values in unit test --- .../Framework/CHIPTests/MTRDeviceTests.m | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index 8bdfa5c386f9b7..b0254fbde38ad4 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -3668,6 +3668,18 @@ - (void)test035_TestMTRDeviceSubscriptionNotEstablishedOverXPC XCTAssertEqual([device _getInternalState], MTRInternalDeviceStateUnsubscribed); } +- (NSArray *> *)testAttributeReportWithValue:(unsigned int)testValue +{ + return @[ @{ + MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeLevelControlID) attributeID:@(MTRAttributeIDTypeClusterLevelControlAttributeCurrentLevelID)], + MTRDataKey : @ { + MTRDataVersionKey : @(testValue), + MTRTypeKey : MTRUnsignedIntegerValueType, + MTRValueKey : @(testValue), + } + } ]; +} + - (void)test036_TestStorageBehaviorConfiguration { // Use separate queue for timing sensitive test @@ -3719,21 +3731,11 @@ - (void)test036_TestStorageBehaviorConfiguration [device setDelegate:delegate queue:queue]; - // Use a mutable dictionary so the data value can be changed between reports + // Use a mutable dictionary so the data value can be easily changed between reports unsigned int currentTestValue = 1; - NSMutableDictionary * mutableResponseValue = [NSMutableDictionary dictionaryWithDictionary:@{ - MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeLevelControlID) attributeID:@(MTRAttributeIDTypeClusterLevelControlAttributeCurrentLevelID)], - MTRDataKey : @ { - MTRDataVersionKey : @(currentTestValue), - MTRTypeKey : MTRUnsignedIntegerValueType, - MTRValueKey : @(currentTestValue), - } - }]; - - NSArray *> * attributeReport = @[ mutableResponseValue ]; // Test 1: Inject report and see that the attribute persisted, with a delay - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted1 ] timeout:60]; @@ -3759,25 +3761,20 @@ - (void)test036_TestStorageBehaviorConfiguration // Test 2: Inject multiple reports with delay and see that the attribute persisted eventually reportEndTime = nil; dataPersistedTime = nil; - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; double frequentReportMultiplier = 0.5; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; // At this point, the threshold for reportToPersistenceDelayTimeMax should have hit, and persistence // should have happened with timer running down to persist again with the 5th report above. Need to @@ -3819,8 +3816,7 @@ - (void)test036_TestStorageBehaviorConfiguration ]]]; // Inject final report that makes MTRDevice recalculate delay with multiplier - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted3 ] timeout:60]; @@ -3859,15 +3855,13 @@ - (void)test036_TestStorageBehaviorConfiguration ]]]; // Inject report that makes MTRDevice detect the device is reporting excessively - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; // Now keep reporting excessively for base delay time max times max multiplier, plus a bit more NSDate * excessiveStartTime = [NSDate now]; for (;;) { usleep((useconds_t) (baseTestDelayTime * 0.1 * USEC_PER_SEC)); - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; NSTimeInterval elapsed = -[excessiveStartTime timeIntervalSinceNow]; if (elapsed > (baseTestDelayTime * 2 * 5 * 1.2)) { break; @@ -3884,8 +3878,7 @@ - (void)test036_TestStorageBehaviorConfiguration // And inject a report to trigger MTRDevice to recalculate that this device is no longer // reporting excessively - mutableResponseValue[MTRDataKey] = @{ MTRDataVersionKey : @(++currentTestValue), MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @(currentTestValue) }; - [device unitTestInjectAttributeReport:attributeReport fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted4 ] timeout:60];