1 #include <gtest/gtest.h> 3 #include <sys/statvfs.h> 10 #include <boost/process.hpp> 12 #include "config/config.h" 13 #include "http/httpclient.h" 15 #include "logging/logging.h" 16 #include "package_manager/packagemanagerfactory.h" 17 #include "package_manager/packagemanagerfake.h" 18 #include "storage/sqlstorage.h" 19 #include "test_utils.h" 20 #include "uptane/tuf.h" 21 #include "utilities/apiqueue.h" 23 static const int pause_after = 50;
24 static const int pause_duration = 1;
25 static const int download_timeout = 200;
27 static std::string server =
"http://127.0.0.1:";
28 static std::string treehub_server =
"http://127.0.0.1:";
31 static std::mutex pause_m;
32 static std::condition_variable cv;
33 static bool do_pause =
false;
37 static void progress_cb(
const Uptane::Target& target,
const std::string& description,
unsigned int progress) {
40 std::cout <<
"progress callback: " << progress << std::endl;
42 if (progress >= pause_after) {
43 std::lock_guard<std::mutex> lk(pause_m);
57 void test_pause(
const Uptane::Target& target,
const std::string& type = PACKAGE_MANAGER_NONE) {
59 config.storage.path = temp_dir.Path();
60 config.uptane.repo_server = server;
61 config.pacman.type = type;
62 config.pacman.sysroot = sysroot;
63 config.pacman.ostree_server = treehub_server;
65 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
66 auto http = std::make_shared<HttpClient>();
68 auto pacman = PackageManagerFactory::makePackageManager(config.pacman, config.bootloader, storage, http);
69 KeyManager keys(storage, config.keymanagerConfig());
73 EXPECT_EQ(token.
setPause(
true),
true);
74 EXPECT_EQ(token.
setPause(
false),
true);
76 std::promise<void> pause_promise;
77 std::promise<bool> download_promise;
78 auto result = download_promise.get_future();
79 auto pause_res = pause_promise.get_future();
80 auto start = std::chrono::high_resolution_clock::now();
83 std::thread([&target, &fetcher, &download_promise, &token, pacman, &keys]() {
84 bool res = pacman->fetchTarget(target, fetcher, keys, progress_cb, &token);
85 download_promise.set_value(res);
88 std::thread([&token, &pause_promise]() {
89 std::unique_lock<std::mutex> lk(pause_m);
90 cv.wait(lk, [] {
return do_pause; });
91 EXPECT_EQ(token.
setPause(
true),
true);
92 EXPECT_EQ(token.
setPause(
true),
false);
93 std::this_thread::sleep_for(std::chrono::seconds(pause_duration));
94 EXPECT_EQ(token.
setPause(
false),
true);
95 EXPECT_EQ(token.
setPause(
false),
false);
96 pause_promise.set_value();
99 ASSERT_EQ(
result.wait_for(std::chrono::seconds(download_timeout)), std::future_status::ready);
100 ASSERT_EQ(pause_res.wait_for(std::chrono::seconds(0)), std::future_status::ready);
103 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - start).count();
104 EXPECT_TRUE(
result.get());
105 EXPECT_GE(duration, pause_duration);
113 TEST(Fetcher, PauseOstree) {
114 Json::Value target_json;
115 target_json[
"hashes"][
"sha256"] =
"b9ac1e45f9227df8ee191b6e51e09417bd36c6ebbeff999431e3073ac50f0563";
116 target_json[
"custom"][
"targetFormat"] =
"OSTREE";
117 target_json[
"length"] = 0;
119 test_pause(target, PACKAGE_MANAGER_OSTREE);
121 #endif // BUILD_OSTREE 123 TEST(Fetcher, PauseBinary) {
124 Json::Value target_json;
125 target_json[
"hashes"][
"sha256"] =
"dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
126 target_json[
"length"] = 100 * (1 << 20);
135 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
136 void* userp, curl_off_t from)
override {
141 EXPECT_EQ(url,
"test-uri");
147 TEST(Fetcher, DownloadCustomUri) {
149 config.storage.path = temp_dir.Path();
150 config.uptane.repo_server = server;
152 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
153 auto http = std::make_shared<HttpCustomUri>(temp_dir.Path());
155 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
156 KeyManager keys(storage, config.keymanagerConfig());
160 Json::Value target_json;
161 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
162 target_json[
"custom"][
"uri"] =
"test-uri";
163 target_json[
"length"] = 1;
166 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
172 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
173 void* userp, curl_off_t from)
override {
178 EXPECT_EQ(url, server +
"/targets/fake_file");
184 TEST(Fetcher, DownloadDefaultUri) {
186 config.storage.path = temp_dir.Path();
187 config.uptane.repo_server = server;
189 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
190 auto http = std::make_shared<HttpDefaultUri>(temp_dir.Path());
191 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
192 KeyManager keys(storage, config.keymanagerConfig());
197 Json::Value target_json;
198 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
199 target_json[
"length"] = 1;
202 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
206 Json::Value target_json;
207 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
208 target_json[
"custom"][
"uri"] =
"";
209 target_json[
"length"] = 1;
212 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
216 Json::Value target_json;
217 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
218 target_json[
"custom"][
"uri"] =
"https://example.com/";
219 target_json[
"length"] = 1;
222 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
229 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
230 void* userp, curl_off_t from)
override {
234 EXPECT_EQ(url, server +
"/targets/fake_file");
235 const std::string content =
"0";
236 write_cb(const_cast<char*>(&content[0]), 1, 1, userp);
246 TEST(Fetcher, DownloadLengthZero) {
248 config.storage.path = temp_dir.Path();
249 config.uptane.repo_server = server;
251 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
252 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
253 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
254 KeyManager keys(storage, config.keymanagerConfig());
258 Json::Value empty_target_json;
259 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
260 empty_target_json[
"length"] = 0;
262 empty_target_json[
"custom"][
"targetFormat"] =
"binary";
264 EXPECT_TRUE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
265 EXPECT_EQ(pacman->verifyTarget(empty_target), TargetStatus::kGood);
266 EXPECT_EQ(http->counter, 0);
270 Json::Value nonempty_target_json;
271 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
272 nonempty_target_json[
"length"] = 1;
273 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
274 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
275 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
276 EXPECT_EQ(http->counter, 1);
281 TEST(Fetcher, NotEnoughDiskSpace) {
283 config.storage.path = temp_dir.Path();
284 config.uptane.repo_server = server;
286 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
287 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
288 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
289 KeyManager keys(storage, config.keymanagerConfig());
293 struct statvfs stvfsbuf {};
294 EXPECT_EQ(statvfs(temp_dir.Path().c_str(), &stvfsbuf), 0);
295 const uint64_t available_bytes = (stvfsbuf.f_bsize * stvfsbuf.f_bavail);
299 Json::Value empty_target_json;
300 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
301 empty_target_json[
"length"] = available_bytes * 2;
303 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
304 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
305 EXPECT_EQ(http->counter, 0);
309 Json::Value nonempty_target_json;
310 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
311 nonempty_target_json[
"length"] = 1;
312 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
313 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
314 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
315 EXPECT_EQ(http->counter, 1);
319 TEST(Fetcher, DownloadOstreeFail) {
321 config.storage.path = temp_dir.Path();
322 config.uptane.repo_server = server;
324 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
325 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
326 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
327 KeyManager keys(storage, config.keymanagerConfig());
331 Json::Value empty_target_json;
332 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
333 empty_target_json[
"length"] = 0;
334 empty_target_json[
"custom"][
"targetFormat"] =
"OSTREE";
336 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
337 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
338 EXPECT_EQ(http->counter, 0);
342 Json::Value nonempty_target_json;
343 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
344 nonempty_target_json[
"length"] = 1;
345 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
346 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
347 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
348 EXPECT_EQ(http->counter, 1);
352 int main(
int argc,
char** argv) {
353 ::testing::InitGoogleTest(&argc, argv);
356 logger_set_threshold(boost::log::trivial::debug);
358 std::string port = TestUtils::getFreePort();
360 boost::process::child http_server_process(
"tests/fake_http_server/fake_test_server.py", port,
"-f");
361 TestUtils::waitForServer(server +
"/");
363 std::string treehub_port = TestUtils::getFreePort();
364 treehub_server += treehub_port;
366 boost::process::child ostree_server_process(
"tests/sota_tools/treehub_server.py", std::string(
"-p"), treehub_port,
367 std::string(
"-d"), treehub_dir.PathString(), std::string(
"-s0.5"),
368 std::string(
"--create"));
370 int r = system((std::string(
"ostree admin init-fs ") + temp_dir.PathString()).c_str());
374 r = system((std::string(
"ostree config --repo=") + temp_dir.PathString() +
375 std::string(
"/ostree/repo set core.mode bare-user-only"))
380 sysroot = temp_dir.Path().string();
381 TestUtils::waitForServer(treehub_server +
"/");
382 #endif // BUILD_OSTREE 383 return RUN_ALL_TESTS();
385 #endif // __NO_MAIN__ Provides a thread-safe way to pause and terminate task execution.
bool setPause(bool set_paused)
Called by the controlling thread to request the task to pause or resume.
Configuration object for an aktualizr instance running on a Primary ECU.
Results of libaktualizr API calls.