1 #include <gtest/gtest.h>
3 #include <sys/statvfs.h>
10 #include <boost/process.hpp>
12 #include "crypto/keymanager.h"
13 #include "http/httpclient.h"
15 #include "libaktualizr/config.h"
16 #include "libaktualizr/packagemanagerfactory.h"
17 #include "logging/logging.h"
18 #include "package_manager/packagemanagerfake.h"
19 #include "storage/sqlstorage.h"
20 #include "test_utils.h"
21 #include "uptane/fetcher.h"
22 #include "uptane/tuf.h"
23 #include "utilities/apiqueue.h"
25 static const int pause_after = 50;
26 static const int pause_duration = 1;
27 static const int download_timeout = 200;
29 static std::string server =
"http://127.0.0.1:";
30 static std::string treehub_server =
"http://127.0.0.1:";
33 static std::mutex pause_m;
34 static std::condition_variable cv;
35 static bool do_pause =
false;
39 static void progress_cb(
const Uptane::Target& target,
const std::string& description,
unsigned int progress) {
42 std::cout <<
"progress callback: " << progress << std::endl;
44 if (progress >= pause_after) {
45 std::lock_guard<std::mutex> lk(pause_m);
59 void test_pause(
const Uptane::Target& target,
const std::string& type = PACKAGE_MANAGER_NONE) {
61 config.storage.path = temp_dir.Path();
62 config.pacman.images_path = temp_dir.Path() /
"images";
63 config.uptane.repo_server = server;
64 config.pacman.type = type;
65 config.pacman.sysroot = sysroot;
66 config.pacman.ostree_server = treehub_server;
68 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
69 auto http = std::make_shared<HttpClient>();
71 auto pacman = PackageManagerFactory::makePackageManager(config.pacman, config.bootloader, storage, http);
72 KeyManager keys(storage, config.keymanagerConfig());
76 EXPECT_EQ(token.
setPause(
true),
true);
77 EXPECT_EQ(token.
setPause(
false),
true);
79 std::promise<void> pause_promise;
80 std::promise<bool> download_promise;
81 auto result = download_promise.get_future();
82 auto pause_res = pause_promise.get_future();
83 auto start = std::chrono::high_resolution_clock::now();
86 std::thread([&target, &fetcher, &download_promise, &token, pacman, &keys]() {
87 bool res = pacman->fetchTarget(target, fetcher, keys, progress_cb, &token);
88 download_promise.set_value(res);
91 std::thread([&token, &pause_promise]() {
92 std::unique_lock<std::mutex> lk(pause_m);
93 cv.wait(lk, [] {
return do_pause; });
94 EXPECT_EQ(token.
setPause(
true),
true);
95 EXPECT_EQ(token.
setPause(
true),
false);
96 std::this_thread::sleep_for(std::chrono::seconds(pause_duration));
97 EXPECT_EQ(token.
setPause(
false),
true);
98 EXPECT_EQ(token.
setPause(
false),
false);
99 pause_promise.set_value();
102 ASSERT_EQ(
result.wait_for(std::chrono::seconds(download_timeout)), std::future_status::ready);
103 ASSERT_EQ(pause_res.wait_for(std::chrono::seconds(0)), std::future_status::ready);
106 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - start).count();
107 EXPECT_TRUE(
result.get());
108 EXPECT_GE(duration, pause_duration);
116 TEST(Fetcher, PauseOstree) {
117 Json::Value target_json;
118 target_json[
"hashes"][
"sha256"] =
"b9ac1e45f9227df8ee191b6e51e09417bd36c6ebbeff999431e3073ac50f0563";
119 target_json[
"custom"][
"targetFormat"] =
"OSTREE";
120 target_json[
"length"] = 0;
122 test_pause(target, PACKAGE_MANAGER_OSTREE);
124 #endif // BUILD_OSTREE
126 TEST(Fetcher, PauseBinary) {
127 Json::Value target_json;
128 target_json[
"hashes"][
"sha256"] =
"dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
129 target_json[
"length"] = 100 * (1 << 20);
138 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
139 void* userp, curl_off_t from)
override {
144 EXPECT_EQ(url,
"test-uri");
150 TEST(Fetcher, DownloadCustomUri) {
152 config.pacman.images_path = temp_dir.Path() /
"images";
153 config.storage.path = temp_dir.Path();
154 config.uptane.repo_server = server;
156 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
157 auto http = std::make_shared<HttpCustomUri>(temp_dir.Path());
159 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
160 KeyManager keys(storage, config.keymanagerConfig());
164 Json::Value target_json;
165 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
166 target_json[
"custom"][
"uri"] =
"test-uri";
167 target_json[
"length"] = 1;
170 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
176 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
177 void* userp, curl_off_t from)
override {
182 EXPECT_EQ(url, server +
"/targets/fake_file");
188 TEST(Fetcher, DownloadDefaultUri) {
190 config.storage.path = temp_dir.Path();
191 config.pacman.images_path = temp_dir.Path() /
"images";
192 config.uptane.repo_server = server;
194 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
195 auto http = std::make_shared<HttpDefaultUri>(temp_dir.Path());
196 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
197 KeyManager keys(storage, config.keymanagerConfig());
202 Json::Value target_json;
203 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
204 target_json[
"length"] = 1;
207 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
211 Json::Value target_json;
212 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
213 target_json[
"custom"][
"uri"] =
"";
214 target_json[
"length"] = 1;
217 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
221 Json::Value target_json;
222 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
223 target_json[
"custom"][
"uri"] =
"https://example.com/";
224 target_json[
"length"] = 1;
227 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
234 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
235 void* userp, curl_off_t from)
override {
239 EXPECT_EQ(url, server +
"/targets/fake_file");
240 const std::string content =
"0";
241 write_cb(
const_cast<char*
>(&content[0]), 1, 1, userp);
251 TEST(Fetcher, DownloadLengthZero) {
253 config.storage.path = temp_dir.Path();
254 config.pacman.images_path = temp_dir.Path() /
"images";
255 config.uptane.repo_server = server;
257 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
258 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
259 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
260 KeyManager keys(storage, config.keymanagerConfig());
264 Json::Value empty_target_json;
265 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
266 empty_target_json[
"length"] = 0;
268 empty_target_json[
"custom"][
"targetFormat"] =
"binary";
270 EXPECT_TRUE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
271 EXPECT_EQ(pacman->verifyTarget(empty_target), TargetStatus::kGood);
272 EXPECT_EQ(http->counter, 0);
276 Json::Value nonempty_target_json;
277 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
278 nonempty_target_json[
"length"] = 1;
279 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
280 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
281 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
282 EXPECT_EQ(http->counter, 1);
287 TEST(Fetcher, NotEnoughDiskSpace) {
289 config.storage.path = temp_dir.Path();
290 config.pacman.images_path = temp_dir.Path() /
"images";
291 config.uptane.repo_server = server;
293 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
294 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
295 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
296 KeyManager keys(storage, config.keymanagerConfig());
300 struct statvfs stvfsbuf {};
301 EXPECT_EQ(statvfs(temp_dir.Path().c_str(), &stvfsbuf), 0);
302 const uint64_t available_bytes = (stvfsbuf.f_bsize * stvfsbuf.f_bavail);
306 Json::Value empty_target_json;
307 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
308 empty_target_json[
"length"] = available_bytes * 2;
310 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
311 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
312 EXPECT_EQ(http->counter, 0);
316 Json::Value nonempty_target_json;
317 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
318 nonempty_target_json[
"length"] = 1;
319 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
320 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
321 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
322 EXPECT_EQ(http->counter, 1);
326 TEST(Fetcher, DownloadOstreeFail) {
328 config.storage.path = temp_dir.Path();
329 config.pacman.images_path = temp_dir.Path() /
"images";
330 config.uptane.repo_server = server;
332 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
333 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
334 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
335 KeyManager keys(storage, config.keymanagerConfig());
339 Json::Value empty_target_json;
340 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
341 empty_target_json[
"length"] = 0;
342 empty_target_json[
"custom"][
"targetFormat"] =
"OSTREE";
344 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
345 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
346 EXPECT_EQ(http->counter, 0);
350 Json::Value nonempty_target_json;
351 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
352 nonempty_target_json[
"length"] = 1;
353 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
354 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
355 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
356 EXPECT_EQ(http->counter, 1);
360 int main(
int argc,
char** argv) {
361 ::testing::InitGoogleTest(&argc, argv);
364 logger_set_threshold(boost::log::trivial::debug);
366 std::string port = TestUtils::getFreePort();
368 boost::process::child http_server_process(
"tests/fake_http_server/fake_test_server.py", port,
"-f");
369 TestUtils::waitForServer(server +
"/");
371 std::string treehub_port = TestUtils::getFreePort();
372 treehub_server += treehub_port;
374 boost::process::child ostree_server_process(
"tests/sota_tools/treehub_server.py", std::string(
"-p"), treehub_port,
375 std::string(
"-d"), treehub_dir.PathString(), std::string(
"-s0.5"),
376 std::string(
"--create"));
378 int r = system((std::string(
"ostree admin init-fs ") + temp_dir.PathString()).c_str());
382 r = system((std::string(
"ostree config --repo=") + temp_dir.PathString() +
383 std::string(
"/ostree/repo set core.mode bare-user-only"))
388 sysroot = temp_dir.Path().string();
389 TestUtils::waitForServer(treehub_server +
"/");
390 #endif // BUILD_OSTREE
391 return RUN_ALL_TESTS();
393 #endif // __NO_MAIN__