diff --git a/examples/chip-tool/commands/tests/Commands.h b/examples/chip-tool/commands/tests/Commands.h index 7777b51603124f..cf0ad3fe79a522 100644 --- a/examples/chip-tool/commands/tests/Commands.h +++ b/examples/chip-tool/commands/tests/Commands.h @@ -19410,6 +19410,185 @@ class Test_TC_OCC_1_1 : public TestCommand } }; +class OperationalCredentialsCluster : public TestCommand +{ +public: + OperationalCredentialsCluster() : TestCommand("OperationalCredentialsCluster"), mTestIndex(0) {} + + /////////// TestCommand Interface ///////// + void NextTest() override + { + CHIP_ERROR err = CHIP_NO_ERROR; + + if (mTestCount == mTestIndex) + { + ChipLogProgress(chipTool, "OperationalCredentialsCluster: Test complete"); + SetCommandExitStatus(CHIP_NO_ERROR); + } + + // Ensure we increment mTestIndex before we start running the relevant + // command. That way if we lose the timeslice after we send the message + // but before our function call returns, we won't end up with an + // incorrect mTestIndex value observed when we get the response. + switch (mTestIndex++) + { + case 0: + err = TestSendClusterOperationalCredentialsCommandReadAttribute_0(); + break; + case 1: + err = TestSendClusterOperationalCredentialsCommandReadAttribute_1(); + break; + } + + if (CHIP_NO_ERROR != err) + { + ChipLogProgress(chipTool, "OperationalCredentialsCluster: %s", chip::ErrorStr(err)); + SetCommandExitStatus(err); + } + } + +private: + std::atomic_uint16_t mTestIndex; + const uint16_t mTestCount = 2; + + // + // Tests methods + // + + // Test Read number of supported fabrics + using SuccessCallback_0 = void (*)(void * context, uint8_t supportedFabrics); + chip::Callback::Callback mOnSuccessCallback_0{ + OnTestSendClusterOperationalCredentialsCommandReadAttribute_0_SuccessResponse, this + }; + chip::Callback::Callback mOnFailureCallback_0{ + OnTestSendClusterOperationalCredentialsCommandReadAttribute_0_FailureResponse, this + }; + bool mIsFailureExpected_0 = 0; + + CHIP_ERROR TestSendClusterOperationalCredentialsCommandReadAttribute_0() + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of supported fabrics: Sending command..."); + + chip::Controller::OperationalCredentialsCluster cluster; + cluster.Associate(mDevice, 0); + + CHIP_ERROR err = CHIP_NO_ERROR; + + err = cluster.ReadAttributeSupportedFabrics(mOnSuccessCallback_0.Cancel(), mOnFailureCallback_0.Cancel()); + + return err; + } + + static void OnTestSendClusterOperationalCredentialsCommandReadAttribute_0_FailureResponse(void * context, uint8_t status) + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of supported fabrics: Failure Response"); + + OperationalCredentialsCluster * runner = reinterpret_cast(context); + + if (runner->mIsFailureExpected_0 == false) + { + ChipLogError(chipTool, "Error: The test was expecting a success callback. Got failure callback"); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + runner->NextTest(); + } + + static void OnTestSendClusterOperationalCredentialsCommandReadAttribute_0_SuccessResponse(void * context, + uint8_t supportedFabrics) + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of supported fabrics: Success Response"); + + OperationalCredentialsCluster * runner = reinterpret_cast(context); + + if (runner->mIsFailureExpected_0 == true) + { + ChipLogError(chipTool, "Error: The test was expecting a failure callback. Got success callback"); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + ChipLogError(chipTool, "Warning: supportedFabrics type checking is not implemented yet. Expected type: '%s'", "uint8"); + + if (supportedFabrics < 4) + { + ChipLogError(chipTool, "Error: supportedFabrics is lower than expected. Min value is 4 but got '%d'", supportedFabrics); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + runner->NextTest(); + } + + // Test Read number of commissioned fabrics + using SuccessCallback_1 = void (*)(void * context, uint8_t commissionedFabrics); + chip::Callback::Callback mOnSuccessCallback_1{ + OnTestSendClusterOperationalCredentialsCommandReadAttribute_1_SuccessResponse, this + }; + chip::Callback::Callback mOnFailureCallback_1{ + OnTestSendClusterOperationalCredentialsCommandReadAttribute_1_FailureResponse, this + }; + bool mIsFailureExpected_1 = 0; + + CHIP_ERROR TestSendClusterOperationalCredentialsCommandReadAttribute_1() + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of commissioned fabrics: Sending command..."); + + chip::Controller::OperationalCredentialsCluster cluster; + cluster.Associate(mDevice, 0); + + CHIP_ERROR err = CHIP_NO_ERROR; + + err = cluster.ReadAttributeCommissionedFabrics(mOnSuccessCallback_1.Cancel(), mOnFailureCallback_1.Cancel()); + + return err; + } + + static void OnTestSendClusterOperationalCredentialsCommandReadAttribute_1_FailureResponse(void * context, uint8_t status) + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of commissioned fabrics: Failure Response"); + + OperationalCredentialsCluster * runner = reinterpret_cast(context); + + if (runner->mIsFailureExpected_1 == false) + { + ChipLogError(chipTool, "Error: The test was expecting a success callback. Got failure callback"); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + runner->NextTest(); + } + + static void OnTestSendClusterOperationalCredentialsCommandReadAttribute_1_SuccessResponse(void * context, + uint8_t commissionedFabrics) + { + ChipLogProgress(chipTool, "Operational Credentials - Read number of commissioned fabrics: Success Response"); + + OperationalCredentialsCluster * runner = reinterpret_cast(context); + + if (runner->mIsFailureExpected_1 == true) + { + ChipLogError(chipTool, "Error: The test was expecting a failure callback. Got success callback"); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + ChipLogError(chipTool, "Warning: commissionedFabrics type checking is not implemented yet. Expected type: '%s'", "uint8"); + + if (commissionedFabrics < 1) + { + ChipLogError(chipTool, "Error: commissionedFabrics is lower than expected. Min value is 1 but got '%d'", + commissionedFabrics); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + + runner->NextTest(); + } +}; + void registerCommandsTests(Commands & commands) { const char * clusterName = "Tests"; @@ -19443,6 +19622,7 @@ void registerCommandsTests(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), }; commands.Register(clusterName, clusterCommands); diff --git a/examples/chip-tool/templates/partials/test_cluster.zapt b/examples/chip-tool/templates/partials/test_cluster.zapt index d9fe9e4716788f..b9f5b179395d05 100644 --- a/examples/chip-tool/templates/partials/test_cluster.zapt +++ b/examples/chip-tool/templates/partials/test_cluster.zapt @@ -171,6 +171,24 @@ class {{filename}}: public TestCommand return; } {{/if}} + + {{#if expectedConstraints.minValue}} + if ({{asLowerCamelCase name}} < {{expectedConstraints.minValue}}) + { + ChipLogError(chipTool, "Error: {{asLowerCamelCase name}} is lower than expected. Min value is {{expectedConstraints.minValue}} but got '%d'", {{asLowerCamelCase name}}); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + {{/if}} + + {{#if expectedConstraints.maxValue}} + if ({{asLowerCamelCase name}} > {{expectedConstraints.maxValue}}) + { + ChipLogError(chipTool, "Error: {{asLowerCamelCase name}} is higher than expected. Max value is {{expectedConstraints.maxValue}} but got '%d'", {{asLowerCamelCase name}}); + runner->SetCommandExitStatus(CHIP_ERROR_INTERNAL); + return; + } + {{/if}} {{/if}} {{/chip_tests_item_response_parameters}} diff --git a/examples/chip-tool/templates/tests-commands.zapt b/examples/chip-tool/templates/tests-commands.zapt index 36dc970186f6b3..2dfc513a179142 100644 --- a/examples/chip-tool/templates/tests-commands.zapt +++ b/examples/chip-tool/templates/tests-commands.zapt @@ -4,4 +4,4 @@ #include "TestCommand.h" -{{>test_cluster tests="TV_TargetNavigatorCluster, TV_AudioOutputCluster, TV_ApplicationLauncherCluster, TV_KeypadInputCluster, TV_AccountLoginCluster, TV_WakeOnLanCluster, TV_ApplicationBasicCluster, TV_MediaPlaybackCluster, TV_TvChannelCluster, TV_LowPowerCluster, TV_MediaInputCluster, TestCluster, Test_TC_OO_1_1, Test_TC_OO_2_1, Test_TC_OO_2_2, Test_TC_DM_1_1, Test_TC_DM_3_1, Test_TC_CC_3_4, Test_TC_CC_5, Test_TC_CC_6, Test_TC_CC_7, Test_TC_CC_8, Test_TC_WNCV_1_1, Test_TC_WNCV_2_1, Test_TC_BI_1_1, Test_TC_FLW_1_1, Test_TC_TM_1_1, Test_TC_OCC_1_1"}} +{{>test_cluster tests="TV_TargetNavigatorCluster, TV_AudioOutputCluster, TV_ApplicationLauncherCluster, TV_KeypadInputCluster, TV_AccountLoginCluster, TV_WakeOnLanCluster, TV_ApplicationBasicCluster, TV_MediaPlaybackCluster, TV_TvChannelCluster, TV_LowPowerCluster, TV_MediaInputCluster, TestCluster, Test_TC_OO_1_1, Test_TC_OO_2_1, Test_TC_OO_2_2, Test_TC_DM_1_1, Test_TC_DM_3_1, Test_TC_CC_3_4, Test_TC_CC_5, Test_TC_CC_6, Test_TC_CC_7, Test_TC_CC_8, Test_TC_WNCV_1_1, Test_TC_WNCV_2_1, Test_TC_BI_1_1, Test_TC_FLW_1_1, Test_TC_TM_1_1, Test_TC_OCC_1_1, OperationalCredentialsCluster"}} diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index 0eca4fb8032505..c344e46c8802db 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -122,7 +122,7 @@ CHIP_ERROR writeFabricsIntoFabricsListAttribute() const uint8_t * fabricLabel = pairing.GetFabricLabel(); // Skip over uninitialized fabrics - if (nodeId == kUndefinedNodeId || fabricId == kUndefinedFabricId || vendorId == kUndefinedVendorId) + if (nodeId == kUndefinedNodeId) { emberAfPrintln(EMBER_AF_PRINT_DEBUG, "OpCreds: Skipping over uninitialized fabric with fabricId 0x" ChipLogFormatX64 @@ -158,6 +158,15 @@ CHIP_ERROR writeFabricsIntoFabricsListAttribute() err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; } + if (err == CHIP_NO_ERROR && + app::Clusters::OperationalCredentials::Attributes::SetSupportedFabrics(0, CHIP_CONFIG_MAX_DEVICE_ADMINS) != + EMBER_ZCL_STATUS_SUCCESS) + { + emberAfPrintln(EMBER_AF_PRINT_DEBUG, "OpCreds: Failed to write %" PRIu8 " in supported fabrics count attribute", + CHIP_CONFIG_MAX_DEVICE_ADMINS); + err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + return err; } diff --git a/src/app/tests/suites/OperationalCredentialsCluster.yaml b/src/app/tests/suites/OperationalCredentialsCluster.yaml new file mode 100644 index 00000000000000..a2fbd460c5bd13 --- /dev/null +++ b/src/app/tests/suites/OperationalCredentialsCluster.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Operational Credentials Cluster Tests + +config: + cluster: "Operational Credentials" + endpoint: 0 + +tests: + - label: "Read number of supported fabrics" + command: "readAttribute" + attribute: "SupportedFabrics" + response: + constraints: + type: uint8 + minValue: 4 + + - label: "Read number of commissioned fabrics" + command: "readAttribute" + attribute: "CommissionedFabrics" + response: + constraints: + type: uint8 + minValue: 1 diff --git a/src/darwin/Framework/CHIP/templates/clusters-tests.zapt b/src/darwin/Framework/CHIP/templates/clusters-tests.zapt index 402ea7dfb5e519..ab6bd2ad1250a4 100644 --- a/src/darwin/Framework/CHIP/templates/clusters-tests.zapt +++ b/src/darwin/Framework/CHIP/templates/clusters-tests.zapt @@ -134,7 +134,7 @@ CHIPDevice * GetPairedDevice(uint64_t deviceId) [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } -{{>test_cluster tests="TestCluster, Test_TC_OO_1_1, Test_TC_OO_2_1, Test_TC_OO_2_2, Test_TC_DM_1_1, Test_TC_DM_3_1, Test_TC_CC_3_4, Test_TC_CC_5, Test_TC_CC_6, Test_TC_CC_7, Test_TC_CC_8, Test_TC_WNCV_1_1, Test_TC_WNCV_2_1, Test_TC_BI_1_1, Test_TC_FLW_1_1, Test_TC_TM_1_1, Test_TC_OCC_1_1"}} +{{>test_cluster tests="TestCluster, Test_TC_OO_1_1, Test_TC_OO_2_1, Test_TC_OO_2_2, Test_TC_DM_1_1, Test_TC_DM_3_1, Test_TC_CC_3_4, Test_TC_CC_5, Test_TC_CC_6, Test_TC_CC_7, Test_TC_CC_8, Test_TC_WNCV_1_1, Test_TC_WNCV_2_1, Test_TC_BI_1_1, Test_TC_FLW_1_1, Test_TC_TM_1_1, Test_TC_OCC_1_1, OperationalCredentialsCluster"}} {{#chip_client_clusters}} {{#unless (isStrEqual "Test Cluster" name)}} diff --git a/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt b/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt index 28d90ec902d3ef..76f49767fdd411 100644 --- a/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt +++ b/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt @@ -69,6 +69,12 @@ {{#if expectedConstraints.maxLength}} XCTAssertLessThanOrEqual([values[@"{{#if parent.isReadAttribute}}value{{else}}{{name}}{{/if}}"] length], {{expectedConstraints.maxLength}}); {{/if}} + {{#if expectedConstraints.minValue}} + XCTAssertGreaterThanOrEqual([values[@"{{#if parent.isReadAttribute}}value{{else}}{{name}}{{/if}}"] {{asObjectiveCNumberType "" type true}}Value], {{expectedConstraints.minValue}}); + {{/if}} + {{#if expectedConstraints.maxValue}} + XCTAssertLessThanOrEqual([values[@"{{#if parent.isReadAttribute}}value{{else}}{{name}}{{/if}}"] {{asObjectiveCNumberType "" type true}}Value], {{expectedConstraints.maxValue}}); + {{/if}} {{/if}} {{/chip_tests_item_response_parameters}} [expectation fulfill]; diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index 4cb74d44761127..202e6ed8c6c4c8 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -5047,6 +5047,43 @@ - (void)testSendClusterTest_TC_OCC_1_1_000001_ReadAttribute [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } +- (void)testSendClusterOperationalCredentialsCluster_000000_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read number of supported fabrics"]; + CHIPDevice * device = GetPairedDevice(kDeviceId); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPOperationalCredentials * cluster = [[CHIPOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeSupportedFabricsWithResponseHandler:^(NSError * err, NSDictionary * values) { + NSLog(@"Read number of supported fabrics Error: %@", err); + + XCTAssertEqual(err.code, 0); + XCTAssertGreaterThanOrEqual([values[@"value"] unsignedCharValue], 4); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterOperationalCredentialsCluster_000001_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read number of commissioned fabrics"]; + CHIPDevice * device = GetPairedDevice(kDeviceId); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPOperationalCredentials * cluster = [[CHIPOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeCommissionedFabricsWithResponseHandler:^(NSError * err, NSDictionary * values) { + NSLog(@"Read number of commissioned fabrics Error: %@", err); + + XCTAssertEqual(err.code, 0); + XCTAssertGreaterThanOrEqual([values[@"value"] unsignedCharValue], 1); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} + - (void)testSendClusterAccountLoginReadAttributeClusterRevisionWithResponseHandler { XCTestExpectation * expectation =