blob: 37e432083a781ad744a1831a6cfc0cbbf9ebabe4 [file] [log] [blame]
// 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