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