Aktualizr
C++ SOTA Client
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 "crypto/crypto.h"
12 #include "libaktualizr/config.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("config/sota-local.toml");
112  EXPECT_EQ(config.provision.mode, ProvisionMode::kSharedCred);
113 }
114 
115 /**
116  * Start in shared credential provisioning mode with reuse.
117  */
118 TEST(config, SharedCredReuseMode) {
119  Config config("tests/config/basic.toml");
120  EXPECT_EQ(config.provision.mode, ProvisionMode::kSharedCredReuse);
121 }
122 
123 /* Write config to file or to the log.
124  * We don't normally dump the config to file anymore, but we do write it to the
125  * log. */
126 TEST(config, TomlConsistentEmpty) {
127  TemporaryDirectory temp_dir;
128  Config config1;
129  std::ofstream sink1((temp_dir / "output1.toml").c_str(), std::ofstream::out);
130  config1.writeToStream(sink1);
131 
132  Config config2((temp_dir / "output1.toml").string());
133  std::ofstream sink2((temp_dir / "output2.toml").c_str(), std::ofstream::out);
134  config2.writeToStream(sink2);
135 
136  std::string conf_str1 = Utils::readFile((temp_dir / "output1.toml").string());
137  std::string conf_str2 = Utils::readFile((temp_dir / "output2.toml").string());
138  EXPECT_EQ(conf_str1, conf_str2);
139 }
140 
141 TEST(config, TomlConsistentNonempty) {
142  TemporaryDirectory temp_dir;
143  Config config1("tests/config/basic.toml");
144  std::ofstream sink1((temp_dir / "output1.toml").c_str(), std::ofstream::out);
145  config1.writeToStream(sink1);
146 
147  Config config2((temp_dir / "output1.toml").string());
148  std::ofstream sink2((temp_dir / "output2.toml").c_str(), std::ofstream::out);
149  config2.writeToStream(sink2);
150 
151  std::string conf_str1 = Utils::readFile((temp_dir / "output1.toml").string());
152  std::string conf_str2 = Utils::readFile((temp_dir / "output2.toml").string());
153  EXPECT_EQ(conf_str1, conf_str2);
154 }
155 
156 static std::vector<boost::filesystem::path> generate_multi_config(TemporaryDirectory &temp_dir) {
157  std::string content;
158  {
159  content += "[storage]\n";
160  content += "path = \"path_a\"\n";
161  content += "\n";
162  content += "[pacman]\n";
163  content += "os = \"os_a\"";
164  }
165  Utils::writeFile((temp_dir / "a_dir/a.toml"), content);
166 
167  content.clear();
168  {
169  content += "[storage]\n";
170  content += "path = \"path_z\"\n";
171  content += "\n";
172  content += "[pacman]\n";
173  content += "sysroot = \"sysroot_z\"";
174  }
175  Utils::writeFile((temp_dir / "a_dir/z.toml"), content);
176 
177  content.clear();
178  {
179  content += "[storage]\n";
180  content += "path = \"cecond_a\"";
181  }
182  Utils::writeFile((temp_dir / "b_dir/a.toml"), content);
183 
184  content.clear();
185  {
186  content += "[storage]\n";
187  content += "path = \"latest_path\"\n";
188  content += "\n";
189  content += "[provision]\n";
190  content += "provision_path = \"y_prov_path\"";
191  }
192  Utils::writeFile((temp_dir / "b_dir/y.toml"), content);
193 
194  content.clear();
195  {
196  content += "[storage]\n";
197  content += "path = \"this is path from text file\"";
198  }
199  Utils::writeFile((temp_dir / "b_dir/z.txt"), content);
200 
201  return std::vector<boost::filesystem::path>{(temp_dir / "a_dir"), (temp_dir / "b_dir")};
202 }
203 /* Parse multiple config files in a directory. */
204 TEST(config, OneDir) {
205  TemporaryDirectory temp_dir;
206  std::vector<boost::filesystem::path> dirs = generate_multi_config(temp_dir);
207 
208  Config config(std::vector<boost::filesystem::path>{dirs[0]});
209  EXPECT_EQ(config.storage.path.string(), "path_z");
210  EXPECT_EQ(config.pacman.sysroot.string(), "sysroot_z");
211  EXPECT_EQ(config.pacman.os, "os_a");
212 }
213 
214 /* Parse multiple config files in multiple directories. */
215 TEST(config, TwoDirs) {
216  TemporaryDirectory temp_dir;
217  std::vector<boost::filesystem::path> dirs = generate_multi_config(temp_dir);
218 
219  Config config(dirs);
220  EXPECT_EQ(config.storage.path.string(), "path_z");
221  EXPECT_EQ(config.pacman.sysroot.string(), "sysroot_z");
222  EXPECT_NE(config.pacman.os, "os_a");
223  EXPECT_EQ(config.provision.provision_path.string(), "y_prov_path");
224 }
225 
226 void checkConfigExpectations(const Config &conf) {
227  EXPECT_EQ(conf.storage.type, StorageType::kSqlite);
228  EXPECT_EQ(conf.pacman.type, PACKAGE_MANAGER_NONE);
229  EXPECT_EQ(conf.tls.ca_source, CryptoSource::kPkcs11);
230  EXPECT_EQ(conf.tls.pkey_source, CryptoSource::kPkcs11);
231  EXPECT_EQ(conf.tls.cert_source, CryptoSource::kPkcs11);
232  EXPECT_EQ(conf.uptane.key_source, CryptoSource::kPkcs11);
233  EXPECT_EQ(conf.uptane.key_type, KeyType::kED25519);
234  EXPECT_EQ(conf.bootloader.rollback_mode, RollbackMode::kUbootMasked);
235 }
236 
237 /* This test is designed to catch a bug in which storage.type and pacman.type
238  * set in the first config file read could be overwritten by the defaults when
239  * reading a second config file. */
240 TEST(config, TwoTomlCorrectness) {
241  TemporaryDirectory temp_dir;
242  const std::string conf_path_str = (temp_dir.Path() / "config.toml").string();
243  TestUtils::writePathToConfig("tests/config/minimal.toml", conf_path_str, temp_dir.Path());
244  {
245  std::ofstream cs(conf_path_str.c_str(), std::ofstream::app);
246  cs << "type = \"sqlite\"\n";
247  cs << "\n";
248  cs << "[pacman]\n";
249  cs << "type = \"none\"\n";
250  cs << "\n";
251  cs << "[tls]\n";
252  cs << "ca_source = \"pkcs11\"\n";
253  cs << "pkey_source = \"pkcs11\"\n";
254  cs << "cert_source = \"pkcs11\"\n";
255  cs << "\n";
256  cs << "[uptane]\n";
257  cs << "key_source = \"pkcs11\"\n";
258  cs << "key_type = \"ED25519\"\n";
259  cs << "\n";
260  cs << "[bootloader]\n";
261  cs << "rollback_mode = \"uboot_masked\"\n";
262  }
263 
264  bpo::variables_map cmd;
265  bpo::options_description description("some text");
266  // clang-format off
267  description.add_options()
268  ("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration directory");
269  // clang-format on
270 
271  const char *argv1[] = {"aktualizr", "-c", conf_path_str.c_str(), "-c", "tests/config/minimal.toml"};
272  bpo::store(bpo::parse_command_line(5, argv1, description), cmd);
273  Config conf1(cmd);
274  checkConfigExpectations(conf1);
275 
276  // Try the reverse order, too, just to make sure.
277  const char *argv2[] = {"aktualizr", "-c", "tests/config/minimal.toml", "-c", conf_path_str.c_str()};
278  bpo::store(bpo::parse_command_line(5, argv2, description), cmd);
279  Config conf2(cmd);
280  checkConfigExpectations(conf2);
281 }
282 
283 #ifndef __NO_MAIN__
284 int main(int argc, char **argv) {
285  ::testing::InitGoogleTest(&argc, argv);
286 
287  if (argc != 2) {
288  std::cerr << "Error: " << argv[0] << " requires the path to the build directory as an input argument.\n";
289  return EXIT_FAILURE;
290  }
291  build_dir = argv[1];
292  return RUN_ALL_TESTS();
293 }
294 #endif
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
TemporaryDirectory
Definition: utils.h:82
Bootstrap
Definition: bootstrap.h:7