| // Copyright 2024 Google LLC |
| // |
| // 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. |
| |
| #include <flashupdate/args.hpp> |
| #include <nlohmann/json.hpp> |
| #include <stdplus/gtest/tmp.hpp> |
| |
| #include <fstream> |
| #include <stdexcept> |
| #include <string> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| namespace flashupdate |
| { |
| |
| using flasher::ModArgs; |
| |
| class ArgsTest : public stdplus::gtest::TestWithTmp |
| { |
| protected: |
| ArgsTest() |
| { |
| createConfig(); |
| } |
| |
| void createConfig() |
| { |
| testName = CaseTmpDir() + "/test-config.json"; |
| close(mkstemps(testName.data(), 5)); |
| std::ofstream testfile; |
| testfile.open(testName, std::ios::out); |
| auto good = R"( |
| { |
| "flash": { |
| "validation_key": ["prod.pem", "dev.pem"], |
| "primary": { |
| "location": "mtd,primary", |
| "mux_select": 1 |
| }, |
| "secondary": [ |
| { |
| "location": "mtd,secondary0", |
| "mux_select": null |
| }, |
| { |
| "location": "mtd,secondary3", |
| "mux_select": 2 |
| } |
| ], |
| "device_id": "device_id", |
| "driver": "/tmp/driver" |
| }, |
| "metadata": { |
| "path": "fake,type=simple,erase=0,metadata", |
| "offset": 0 |
| }, |
| "cr51": null |
| } |
| )"_json; |
| testfile << good.dump(); |
| testfile.flush(); |
| } |
| |
| Args vecArgs(std::vector<std::string> args) |
| { |
| // Setting required configuration file. |
| // Default to `/usr/share/flash-update/config.json` |
| args.push_back("-j"); |
| args.push_back(testName); |
| |
| std::vector<char*> argv; |
| for (auto& arg : args) |
| argv.push_back(arg.data()); |
| |
| argv.push_back(nullptr); |
| return Args(args.size(), argv.data()); |
| } |
| |
| std::string testName; |
| }; |
| |
| TEST_F(ArgsTest, OpRequired) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "-v"}), std::runtime_error); |
| } |
| |
| TEST_F(ArgsTest, ConfigRequired) |
| { |
| std::vector<std::string> args = {"flashupdate", "validate_config"}; |
| std::vector<char*> argv; |
| for (auto& arg : args) |
| { |
| argv.push_back(arg.data()); |
| } |
| argv.push_back(nullptr); |
| |
| EXPECT_THROW(Args(args.size(), argv.data()), std::runtime_error); |
| EXPECT_EQ(vecArgs({"flashupdate", "validate_config"}).configFile, testName); |
| } |
| |
| TEST_F(ArgsTest, HashDescriptor) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "hash_descriptor"}), |
| std::runtime_error); |
| auto args = vecArgs({"flashupdate", "hash_descriptor", "file"}); |
| |
| EXPECT_EQ(args.op, Args::Op::HashDescriptor); |
| EXPECT_EQ(args.file, ModArgs("file")); |
| } |
| |
| TEST_F(ArgsTest, ReadTest) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "read"}), std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "read", "primary"}), |
| std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "read", "other", "file"}), |
| std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "read", "secondary/x", "file"}), |
| std::runtime_error); |
| |
| auto args = vecArgs({"flashupdate", "read", "primary", "file"}); |
| EXPECT_EQ(args.op, Args::Op::Read); |
| EXPECT_EQ(args.file, ModArgs("file")); |
| EXPECT_EQ(args.primary, true); |
| EXPECT_EQ(args.stagingIndex, 0); |
| |
| args = vecArgs({"flashupdate", "read", "secondary/0", "file"}); |
| EXPECT_EQ(args.op, Args::Op::Read); |
| EXPECT_EQ(args.file, ModArgs("file")); |
| EXPECT_EQ(args.primary, false); |
| EXPECT_EQ(args.stagingIndex, 0); |
| } |
| |
| TEST_F(ArgsTest, WriteTest) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "write"}), std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "write", "file"}), std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "write", "file", "other"}), |
| std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "write", "file", "secondary/x"}), |
| std::runtime_error); |
| |
| auto args = vecArgs({"flashupdate", "write", "file", "primary"}); |
| EXPECT_EQ(args.op, Args::Op::Write); |
| EXPECT_EQ(args.file, ModArgs("file")); |
| EXPECT_EQ(args.primary, true); |
| EXPECT_EQ(args.stagingIndex, 0); |
| |
| args = vecArgs({"flashupdate", "write", "file", "secondary/0"}); |
| EXPECT_EQ(args.op, Args::Op::Write); |
| EXPECT_EQ(args.file, ModArgs("file")); |
| EXPECT_EQ(args.primary, false); |
| EXPECT_EQ(args.stagingIndex, 0); |
| } |
| |
| TEST_F(ArgsTest, UpdateStateTest) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "update_state"}), std::runtime_error); |
| |
| auto args = vecArgs({"flashupdate", "update_state", "state"}); |
| EXPECT_EQ(args.op, Args::Op::UpdateState); |
| EXPECT_EQ(args.file, std::nullopt); |
| EXPECT_EQ(args.state, "state"); |
| } |
| |
| TEST_F(ArgsTest, Verbose) |
| { |
| EXPECT_EQ(0, vecArgs({"flashupdate", "validate_config"}).verbose); |
| EXPECT_EQ( |
| 4, vecArgs({"flashupdate", "--verbose", "-v", "validate_config", "-vv"}) |
| .verbose); |
| } |
| |
| TEST_F(ArgsTest, ActiveVersion) |
| { |
| EXPECT_EQ( |
| false, |
| vecArgs({"flashupdate", "validate_config", "-s"}).checkActiveVersion); |
| |
| // No options will also set the flag to be true |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config"}).checkActiveVersion); |
| EXPECT_EQ( |
| true, |
| vecArgs({"flashupdate", "validate_config", "-a"}).checkActiveVersion); |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config", "--active_version"}) |
| .checkActiveVersion); |
| } |
| |
| TEST_F(ArgsTest, CleanOutput) |
| { |
| EXPECT_EQ(false, vecArgs({"flashupdate", "validate_config"}).cleanOutput); |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config", "-c"}).cleanOutput); |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config", "--clean_output"}) |
| .cleanOutput); |
| } |
| |
| TEST_F(ArgsTest, StageState) |
| { |
| EXPECT_EQ( |
| false, |
| vecArgs({"flashupdate", "validate_config", "-a"}).checkStageState); |
| |
| // No options will also set the flag to be true |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config"}).checkStageState); |
| EXPECT_EQ( |
| true, |
| vecArgs({"flashupdate", "validate_config", "-S"}).checkStageState); |
| EXPECT_EQ(true, vecArgs({"flashupdate", "validate_config", "--stage_state"}) |
| .checkStageState); |
| } |
| |
| TEST_F(ArgsTest, StageVersion) |
| { |
| EXPECT_EQ( |
| false, |
| vecArgs({"flashupdate", "validate_config", "-a"}).checkStagedVersion); |
| |
| // No options will also set the flag to be true |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config"}).checkStagedVersion); |
| EXPECT_EQ( |
| true, |
| vecArgs({"flashupdate", "validate_config", "-s"}).checkStagedVersion); |
| EXPECT_EQ(true, |
| vecArgs({"flashupdate", "validate_config", "--staged_version"}) |
| .checkStagedVersion); |
| } |
| |
| TEST_F(ArgsTest, KeepMux) |
| { |
| EXPECT_EQ(false, vecArgs({"flashupdate", "validate_config"}).keepMux); |
| EXPECT_EQ(true, vecArgs({"flashupdate", "validate_config", "-k"}).keepMux); |
| EXPECT_EQ( |
| true, |
| vecArgs({"flashupdate", "validate_config", "--keep_mux"}).keepMux); |
| } |
| |
| TEST_F(ArgsTest, CopyPartition) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "copy_partition"}), |
| std::runtime_error); |
| EXPECT_THROW( |
| vecArgs({"flashupdate", "copy_partition", "primary", "primary"}), |
| std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "copy_partition", "secondary/0", |
| "secondary/0"}), |
| std::runtime_error); |
| |
| EXPECT_EQ(false, vecArgs({"flashupdate", "copy_partition", "primary", |
| "secondary/0"}) |
| .primary); |
| EXPECT_EQ( |
| 1, vecArgs({"flashupdate", "copy_partition", "primary", "secondary/1"}) |
| .stagingIndex); |
| |
| EXPECT_EQ(true, vecArgs({"flashupdate", "copy_partition", "secondary/0", |
| "primary"}) |
| .primary); |
| auto args = |
| vecArgs({"flashupdate", "copy_partition", "secondary/1", "primary"}); |
| |
| EXPECT_EQ(args.fromPartition, 1); |
| EXPECT_EQ(args.toPartition, std::nullopt); |
| } |
| |
| TEST_F(ArgsTest, Erase) |
| { |
| EXPECT_THROW(vecArgs({"flashupdate", "erase"}), std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "erase", "random"}), |
| std::runtime_error); |
| EXPECT_THROW(vecArgs({"flashupdate", "erase", "primary"}), |
| std::runtime_error); |
| auto args = vecArgs({"flashupdate", "erase", "secondary/1"}); |
| |
| EXPECT_EQ(args.primary, false); |
| EXPECT_EQ(args.stagingIndex, 1); |
| } |
| |
| } // namespace flashupdate |