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);
89 std::thread([&token, &pause_promise]() {
90 std::unique_lock<std::mutex> lk(pause_m);
91 cv.wait(lk, [] {
return do_pause; });
92 EXPECT_EQ(token.
setPause(
true),
true);
93 EXPECT_EQ(token.
setPause(
true),
false);
94 std::this_thread::sleep_for(std::chrono::seconds(pause_duration));
95 EXPECT_EQ(token.
setPause(
false),
true);
96 EXPECT_EQ(token.
setPause(
false),
false);
97 pause_promise.set_value();
101 ASSERT_EQ(
result.wait_for(std::chrono::seconds(download_timeout)), std::future_status::ready);
102 ASSERT_EQ(pause_res.wait_for(std::chrono::seconds(0)), std::future_status::ready);
105 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - start).count();
106 EXPECT_TRUE(
result.get());
107 EXPECT_GE(duration, pause_duration);
115 TEST(Fetcher, PauseOstree) {
116 Json::Value target_json;
117 target_json[
"hashes"][
"sha256"] =
"b9ac1e45f9227df8ee191b6e51e09417bd36c6ebbeff999431e3073ac50f0563";
118 target_json[
"custom"][
"targetFormat"] =
"OSTREE";
119 target_json[
"length"] = 0;
121 test_pause(target, PACKAGE_MANAGER_OSTREE);
123 #endif // BUILD_OSTREE
125 TEST(Fetcher, PauseBinary) {
126 Json::Value target_json;
127 target_json[
"hashes"][
"sha256"] =
"dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
128 target_json[
"length"] = 100 * (1 << 20);
137 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
138 void* userp, curl_off_t from)
override {
143 EXPECT_EQ(url,
"test-uri");
149 TEST(Fetcher, DownloadCustomUri) {
151 config.storage.path = temp_dir.Path();
152 config.uptane.repo_server = server;
154 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
155 auto http = std::make_shared<HttpCustomUri>(temp_dir.Path());
157 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
158 KeyManager keys(storage, config.keymanagerConfig());
162 Json::Value target_json;
163 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
164 target_json[
"custom"][
"uri"] =
"test-uri";
165 target_json[
"length"] = 1;
168 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
174 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
175 void* userp, curl_off_t from)
override {
180 EXPECT_EQ(url, server +
"/targets/fake_file");
186 TEST(Fetcher, DownloadDefaultUri) {
188 config.storage.path = temp_dir.Path();
189 config.uptane.repo_server = server;
191 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
192 auto http = std::make_shared<HttpDefaultUri>(temp_dir.Path());
193 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
194 KeyManager keys(storage, config.keymanagerConfig());
199 Json::Value target_json;
200 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
201 target_json[
"length"] = 1;
204 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
208 Json::Value target_json;
209 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
210 target_json[
"custom"][
"uri"] =
"";
211 target_json[
"length"] = 1;
214 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
218 Json::Value target_json;
219 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
220 target_json[
"custom"][
"uri"] =
"https://example.com/";
221 target_json[
"length"] = 1;
224 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
231 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
232 void* userp, curl_off_t from)
override {
236 EXPECT_EQ(url, server +
"/targets/fake_file");
237 const std::string content =
"0";
238 write_cb(const_cast<char*>(&content[0]), 1, 1, userp);
248 TEST(Fetcher, DownloadLengthZero) {
250 config.storage.path = temp_dir.Path();
251 config.uptane.repo_server = server;
253 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
254 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
255 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
256 KeyManager keys(storage, config.keymanagerConfig());
260 Json::Value empty_target_json;
261 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
262 empty_target_json[
"length"] = 0;
264 empty_target_json[
"custom"][
"targetFormat"] =
"binary";
266 EXPECT_TRUE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
267 EXPECT_EQ(pacman->verifyTarget(empty_target), TargetStatus::kGood);
268 EXPECT_EQ(http->counter, 0);
272 Json::Value nonempty_target_json;
273 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
274 nonempty_target_json[
"length"] = 1;
275 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
276 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
277 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
278 EXPECT_EQ(http->counter, 1);
283 TEST(Fetcher, NotEnoughDiskSpace) {
285 config.storage.path = temp_dir.Path();
286 config.uptane.repo_server = server;
288 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
289 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
290 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
291 KeyManager keys(storage, config.keymanagerConfig());
295 struct statvfs stvfsbuf {};
296 EXPECT_EQ(statvfs(temp_dir.Path().c_str(), &stvfsbuf), 0);
297 const uint64_t available_bytes = (stvfsbuf.f_bsize * stvfsbuf.f_bavail);
301 Json::Value empty_target_json;
302 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
303 empty_target_json[
"length"] = available_bytes * 2;
305 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
306 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
307 EXPECT_EQ(http->counter, 0);
311 Json::Value nonempty_target_json;
312 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
313 nonempty_target_json[
"length"] = 1;
314 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
315 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
316 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
317 EXPECT_EQ(http->counter, 1);
321 TEST(Fetcher, DownloadOstreeFail) {
323 config.storage.path = temp_dir.Path();
324 config.uptane.repo_server = server;
326 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
327 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
328 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
329 KeyManager keys(storage, config.keymanagerConfig());
333 Json::Value empty_target_json;
334 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
335 empty_target_json[
"length"] = 0;
336 empty_target_json[
"custom"][
"targetFormat"] =
"OSTREE";
338 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
339 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
340 EXPECT_EQ(http->counter, 0);
344 Json::Value nonempty_target_json;
345 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
346 nonempty_target_json[
"length"] = 1;
347 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
348 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
349 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
350 EXPECT_EQ(http->counter, 1);
354 int main(
int argc,
char** argv) {
355 ::testing::InitGoogleTest(&argc, argv);
358 logger_set_threshold(boost::log::trivial::debug);
360 std::string port = TestUtils::getFreePort();
362 boost::process::child http_server_process(
"tests/fake_http_server/fake_test_server.py", port,
"-f");
363 TestUtils::waitForServer(server +
"/");
365 std::string treehub_port = TestUtils::getFreePort();
366 treehub_server += treehub_port;
368 boost::process::child ostree_server_process(
"tests/sota_tools/treehub_server.py", std::string(
"-p"), treehub_port,
369 std::string(
"-d"), treehub_dir.PathString(), std::string(
"-s0.5"),
370 std::string(
"--create"));
372 int r = system((std::string(
"ostree admin init-fs ") + temp_dir.PathString()).c_str());
376 r = system((std::string(
"ostree config --repo=") + temp_dir.PathString() +
377 std::string(
"/ostree/repo set core.mode bare-user-only"))
382 sysroot = temp_dir.Path().string();
383 TestUtils::waitForServer(treehub_server +
"/");
384 #endif // BUILD_OSTREE
385 return RUN_ALL_TESTS();
387 #endif // __NO_MAIN__