From 24540888991a0315bd1afc271dfad60485f30e1f Mon Sep 17 00:00:00 2001 From: Carol Yang Date: Tue, 17 May 2022 19:49:48 -0700 Subject: [PATCH] [CI] Add a test for successful OTA transfer (#18344) --- .github/workflows/darwin-tests.yaml | 4 + .github/workflows/tests.yaml | 8 + scripts/tests/chiptest/__init__.py | 2 + scripts/tests/chiptest/accessories.py | 13 +- scripts/tests/chiptest/linux.py | 2 + scripts/tests/chiptest/test_definition.py | 11 +- scripts/tests/run_test_suite.py | 16 +- .../tests/suites/OTA_SuccessfulTransfer.yaml | 177 ++++++++++ .../suites/commands/delay/DelayCommands.cpp | 20 ++ .../suites/commands/delay/DelayCommands.h | 4 + .../commands/delay/scripts/WaitForMessage.py | 33 ++ .../suites/commands/system/SystemCommands.cpp | 73 +++- .../suites/commands/system/SystemCommands.h | 4 + .../commands/system/scripts/CompareFiles.py | 30 ++ .../commands/system/scripts/CreateOtaImage.py | 45 +++ src/app/tests/suites/tests.js | 11 +- .../clusters/DelayCommands.js | 13 +- .../clusters/SystemCommands.js | 21 +- .../tests/simulated-cluster-objects.h | 181 +++++++++- .../zap-generated/test/Commands.h | 330 +++++++++++++++++- .../chip-tool/zap-generated/test/Commands.h | 249 ++++++++++++- 21 files changed, 1206 insertions(+), 41 deletions(-) create mode 100644 src/app/tests/suites/OTA_SuccessfulTransfer.yaml create mode 100755 src/app/tests/suites/commands/delay/scripts/WaitForMessage.py create mode 100755 src/app/tests/suites/commands/system/scripts/CompareFiles.py create mode 100755 src/app/tests/suites/commands/system/scripts/CreateOtaImage.py diff --git a/.github/workflows/darwin-tests.yaml b/.github/workflows/darwin-tests.yaml index b8face5cb0aeaa..384a85e4d4032d 100644 --- a/.github/workflows/darwin-tests.yaml +++ b/.github/workflows/darwin-tests.yaml @@ -89,6 +89,8 @@ jobs: --target darwin-x64-chip-tool-darwin-${BUILD_VARIANT} \ --target darwin-x64-all-clusters-${BUILD_VARIANT} \ --target darwin-x64-lock-${BUILD_VARIANT} \ + --target darwin-x64-ota-provider-${BUILD_VARIANT} \ + --target darwin-x64-ota-requestor-${BUILD_VARIANT} \ --target darwin-x64-tv-app-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ @@ -104,6 +106,8 @@ jobs: --iterations 1 \ --all-clusters-app ./out/darwin-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \ --lock-app ./out/darwin-x64-lock-${BUILD_VARIANT}/chip-lock-app \ + --ota-provider-app ./out/darwin-x64-ota-provider-${BUILD_VARIANT}/chip-ota-provider-app \ + --ota-requestor-app ./out/darwin-x64-ota-requestor-${BUILD_VARIANT}/chip-ota-requestor-app \ --tv-app ./out/darwin-x64-tv-app-${BUILD_VARIANT}/chip-tv-app \ " - name: Uploading core files diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index cc50432aa0c0ee..652edab6f36f51 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -83,6 +83,8 @@ jobs: --target linux-x64-chip-tool${CHIP_TOOL_VARIANT}-${BUILD_VARIANT} \ --target linux-x64-all-clusters-${BUILD_VARIANT} \ --target linux-x64-lock-${BUILD_VARIANT} \ + --target linux-x64-ota-provider-${BUILD_VARIANT} \ + --target linux-x64-ota-requestor-${BUILD_VARIANT} \ --target linux-x64-tv-app-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ @@ -97,6 +99,8 @@ jobs: --iterations 1 \ --all-clusters-app ./out/linux-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \ --lock-app ./out/linux-x64-lock-${BUILD_VARIANT}/chip-lock-app \ + --ota-provider-app ./out/linux-x64-ota-provider-${BUILD_VARIANT}/chip-ota-provider-app \ + --ota-requestor-app ./out/linux-x64-ota-requestor-${BUILD_VARIANT}/chip-ota-requestor-app \ --tv-app ./out/linux-x64-tv-app-${BUILD_VARIANT}/chip-tv-app \ " - name: Uploading core files @@ -179,6 +183,8 @@ jobs: --target darwin-x64-chip-tool${CHIP_TOOL_VARIANT}-${BUILD_VARIANT} \ --target darwin-x64-all-clusters-${BUILD_VARIANT} \ --target darwin-x64-lock-${BUILD_VARIANT} \ + --target darwin-x64-ota-provider-${BUILD_VARIANT} \ + --target darwin-x64-ota-requestor-${BUILD_VARIANT} \ --target darwin-x64-tv-app-${BUILD_VARIANT} \ build \ --copy-artifacts-to objdir-clone \ @@ -194,6 +200,8 @@ jobs: --iterations 1 \ --all-clusters-app ./out/darwin-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \ --lock-app ./out/darwin-x64-lock-${BUILD_VARIANT}/chip-lock-app \ + --ota-provider-app ./out/darwin-x64-ota-provider-${BUILD_VARIANT}/chip-ota-provider-app \ + --ota-requestor-app ./out/darwin-x64-ota-requestor-${BUILD_VARIANT}/chip-ota-requestor-app \ --tv-app ./out/darwin-x64-tv-app-${BUILD_VARIANT}/chip-tv-app \ " - name: Uploading core files diff --git a/scripts/tests/chiptest/__init__.py b/scripts/tests/chiptest/__init__.py index 60e68c73361a2c..0b32c373f70ecf 100644 --- a/scripts/tests/chiptest/__init__.py +++ b/scripts/tests/chiptest/__init__.py @@ -34,6 +34,8 @@ def AllTests(chip_tool: str): target = TestTarget.TV elif name.startswith('DL_'): target = TestTarget.LOCK + elif name.startswith('OTA_'): + target = TestTarget.OTA else: target = TestTarget.ALL_CLUSTERS diff --git a/scripts/tests/chiptest/accessories.py b/scripts/tests/chiptest/accessories.py index e397ce94ca1857..e84e5e074c5dae 100644 --- a/scripts/tests/chiptest/accessories.py +++ b/scripts/tests/chiptest/accessories.py @@ -64,7 +64,7 @@ def killAll(self): def start(self, name, args): accessory = self.__accessories[name] if accessory: - # The args param comes directly from the sys.argv[1:] of Start.py and should contain a list of strings in + # The args param comes directly from the sys.argv[2:] of Start.py and should contain a list of strings in # key-value pair, e.g. [option1, value1, option2, value2, ...] options = self.__createCommandLineOptions(args) return accessory.start(options) @@ -104,6 +104,14 @@ def waitForOperationalAdvertisement(self, name): return accessory.waitForOperationalAdvertisement() return False + def waitForMessage(self, name, message): + accessory = self.__accessories[name] + if accessory: + # The message param comes directly from the sys.argv[2:] of WaitForMessage.py and should contain a list of strings that + # comprise the entire message to wait for + return accessory.waitForMessage(' '.join(message)) + return False + def __startXMLRPCServer(self): self.server = SimpleXMLRPCServer((IP, PORT)) @@ -117,6 +125,9 @@ def __startXMLRPCServer(self): self.server.register_function( self.waitForOperationalAdvertisement, 'waitForOperationalAdvertisement') + self.server.register_function( + self.waitForMessage, + 'waitForMessage') self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.start() diff --git a/scripts/tests/chiptest/linux.py b/scripts/tests/chiptest/linux.py index eac1f573c09932..872d6b5040ea33 100644 --- a/scripts/tests/chiptest/linux.py +++ b/scripts/tests/chiptest/linux.py @@ -145,5 +145,7 @@ def PathsWithNetworkNamespaces(paths: ApplicationPaths) -> ApplicationPaths: chip_tool='ip netns exec tool'.split() + paths.chip_tool, all_clusters_app='ip netns exec app'.split() + paths.all_clusters_app, lock_app='ip netns exec app'.split() + paths.lock_app, + ota_provider_app='ip netns exec app'.split() + paths.ota_provider_app, + ota_requestor_app='ip netns exec app'.split() + paths.ota_requestor_app, tv_app='ip netns exec app'.split() + paths.tv_app, ) diff --git a/scripts/tests/chiptest/test_definition.py b/scripts/tests/chiptest/test_definition.py index d5c593e7818d4f..04d14787c08be9 100644 --- a/scripts/tests/chiptest/test_definition.py +++ b/scripts/tests/chiptest/test_definition.py @@ -89,6 +89,10 @@ def waitForOperationalAdvertisement(self): self.process, self.outpipe) return True + def waitForMessage(self, message): + self.__waitFor(message, self.process, self.outpipe) + return True + def kill(self): if self.process: self.process.kill() @@ -154,6 +158,7 @@ class TestTarget(Enum): ALL_CLUSTERS = auto() TV = auto() LOCK = auto() + OTA = auto() @dataclass @@ -161,10 +166,12 @@ class ApplicationPaths: chip_tool: typing.List[str] all_clusters_app: typing.List[str] lock_app: typing.List[str] + ota_provider_app: typing.List[str] + ota_requestor_app: typing.List[str] tv_app: typing.List[str] def items(self): - return [self.chip_tool, self.all_clusters_app, self.lock_app, self.tv_app] + return [self.chip_tool, self.all_clusters_app, self.lock_app, self.ota_provider_app, self.ota_requestor_app, self.tv_app] @dataclass @@ -225,6 +232,8 @@ def Run(self, runner, apps_register, paths: ApplicationPaths, pics_file: str): target_app = paths.tv_app elif self.target == TestTarget.LOCK: target_app = paths.lock_app + elif self.target == TestTarget.OTA: + target_app = paths.ota_requestor_app else: raise Exception("Unknown test target - " "don't know which application to run") diff --git a/scripts/tests/run_test_suite.py b/scripts/tests/run_test_suite.py index 61cbf3adde1aad..5dc802c3b89991 100755 --- a/scripts/tests/run_test_suite.py +++ b/scripts/tests/run_test_suite.py @@ -171,6 +171,12 @@ def cmd_list(context): @click.option( '--lock-app', help='what lock app to use') +@click.option( + '--ota-provider-app', + help='what ota provider app to use') +@click.option( + '--ota-requestor-app', + help='what ota requestor app to use') @click.option( '--tv-app', help='what tv app to use') @@ -180,7 +186,7 @@ def cmd_list(context): default="src/app/tests/suites/certification/ci-pics-values", help='PICS file to use for test runs.') @click.pass_context -def cmd_run(context, iterations, all_clusters_app, lock_app, tv_app, pics_file): +def cmd_run(context, iterations, all_clusters_app, lock_app, ota_provider_app, ota_requestor_app, tv_app, pics_file): runner = chiptest.runner.Runner() if all_clusters_app is None: @@ -189,6 +195,12 @@ def cmd_run(context, iterations, all_clusters_app, lock_app, tv_app, pics_file): if lock_app is None: lock_app = FindBinaryPath('chip-lock-app') + if ota_provider_app is None: + ota_provider_app = FindBinaryPath('chip-ota-provider-app') + + if ota_requestor_app is None: + ota_requestor_app = FindBinaryPath('chip-ota-requestor-app') + if tv_app is None: tv_app = FindBinaryPath('chip-tv-app') @@ -197,6 +209,8 @@ def cmd_run(context, iterations, all_clusters_app, lock_app, tv_app, pics_file): chip_tool=[context.obj.chip_tool], all_clusters_app=[all_clusters_app], lock_app=[lock_app], + ota_provider_app=[ota_provider_app], + ota_requestor_app=[ota_requestor_app], tv_app=[tv_app] ) diff --git a/src/app/tests/suites/OTA_SuccessfulTransfer.yaml b/src/app/tests/suites/OTA_SuccessfulTransfer.yaml new file mode 100644 index 00000000000000..6eb533f7bf27a8 --- /dev/null +++ b/src/app/tests/suites/OTA_SuccessfulTransfer.yaml @@ -0,0 +1,177 @@ +# Copyright (c) 2022 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: Test OTA Software Update Successful Transfer + +config: + endpoint: 0 + requestorNodeId: + type: NODE_ID + defaultValue: 0x12344321 + providerNodeId: + type: NODE_ID + defaultValue: 0xC0FFEE + providerPayload: + type: CHAR_STRING + defaultValue: "MT:-24J0IX4122-.548G00" # This value needs to be generated + providerDiscriminator: + type: INT16U + defaultValue: 50 + providerPort: + type: INT16U + defaultValue: 5560 + providerKvs: + type: CHAR_STRING + defaultValue: "/tmp/chip_kvs_provider" + otaImageFilePath: + type: CHAR_STRING + defaultValue: "/tmp/otaImage" + rawImageFilePath: + type: CHAR_STRING + defaultValue: "/tmp/rawImage" + rawImageContent: + type: CHAR_STRING + defaultValue: "Have a hootenanny!" + downloadImageFilePath: + type: CHAR_STRING + defaultValue: "/tmp/downloadedImage" + +tests: + - label: "Create OTA image" + cluster: "SystemCommands" + command: "CreateOtaImage" + arguments: + values: + - name: "otaImageFilePath" + value: otaImageFilePath + - name: "rawImageFilePath" + value: rawImageFilePath + - name: "rawImageContent" + value: rawImageContent + + - label: "Start the provider with an image" + cluster: "SystemCommands" + command: "Start" + arguments: + values: + - name: "registerKey" + value: "chip-ota-provider-app" + - name: "discriminator" + value: providerDiscriminator + - name: "port" + value: providerPort + - name: "kvs" + value: providerKvs + - name: "filepath" + value: otaImageFilePath + + - label: "Commission the provider from alpha" + identity: "alpha" + cluster: "CommissionerCommands" + command: "PairWithQRCode" + arguments: + values: + - name: "nodeId" + value: providerNodeId + - name: "payload" + value: providerPayload + + - label: "Wait for the commissioned provider to be retrieved for alpha" + identity: "alpha" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: providerNodeId + + - label: "Install ACL for QueryImage" + cluster: "Access Control" + command: "writeAttribute" + attribute: "ACL" + arguments: + value: [ + # Grant administer privilege to the default controller node ID 112233 + { + FabricIndex: 1, + Privilege: 5, + AuthMode: 2, + Subjects: [112233], + Targets: null, + }, + # Grant operate privileges to all nodes for the OTA Provider cluster on every endpoint + { + FabricIndex: 1, + Privilege: 3, + AuthMode: 2, + Subjects: null, + Targets: null, + [{ Cluster: 41, Endpoint: null, DeviceType: null }], + }, + ] + + - label: "Stop the requestor" + cluster: "SystemCommands" + command: "Stop" + + - label: "Start the requestor with an OTA download path" + cluster: "SystemCommands" + command: "Start" + arguments: + values: + - name: "otaDownloadPath" + value: downloadImageFilePath + + - label: "Wait for the commissioned requestor to be retrieved for alpha" + identity: "alpha" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: requestorNodeId + + - label: "Send an announce OTA provider command to the requestor" + cluster: "OTA Software Update Requestor" + command: "AnnounceOtaProvider" + arguments: + values: + - name: "providerNodeId" + value: providerNodeId + - name: "vendorId" + value: 0 + - name: "announcementReason" + value: 0 + - name: "endpoint" + value: endpoint + + - label: "Wait for transfer complete message" + cluster: "DelayCommands" + command: "WaitForMessage" + arguments: + values: + - name: "registerKey" + value: "default" + - name: "message" + value: "OTA image downloaded" + + - label: "Compare original file to downloaded file" + cluster: "SystemCommands" + command: "CompareFiles" + arguments: + values: + - name: "file1" + value: rawImageFilePath + - name: "file2" + value: downloadImageFilePath diff --git a/src/app/tests/suites/commands/delay/DelayCommands.cpp b/src/app/tests/suites/commands/delay/DelayCommands.cpp index af423382e6f400..e300283e944754 100644 --- a/src/app/tests/suites/commands/delay/DelayCommands.cpp +++ b/src/app/tests/suites/commands/delay/DelayCommands.cpp @@ -26,6 +26,8 @@ const char * getScriptsFolder() } } // namespace +constexpr const char * kDefaultKey = "default"; + CHIP_ERROR DelayCommands::WaitForMs(const char * identity, const chip::app::Clusters::DelayCommands::Commands::WaitForMs::Type & value) { @@ -61,6 +63,24 @@ CHIP_ERROR DelayCommands::WaitForOperationalAdvertisement( return RunInternal(command); } +CHIP_ERROR DelayCommands::WaitForMessage(const char * identity, + const chip::app::Clusters::DelayCommands::Commands::WaitForMessage::Type & value) +{ + VerifyOrReturnError(!value.message.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + const char * scriptDir = getScriptsFolder(); + constexpr const char * scriptName = "WaitForMessage.py"; + const char * registerKeyValue = value.registerKey.HasValue() ? value.registerKey.Value().data() : kDefaultKey; + const size_t registerKeyLen = value.registerKey.HasValue() ? value.registerKey.Value().size() : strlen(kDefaultKey); + + char command[128]; + VerifyOrReturnError(snprintf(command, sizeof(command), "%s%s %.*s %.*s", scriptDir, scriptName, + static_cast(registerKeyLen), registerKeyValue, static_cast(value.message.size()), + value.message.data()) >= 0, + CHIP_ERROR_INTERNAL); + return RunInternal(command); +} + CHIP_ERROR DelayCommands::RunInternal(const char * command) { VerifyOrReturnError(system(command) == 0, CHIP_ERROR_INTERNAL); diff --git a/src/app/tests/suites/commands/delay/DelayCommands.h b/src/app/tests/suites/commands/delay/DelayCommands.h index 84bfdcc166800b..332921cefdc2a4 100644 --- a/src/app/tests/suites/commands/delay/DelayCommands.h +++ b/src/app/tests/suites/commands/delay/DelayCommands.h @@ -49,6 +49,10 @@ class DelayCommands const chip::app::Clusters::DelayCommands::Commands::WaitForCommissionableAdvertisement::Type & value); CHIP_ERROR WaitForOperationalAdvertisement( const char * identity, const chip::app::Clusters::DelayCommands::Commands::WaitForOperationalAdvertisement::Type & value); + // Wait for any message specified by value.message for the application specified by value.registerKey + // If the message is never seen, a timeout would occur + CHIP_ERROR WaitForMessage(const char * identity, + const chip::app::Clusters::DelayCommands::Commands::WaitForMessage::Type & value); // Busy-wait for a given duration in milliseconds CHIP_ERROR BusyWaitFor(chip::System::Clock::Milliseconds32 durationInMs); diff --git a/src/app/tests/suites/commands/delay/scripts/WaitForMessage.py b/src/app/tests/suites/commands/delay/scripts/WaitForMessage.py new file mode 100755 index 00000000000000..345d6b37cf1bc9 --- /dev/null +++ b/src/app/tests/suites/commands/delay/scripts/WaitForMessage.py @@ -0,0 +1,33 @@ +#!/usr/bin/env -S python3 -B + +# Copyright (c) 2022 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. + +import sys +import xmlrpc.client + +IP = '127.0.0.1' +PORT = 9000 + +if sys.platform == 'linux': + IP = '10.10.10.5' + + +def main(): + with xmlrpc.client.ServerProxy('http://' + IP + ':' + str(PORT) + '/', allow_none=True) as proxy: + proxy.waitForMessage(sys.argv[1], sys.argv[2:]) + + +if __name__ == "__main__": + main() diff --git a/src/app/tests/suites/commands/system/SystemCommands.cpp b/src/app/tests/suites/commands/system/SystemCommands.cpp index 24bb74ed1820cc..c7f089065b1932 100644 --- a/src/app/tests/suites/commands/system/SystemCommands.cpp +++ b/src/app/tests/suites/commands/system/SystemCommands.cpp @@ -27,6 +27,7 @@ const char * getScriptsFolder() } // namespace constexpr size_t kCommandMaxLen = 256; +constexpr size_t kArgumentMaxLen = 128; constexpr const char * kDefaultKey = "default"; CHIP_ERROR SystemCommands::Start(const char * identity, const chip::app::Clusters::SystemCommands::Commands::Start::Type & value) @@ -68,12 +69,7 @@ CHIP_ERROR SystemCommands::Start(const char * identity, const chip::app::Cluster if (value.kvs.HasValue()) { - VerifyOrReturnError(value.kvs.Value().size() < 128, CHIP_ERROR_INVALID_ARGUMENT); - builder.Add(" --KVS "); - char kvs[128]; - memset(kvs, '\0', sizeof(kvs)); - strncpy(kvs, value.kvs.Value().data(), value.kvs.Value().size()); - builder.Add(kvs); + AddSystemCommandArgument(builder, "--KVS", value.kvs.Value()); } if (value.minCommissioningTimeout.HasValue()) @@ -82,6 +78,18 @@ CHIP_ERROR SystemCommands::Start(const char * identity, const chip::app::Cluster builder.Add(value.minCommissioningTimeout.Value()); } + // OTA provider specific arguments + if (value.filepath.HasValue()) + { + AddSystemCommandArgument(builder, "--filepath", value.filepath.Value()); + } + + // OTA requstor specific arguments + if (value.otaDownloadPath.HasValue()) + { + AddSystemCommandArgument(builder, "--otaDownloadPath", value.otaDownloadPath.Value()); + } + VerifyOrReturnError(builder.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL); return RunInternal(command); @@ -106,6 +114,42 @@ CHIP_ERROR SystemCommands::FactoryReset(const char * identity, return RunInternal(scriptName, value.registerKey); } +CHIP_ERROR SystemCommands::CreateOtaImage(const char * identity, + const chip::app::Clusters::SystemCommands::Commands::CreateOtaImage::Type & value) +{ + VerifyOrReturnError(!value.rawImageContent.empty(), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!value.rawImageFilePath.empty(), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!value.otaImageFilePath.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + const char * scriptDir = getScriptsFolder(); + constexpr const char * scriptName = "CreateOtaImage.py"; + + char command[128]; + VerifyOrReturnError(snprintf(command, sizeof(command), "%s%s %.*s %.*s %.*s", scriptDir, scriptName, + static_cast(value.otaImageFilePath.size()), value.otaImageFilePath.data(), + static_cast(value.rawImageFilePath.size()), value.rawImageFilePath.data(), + static_cast(value.rawImageContent.size()), value.rawImageContent.data()) >= 0, + CHIP_ERROR_INTERNAL); + return RunInternal(command); +} + +CHIP_ERROR SystemCommands::CompareFiles(const char * identity, + const chip::app::Clusters::SystemCommands::Commands::CompareFiles::Type & value) +{ + VerifyOrReturnError(!value.file1.empty(), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!value.file2.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + const char * scriptDir = getScriptsFolder(); + constexpr const char * scriptName = "CompareFiles.py"; + + char command[128]; + VerifyOrReturnError(snprintf(command, sizeof(command), "%s%s %.*s %.*s", scriptDir, scriptName, + static_cast(value.file1.size()), value.file1.data(), static_cast(value.file2.size()), + value.file2.data()) >= 0, + CHIP_ERROR_INTERNAL); + return RunInternal(command); +} + CHIP_ERROR SystemCommands::RunInternal(const char * scriptName, const chip::Optional registerKey) { const char * scriptDir = getScriptsFolder(); @@ -124,3 +168,20 @@ CHIP_ERROR SystemCommands::RunInternal(const char * command) VerifyOrReturnError(system(command) == 0, CHIP_ERROR_INTERNAL); return ContinueOnChipMainThread(CHIP_NO_ERROR); } + +CHIP_ERROR SystemCommands::AddSystemCommandArgument(chip::StringBuilderBase & builder, const char * argName, + const chip::CharSpan & argValue) +{ + VerifyOrReturnError(argValue.size() < kArgumentMaxLen, CHIP_ERROR_INVALID_ARGUMENT); + + builder.Add(" "); + builder.Add(argName); + builder.Add(" "); + + char arg[kArgumentMaxLen]; + memset(arg, 0, sizeof(arg)); + strncpy(arg, argValue.data(), argValue.size()); + builder.Add(arg); + + return CHIP_NO_ERROR; +} diff --git a/src/app/tests/suites/commands/system/SystemCommands.h b/src/app/tests/suites/commands/system/SystemCommands.h index 594fedc9d2bd8d..7e14fc89c5bcfe 100644 --- a/src/app/tests/suites/commands/system/SystemCommands.h +++ b/src/app/tests/suites/commands/system/SystemCommands.h @@ -35,8 +35,12 @@ class SystemCommands CHIP_ERROR Stop(const char * identity, const chip::app::Clusters::SystemCommands::Commands::Stop::Type & value); CHIP_ERROR Reboot(const char * identity, const chip::app::Clusters::SystemCommands::Commands::Reboot::Type & value); CHIP_ERROR FactoryReset(const char * identity, const chip::app::Clusters::SystemCommands::Commands::FactoryReset::Type & value); + CHIP_ERROR CreateOtaImage(const char * identity, + const chip::app::Clusters::SystemCommands::Commands::CreateOtaImage::Type & value); + CHIP_ERROR CompareFiles(const char * identity, const chip::app::Clusters::SystemCommands::Commands::CompareFiles::Type & value); private: CHIP_ERROR RunInternal(const char * scriptName, const chip::Optional registerKey); CHIP_ERROR RunInternal(const char * command); + CHIP_ERROR AddSystemCommandArgument(chip::StringBuilderBase & builder, const char * argName, const chip::CharSpan & argValue); }; diff --git a/src/app/tests/suites/commands/system/scripts/CompareFiles.py b/src/app/tests/suites/commands/system/scripts/CompareFiles.py new file mode 100755 index 00000000000000..98cbf811662c44 --- /dev/null +++ b/src/app/tests/suites/commands/system/scripts/CompareFiles.py @@ -0,0 +1,30 @@ +#!/usr/bin/env -S python3 -B + +# Copyright (c) 2022 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. + +import filecmp +import sys + +file1 = sys.argv[1] +file2 = sys.argv[2] + + +def main(): + if filecmp.cmp(file1, file2, shallow=False) is False: + raise Exception('Files %s and %s do not match' % (file1, file2)) + + +if __name__ == "__main__": + main() diff --git a/src/app/tests/suites/commands/system/scripts/CreateOtaImage.py b/src/app/tests/suites/commands/system/scripts/CreateOtaImage.py new file mode 100755 index 00000000000000..1317e212a99419 --- /dev/null +++ b/src/app/tests/suites/commands/system/scripts/CreateOtaImage.py @@ -0,0 +1,45 @@ +#!/usr/bin/env -S python3 -B + +# Copyright (c) 2022 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. + +import os +import subprocess +import sys + +DEFAULT_CHIP_ROOT = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..', '..', '..')) + +otaImageFilePath = sys.argv[1] +rawImageFilePath = sys.argv[2] +rawImageContent = ' '.join(sys.argv[3:]) + + +def main(): + # Write the raw image content + with open(rawImageFilePath, 'w') as rawFile: + rawFile.write(rawImageContent) + + # Add an OTA header to the raw file + otaImageTool = DEFAULT_CHIP_ROOT + '/src/app/ota_image_tool.py' + cmd = [otaImageTool, 'create', '-v', '0xDEAD', '-p', '0xBEEF', '-vn', '2', + '-vs', "2.0", '-da', 'sha256', rawImageFilePath, otaImageFilePath] + s = subprocess.Popen(cmd) + s.wait() + if s.returncode != 0: + raise Exception('Cannot create OTA image file') + + +if __name__ == "__main__": + main() diff --git a/src/app/tests/suites/tests.js b/src/app/tests/suites/tests.js index b69a67a00bfc1f..a04b80fd0f109a 100644 --- a/src/app/tests/suites/tests.js +++ b/src/app/tests/suites/tests.js @@ -28,8 +28,7 @@ function disable(testName) // clang-format off -function getManualTests() -{ +function getManualTests() { const DeviceDiscovery = [ 'Test_TC_DD_1_5', 'Test_TC_DD_1_6', @@ -451,8 +450,7 @@ function getManualTests() return tests; } -function getTests() -{ +function getTests() { const AccessControl = [ 'TestAccessControlCluster', ]; @@ -606,6 +604,10 @@ function getTests() 'Test_TC_MF_1_15', ]; + const OTASoftwareUpdate = [ + 'OTA_SuccessfulTransfer', + ]; + const OnOff = [ 'Test_TC_OO_1_1', 'Test_TC_OO_2_1', @@ -785,6 +787,7 @@ function getTests() MediaControl, ModeSelect, MultipleFabrics, + OTASoftwareUpdate, OccupancySensing, OnOff, PowerSource, diff --git a/src/app/zap-templates/common/simulated-clusters/clusters/DelayCommands.js b/src/app/zap-templates/common/simulated-clusters/clusters/DelayCommands.js index 5e207f81754424..9841136ab1382c 100644 --- a/src/app/zap-templates/common/simulated-clusters/clusters/DelayCommands.js +++ b/src/app/zap-templates/common/simulated-clusters/clusters/DelayCommands.js @@ -46,9 +46,16 @@ const WaitForOperationalAdvertisement = { name : 'WaitForOperationalAdvertisement', }; -const name = 'DelayCommands'; -const commands = - [ WaitForMs, WaitForCommissioning, WaitForCommissionee, WaitForCommissionableAdvertisement, WaitForOperationalAdvertisement ]; +const WaitForMessage = { + name : 'WaitForMessage', + arguments : [ { type : 'CHAR_STRING', name : 'registerKey', isOptional : true }, { type : 'CHAR_STRING', name : 'message' } ], +}; + +const name = 'DelayCommands'; +const commands = [ + WaitForMs, WaitForCommissioning, WaitForCommissionee, WaitForCommissionableAdvertisement, WaitForOperationalAdvertisement, + WaitForMessage +]; const DelayCommands = { name, diff --git a/src/app/zap-templates/common/simulated-clusters/clusters/SystemCommands.js b/src/app/zap-templates/common/simulated-clusters/clusters/SystemCommands.js index 516555f68a1778..b59f9c9fc925a0 100644 --- a/src/app/zap-templates/common/simulated-clusters/clusters/SystemCommands.js +++ b/src/app/zap-templates/common/simulated-clusters/clusters/SystemCommands.js @@ -27,10 +27,14 @@ const Start = { name : 'Start', arguments : [ + { 'name' : 'registerKey', type : 'CHAR_STRING', isOptional : true }, { 'name' : 'discriminator', type : 'INT16U', isOptional : true }, { 'name' : 'port', type : 'INT16U', isOptional : true }, { 'name' : 'kvs', type : 'CHAR_STRING', isOptional : true }, { 'name' : 'minCommissioningTimeout', type : 'INT16U', isOptional : true }, - { 'name' : 'registerKey', type : 'CHAR_STRING', isOptional : true } + // OTA provider specific arguments + { 'name' : 'filepath', type : 'CHAR_STRING', isOptional : true }, + // OTA requestor specific arguments + { 'name' : 'otaDownloadPath', type : 'CHAR_STRING', isOptional : true } ], }; @@ -49,9 +53,22 @@ const FactoryReset = { arguments : [ { 'name' : 'registerKey', type : 'CHAR_STRING', isOptional : true } ], }; +const CreateOtaImage = { + name : 'CreateOtaImage', + arguments : [ + { 'name' : 'otaImageFilePath', type : 'CHAR_STRING' }, { 'name' : 'rawImageFilePath', type : 'CHAR_STRING' }, + { 'name' : 'rawImageContent', type : 'CHAR_STRING' } + ], +}; + +const CompareFiles = { + name : 'CompareFiles', + arguments : [ { 'name' : 'file1', type : 'CHAR_STRING' }, { 'name' : 'file2', type : 'CHAR_STRING' } ], +}; + const SystemCommands = { name : 'SystemCommands', - commands : [ Start, Stop, Reboot, FactoryReset ], + commands : [ Start, Stop, Reboot, FactoryReset, CreateOtaImage, CompareFiles ], }; // diff --git a/zzz_generated/app-common/app-common/zap-generated/tests/simulated-cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/tests/simulated-cluster-objects.h index 80a62f725a60b0..cdf72e9b5df2ac 100644 --- a/zzz_generated/app-common/app-common/zap-generated/tests/simulated-cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/tests/simulated-cluster-objects.h @@ -339,6 +339,51 @@ struct WaitForOperationalAdvertisementCommand } }; +struct WaitForMessageCommand +{ + Optional registerKey; + chip::CharSpan message; + + CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const + { + chip::TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(0), registerKey)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(1), message)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; + } + + CHIP_ERROR Decode(chip::TLV::TLVReader & reader) + { + CHIP_ERROR err = CHIP_NO_ERROR; + chip::TLV::TLVType outer; + VerifyOrReturnError(chip::TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(chip::TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (chip::TLV::TagNumFromTag(reader.GetTag())) + { + case 0: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, registerKey)); + break; + case 1: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, message)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + + return CHIP_NO_ERROR; + } +}; + struct FindCommissionableCommand { @@ -936,21 +981,25 @@ struct UserPromptCommand struct StartCommand { + Optional registerKey; Optional discriminator; Optional port; Optional kvs; Optional minCommissioningTimeout; - Optional registerKey; + Optional filepath; + Optional otaDownloadPath; CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const { chip::TLV::TLVType outer; ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(0), discriminator)); - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(1), port)); - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(2), kvs)); - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(3), minCommissioningTimeout)); - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(4), registerKey)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(0), registerKey)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(1), discriminator)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(2), port)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(3), kvs)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(4), minCommissioningTimeout)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(5), filepath)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(6), otaDownloadPath)); ReturnErrorOnFailure(writer.EndContainer(outer)); return CHIP_NO_ERROR; } @@ -968,19 +1017,25 @@ struct StartCommand switch (chip::TLV::TagNumFromTag(reader.GetTag())) { case 0: - ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, discriminator)); + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, registerKey)); break; case 1: - ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, port)); + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, discriminator)); break; case 2: - ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, kvs)); + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, port)); break; case 3: - ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, minCommissioningTimeout)); + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, kvs)); break; case 4: - ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, registerKey)); + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, minCommissioningTimeout)); + break; + case 5: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, filepath)); + break; + case 6: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, otaDownloadPath)); break; default: break; @@ -1114,6 +1169,101 @@ struct FactoryResetCommand } }; +struct CreateOtaImageCommand +{ + chip::CharSpan otaImageFilePath; + chip::CharSpan rawImageFilePath; + chip::CharSpan rawImageContent; + + CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const + { + chip::TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(0), otaImageFilePath)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(1), rawImageFilePath)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(2), rawImageContent)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; + } + + CHIP_ERROR Decode(chip::TLV::TLVReader & reader) + { + CHIP_ERROR err = CHIP_NO_ERROR; + chip::TLV::TLVType outer; + VerifyOrReturnError(chip::TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(chip::TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (chip::TLV::TagNumFromTag(reader.GetTag())) + { + case 0: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, otaImageFilePath)); + break; + case 1: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, rawImageFilePath)); + break; + case 2: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, rawImageContent)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + + return CHIP_NO_ERROR; + } +}; + +struct CompareFilesCommand +{ + chip::CharSpan file1; + chip::CharSpan file2; + + CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const + { + chip::TLV::TLVType outer; + ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(0), file1)); + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::ContextTag(1), file2)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; + } + + CHIP_ERROR Decode(chip::TLV::TLVReader & reader) + { + CHIP_ERROR err = CHIP_NO_ERROR; + chip::TLV::TLVType outer; + VerifyOrReturnError(chip::TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(chip::TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + switch (chip::TLV::TagNumFromTag(reader.GetTag())) + { + case 0: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, file1)); + break; + case 1: + ReturnErrorOnFailure(chip::app::DataModel::Decode(reader, file2)); + break; + default: + break; + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + + return CHIP_NO_ERROR; + } +}; + namespace app { namespace Clusters { @@ -1148,6 +1298,9 @@ using Type = struct WaitForCommissionableAdvertisementCommand; namespace WaitForOperationalAdvertisement { using Type = struct WaitForOperationalAdvertisementCommand; } +namespace WaitForMessage { +using Type = struct WaitForMessageCommand; +} } // namespace Commands } // namespace DelayCommands @@ -1214,6 +1367,12 @@ using Type = struct RebootCommand; namespace FactoryReset { using Type = struct FactoryResetCommand; } +namespace CreateOtaImage { +using Type = struct CreateOtaImageCommand; +} +namespace CompareFiles { +using Type = struct CompareFilesCommand; +} } // namespace Commands } // namespace SystemCommands diff --git a/zzz_generated/chip-tool-darwin/zap-generated/test/Commands.h b/zzz_generated/chip-tool-darwin/zap-generated/test/Commands.h index ed576340253a9d..46bea59e919c86 100644 --- a/zzz_generated/chip-tool-darwin/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool-darwin/zap-generated/test/Commands.h @@ -128,6 +128,7 @@ class TestList : public Command { printf("Test_TC_MF_1_5\n"); printf("Test_TC_MF_1_6\n"); printf("Test_TC_MF_1_15\n"); + printf("OTA_SuccessfulTransfer\n"); printf("Test_TC_OCC_1_1\n"); printf("Test_TC_OCC_2_1\n"); printf("Test_TC_OCC_2_2\n"); @@ -40810,6 +40811,322 @@ class Test_TC_MF_1_15 : public TestCommandBridge { } }; +class OTA_SuccessfulTransfer : public TestCommandBridge { +public: + // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced + OTA_SuccessfulTransfer() + : TestCommandBridge("OTA_SuccessfulTransfer") + , mTestIndex(0) + { + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("requestorNodeId", 0, UINT64_MAX, &mRequestorNodeId); + AddArgument("providerNodeId", 0, UINT64_MAX, &mProviderNodeId); + AddArgument("providerPayload", &mProviderPayload); + AddArgument("providerDiscriminator", 0, UINT16_MAX, &mProviderDiscriminator); + AddArgument("providerPort", 0, UINT16_MAX, &mProviderPort); + AddArgument("providerKvs", &mProviderKvs); + AddArgument("otaImageFilePath", &mOtaImageFilePath); + AddArgument("rawImageFilePath", &mRawImageFilePath); + AddArgument("rawImageContent", &mRawImageContent); + AddArgument("downloadImageFilePath", &mDownloadImageFilePath); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull) + + ~OTA_SuccessfulTransfer() {} + + /////////// TestCommand Interface ///////// + void NextTest() override + { + CHIP_ERROR err = CHIP_NO_ERROR; + + if (0 == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Start: OTA_SuccessfulTransfer\n"); + } + + if (mTestCount == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Complete: OTA_SuccessfulTransfer\n"); + SetCommandExitStatus(CHIP_NO_ERROR); + return; + } + + Wait(); + + // 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: + ChipLogProgress(chipTool, " ***** Test Step 0 : Create OTA image\n"); + err = TestCreateOtaImage_0(); + break; + case 1: + ChipLogProgress(chipTool, " ***** Test Step 1 : Start the provider with an image\n"); + err = TestStartTheProviderWithAnImage_1(); + break; + case 2: + ChipLogProgress(chipTool, " ***** Test Step 2 : Commission the provider from alpha\n"); + err = TestCommissionTheProviderFromAlpha_2(); + break; + case 3: + ChipLogProgress(chipTool, " ***** Test Step 3 : Wait for the commissioned provider to be retrieved for alpha\n"); + err = TestWaitForTheCommissionedProviderToBeRetrievedForAlpha_3(); + break; + case 4: + ChipLogProgress(chipTool, " ***** Test Step 4 : Install ACL for QueryImage\n"); + err = TestInstallAclForQueryImage_4(); + break; + case 5: + ChipLogProgress(chipTool, " ***** Test Step 5 : Stop the requestor\n"); + err = TestStopTheRequestor_5(); + break; + case 6: + ChipLogProgress(chipTool, " ***** Test Step 6 : Start the requestor with an OTA download path\n"); + err = TestStartTheRequestorWithAnOtaDownloadPath_6(); + break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : Wait for the commissioned requestor to be retrieved for alpha\n"); + err = TestWaitForTheCommissionedRequestorToBeRetrievedForAlpha_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Send an announce OTA provider command to the requestor\n"); + err = TestSendAnAnnounceOtaProviderCommandToTheRequestor_8(); + break; + case 9: + ChipLogProgress(chipTool, " ***** Test Step 9 : Wait for transfer complete message\n"); + err = TestWaitForTransferCompleteMessage_9(); + break; + case 10: + ChipLogProgress(chipTool, " ***** Test Step 10 : Compare original file to downloaded file\n"); + err = TestCompareOriginalFileToDownloadedFile_10(); + break; + } + + if (CHIP_NO_ERROR != err) { + ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err)); + SetCommandExitStatus(err); + } + } + + void OnStatusUpdate(const chip::app::StatusIB & status) override + { + switch (mTestIndex - 1) { + case 0: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 1: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 2: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 3: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 4: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 5: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 6: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 7: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 8: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 9: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 10: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + } + + // Go on to the next test. + ContinueOnChipMainThread(CHIP_NO_ERROR); + } + + chip::System::Clock::Timeout GetWaitDuration() const override + { + return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds)); + } + +private: + std::atomic_uint16_t mTestIndex; + const uint16_t mTestCount = 11; + + chip::Optional mEndpoint; + chip::Optional mRequestorNodeId; + chip::Optional mProviderNodeId; + chip::Optional mProviderPayload; + chip::Optional mProviderDiscriminator; + chip::Optional mProviderPort; + chip::Optional mProviderKvs; + chip::Optional mOtaImageFilePath; + chip::Optional mRawImageFilePath; + chip::Optional mRawImageContent; + chip::Optional mDownloadImageFilePath; + chip::Optional mTimeout; + + CHIP_ERROR TestCreateOtaImage_0() + { + chip::app::Clusters::SystemCommands::Commands::CreateOtaImage::Type value; + value.otaImageFilePath + = mOtaImageFilePath.HasValue() ? mOtaImageFilePath.Value() : chip::Span("/tmp/otaImage", 13); + value.rawImageFilePath + = mRawImageFilePath.HasValue() ? mRawImageFilePath.Value() : chip::Span("/tmp/rawImage", 13); + value.rawImageContent + = mRawImageContent.HasValue() ? mRawImageContent.Value() : chip::Span("Have a hootenanny!", 18); + return CreateOtaImage("alpha", value); + } + + CHIP_ERROR TestStartTheProviderWithAnImage_1() + { + chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-ota-provider-appgarbage: not in length on purpose", 21); + value.discriminator.Emplace(); + value.discriminator.Value() = mProviderDiscriminator.HasValue() ? mProviderDiscriminator.Value() : 50U; + value.port.Emplace(); + value.port.Value() = mProviderPort.HasValue() ? mProviderPort.Value() : 5560U; + value.kvs.Emplace(); + value.kvs.Value() = mProviderKvs.HasValue() ? mProviderKvs.Value() : chip::Span("/tmp/chip_kvs_provider", 22); + value.filepath.Emplace(); + value.filepath.Value() + = mOtaImageFilePath.HasValue() ? mOtaImageFilePath.Value() : chip::Span("/tmp/otaImage", 13); + return Start("alpha", value); + } + + CHIP_ERROR TestCommissionTheProviderFromAlpha_2() + { + chip::app::Clusters::CommissionerCommands::Commands::PairWithQRCode::Type value; + value.nodeId = mProviderNodeId.HasValue() ? mProviderNodeId.Value() : 12648430ULL; + value.payload + = mProviderPayload.HasValue() ? mProviderPayload.Value() : chip::Span("MT:-24J0IX4122-.548G00", 22); + return PairWithQRCode("alpha", value); + } + + CHIP_ERROR TestWaitForTheCommissionedProviderToBeRetrievedForAlpha_3() + { + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mProviderNodeId.HasValue() ? mProviderNodeId.Value() : 12648430ULL; + return WaitForCommissionee("alpha", value); + } + + CHIP_ERROR TestInstallAclForQueryImage_4() + { + CHIPDevice * device = GetDevice("alpha"); + CHIPTestAccessControl * cluster = [[CHIPTestAccessControl alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + id aclArgument; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + temp_0[0] = [[CHIPAccessControlClusterAccessControlEntry alloc] init]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[0]).privilege = [NSNumber numberWithUnsignedChar:5]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[0]).authMode = [NSNumber numberWithUnsignedChar:2]; + { + NSMutableArray * temp_3 = [[NSMutableArray alloc] init]; + temp_3[0] = [NSNumber numberWithUnsignedLongLong:112233ULL]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[0]).subjects = temp_3; + } + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[0]).targets = nil; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[0]).fabricIndex = [NSNumber numberWithUnsignedChar:1]; + + temp_0[1] = [[CHIPAccessControlClusterAccessControlEntry alloc] init]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[1]).privilege = [NSNumber numberWithUnsignedChar:3]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[1]).authMode = [NSNumber numberWithUnsignedChar:2]; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[1]).subjects = nil; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[1]).targets = nil; + ((CHIPAccessControlClusterAccessControlEntry *) temp_0[1]).fabricIndex = [NSNumber numberWithUnsignedChar:1]; + + aclArgument = temp_0; + } + [cluster writeAttributeAclWithValue:aclArgument + completionHandler:^(NSError * _Nullable err) { + NSLog(@"Install ACL for QueryImage Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestStopTheRequestor_5() + { + chip::app::Clusters::SystemCommands::Commands::Stop::Type value; + return Stop("alpha", value); + } + + CHIP_ERROR TestStartTheRequestorWithAnOtaDownloadPath_6() + { + chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.otaDownloadPath.Emplace(); + value.otaDownloadPath.Value() = mDownloadImageFilePath.HasValue() ? mDownloadImageFilePath.Value() + : chip::Span("/tmp/downloadedImage", 20); + return Start("alpha", value); + } + + CHIP_ERROR TestWaitForTheCommissionedRequestorToBeRetrievedForAlpha_7() + { + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mRequestorNodeId.HasValue() ? mRequestorNodeId.Value() : 305414945ULL; + return WaitForCommissionee("alpha", value); + } + + CHIP_ERROR TestSendAnAnnounceOtaProviderCommandToTheRequestor_8() + { + CHIPDevice * device = GetDevice("alpha"); + CHIPTestOtaSoftwareUpdateRequestor * cluster = [[CHIPTestOtaSoftwareUpdateRequestor alloc] initWithDevice:device + endpoint:0 + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[CHIPOtaSoftwareUpdateRequestorClusterAnnounceOtaProviderParams alloc] init]; + params.providerNodeId = mProviderNodeId.HasValue() ? [NSNumber numberWithUnsignedLongLong:mProviderNodeId.Value()] + : [NSNumber numberWithUnsignedLongLong:12648430ULL]; + params.vendorId = [NSNumber numberWithUnsignedShort:0U]; + params.announcementReason = [NSNumber numberWithUnsignedChar:0]; + params.endpoint + = mEndpoint.HasValue() ? [NSNumber numberWithUnsignedShort:mEndpoint.Value()] : [NSNumber numberWithUnsignedShort:0U]; + [cluster announceOtaProviderWithParams:params + completionHandler:^(NSError * _Nullable err) { + NSLog(@"Send an announce OTA provider command to the requestor Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestWaitForTransferCompleteMessage_9() + { + chip::app::Clusters::DelayCommands::Commands::WaitForMessage::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); + value.message = chip::Span("OTA image downloadedgarbage: not in length on purpose", 20); + return WaitForMessage("alpha", value); + } + + CHIP_ERROR TestCompareOriginalFileToDownloadedFile_10() + { + chip::app::Clusters::SystemCommands::Commands::CompareFiles::Type value; + value.file1 = mRawImageFilePath.HasValue() ? mRawImageFilePath.Value() : chip::Span("/tmp/rawImage", 13); + value.file2 = mDownloadImageFilePath.HasValue() ? mDownloadImageFilePath.Value() + : chip::Span("/tmp/downloadedImage", 20); + return CompareFiles("alpha", value); + } +}; + class Test_TC_OCC_1_1 : public TestCommandBridge { public: // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced @@ -93554,6 +93871,8 @@ class TestSystemCommands : public TestCommandBridge { CHIP_ERROR TestStartTheDefaultAccessoryByKeyWithAllCommandLineOptions_10() { chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); value.discriminator.Emplace(); value.discriminator.Value() = 1111U; value.port.Emplace(); @@ -93562,22 +93881,20 @@ class TestSystemCommands : public TestCommandBridge { value.kvs.Value() = chip::Span("/tmp/chip_kvs_defaultgarbage: not in length on purpose", 21); value.minCommissioningTimeout.Emplace(); value.minCommissioningTimeout.Value() = 10U; - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); return Start("alpha", value); } CHIP_ERROR TestStartASecondAccessoryWithAllCommandLineOptions_11() { chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); value.discriminator.Emplace(); value.discriminator.Value() = 50U; value.port.Emplace(); value.port.Value() = 5561U; value.kvs.Emplace(); value.kvs.Value() = chip::Span("/tmp/chip_kvs_lockgarbage: not in length on purpose", 18); - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); return Start("alpha", value); } @@ -93607,14 +93924,14 @@ class TestSystemCommands : public TestCommandBridge { CHIP_ERROR TestStartASecondAccessoryWithDifferentKvs_15() { chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); value.discriminator.Emplace(); value.discriminator.Value() = 50U; value.port.Emplace(); value.port.Value() = 5561U; value.kvs.Emplace(); value.kvs.Value() = chip::Span("/tmp/chip_kvs_lock2garbage: not in length on purpose", 19); - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); return Start("alpha", value); } @@ -109129,6 +109446,7 @@ void registerCommandsTests(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), make_unique(), make_unique(), make_unique(), diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 1699e6c17884e1..7c065491adcfdf 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -129,6 +129,7 @@ class TestList : public Command printf("Test_TC_MF_1_5\n"); printf("Test_TC_MF_1_6\n"); printf("Test_TC_MF_1_15\n"); + printf("OTA_SuccessfulTransfer\n"); printf("Test_TC_OCC_1_1\n"); printf("Test_TC_OCC_2_1\n"); printf("Test_TC_OCC_2_2\n"); @@ -22791,6 +22792,241 @@ class Test_TC_MF_1_15Suite : public TestCommand } }; +class OTA_SuccessfulTransferSuite : public TestCommand +{ +public: + OTA_SuccessfulTransferSuite(CredentialIssuerCommands * credsIssuerConfig) : + TestCommand("OTA_SuccessfulTransfer", 11, credsIssuerConfig) + { + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("requestorNodeId", 0, UINT64_MAX, &mRequestorNodeId); + AddArgument("providerNodeId", 0, UINT64_MAX, &mProviderNodeId); + AddArgument("providerPayload", &mProviderPayload); + AddArgument("providerDiscriminator", 0, UINT16_MAX, &mProviderDiscriminator); + AddArgument("providerPort", 0, UINT16_MAX, &mProviderPort); + AddArgument("providerKvs", &mProviderKvs); + AddArgument("otaImageFilePath", &mOtaImageFilePath); + AddArgument("rawImageFilePath", &mRawImageFilePath); + AddArgument("rawImageContent", &mRawImageContent); + AddArgument("downloadImageFilePath", &mDownloadImageFilePath); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + + ~OTA_SuccessfulTransferSuite() {} + + chip::System::Clock::Timeout GetWaitDuration() const override + { + return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds)); + } + +private: + chip::Optional mEndpoint; + chip::Optional mRequestorNodeId; + chip::Optional mProviderNodeId; + chip::Optional mProviderPayload; + chip::Optional mProviderDiscriminator; + chip::Optional mProviderPort; + chip::Optional mProviderKvs; + chip::Optional mOtaImageFilePath; + chip::Optional mRawImageFilePath; + chip::Optional mRawImageContent; + chip::Optional mDownloadImageFilePath; + chip::Optional mTimeout; + + chip::EndpointId GetEndpoint(chip::EndpointId endpoint) { return mEndpoint.HasValue() ? mEndpoint.Value() : endpoint; } + + // + // Tests methods + // + + void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override + { + bool shouldContinue = false; + + switch (mTestIndex - 1) + { + case 0: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 1: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 2: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 3: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 4: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 5: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 6: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 7: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 8: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 9: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 10: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + default: + LogErrorOnFailure(ContinueOnChipMainThread(CHIP_ERROR_INVALID_ARGUMENT)); + } + + if (shouldContinue) + { + ContinueOnChipMainThread(CHIP_NO_ERROR); + } + } + + CHIP_ERROR DoTestStep(uint16_t testIndex) override + { + using namespace chip::app::Clusters; + switch (testIndex) + { + case 0: { + LogStep(0, "Create OTA image"); + chip::app::Clusters::SystemCommands::Commands::CreateOtaImage::Type value; + value.otaImageFilePath = + mOtaImageFilePath.HasValue() ? mOtaImageFilePath.Value() : chip::Span("/tmp/otaImage", 13); + value.rawImageFilePath = + mRawImageFilePath.HasValue() ? mRawImageFilePath.Value() : chip::Span("/tmp/rawImage", 13); + value.rawImageContent = + mRawImageContent.HasValue() ? mRawImageContent.Value() : chip::Span("Have a hootenanny!", 18); + return CreateOtaImage(kIdentityAlpha, value); + } + case 1: { + LogStep(1, "Start the provider with an image"); + chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-ota-provider-appgarbage: not in length on purpose", 21); + value.discriminator.Emplace(); + value.discriminator.Value() = mProviderDiscriminator.HasValue() ? mProviderDiscriminator.Value() : 50U; + value.port.Emplace(); + value.port.Value() = mProviderPort.HasValue() ? mProviderPort.Value() : 5560U; + value.kvs.Emplace(); + value.kvs.Value() = + mProviderKvs.HasValue() ? mProviderKvs.Value() : chip::Span("/tmp/chip_kvs_provider", 22); + value.filepath.Emplace(); + value.filepath.Value() = + mOtaImageFilePath.HasValue() ? mOtaImageFilePath.Value() : chip::Span("/tmp/otaImage", 13); + return Start(kIdentityAlpha, value); + } + case 2: { + LogStep(2, "Commission the provider from alpha"); + chip::app::Clusters::CommissionerCommands::Commands::PairWithQRCode::Type value; + value.nodeId = mProviderNodeId.HasValue() ? mProviderNodeId.Value() : 12648430ULL; + value.payload = + mProviderPayload.HasValue() ? mProviderPayload.Value() : chip::Span("MT:-24J0IX4122-.548G00", 22); + return PairWithQRCode(kIdentityAlpha, value); + } + case 3: { + LogStep(3, "Wait for the commissioned provider to be retrieved for alpha"); + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mProviderNodeId.HasValue() ? mProviderNodeId.Value() : 12648430ULL; + return WaitForCommissionee(kIdentityAlpha, value); + } + case 4: { + LogStep(4, "Install ACL for QueryImage"); + ListFreer listFreer; + chip::app::DataModel::List value; + + { + auto * listHolder_0 = new ListHolder(2); + listFreer.add(listHolder_0); + + listHolder_0->mList[0].privilege = static_cast(5); + listHolder_0->mList[0].authMode = static_cast(2); + listHolder_0->mList[0].subjects.SetNonNull(); + + { + auto * listHolder_3 = new ListHolder(1); + listFreer.add(listHolder_3); + listHolder_3->mList[0] = 112233ULL; + listHolder_0->mList[0].subjects.Value() = chip::app::DataModel::List(listHolder_3->mList, 1); + } + listHolder_0->mList[0].targets.SetNull(); + listHolder_0->mList[0].fabricIndex = 1; + + listHolder_0->mList[1].privilege = static_cast(3); + listHolder_0->mList[1].authMode = static_cast(2); + listHolder_0->mList[1].subjects.SetNull(); + listHolder_0->mList[1].targets.SetNull(); + listHolder_0->mList[1].fabricIndex = 1; + + value = chip::app::DataModel::List( + listHolder_0->mList, 2); + } + return WriteAttribute(kIdentityAlpha, GetEndpoint(0), AccessControl::Id, AccessControl::Attributes::Acl::Id, value); + } + case 5: { + LogStep(5, "Stop the requestor"); + chip::app::Clusters::SystemCommands::Commands::Stop::Type value; + return Stop(kIdentityAlpha, value); + } + case 6: { + LogStep(6, "Start the requestor with an OTA download path"); + chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.otaDownloadPath.Emplace(); + value.otaDownloadPath.Value() = mDownloadImageFilePath.HasValue() ? mDownloadImageFilePath.Value() + : chip::Span("/tmp/downloadedImage", 20); + return Start(kIdentityAlpha, value); + } + case 7: { + LogStep(7, "Wait for the commissioned requestor to be retrieved for alpha"); + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mRequestorNodeId.HasValue() ? mRequestorNodeId.Value() : 305414945ULL; + return WaitForCommissionee(kIdentityAlpha, value); + } + case 8: { + LogStep(8, "Send an announce OTA provider command to the requestor"); + chip::app::Clusters::OtaSoftwareUpdateRequestor::Commands::AnnounceOtaProvider::Type value; + value.providerNodeId = mProviderNodeId.HasValue() ? mProviderNodeId.Value() : 12648430ULL; + value.vendorId = static_cast(0); + value.announcementReason = static_cast(0); + value.endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0U; + return SendCommand(kIdentityAlpha, GetEndpoint(0), OtaSoftwareUpdateRequestor::Id, + OtaSoftwareUpdateRequestor::Commands::AnnounceOtaProvider::Id, value); + } + case 9: { + LogStep(9, "Wait for transfer complete message"); + chip::app::Clusters::DelayCommands::Commands::WaitForMessage::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); + value.message = chip::Span("OTA image downloadedgarbage: not in length on purpose", 20); + return WaitForMessage(kIdentityAlpha, value); + } + case 10: { + LogStep(10, "Compare original file to downloaded file"); + chip::app::Clusters::SystemCommands::Commands::CompareFiles::Type value; + value.file1 = mRawImageFilePath.HasValue() ? mRawImageFilePath.Value() : chip::Span("/tmp/rawImage", 13); + value.file2 = mDownloadImageFilePath.HasValue() ? mDownloadImageFilePath.Value() + : chip::Span("/tmp/downloadedImage", 20); + return CompareFiles(kIdentityAlpha, value); + } + } + return CHIP_NO_ERROR; + } +}; + class Test_TC_OCC_1_1Suite : public TestCommand { public: @@ -50323,6 +50559,8 @@ class TestSystemCommandsSuite : public TestCommand case 10: { LogStep(10, "Start the default accessory by key with all command line options"); chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); value.discriminator.Emplace(); value.discriminator.Value() = 1111U; value.port.Emplace(); @@ -50331,21 +50569,19 @@ class TestSystemCommandsSuite : public TestCommand value.kvs.Value() = chip::Span("/tmp/chip_kvs_defaultgarbage: not in length on purpose", 21); value.minCommissioningTimeout.Emplace(); value.minCommissioningTimeout.Value() = 10U; - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("defaultgarbage: not in length on purpose", 7); return Start(kIdentityAlpha, value); } case 11: { LogStep(11, "Start a second accessory with all command line options"); chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); value.discriminator.Emplace(); value.discriminator.Value() = 50U; value.port.Emplace(); value.port.Value() = 5561U; value.kvs.Emplace(); value.kvs.Value() = chip::Span("/tmp/chip_kvs_lockgarbage: not in length on purpose", 18); - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); return Start(kIdentityAlpha, value); } case 12: { @@ -50371,14 +50607,14 @@ class TestSystemCommandsSuite : public TestCommand case 15: { LogStep(15, "Start a second accessory with different KVS"); chip::app::Clusters::SystemCommands::Commands::Start::Type value; + value.registerKey.Emplace(); + value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); value.discriminator.Emplace(); value.discriminator.Value() = 50U; value.port.Emplace(); value.port.Value() = 5561U; value.kvs.Emplace(); value.kvs.Value() = chip::Span("/tmp/chip_kvs_lock2garbage: not in length on purpose", 19); - value.registerKey.Emplace(); - value.registerKey.Value() = chip::Span("chip-lock-appgarbage: not in length on purpose", 13); return Start(kIdentityAlpha, value); } case 16: { @@ -72845,6 +73081,7 @@ void registerCommandsTests(Commands & commands, CredentialIssuerCommands * creds make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig),