Aktualizr
C++ SOTA Client
metadata_expiration_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <string>
4 
5 #include "httpfake.h"
6 #include "libaktualizr/aktualizr.h"
7 #include "test_utils.h"
8 #include "uptane_test_common.h"
9 
10 boost::filesystem::path uptane_generator_path;
11 
12 class MetadataExpirationTest : public ::testing::Test {
13  protected:
14  MetadataExpirationTest() : uptane_gen_(uptane_generator_path.string()) {
15  Process uptane_gen(uptane_generator_path.string());
16  uptane_gen.run({"generate", "--path", meta_dir_.PathString()});
17 
18  auto http = std::make_shared<HttpFake>(temp_dir_.Path(), "", meta_dir_.Path() / "repo");
19  Config conf = UptaneTestCommon::makeTestConfig(temp_dir_, http->tls_server);
20  conf.pacman.fake_need_reboot = true;
21  conf.uptane.force_install_completion = true;
22  conf.bootloader.reboot_sentinel_dir = temp_dir_.Path();
23 
24  logger_set_threshold(boost::log::trivial::trace);
25 
26  storage_ = INvStorage::newStorage(conf.storage);
27  aktualizr_ = std::make_shared<UptaneTestCommon::TestAktualizr>(conf, storage_, http);
28  }
29 
30  void addImage() {
31  uptane_gen_.run({"image", "--path", meta_dir_.PathString(), "--filename", "tests/test_data/firmware.txt",
32  "--targetname", target_filename_, "--hwid", "primary_hw"});
33 
34  target_image_hash_ = boost::algorithm::to_lower_copy(
35  boost::algorithm::hex(Crypto::sha256digest(Utils::readFile("tests/test_data/firmware.txt"))));
36  }
37 
38  void addTarget(const std::string& target_filename, int expiration_delta = 0) {
39  if (expiration_delta != 0) {
40  time_t new_expiration_time;
41  std::time(&new_expiration_time);
42  new_expiration_time += expiration_delta;
43  struct tm new_expiration_time_str {};
44  gmtime_r(&new_expiration_time, &new_expiration_time_str);
45 
46  uptane_gen_.run({"addtarget", "--path", meta_dir_.PathString(), "--targetname", target_filename, "--hwid",
47  "primary_hw", "--serial", "CA:FE:A6:D2:84:9D", "--expires",
48  TimeStamp(new_expiration_time_str).ToString()});
49 
50  } else {
51  uptane_gen_.run({"addtarget", "--path", meta_dir_.PathString(), "--targetname", target_filename, "--hwid",
52  "primary_hw", "--serial", "CA:FE:A6:D2:84:9D"});
53  }
54  }
55 
56  void addTargetAndSign(const std::string& target_filename, int expiration_delta = 0) {
57  addTarget(target_filename, expiration_delta);
58  uptane_gen_.run({"signtargets", "--path", meta_dir_.PathString()});
59  }
60 
61  void refreshTargetsMetadata() {
62  // refresh the Targets metadata in the repo/Director
63  uptane_gen_.run({"refresh", "--path", meta_dir_.PathString(), "--repotype", "director", "--keyname", "targets"});
64  }
65 
66  void addTargetToInstall(int expiration_delta = 0) {
67  addImage();
68  addTargetAndSign(target_filename_, expiration_delta);
69  }
70 
71  protected:
72  Process uptane_gen_;
73  const std::string target_filename_ = "firmware.txt";
74  std::string target_image_hash_;
75 
76  TemporaryDirectory meta_dir_;
77  TemporaryDirectory temp_dir_;
78  std::shared_ptr<INvStorage> storage_;
79  std::shared_ptr<UptaneTestCommon::TestAktualizr> aktualizr_;
80 };
81 
82 TEST_F(MetadataExpirationTest, MetadataExpirationBeforeInstallation) {
83  aktualizr_->Initialize();
84  result::UpdateCheck update_result = aktualizr_->CheckUpdates().get();
85  EXPECT_EQ(update_result.status, result::UpdateStatus::kNoUpdatesAvailable);
86 
87  addTargetToInstall(-1);
88 
89  // run the uptane cycle an try to install the target
90  aktualizr_->UptaneCycle();
91 
92  // check if the target has been installed and pending to be applied after a reboot
93  auto& client = aktualizr_->uptane_client();
94  ASSERT_FALSE(client->hasPendingUpdates());
95  ASSERT_FALSE(client->isInstallCompletionRequired());
96 
97  auto currently_installed_target = client->getCurrent();
98 
99  EXPECT_NE(target_image_hash_, currently_installed_target.sha256Hash());
100  EXPECT_NE(target_filename_, currently_installed_target.filename());
101 
102  refreshTargetsMetadata();
103 
104  // run the uptane cycle an try to install the target
105  aktualizr_->UptaneCycle();
106 
107  // check if the target has been installed and pending to be applied after a reboot
108  ASSERT_TRUE(client->hasPendingUpdates());
109  ASSERT_TRUE(client->isInstallCompletionRequired());
110 
111  // force reboot
112  client->completeInstall();
113 
114  // emulate aktualizr fresh start
115  aktualizr_->Initialize();
116  aktualizr_->UptaneCycle();
117 
118  ASSERT_FALSE(client->hasPendingUpdates());
119  ASSERT_FALSE(client->isInstallCompletionRequired());
120 
121  currently_installed_target = client->getCurrent();
122  EXPECT_EQ(target_image_hash_, currently_installed_target.sha256Hash());
123  EXPECT_EQ(target_filename_, currently_installed_target.filename());
124 }
125 
126 TEST_F(MetadataExpirationTest, MetadataExpirationAfterInstallationAndBeforeReboot) {
127  aktualizr_->Initialize();
128 
129  result::UpdateCheck update_result = aktualizr_->CheckUpdates().get();
130  EXPECT_EQ(update_result.status, result::UpdateStatus::kNoUpdatesAvailable);
131 
132  const int expiration_in_sec = 5;
133  addTargetToInstall(expiration_in_sec);
134  auto target_init_time = std::chrono::system_clock::now();
135 
136  // run the uptane cycle to install the target
137  aktualizr_->UptaneCycle();
138 
139  // check if the target has been installed and pending to be applied after a reboot
140  auto& client = aktualizr_->uptane_client();
141  ASSERT_TRUE(client->hasPendingUpdates());
142  ASSERT_TRUE(client->isInstallCompletionRequired());
143 
144  // emulate the target metadata expiration while the uptane cycle is running
145  std::this_thread::sleep_for(std::chrono::seconds(expiration_in_sec) -
146  (std::chrono::system_clock::now() - target_init_time));
147  aktualizr_->UptaneCycle();
148 
149  // since the installation happenned before the metadata expiration we expect that
150  // the update is still pending and will be applied after a reboot
151  ASSERT_TRUE(client->hasPendingUpdates());
152  ASSERT_TRUE(client->isInstallCompletionRequired());
153 
154  // force reboot
155  client->completeInstall();
156 
157  // emulate aktualizr fresh start
158  aktualizr_->Initialize();
159  aktualizr_->UptaneCycle();
160 
161  // check if the pending target has been applied. it should be applied in even if it's metadata are expired
162  // as long as it was installed at the moment when they were not expired
163  auto currently_installed_target = client->getCurrent();
164  EXPECT_EQ(target_image_hash_, currently_installed_target.sha256Hash());
165  EXPECT_EQ(target_filename_, currently_installed_target.filename());
166 }
167 
168 TEST_F(MetadataExpirationTest, MetadataExpirationAfterInstallationAndBeforeApplication) {
169  aktualizr_->Initialize();
170 
171  result::UpdateCheck update_result = aktualizr_->CheckUpdates().get();
172  EXPECT_EQ(update_result.status, result::UpdateStatus::kNoUpdatesAvailable);
173 
174  const int expiration_in_sec = 5;
175  addTargetToInstall(expiration_in_sec);
176  auto target_init_time = std::chrono::system_clock::now();
177 
178  // run the uptane cycle to install the target
179  aktualizr_->UptaneCycle();
180 
181  // check if the target has been installed and pending to be applied after a reboot
182  auto& client = aktualizr_->uptane_client();
183  ASSERT_TRUE(client->hasPendingUpdates());
184  ASSERT_TRUE(client->isInstallCompletionRequired());
185 
186  // wait until the target metadata are expired
187  // emulate the target metadata expiration while the Uptane cycle is running
188  std::this_thread::sleep_for(std::chrono::seconds(expiration_in_sec) -
189  (std::chrono::system_clock::now() - target_init_time));
190 
191  // force reboot
192  client->completeInstall();
193 
194  // emulate aktualizr fresh start
195  aktualizr_->Initialize();
196  aktualizr_->UptaneCycle();
197 
198  // check if the pending target has been applied. it should be applied in even if it's metadta are expired
199  // as long as it was installed at the moment when they were not expired
200  auto currently_installed_target = client->getCurrent();
201  EXPECT_EQ(target_image_hash_, currently_installed_target.sha256Hash());
202  EXPECT_EQ(target_filename_, currently_installed_target.filename());
203 }
204 
205 int main(int argc, char** argv) {
206  ::testing::InitGoogleTest(&argc, argv);
207  if (argc != 2) {
208  std::cerr << "Error: " << argv[0] << " requires the path to the uptane-generator utility\n";
209  return EXIT_FAILURE;
210  }
211  uptane_generator_path = argv[1];
212 
213  logger_init();
214  logger_set_threshold(boost::log::trivial::trace);
215 
216  return RUN_ALL_TESTS();
217 }
218 
219 // vim: set tabstop=2 shiftwidth=2 expandtab:
MetadataExpirationTest
Definition: metadata_expiration_test.cc:12
result::UpdateCheck
Container for information about available updates.
Definition: results.h:37
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
TimeStamp
Definition: types.h:188
Process
Definition: test_utils.h:19
TemporaryDirectory
Definition: utils.h:82