Skip to content

Commit

Permalink
Fix command path checking in Darwin NSObjectCommandCallback. (#21817)
Browse files Browse the repository at this point in the history
Fixes #21814
  • Loading branch information
bzbarsky-apple authored Aug 11, 2022
1 parent a011b54 commit b9e1e7a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 23 deletions.
8 changes: 7 additions & 1 deletion src/darwin/Framework/CHIP/MTRBaseDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommand
OnErrorCallbackType mOnError;
OnDoneCallbackType mOnDone;
chip::ClusterId mClusterId;
// Id of the command we send.
chip::CommandId mCommandId;
};

Expand All @@ -1051,7 +1052,12 @@ void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommand
//
// Validate that the data response we received matches what we expect in terms of its cluster and command IDs.
//
VerifyOrExit(aCommandPath.mClusterId == mClusterId && aCommandPath.mCommandId == mCommandId, err = CHIP_ERROR_SCHEMA_MISMATCH);
VerifyOrExit(aCommandPath.mClusterId == mClusterId, err = CHIP_ERROR_SCHEMA_MISMATCH);

// If aReader is null, we got a status response and the command id in the
// path should match our command id. If aReader is not null, we got a data
// response, which will have its own command id, which we don't know.
VerifyOrExit(aCommandPath.mCommandId == mCommandId || aReader != nullptr, err = CHIP_ERROR_SCHEMA_MISMATCH);

if (aReader != nullptr) {
err = app::DataModel::Decode(*aReader, response);
Expand Down
103 changes: 81 additions & 22 deletions src/darwin/Framework/CHIPTests/MTRDeviceTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,6 @@ - (void)test007_WriteAttributeFailure
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:kTimeoutInSeconds];
}

#if 0 // Re-enable test if the crash bug in CHIP stack is fixed to handle bad command Id
- (void)test008_InvokeCommandFailure
{
#if MANUAL_INDIVIDUAL_TEST
Expand All @@ -608,34 +607,31 @@ - (void)test008_InvokeCommandFailure
MTRBaseDevice * device = GetConnectedDevice();
dispatch_queue_t queue = dispatch_get_main_queue();

NSDictionary * fields = @ {
@"type" :
@"Structure",
@"value" :
@[
@{ @"contextTag" : @0, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @0 } },
@{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } }
NSDictionary * fields = @{
@"type" : @"Structure",
@"value" : @[
@{ @"contextTag" : @0, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @0 } },
@{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } }
]
};
[device
invokeCommandWithEndpointId:@1
clusterId:@8
commandId:@40000
commandFields:fields
timedInvokeTimeout:nil
clientQueue:queue
completion:^(id _Nullable values, NSError * _Nullable error) {
NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error);

XCTAssertNil(values);
XCTAssertEqual([MTRErrorTestUtils errorToZCLErrorCode:error], EMBER_ZCL_STATUS_UNSUPPORTED_COMMAND);
invokeCommandWithEndpointId:@1
clusterId:@8
commandId:@40000
commandFields:fields
timedInvokeTimeout:nil
clientQueue:queue
completion:^(id _Nullable values, NSError * _Nullable error) {
NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error);

[expectation fulfill];
}];
XCTAssertNil(values);
XCTAssertEqual([MTRErrorTestUtils errorToZCLErrorCode:error], EMBER_ZCL_STATUS_UNSUPPORTED_COMMAND);

[expectation fulfill];
}];

[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:kTimeoutInSeconds];
}
#endif

- (void)test009_SubscribeFailure
{
Expand Down Expand Up @@ -1142,6 +1138,69 @@ - (void)test013_ReuseChipClusterObject
[self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil];
}

- (void)test014_InvokeCommandWithDifferentIdResponse
{
#if MANUAL_INDIVIDUAL_TEST
[self initStack];
[self waitForCommissionee];
#endif
XCTestExpectation * expectation = [self expectationWithDescription:@"invoke Off command"];

MTRBaseDevice * device = GetConnectedDevice();
dispatch_queue_t queue = dispatch_get_main_queue();

NSDictionary * fields = @{
@"type" : @"Structure",
@"value" : @[],
};
// KeySetReadAllIndices in the Group Key Management has id 4 and a data response with id 5
[device
invokeCommandWithEndpointId:@0
clusterId:@(0x003F)
commandId:@4
commandFields:fields
timedInvokeTimeout:nil
clientQueue:queue
completion:^(id _Nullable values, NSError * _Nullable error) {
NSLog(@"invoke command: KeySetReadAllIndices values: %@, error: %@", values, error);

XCTAssertNil(error);

{
XCTAssertTrue([values isKindOfClass:[NSArray class]]);
NSArray * resultArray = values;
for (NSDictionary * result in resultArray) {
MTRCommandPath * path = result[MTRCommandPathKey];
XCTAssertEqual([path.endpoint unsignedIntegerValue], 0);
XCTAssertEqual([path.cluster unsignedIntegerValue], 0x003F);
XCTAssertEqual([path.command unsignedIntegerValue], 5);
// We expect a KeySetReadAllIndicesResponse struct,
// which has context tag 0 pointing to a list with one
// item: 0 (the IPK's keyset id).
NSDictionary * expectedResult = @{
MTRTypeKey : MTRStructureValueType,
MTRValueKey : @[ @{
MTRContextTagKey : @0,
MTRDataKey : @ {
MTRTypeKey : MTRArrayValueType,
MTRValueKey : @[ @{
MTRDataKey : @ { MTRTypeKey : MTRUnsignedIntegerValueType, MTRValueKey : @0 }
} ]
}
} ],
};
XCTAssertEqualObjects(result[MTRDataKey], expectedResult);
XCTAssertNil(result[MTRErrorKey]);
}
XCTAssertEqual([resultArray count], 1);
}

[expectation fulfill];
}];

[self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil];
}

- (void)test900_SubscribeAllAttributes
{
#if MANUAL_INDIVIDUAL_TEST
Expand Down

0 comments on commit b9e1e7a

Please sign in to comment.