Skip to content

Commit

Permalink
[Darwin] Add internal method to get report of all attributes to MTRDe…
Browse files Browse the repository at this point in the history
  • Loading branch information
jtung-apple authored Sep 7, 2024
1 parent d5a3b4f commit b3d527e
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,17 @@ - (NSDictionary *)_dataValueWithoutDataVersion:(NSDictionary *)attributeValue
}
}

- (NSArray<NSDictionary<NSString *, id> *> *)getAllAttributesReport
{
#define MTRDeviceErrorStr "MTRDevice getAllAttributesReport must be handled by subclasses that support it"
MTR_LOG_ERROR(MTRDeviceErrorStr);
#ifdef DEBUG
NSAssert(NO, @MTRDeviceErrorStr);
#endif // DEBUG
#undef MTRDeviceErrorStr
return nil;
}

#ifdef DEBUG
- (NSUInteger)unitTestAttributeCount
{
Expand Down
27 changes: 27 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3092,6 +3092,12 @@ - (void)_performScheduledExpirationCheck
- (NSDictionary<NSString *, id> *)_attributeValueDictionaryForAttributePath:(MTRAttributePath *)attributePath
{
std::lock_guard lock(_lock);
return [self _lockedAttributeValueDictionaryForAttributePath:attributePath];
}

- (NSDictionary<NSString *, id> *)_lockedAttributeValueDictionaryForAttributePath:(MTRAttributePath *)attributePath
{
os_unfair_lock_assert_owner(&self->_lock);

// First check expected value cache
NSArray * expectedValue = _expectedValueCache[attributePath];
Expand Down Expand Up @@ -3478,6 +3484,27 @@ - (NSArray *)_getAttributesToReportWithReportedValues:(NSArray<NSDictionary<NSSt
return attributesToReport;
}

- (NSArray<NSDictionary<NSString *, id> *> *)getAllAttributesReport
{
std::lock_guard lock(_lock);

NSMutableArray * attributeReport = [NSMutableArray array];
for (MTRClusterPath * clusterPath in [self _knownClusters]) {
MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath];

for (NSNumber * attributeID in clusterData.attributes) {
auto * attributePath = [MTRAttributePath attributePathWithEndpointID:clusterPath.endpoint
clusterID:clusterPath.cluster
attributeID:attributeID];

// Using _lockedAttributeValueDictionaryForAttributePath because it takes into consideration expected values too
[attributeReport addObject:[self _lockedAttributeValueDictionaryForAttributePath:attributePath]];
}
}

return attributeReport;
}

#ifdef DEBUG
- (NSUInteger)unitTestAttributeCount
{
Expand Down
3 changes: 3 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ MTR_DIRECT_MEMBERS
- (void)_callFirstDelegateSynchronouslyWithBlock:(void (^)(id<MTRDeviceDelegate> delegate))block;
#endif

// Used to generate attribute report that contains all known attributes, taking into consideration expected values
- (NSArray<NSDictionary<NSString *, id> *> *)getAllAttributesReport;

@end

#pragma mark - MTRDevice internal state monitoring
Expand Down
56 changes: 56 additions & 0 deletions src/darwin/Framework/CHIPTests/MTRDeviceTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -4022,6 +4022,7 @@ - (void)test037_MTRDeviceMultipleDelegatesGetReports
// For unit test no real data is needed, but timestamp is required
};
}

- (void)test038_MTRDeviceMultipleDelegatesInterestedPaths
{
dispatch_queue_t queue = dispatch_get_main_queue();
Expand Down Expand Up @@ -4274,6 +4275,61 @@ - (void)test038_MTRDeviceMultipleDelegatesInterestedPaths
XCTAssertEqual(eventsReceived4, 36);
}

- (void)test039_GetAllAttributesReport
{
dispatch_queue_t queue = dispatch_get_main_queue();

// First start with clean slate by removing the MTRDevice and clearing the persisted cache
__auto_type * device = [MTRDevice deviceWithNodeID:@(kDeviceId) controller:sController];
[sController removeDevice:device];
[sController.controllerDataStore clearAllStoredClusterData];
NSDictionary * storedClusterDataAfterClear = [sController.controllerDataStore getStoredClusterDataForNodeID:@(kDeviceId)];
XCTAssertEqual(storedClusterDataAfterClear.count, 0);

// Now recreate device and get subscription primed
device = [MTRDevice deviceWithNodeID:@(kDeviceId) controller:sController];
XCTestExpectation * gotReportEnd = [self expectationWithDescription:@"Report end for delegate"];

__auto_type * delegate = [[MTRDeviceTestDelegateWithSubscriptionSetupOverride alloc] init];
delegate.skipSetupSubscription = YES;
__weak __auto_type weakdelegate = delegate;
__block NSUInteger attributesReceived = 0;
delegate.onAttributeDataReceived = ^(NSArray<NSDictionary<NSString *, id> *> * data) {
attributesReceived += data.count;
};
delegate.onReportEnd = ^{
[gotReportEnd fulfill];
__strong __auto_type strongDelegate = weakdelegate;
strongDelegate.onReportEnd = nil;
};

[device addDelegate:delegate queue:queue];

// Now inject attributes and check that each delegate gets the right set of attributes
NSMutableArray * attributeReport = [NSMutableArray array];
// Construct 36 attributes with endpoints 1~4, clusters 11 ~ 33, and attributes 111~333
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 3; j++) {
for (int k = 1; k <= 3; k++) {
int endpointID = i;
int clusterID = i * 10 + j;
int attributeID = i * 100 + j * 10 + k;
int value = attributeID + 10000;
[attributeReport addObject:[self _testAttributeResponseValueWithEndpointID:@(endpointID) clusterID:@(clusterID) attributeID:@(attributeID) value:value]];
}
}
}
[device unitTestInjectAttributeReport:attributeReport fromSubscription:YES];

[self waitForExpectations:@[ gotReportEnd ] timeout:60];

XCTAssertEqual(attributesReceived, 36);

NSArray * allAttributesReport = [device getAllAttributesReport];

XCTAssertEqual(allAttributesReport.count, 36);
}

@end

@interface MTRDeviceEncoderTests : XCTestCase
Expand Down

0 comments on commit b3d527e

Please sign in to comment.