Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
config_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <iostream>
4 #include <string>
5 
6 #include <boost/algorithm/hex.hpp>
7 #include <boost/filesystem.hpp>
8 #include <boost/program_options.hpp>
9 
10 #include "bootstrap/bootstrap.h"
11 #include "config/config.h"
12 #include "crypto/crypto.h"
13 #include "test_utils.h"
14 #include "utilities/utils.h"
15 
16 namespace bpo = boost::program_options;
17 boost::filesystem::path build_dir;
18 
19 TEST(config, DefaultValues) {
20  Config conf;
21  EXPECT_EQ(conf.uptane.key_type, KeyType::kRSA2048);
22  EXPECT_EQ(conf.uptane.polling_sec, 10u);
23 }
24 
25 TEST(config, TomlBasic) {
26  Config conf("tests/config/basic.toml");
27  EXPECT_EQ(conf.pacman.type, PACKAGE_MANAGER_NONE);
28 }
29 
30 TEST(config, TomlEmpty) {
31  Config conf;
32  conf.updateFromTomlString("");
33  EXPECT_EQ(conf.uptane.key_type, KeyType::kRSA2048);
34  EXPECT_EQ(conf.uptane.polling_sec, 10u);
35 }
36 
37 TEST(config, TomlInt) {
38  Config conf;
39  conf.updateFromTomlString("[uptane]\nkey_type = \"ED25519\"\npolling_sec = 99\n");
40  EXPECT_EQ(conf.uptane.key_type, KeyType::kED25519);
41  EXPECT_EQ(conf.uptane.polling_sec, 99u);
42 }
43 
44 /*
45  * Check that user can specify Primary serial via a config file.
46  */
47 TEST(config, TomlPrimarySerial) {
48  RecordProperty("zephyr_key", "OTA-988");
49  Config conf("tests/config/testupdate.toml");
50  EXPECT_EQ(conf.provision.primary_ecu_serial, "723f79763eda1c753ce565c16862c79acdde32eb922d6662f088083c51ffde66");
51 }
52 
53 /*
54  * Check that user can specify Primary serial on the command line.
55  */
56 TEST(config, CmdlPrimarySerial) {
57  RecordProperty("zephyr_key", "OTA-988");
58  constexpr int argc = 5;
59  const char *argv[argc] = {"./aktualizr", "--primary-ecu-serial", "test-serial", "-c", "tests/config/minimal.toml"};
60 
61  bpo::options_description description("CommandLine Options");
62  // clang-format off
63  description.add_options()
64  ("primary-ecu-serial", bpo::value<std::string>(), "serial number of primary ecu")
65  ("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration directory");
66  // clang-format on
67 
68  bpo::variables_map vm;
69  bpo::store(bpo::parse_command_line(argc, argv, description), vm);
70  Config conf(vm);
71 
72  EXPECT_EQ(conf.provision.primary_ecu_serial, "test-serial");
73 }
74 
75 /*
76  * Extract credentials from a provided archive.
77  */
78 TEST(config, ExtractCredentials) {
79  TemporaryDirectory temp_dir;
80  Config conf;
81  conf.storage.path = temp_dir.Path();
82  conf.provision.provision_path = "tests/test_data/credentials.zip";
83  conf.tls.server.clear();
84  conf.postUpdateValues();
85  EXPECT_EQ(conf.tls.server, "https://bd8012b4-cf0f-46ca-9d2c-46a41d534af5.tcpgw.prod01.advancedtelematic.com:443");
86 
87  Bootstrap boot(conf.provision.provision_path, "");
88  EXPECT_EQ(boost::algorithm::hex(Crypto::sha256digest(boot.getCa())),
89  "FBA3C8FAD16D8B3EC64F7D47CBDD8456A51A6399734A3F6B7E2D6E562072F264");
90  std::cout << "Certificate: " << boot.getCert() << std::endl;
91  EXPECT_EQ(boost::algorithm::hex(Crypto::sha256digest(boot.getCert())),
92  "02300CC9797556915D88CFA05644BFF22D8C458367A3636F7921585F828ECB81");
93  std::cout << "Pkey: " << boot.getPkey() << std::endl;
94  EXPECT_EQ(boost::algorithm::hex(Crypto::sha256digest(boot.getPkey())),
95  "D27E3E56BEF02AAA6D6FFEFDA5357458C477A8E891C5EADF4F04CE67BB5866A4");
96 }
97 
98 /**
99  * Start in device credential provisioning mode.
100  */
101 TEST(config, DeviceCredMode) {
102  RecordProperty("zephyr_key", "OTA-996,TST-184");
103  Config config;
104  EXPECT_EQ(config.provision.mode, ProvisionMode::kDeviceCred);
105 }
106 
107 /**
108  * Start in shared credential provisioning mode.
109  */
110 TEST(config, SharedCredMode) {
111  Config config("tests/config/basic.toml");
112  EXPECT_EQ(config.provision.mode, ProvisionMode::kSharedCred);
113 }
114 
115 /* Write config to file or to the log.
116  * We don't normally dump the config to file anymore, but we do write it to the
117  * log. */
118 TEST(config, TomlConsistentEmpty) {
119  TemporaryDirectory temp_dir;
120  Config config1;
121  std::ofstream sink1((temp_dir / "output1.toml").c_str(), std::ofstream::out);
122  config1.writeToStream(sink1);
123 
124  Config config2((temp_dir / "output1.toml").string());
125  std::ofstream sink2((temp_dir / "output2.toml").c_str(), std::ofstream::out);
126  config2.writeToStream(sink2);
127 
128  std::string conf_str1 = Utils::readFile((temp_dir / "output1.toml").string());
129  std::string conf_str2 = Utils::readFile((temp_dir / "output2.toml").string());
130  EXPECT_EQ(conf_str1, conf_str2);
131 }
132 
133 TEST(config, TomlConsistentNonempty) {
134  TemporaryDirectory temp_dir;
135  Config config1("tests/config/basic.toml");
136  std::ofstream sink1((temp_dir / "output1.toml").c_str(), std::ofstream::out);
137  config1.writeToStream(sink1);
138 
139  Config config2((temp_dir / "output1.toml").string());
140  std::ofstream sink2((temp_dir / "output2.toml").c_str(), std::ofstream::out);
141  config2.writeToStream(sink2);
142 
143  std::string conf_str1 = Utils::readFile((temp_dir / "output1.toml").string());
144  std::string conf_str2 = Utils::readFile((temp_dir / "output2.toml").string());
145  EXPECT_EQ(conf_str1, conf_str2);
146 }
147 
148 static std::vector<boost::filesystem::path> generate_multi_config(TemporaryDirectory &temp_dir) {
149  std::string content;
150  {
151  content += "[storage]\n";
152  content += "path = \"path_a\"\n";
153  content += "\n";
154  content += "[pacman]\n";
155  content += "os = \"os_a\"";
156  }
157  Utils::writeFile((temp_dir / "a_dir/a.toml"), content);
158 
159  content.clear();
160  {
161  content += "[storage]\n";
162  content += "path = \"path_z\"\n";
163  content += "\n";
164  content += "[pacman]\n";
165  content += "sysroot = \"sysroot_z\"";
166  }
167  Utils::writeFile((temp_dir / "a_dir/z.toml"), content);
168 
169  content.clear();
170  {
171  content += "[storage]\n";
172  content += "path = \"cecond_a\"";
173  }
174  Utils::writeFile((temp_dir / "b_dir/a.toml"), content);
175 
176  content.clear();
177  {
178  content += "[storage]\n";
179  content += "path = \"latest_path\"\n";
180  content += "\n";
181  content += "[provision]\n";
182  content += "provision_path = \"y_prov_path\"";
183  }
184  Utils::writeFile((temp_dir / "b_dir/y.toml"), content);
185 
186  content.clear();
187  {
188  content += "[storage]\n";
189  content += "path = \"this is path from text file\"";
190  }
191  Utils::writeFile((temp_dir / "b_dir/z.txt"), content);
192 
193  return std::vector<boost::filesystem::path>{(temp_dir / "a_dir"), (temp_dir / "b_dir")};
194 }
195 /* Parse multiple config files in a directory. */
196 TEST(config, OneDir) {
197  TemporaryDirectory temp_dir;
198  std::vector<boost::filesystem::path> dirs = generate_multi_config(temp_dir);
199 
200  Config config(std::vector<boost::filesystem::path>{dirs[0]});
201  EXPECT_EQ(config.storage.path.string(), "path_z");
202  EXPECT_EQ(config.pacman.sysroot.string(), "sysroot_z");
203  EXPECT_EQ(config.pacman.os, "os_a");
204 }
205 
206 /* Parse multiple config files in multiple directories. */
207 TEST(config, TwoDirs) {
208  TemporaryDirectory temp_dir;
209  std::vector<boost::filesystem::path> dirs = generate_multi_config(temp_dir);
210 
211  Config config(dirs);
212  EXPECT_EQ(config.storage.path.string(), "path_z");
213  EXPECT_EQ(config.pacman.sysroot.string(), "sysroot_z");
214  EXPECT_NE(config.pacman.os, "os_a");
215  EXPECT_EQ(config.provision.provision_path.string(), "y_prov_path");
216 }
217 
218 void checkConfigExpectations(const Config &conf) {
219  EXPECT_EQ(conf.storage.type, StorageType::kSqlite);
220  EXPECT_EQ(conf.pacman.type, PACKAGE_MANAGER_NONE);
221  EXPECT_EQ(conf.tls.ca_source, CryptoSource::kPkcs11);
222  EXPECT_EQ(conf.tls.pkey_source, CryptoSource::kPkcs11);
223  EXPECT_EQ(conf.tls.cert_source, CryptoSource::kPkcs11);
224  EXPECT_EQ(conf.uptane.key_source, CryptoSource::kPkcs11);
225  EXPECT_EQ(conf.uptane.key_type, KeyType::kED25519);
226  EXPECT_EQ(conf.bootloader.rollback_mode, RollbackMode::kUbootMasked);
227 }
228 
229 /* This test is designed to catch a bug in which storage.type and pacman.type
230  * set in the first config file read could be overwritten by the defaults when
231  * reading a second config file. */
232 TEST(config, TwoTomlCorrectness) {
233  TemporaryDirectory temp_dir;
234  const std::string conf_path_str = (temp_dir.Path() / "config.toml").string();
235  TestUtils::writePathToConfig("tests/config/minimal.toml", conf_path_str, temp_dir.Path());
236  {
237  std::ofstream cs(conf_path_str.c_str(), std::ofstream::app);
238  cs << "type = \"sqlite\"\n";
239  cs << "\n";
240  cs << "[pacman]\n";
241  cs << "type = \"none\"\n";
242  cs << "\n";
243  cs << "[tls]\n";
244  cs << "ca_source = \"pkcs11\"\n";
245  cs << "pkey_source = \"pkcs11\"\n";
246  cs << "cert_source = \"pkcs11\"\n";
247  cs << "\n";
248  cs << "[uptane]\n";
249  cs << "key_source = \"pkcs11\"\n";
250  cs << "key_type = \"ED25519\"\n";
251  cs << "\n";
252  cs << "[bootloader]\n";
253  cs << "rollback_mode = \"uboot_masked\"\n";
254  }
255 
256  bpo::variables_map cmd;
257  bpo::options_description description("some text");
258  // clang-format off
259  description.add_options()
260  ("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration directory");
261  // clang-format on
262 
263  const char *argv1[] = {"aktualizr", "-c", conf_path_str.c_str(), "-c", "tests/config/minimal.toml"};
264  bpo::store(bpo::parse_command_line(5, argv1, description), cmd);
265  Config conf1(cmd);
266  checkConfigExpectations(conf1);
267 
268  // Try the reverse order, too, just to make sure.
269  const char *argv2[] = {"aktualizr", "-c", "tests/config/minimal.toml", "-c", conf_path_str.c_str()};
270  bpo::store(bpo::parse_command_line(5, argv2, description), cmd);
271  Config conf2(cmd);
272  checkConfigExpectations(conf2);
273 }
274 
275 #ifndef __NO_MAIN__
276 int main(int argc, char **argv) {
277  ::testing::InitGoogleTest(&argc, argv);
278 
279  if (argc != 2) {
280  std::cerr << "Error: " << argv[0] << " requires the path to the build directory as an input argument.\n";
281  return EXIT_FAILURE;
282  }
283  build_dir = argv[1];
284  return RUN_ALL_TESTS();
285 }
286 #endif
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:74
TemporaryDirectory
Definition: utils.h:82
Bootstrap
Definition: bootstrap.h:7