| // Copyright 2021 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/config.hpp> |
| #include <nlohmann/json.hpp> |
| #include <stdplus/gtest/tmp.hpp> |
| |
| #include <fstream> |
| #include <string> |
| |
| #include <gtest/gtest.h> |
| |
| namespace flashupdate |
| { |
| |
| class ConfigTest : public stdplus::gtest::TestWithTmp |
| {}; |
| |
| TEST_F(ConfigTest, EmptyConfig) |
| { |
| std::ofstream testfile; |
| std::string emptyFilename = CaseTmpDir() + "/empty.json"; |
| testfile.open(emptyFilename, std::ios::out); |
| auto empty = R"({})"_json; |
| testfile << empty.dump(); |
| testfile.flush(); |
| |
| EXPECT_THROW(createConfig(emptyFilename, 0), |
| nlohmann::detail::out_of_range); |
| } |
| |
| TEST_F(ConfigTest, ValidConfigWithMissingPirmaryMuxSelect) |
| { |
| std::ofstream testfile; |
| std::string missingPrimaryMuxFilename = |
| CaseTmpDir() + "/missing_primary_mux.json"; |
| testfile.open(missingPrimaryMuxFilename, std::ios::out); |
| auto valid = R"( |
| { |
| "flash": { |
| "validation_key": ["prod.pem", "dev.pem"], |
| "primary": { |
| "location": "mtd,primary", |
| "mux_select": null |
| }, |
| "secondary": [ |
| { |
| "location": "mtd,secondary0", |
| "mux_select": null |
| } |
| ], |
| "device_id": "device_id", |
| "driver": "/tmp/driver" |
| }, |
| "metadata": { |
| "path": "fake,type=simple,erase=0,metadata", |
| "offset": 0 |
| }, |
| "cr51": null |
| } |
| )"_json; |
| testfile << valid.dump(); |
| testfile.flush(); |
| |
| EXPECT_THROW(createConfig(missingPrimaryMuxFilename, 0), |
| std::runtime_error); |
| } |
| |
| TEST_F(ConfigTest, ValidConfigWithMissingCR51Property) |
| { |
| std::ofstream testfile; |
| std::string missingCr51Filename = CaseTmpDir() + "/missing_cr51.json"; |
| testfile.open(missingCr51Filename, std::ios::out); |
| auto valid = R"( |
| { |
| "flash": { |
| "validation_key": ["prod.pem", "dev.pem"], |
| "primary": { |
| "location": "mtd,primary", |
| "mux_select": null |
| }, |
| "secondary": [ |
| { |
| "location": "mtd,secondary0", |
| "mux_select": null |
| } |
| ], |
| "device_id": "device_id", |
| "driver": "/tmp/driver" |
| }, |
| "metadata": { |
| "path": "fake,type=simple,erase=0,metadata", |
| "offset": 0 |
| }, |
| "cr51": { |
| "prod_to_dev": false, |
| "image_family": 3 |
| } |
| } |
| )"_json; |
| testfile << valid.dump(); |
| testfile.flush(); |
| |
| EXPECT_THROW(createConfig(missingCr51Filename, 0), std::runtime_error); |
| } |
| |
| TEST_F(ConfigTest, ValidConfig) |
| { |
| std::ofstream testfile; |
| std::string validFilename = CaseTmpDir() + "/valid.json"; |
| // Example, validFilename should be /tmp/valid.json |
| // name = "valid" |
| // configPath = CaseTmpDir() |
| std::string configPath = CaseTmpDir() + "/"; |
| size_t index = configPath.size(); // /tmp/ |
| std::string name = |
| validFilename.substr(index, validFilename.size() - index - /*.json*/ 5); |
| testfile.open(validFilename, std::ios::out); |
| auto valid = R"( |
| { |
| "flash": { |
| "validation_key": ["prod.pem", "dev.pem"], |
| "primary": { |
| "location": "mtd,primary", |
| "mux_select": 1 |
| }, |
| "secondary": [ |
| { |
| "location": "mtd,secondary0", |
| "mux_select": null |
| }, |
| { |
| "location": "mtd,secondary1", |
| "mux_select": 2 |
| } |
| ], |
| "device_id": "device_id", |
| "driver": "/tmp/driver" |
| }, |
| "metadata": { |
| "path": "fake,type=simple,erase=0,metadata", |
| "offset": 128 |
| }, |
| "cr51": { |
| "prod_to_dev": false, |
| "production_mode": true, |
| "unsigned_to_dev": true, |
| "image_family": 3 |
| }, |
| "supported_version": [{ |
| "min": { |
| "major": 10, |
| "minor": 10, |
| "point": 10, |
| "subpoint": 10 |
| } |
| }, |
| { |
| "max": { |
| "major": 10, |
| "minor": 10, |
| "point": 10, |
| "subpoint": 10 |
| } |
| }] |
| } |
| )"_json; |
| testfile << valid.dump(); |
| testfile.flush(); |
| std::vector<std::string> expectedKey = {"prod.pem", "dev.pem"}; |
| |
| // Test auto config finding with wrong path |
| EXPECT_THROW(createConfig(name, 0, "/bad/"), std::runtime_error); |
| |
| // Test Invalid secondary index |
| // secondary index > count(secondaries) |
| EXPECT_THROW(createConfig(validFilename, 3), std::runtime_error); |
| |
| // Test Validate Json Config |
| auto config = createConfig(validFilename, 1); |
| |
| // Test auto config finding |
| auto config1 = createConfig(name, 1, configPath); |
| EXPECT_EQ(config, config1); |
| |
| // BIOS |
| EXPECT_EQ(config.flash.deviceId, "device_id"); |
| EXPECT_EQ(config.flash.driver, "/tmp/driver"); |
| EXPECT_EQ(config.flash.stagingIndex, 1); |
| |
| // BIOS Public Key |
| EXPECT_TRUE(config.flash.validationKey == expectedKey); |
| |
| // BIOS Primary |
| EXPECT_EQ(config.flash.primary.location, "mtd,primary"); |
| EXPECT_EQ(config.flash.primary.muxSelect, 1); |
| |
| // BIOS Secondary |
| ASSERT_EQ(config.flash.secondary.size(), 2); |
| EXPECT_EQ(config.flash.secondary[0].location, "mtd,secondary0"); |
| EXPECT_EQ(config.flash.secondary[0].muxSelect, std::nullopt); |
| EXPECT_EQ(config.flash.secondary[1].location, "mtd,secondary1"); |
| EXPECT_EQ(config.flash.secondary[1].muxSelect, 2); |
| |
| // METADATA |
| EXPECT_EQ(config.metadata.offset, 128); |
| EXPECT_EQ(config.metadata.path, "fake,type=simple,erase=0,metadata"); |
| |
| // CR51 Config |
| EXPECT_EQ(config.cr51->imageFamily, 3); |
| EXPECT_FALSE(config.cr51->prodToDev); |
| EXPECT_TRUE(config.cr51->productionMode); |
| EXPECT_TRUE(config.cr51->unsignedToDev); |
| |
| // CR51 Config |
| std::string versionStr = "10.10.10.10"; |
| auto version = version::Version(versionStr); |
| ASSERT_NE(config.supportedVersion, std::nullopt); |
| ASSERT_EQ(config.supportedVersion->size(), 2); |
| EXPECT_EQ((*config.supportedVersion)[0].min, version); |
| EXPECT_EQ((*config.supportedVersion)[0].max, std::nullopt); |
| EXPECT_EQ((*config.supportedVersion)[1].min, std::nullopt); |
| EXPECT_EQ((*config.supportedVersion)[1].max, version); |
| } |
| |
| } // namespace flashupdate |