1 #include <gtest/gtest.h> 3 #include <sys/statvfs.h> 10 #include <boost/process.hpp> 12 #include "http/httpclient.h" 14 #include "libaktualizr/config.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.pacman.images_path = temp_dir.Path() /
"images";
61 config.uptane.repo_server = server;
62 config.pacman.type = type;
63 config.pacman.sysroot = sysroot;
64 config.pacman.ostree_server = treehub_server;
66 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
67 auto http = std::make_shared<HttpClient>();
69 auto pacman = PackageManagerFactory::makePackageManager(config.pacman, config.bootloader, storage, http);
70 KeyManager keys(storage, config.keymanagerConfig());
74 EXPECT_EQ(token.
setPause(
true),
true);
75 EXPECT_EQ(token.
setPause(
false),
true);
77 std::promise<void> pause_promise;
78 std::promise<bool> download_promise;
79 auto result = download_promise.get_future();
80 auto pause_res = pause_promise.get_future();
81 auto start = std::chrono::high_resolution_clock::now();
84 std::thread([&target, &fetcher, &download_promise, &token, pacman, &keys]() {
85 bool res = pacman->fetchTarget(target, fetcher, keys, progress_cb, &token);
86 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();
100 ASSERT_EQ(
result.wait_for(std::chrono::seconds(download_timeout)), std::future_status::ready);
101 ASSERT_EQ(pause_res.wait_for(std::chrono::seconds(0)), std::future_status::ready);
104 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - start).count();
105 EXPECT_TRUE(
result.get());
106 EXPECT_GE(duration, pause_duration);
114 TEST(Fetcher, PauseOstree) {
115 Json::Value target_json;
116 target_json[
"hashes"][
"sha256"] =
"b9ac1e45f9227df8ee191b6e51e09417bd36c6ebbeff999431e3073ac50f0563";
117 target_json[
"custom"][
"targetFormat"] =
"OSTREE";
118 target_json[
"length"] = 0;
120 test_pause(target, PACKAGE_MANAGER_OSTREE);
122 #endif // BUILD_OSTREE 124 TEST(Fetcher, PauseBinary) {
125 Json::Value target_json;
126 target_json[
"hashes"][
"sha256"] =
"dd7bd1c37a3226e520b8d6939c30991b1c08772d5dab62b381c3a63541dc629a";
127 target_json[
"length"] = 100 * (1 << 20);
136 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
137 void* userp, curl_off_t from)
override {
142 EXPECT_EQ(url,
"test-uri");
148 TEST(Fetcher, DownloadCustomUri) {
150 config.pacman.images_path = temp_dir.Path() /
"images";
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.pacman.images_path = temp_dir.Path() /
"images";
190 config.uptane.repo_server = server;
192 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
193 auto http = std::make_shared<HttpDefaultUri>(temp_dir.Path());
194 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
195 KeyManager keys(storage, config.keymanagerConfig());
200 Json::Value target_json;
201 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
202 target_json[
"length"] = 1;
205 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
209 Json::Value target_json;
210 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
211 target_json[
"custom"][
"uri"] =
"";
212 target_json[
"length"] = 1;
215 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
219 Json::Value target_json;
220 target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
221 target_json[
"custom"][
"uri"] =
"https://example.com/";
222 target_json[
"length"] = 1;
225 EXPECT_TRUE(pacman->fetchTarget(target, fetcher, keys, progress_cb,
nullptr));
232 HttpResponse download(
const std::string& url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
233 void* userp, curl_off_t from)
override {
237 EXPECT_EQ(url, server +
"/targets/fake_file");
238 const std::string content =
"0";
239 write_cb(const_cast<char*>(&content[0]), 1, 1, userp);
249 TEST(Fetcher, DownloadLengthZero) {
251 config.storage.path = temp_dir.Path();
252 config.pacman.images_path = temp_dir.Path() /
"images";
253 config.uptane.repo_server = server;
255 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
256 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
257 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
258 KeyManager keys(storage, config.keymanagerConfig());
262 Json::Value empty_target_json;
263 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
264 empty_target_json[
"length"] = 0;
266 empty_target_json[
"custom"][
"targetFormat"] =
"binary";
268 EXPECT_TRUE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
269 EXPECT_EQ(pacman->verifyTarget(empty_target), TargetStatus::kGood);
270 EXPECT_EQ(http->counter, 0);
274 Json::Value nonempty_target_json;
275 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
276 nonempty_target_json[
"length"] = 1;
277 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
278 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
279 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
280 EXPECT_EQ(http->counter, 1);
285 TEST(Fetcher, NotEnoughDiskSpace) {
287 config.storage.path = temp_dir.Path();
288 config.pacman.images_path = temp_dir.Path() /
"images";
289 config.uptane.repo_server = server;
291 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
292 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
293 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
294 KeyManager keys(storage, config.keymanagerConfig());
298 struct statvfs stvfsbuf {};
299 EXPECT_EQ(statvfs(temp_dir.Path().c_str(), &stvfsbuf), 0);
300 const uint64_t available_bytes = (stvfsbuf.f_bsize * stvfsbuf.f_bavail);
304 Json::Value empty_target_json;
305 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
306 empty_target_json[
"length"] = available_bytes * 2;
308 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
309 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
310 EXPECT_EQ(http->counter, 0);
314 Json::Value nonempty_target_json;
315 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
316 nonempty_target_json[
"length"] = 1;
317 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
318 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
319 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
320 EXPECT_EQ(http->counter, 1);
324 TEST(Fetcher, DownloadOstreeFail) {
326 config.storage.path = temp_dir.Path();
327 config.pacman.images_path = temp_dir.Path() /
"images";
328 config.uptane.repo_server = server;
330 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
331 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
332 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
333 KeyManager keys(storage, config.keymanagerConfig());
337 Json::Value empty_target_json;
338 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
339 empty_target_json[
"length"] = 0;
340 empty_target_json[
"custom"][
"targetFormat"] =
"OSTREE";
342 EXPECT_FALSE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
343 EXPECT_NE(pacman->verifyTarget(empty_target), TargetStatus::kGood);
344 EXPECT_EQ(http->counter, 0);
348 Json::Value nonempty_target_json;
349 nonempty_target_json[
"hashes"][
"sha256"] =
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9";
350 nonempty_target_json[
"length"] = 1;
351 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
352 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
353 EXPECT_EQ(pacman->verifyTarget(nonempty_target), TargetStatus::kGood);
354 EXPECT_EQ(http->counter, 1);
358 int main(
int argc,
char** argv) {
359 ::testing::InitGoogleTest(&argc, argv);
362 logger_set_threshold(boost::log::trivial::debug);
364 std::string port = TestUtils::getFreePort();
366 boost::process::child http_server_process(
"tests/fake_http_server/fake_test_server.py", port,
"-f");
367 TestUtils::waitForServer(server +
"/");
369 std::string treehub_port = TestUtils::getFreePort();
370 treehub_server += treehub_port;
372 boost::process::child ostree_server_process(
"tests/sota_tools/treehub_server.py", std::string(
"-p"), treehub_port,
373 std::string(
"-d"), treehub_dir.PathString(), std::string(
"-s0.5"),
374 std::string(
"--create"));
376 int r = system((std::string(
"ostree admin init-fs ") + temp_dir.PathString()).c_str());
380 r = system((std::string(
"ostree config --repo=") + temp_dir.PathString() +
381 std::string(
"/ostree/repo set core.mode bare-user-only"))
386 sysroot = temp_dir.Path().string();
387 TestUtils::waitForServer(treehub_server +
"/");
388 #endif // BUILD_OSTREE 389 return RUN_ALL_TESTS();
391 #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.