Aktualizr
C++ SOTA Client
aktualizr_fullostree_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <future>
4 #include <iostream>
5 #include <string>
6 #include <thread>
7 
8 #include <boost/process.hpp>
9 
10 #include "uptane_test_common.h"
11 
12 #include "libaktualizr/aktualizr.h"
13 #include "libaktualizr/config.h"
14 #include "logging/logging.h"
15 #include "package_manager/ostreemanager.h"
16 #include "storage/sqlstorage.h"
17 #include "test_utils.h"
18 
19 boost::filesystem::path uptane_generator_path;
20 static std::string server = "http://127.0.0.1:";
21 static std::string treehub_server = "http://127.0.0.1:";
22 static boost::filesystem::path sysroot;
23 
24 static struct {
25  int serial{0};
26  std::string rev;
27 } ostree_deployment;
28 static std::string new_rev;
29 
30 #include <ostree.h>
31 extern "C" OstreeDeployment *ostree_sysroot_get_booted_deployment(OstreeSysroot *self) {
32  (void)self;
33  static GObjectUniquePtr<OstreeDeployment> dep;
34 
35  dep.reset(ostree_deployment_new(0, "dummy-os", ostree_deployment.rev.c_str(), ostree_deployment.serial,
36  ostree_deployment.rev.c_str(), ostree_deployment.serial));
37  return dep.get();
38 }
39 
40 extern "C" const char *ostree_deployment_get_csum(OstreeDeployment *self) {
41  (void)self;
42  return ostree_deployment.rev.c_str();
43 }
44 
45 /*
46  * Install an OSTree update on the primary.
47  */
48 TEST(Aktualizr, FullOstreeUpdate) {
49  TemporaryDirectory temp_dir;
50  Config conf = UptaneTestCommon::makeTestConfig(temp_dir, server);
51  conf.pacman.type = PACKAGE_MANAGER_OSTREE;
52  conf.pacman.sysroot = sysroot.string();
53  conf.pacman.ostree_server = treehub_server;
54  conf.pacman.os = "dummy-os";
55  conf.provision.device_id = "device_id";
56  conf.provision.ecu_registration_endpoint = server + "/director/ecus";
57  conf.tls.server = server;
58 
59  LOG_INFO << "conf: " << conf;
60 
61  {
62  UptaneTestCommon::TestAktualizr aktualizr(conf);
63  aktualizr.Initialize();
64 
65  result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
66  ASSERT_EQ(update_result.status, result::UpdateStatus::kUpdatesAvailable);
67  // Verify the target has not yet been downloaded.
68  EXPECT_EQ(aktualizr.uptane_client()->package_manager_->verifyTarget(update_result.updates[0]),
69  TargetStatus::kNotFound);
70 
71  result::Download download_result = aktualizr.Download(update_result.updates).get();
72  EXPECT_EQ(download_result.status, result::DownloadStatus::kSuccess);
73  // Verify the target has been downloaded.
74  EXPECT_EQ(aktualizr.uptane_client()->package_manager_->verifyTarget(update_result.updates[0]), TargetStatus::kGood);
75 
76  result::Install install_result = aktualizr.Install(update_result.updates).get();
77  EXPECT_EQ(install_result.ecu_reports.size(), 1);
78  EXPECT_EQ(install_result.ecu_reports[0].install_res.result_code.num_code,
79  data::ResultCode::Numeric::kNeedCompletion);
80  }
81 
82  // do "reboot" and finalize
83  ostree_deployment.serial = 1;
84  ostree_deployment.rev = new_rev;
85  boost::filesystem::remove(conf.bootloader.reboot_sentinel_dir / conf.bootloader.reboot_sentinel_name);
86 
87  {
88  UptaneTestCommon::TestAktualizr aktualizr(conf);
89  aktualizr.Initialize();
90 
91  result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
92  ASSERT_EQ(update_result.status, result::UpdateStatus::kNoUpdatesAvailable);
93 
94  // check new version
95  const auto target = aktualizr.uptane_client()->package_manager_->getCurrent();
96  EXPECT_EQ(target.sha256Hash(), new_rev);
97  // TODO(OTA-3659): verify the target. It doesn't work because
98  // ostree_repo_list_commit_objects_starting_with() doesn't find the commit.
99  // The already mocked functions are not enough to do this; it seems the
100  // commit is not written with the correct hash.
101 
102  // Verify a bogus target is not present.
103  Uptane::EcuMap primary_ecu{{Uptane::EcuSerial(conf.provision.primary_ecu_serial),
104  Uptane::HardwareIdentifier(conf.provision.primary_ecu_hardware_id)}};
105  Uptane::Target target_bad("some-pkg", primary_ecu, {Hash(Hash::Type::kSha256, "hash-bad")}, 4, "");
106  EXPECT_EQ(aktualizr.uptane_client()->package_manager_->verifyTarget(target_bad), TargetStatus::kNotFound);
107  }
108 }
109 
110 #ifndef __NO_MAIN__
111 int main(int argc, char **argv) {
112  ::testing::InitGoogleTest(&argc, argv);
113 
114  logger_init();
115 
116  if (argc != 3) {
117  std::cerr << "Error: " << argv[0] << " requires the path to the uptane-generator utility "
118  << "and an OSTree sysroot\n";
119  return EXIT_FAILURE;
120  }
121  uptane_generator_path = argv[1];
122 
123  Process ostree("ostree");
124 
125  TemporaryDirectory meta_dir;
126  TemporaryDirectory temp_sysroot;
127  sysroot = temp_sysroot / "sysroot";
128  // uses cp, as boost doesn't like to copy bad symlinks
129  int res = system((std::string("cp -r ") + argv[2] + std::string(" ") + sysroot.string()).c_str());
130  if (res != 0) {
131  return -1;
132  }
133  auto r = ostree.run(
134  {"rev-parse", std::string("--repo"), (sysroot / "/ostree/repo").string(), "generate-remote/generated"});
135  if (std::get<0>(r) != 0) {
136  return -1;
137  }
138  ostree_deployment.serial = 0;
139  ostree_deployment.rev = ostree.lastStdOut();
140  boost::trim_if(ostree_deployment.rev, boost::is_any_of(" \t\r\n"));
141  LOG_INFO << "ORIG: " << ostree_deployment.rev;
142 
143  std::string port = TestUtils::getFreePort();
144  server += port;
145  boost::process::child http_server_process("tests/fake_http_server/fake_test_server.py", port, "-m", meta_dir.Path());
146  TestUtils::waitForServer(server + "/");
147 
148  std::string treehub_port = TestUtils::getFreePort();
149  treehub_server += treehub_port;
150  TemporaryDirectory treehub_dir;
151  boost::process::child ostree_server_process("tests/sota_tools/treehub_server.py", std::string("-p"), treehub_port,
152  std::string("-d"), treehub_dir.PathString(), std::string("-s0.5"),
153  std::string("--create"));
154  TestUtils::waitForServer(treehub_server + "/");
155  r = ostree.run({"rev-parse", std::string("--repo"), treehub_dir.PathString(), "master"});
156  if (std::get<0>(r) != 0) {
157  return -1;
158  }
159  new_rev = ostree.lastStdOut();
160  boost::trim_if(new_rev, boost::is_any_of(" \t\r\n"));
161  LOG_INFO << "DEST: " << new_rev;
162 
163  Process uptane_gen(uptane_generator_path.string());
164  uptane_gen.run({"generate", "--path", meta_dir.PathString(), "--correlationid", "abc123"});
165  uptane_gen.run({"image", "--path", meta_dir.PathString(), "--targetname", "update_1.0", "--targetsha256", new_rev,
166  "--targetlength", "0", "--targetformat", "OSTREE", "--hwid", "primary_hw"});
167  uptane_gen.run({"addtarget", "--path", meta_dir.PathString(), "--targetname", "update_1.0", "--hwid", "primary_hw",
168  "--serial", "CA:FE:A6:D2:84:9D"});
169  uptane_gen.run({"signtargets", "--path", meta_dir.PathString(), "--correlationid", "abc123"});
170  LOG_INFO << uptane_gen.lastStdOut();
171 
172  return RUN_ALL_TESTS();
173 }
174 #endif // __NO_MAIN__
Hash
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:159
UptaneTestCommon::TestAktualizr
Definition: uptane_test_common.h:21
result::UpdateCheck
Container for information about available updates.
Definition: results.h:37
Uptane::HardwareIdentifier
Definition: types.h:315
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
Uptane::EcuSerial
Definition: types.h:346
Aktualizr
This class provides the main APIs necessary for launching and controlling libaktualizr.
Definition: aktualizr.h:24
result::Download
Container for information about downloading an update.
Definition: results.h:116
Process
Definition: test_utils.h:19
TemporaryDirectory
Definition: utils.h:82
result::Install
Container for information about installing an update.
Definition: results.h:129
Uptane::Target
Definition: types.h:379