Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
packagemanagerfake_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <fstream>
4 #include <iostream>
5 #include <memory>
6 #include <string>
7 
8 #include <boost/filesystem.hpp>
9 
10 #include "httpfake.h"
11 #include "libaktualizr/config.h"
12 #include "libaktualizr/types.h"
13 #include "package_manager/packagemanagerfake.h"
14 #include "storage/invstorage.h"
15 #include "uptane/tuf.h"
16 #include "utilities/utils.h"
17 
18 // Test creating, appending and reading binary targets.
19 TEST(PackageManagerFake, Binary) {
20  TemporaryDirectory temp_dir;
21  Config config;
22  config.pacman.type = PACKAGE_MANAGER_NONE;
23  config.pacman.images_path = temp_dir.Path() / "images";
24  config.storage.path = temp_dir.Path();
25 
26  auto storage = INvStorage::newStorage(config.storage);
27  PackageManagerFake pacman(config.pacman, config.bootloader, storage, nullptr);
28 
29  Json::Value target_json;
30  target_json["hashes"]["sha256"] = "D9CD8155764C3543F10FAD8A480D743137466F8D55213C8EAEFCD12F06D43A80";
31  Uptane::Target target("aa.bin", target_json);
32 
33  {
34  auto out = pacman.createTargetFile(target);
35  out << "a";
36  }
37  {
38  auto in = pacman.openTargetFile(target);
39  std::stringstream ss;
40  ss << in.rdbuf();
41  ASSERT_EQ(ss.str(), "a");
42  }
43  {
44  auto out = pacman.appendTargetFile(target);
45  out << "a";
46  }
47  {
48  auto in = pacman.openTargetFile(target);
49  std::stringstream ss;
50  ss << in.rdbuf();
51  ASSERT_EQ(ss.str(), "aa");
52  }
53  // Test overwriting
54  {
55  auto out = pacman.createTargetFile(target);
56  out << "a";
57  }
58  {
59  auto in = pacman.openTargetFile(target);
60  std::stringstream ss;
61  ss << in.rdbuf();
62  ASSERT_EQ(ss.str(), "a");
63  }
64 
65  pacman.removeTargetFile(target);
66  EXPECT_THROW(pacman.appendTargetFile(target), std::runtime_error);
67  EXPECT_THROW(pacman.openTargetFile(target), std::runtime_error);
68 }
69 
70 // Test listing and removing binary targets
71 TEST(PackageManagerFake, ListRemove) {
72  TemporaryDirectory temp_dir;
73  Config config;
74  config.pacman.type = PACKAGE_MANAGER_NONE;
75  config.pacman.images_path = temp_dir.Path() / "images";
76  config.storage.path = temp_dir.Path();
77 
78  auto storage = INvStorage::newStorage(config.storage);
79  PackageManagerFake pacman(config.pacman, config.bootloader, storage, nullptr);
80 
81  Json::Value target_json;
82  target_json["hashes"]["sha256"] = "D9CD8155764C3543F10FAD8A480D743137466F8D55213C8EAEFCD12F06D43A80";
83  Uptane::Target t1("aa.bin", target_json);
84  target_json["hashes"]["sha256"] = "A81C31AC62620B9215A14FF00544CB07A55B765594F3AB3BE77E70923AE27CF1";
85  Uptane::Target t2("bb.bin", target_json);
86 
87  pacman.createTargetFile(t1);
88  pacman.createTargetFile(t2);
89 
90  auto targets = pacman.getTargetFiles();
91  ASSERT_EQ(targets.size(), 2);
92  ASSERT_EQ(targets.at(0).filename(), "aa.bin");
93  ASSERT_EQ(targets.at(1).filename(), "bb.bin");
94 
95  pacman.removeTargetFile(t1);
96  targets = pacman.getTargetFiles();
97  ASSERT_EQ(targets.size(), 1);
98  ASSERT_EQ(targets.at(0).filename(), "bb.bin");
99  EXPECT_FALSE(boost::filesystem::exists(temp_dir.Path() / "images" /
100  "D9CD8155764C3543F10FAD8A480D743137466F8D55213C8EAEFCD12F06D43A80"));
101  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "images" /
102  "A81C31AC62620B9215A14FF00544CB07A55B765594F3AB3BE77E70923AE27CF1"));
103 }
104 
105 /*
106  * Verify a stored target.
107  * Verify that a target is unavailable.
108  * Reject a target whose hash does not match the metadata.
109  * Reject an oversized target.
110  * Reject an incomplete target.
111  */
112 TEST(PackageManagerFake, Verify) {
113  TemporaryDirectory temp_dir;
114  Config config;
115  config.pacman.type = PACKAGE_MANAGER_NONE;
116  config.pacman.images_path = temp_dir.Path() / "images";
117  config.storage.path = temp_dir.Path();
118  std::shared_ptr<INvStorage> storage = INvStorage::newStorage(config.storage);
119 
120  Uptane::EcuMap primary_ecu{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")}};
121  const int length = 4;
122  char content[length];
123  memcpy(content, "good", length);
124  MultiPartSHA256Hasher hasher;
125  hasher.update(reinterpret_cast<uint8_t *>(content), length);
126  const std::string hash = hasher.getHexDigest();
127  Uptane::Target target("some-pkg", primary_ecu, {Hash(Hash::Type::kSha256, hash)}, length, "");
128 
129  PackageManagerFake fakepm(config.pacman, config.bootloader, storage, nullptr);
130  // Target is not yet available.
131  EXPECT_EQ(fakepm.verifyTarget(target), TargetStatus::kNotFound);
132 
133  // Target has a bad hash.
134  auto whandle = fakepm.createTargetFile(target);
135  char content_bad[length + 1];
136  memset(content_bad, 0, length + 1);
137  whandle.write(content_bad, length);
138  whandle.close();
139  EXPECT_EQ(fakepm.verifyTarget(target), TargetStatus::kHashMismatch);
140 
141  // Target is oversized.
142  whandle = fakepm.createTargetFile(target);
143  whandle.write(content_bad, length + 1);
144  whandle.close();
145  EXPECT_EQ(fakepm.verifyTarget(target), TargetStatus::kOversized);
146 
147  // Target is incomplete.
148  whandle = fakepm.createTargetFile(target);
149  whandle.write(content, length - 1);
150  whandle.close();
151  EXPECT_EQ(fakepm.verifyTarget(target), TargetStatus::kIncomplete);
152 
153  // Target is good.
154  whandle = fakepm.createTargetFile(target);
155  whandle.write(content, length);
156  whandle.close();
157  EXPECT_EQ(fakepm.verifyTarget(target), TargetStatus::kGood);
158 }
159 
160 TEST(PackageManagerFake, FinalizeAfterReboot) {
161  TemporaryDirectory temp_dir;
162  Config config;
163  config.pacman.type = PACKAGE_MANAGER_NONE;
164  config.pacman.images_path = temp_dir.Path() / "images";
165  config.pacman.fake_need_reboot = true;
166  config.bootloader.reboot_sentinel_dir = temp_dir.Path();
167  config.storage.path = temp_dir.Path();
168  std::shared_ptr<INvStorage> storage = INvStorage::newStorage(config.storage);
169  std::shared_ptr<Bootloader> bootloader = std::make_shared<Bootloader>(config.bootloader, *storage);
170 
171  PackageManagerFake fakepm(config.pacman, config.bootloader, storage, nullptr);
172 
173  Uptane::EcuMap primary_ecu;
174  Uptane::Target target("pkg", primary_ecu, {Hash(Hash::Type::kSha256, "hash")}, 1, "");
175  auto result = fakepm.install(target);
176  EXPECT_EQ(result.result_code, data::ResultCode::Numeric::kNeedCompletion);
177  storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kPending);
178 
179  fakepm.completeInstall();
180 
181  result = fakepm.finalizeInstall(target);
182  EXPECT_EQ(result.result_code, data::ResultCode::Numeric::kOk);
183 }
184 
185 #ifdef FIU_ENABLE
186 
187 #include "utilities/fault_injection.h"
188 
189 TEST(PackageManagerFake, DownloadFailureInjection) {
190  TemporaryDirectory temp_dir;
191  Config config;
192  config.pacman.type = PACKAGE_MANAGER_NONE;
193  config.pacman.images_path = temp_dir.Path() / "images";
194  config.storage.path = temp_dir.Path();
195  std::shared_ptr<INvStorage> storage = INvStorage::newStorage(config.storage);
196  auto http = std::make_shared<HttpFake>(temp_dir.Path());
197  Uptane::Fetcher uptane_fetcher(config, http);
198  KeyManager keys(storage, config.keymanagerConfig());
199 
200  PackageManagerFake fakepm(config.pacman, config.bootloader, storage, http);
201 
202  fault_injection_init();
203 
204  // no fault
205  Uptane::EcuMap primary_ecu{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")}};
206  Uptane::Target target("pkg", primary_ecu, {Hash(Hash::Type::kSha256, "hash")}, 0, "");
207  EXPECT_TRUE(fakepm.fetchTarget(target, uptane_fetcher, keys, nullptr, nullptr));
208 
209  // fault
210  fault_injection_enable("fake_package_download", 1, "", 0);
211  EXPECT_FALSE(fakepm.fetchTarget(target, uptane_fetcher, keys, nullptr, nullptr));
212  fault_injection_disable("fake_package_download");
213 
214  // fault with custom data (through pid file). Unfortunately no easy way to
215  // test the custom emssage.
216  fault_injection_enable("fake_package_download", 1, "RANDOM_DOWNLOAD_CAUSE", 0);
217  EXPECT_FALSE(fakepm.fetchTarget(target, uptane_fetcher, keys, nullptr, nullptr));
218  fault_injection_disable("fake_package_download");
219 }
220 
221 TEST(PackageManagerFake, InstallFailureInjection) {
222  TemporaryDirectory temp_dir;
223  Config config;
224  config.pacman.type = PACKAGE_MANAGER_NONE;
225  config.pacman.images_path = temp_dir.Path() / "images";
226  config.storage.path = temp_dir.Path();
227  std::shared_ptr<INvStorage> storage = INvStorage::newStorage(config.storage);
228 
229  PackageManagerFake fakepm(config.pacman, config.bootloader, storage, nullptr);
230 
231  fault_injection_init();
232 
233  // no fault
234  Uptane::EcuMap primary_ecu{{Uptane::EcuSerial("primary"), Uptane::HardwareIdentifier("primary_hw")}};
235  Uptane::Target target("pkg", primary_ecu, {Hash(Hash::Type::kSha256, "hash")}, 1, "");
236  auto result = fakepm.install(target);
237  EXPECT_EQ(result.result_code, data::ResultCode::Numeric::kOk);
238 
239  // fault
240  fault_injection_enable("fake_package_install", 1, "", 0);
241  result = fakepm.install(target);
242  EXPECT_EQ(result.result_code, data::ResultCode::Numeric::kInstallFailed);
243  fault_injection_disable("fake_package_install");
244 
245  // fault with custom data (through pid file)
246  fault_injection_enable("fake_package_install", 1, "RANDOM_INSTALL_CAUSE", 0);
247  result = fakepm.install(target);
248  EXPECT_EQ(result.result_code, data::ResultCode(data::ResultCode::Numeric::kInstallFailed, "RANDOM_INSTALL_CAUSE"));
249  fault_injection_disable("fake_package_install");
250 }
251 
252 #endif // FIU_ENABLE
253 
254 #ifndef __NO_MAIN__
255 int main(int argc, char **argv) {
256  ::testing::InitGoogleTest(&argc, argv);
257 
258  return RUN_ALL_TESTS();
259 }
260 #endif
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:210
Package installation failed.
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:157
Results of libaktualizr API calls.
Definition: results.h:12