Aktualizr
C++ SOTA Client
fetcher_death_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <boost/process.hpp>
4 #include <chrono>
5 #include <csignal>
6 #include <future>
7 #include <iostream>
8 #include <string>
9 #include <thread>
10 
11 #include "crypto/keymanager.h"
12 #include "http/httpclient.h"
13 #include "libaktualizr/config.h"
14 #include "logging/logging.h"
15 #include "package_manager/packagemanagerfake.h"
16 #include "storage/sqlstorage.h"
17 #include "test_utils.h"
18 #include "uptane/fetcher.h"
19 #include "uptane/tuf.h"
20 #include "utilities/apiqueue.h"
21 
22 static const int die_after = 50; // percent
23 static const int pause_duration = 2; // seconds
24 
25 std::string server;
26 
27 static std::mutex pause_m;
28 static std::condition_variable cv;
29 static bool die = false;
30 static bool resumed = false;
31 
32 Config config;
33 
34 static void progress_cb(const Uptane::Target& target, const std::string& description, unsigned int progress) {
35  (void)target;
36  (void)description;
37  std::cout << "progress: " << progress << std::endl;
38  if (progress >= die_after) {
39  std::lock_guard<std::mutex> lk(pause_m);
40  die = true;
41  cv.notify_all();
42  }
43  if (resumed) {
44  EXPECT_GE(progress, die_after);
45  }
46 }
47 
48 void resume(const Uptane::Target& target) {
49  std::shared_ptr<INvStorage> storage(new SQLStorage(config.storage, false));
50  auto http = std::make_shared<HttpClient>();
51  auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
53  KeyManager keys(storage, config.keymanagerConfig());
54  Uptane::Fetcher fetcher(config, http);
55 
56  resumed = true;
57  bool res = pacman->fetchTarget(target, fetcher, keys, progress_cb, &token);
58 
59  EXPECT_TRUE(res);
60 }
61 
62 void try_and_die(const Uptane::Target& target, bool graceful) {
63  std::shared_ptr<INvStorage> storage(new SQLStorage(config.storage, false));
64  auto http = std::make_shared<HttpClient>();
66  auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
67  KeyManager keys(storage, config.keymanagerConfig());
68  Uptane::Fetcher fetcher(config, http);
69 
70  std::promise<bool> download_promise;
71  auto result = download_promise.get_future();
72 
73  std::thread([&target, &fetcher, &download_promise, &token, pacman, &keys]() {
74  bool res = pacman->fetchTarget(target, fetcher, keys, progress_cb, &token);
75  download_promise.set_value(res);
76  }).detach();
77 
78  std::unique_lock<std::mutex> lk(pause_m);
79  cv.wait(lk, [] { return die; });
80  if (graceful) {
81  token.setPause(true);
82  std::this_thread::sleep_for(std::chrono::seconds(pause_duration));
83  std::raise(SIGTERM);
84  } else {
85  std::raise(SIGKILL);
86  }
87 }
88 
89 TEST(FetcherDeathTest, TestResumeAfterPause) {
90  TemporaryDirectory temp_dir;
91  config.storage.path = temp_dir.Path();
92  config.pacman.images_path = temp_dir.Path() / "images";
93 
94  Json::Value target_json;
95  target_json["hashes"]["sha256"] = "dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
96  target_json["length"] = 100 * (1 << 20);
97 
98  Uptane::Target target("large_file", target_json);
99  die = false;
100  resumed = false;
101  ASSERT_DEATH(try_and_die(target, true), "");
102  std::cout << "Fetcher died, retrying" << std::endl;
103  resume(target);
104 }
105 
106 TEST(FetcherDeathTest, TestResumeAfterSigkill) {
107  TemporaryDirectory temp_dir;
108  config.storage.path = temp_dir.Path();
109 
110  Json::Value target_json;
111  target_json["hashes"]["sha256"] = "dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
112  target_json["length"] = 100 * (1 << 20);
113 
114  Uptane::Target target("large_file", target_json);
115  die = false;
116  resumed = false;
117  ASSERT_DEATH(try_and_die(target, false), "");
118  std::cout << "Fetcher died, retrying" << std::endl;
119  resume(target);
120 }
121 
122 #ifndef __NO_MAIN__
123 int main(int argc, char** argv) {
124  ::testing::InitGoogleTest(&argc, argv);
125 
126  logger_init();
127  logger_set_threshold(boost::log::trivial::trace);
128 
129  std::string port = TestUtils::getFreePort();
130  server = "http://127.0.0.1:" + port;
131  config.uptane.repo_server = server;
132  boost::process::child http_server_process("tests/fake_http_server/fake_test_server.py", port, "-f");
133  TestUtils::waitForServer(server + "/");
134  return RUN_ALL_TESTS();
135 }
136 #endif // __NO_MAIN__
Uptane::Fetcher
Definition: fetcher.h:33
KeyManager
Definition: keymanager.h:13
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
api::FlowControlToken
Provides a thread-safe way to pause and terminate task execution.
Definition: apiqueue.h:19
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:12
Uptane::Target
Definition: types.h:379
api::FlowControlToken::setPause
bool setPause(bool set_paused)
Called by the controlling thread to request the task to pause or resume.
Definition: apiqueue.cc:6
SQLStorage
Definition: sqlstorage.h:18