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, PackageManager type = PackageManager::kNone) {
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, PackageManager::kOstree);
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 {
238 EXPECT_EQ(url, server +
"/targets/fake_file");
247 TEST(Fetcher, DownloadLengthZero) {
249 config.storage.path = temp_dir.Path();
250 config.uptane.repo_server = server;
252 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
253 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
254 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
255 KeyManager keys(storage, config.keymanagerConfig());
259 Json::Value empty_target_json;
260 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
261 empty_target_json[
"length"] = 0;
263 EXPECT_TRUE(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr));
264 EXPECT_EQ(http->counter, 0);
268 Json::Value nonempty_target_json;
269 nonempty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
270 nonempty_target_json[
"length"] = 1;
271 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
272 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
273 EXPECT_EQ(http->counter, 1);
278 TEST(Fetcher, NotEnoughDiskSpace) {
280 config.storage.path = temp_dir.Path();
281 config.uptane.repo_server = server;
283 std::shared_ptr<INvStorage> storage(
new SQLStorage(config.storage,
false));
284 auto http = std::make_shared<HttpZeroLength>(temp_dir.Path());
285 auto pacman = std::make_shared<PackageManagerFake>(config.pacman, config.bootloader, storage, http);
286 KeyManager keys(storage, config.keymanagerConfig());
290 struct statvfs stvfsbuf {};
291 EXPECT_EQ(statvfs(temp_dir.Path().c_str(), &stvfsbuf), 0);
292 const uint64_t available_bytes = (stvfsbuf.f_bsize * stvfsbuf.f_bavail);
296 Json::Value empty_target_json;
297 empty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
298 empty_target_json[
"length"] = available_bytes * 2;
300 EXPECT_THROW(pacman->fetchTarget(empty_target, fetcher, keys, progress_cb,
nullptr), std::runtime_error);
301 EXPECT_EQ(http->counter, 0);
305 Json::Value nonempty_target_json;
306 nonempty_target_json[
"hashes"][
"sha256"] =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
307 nonempty_target_json[
"length"] = 1;
308 Uptane::Target nonempty_target(
"fake_file", nonempty_target_json);
309 EXPECT_TRUE(pacman->fetchTarget(nonempty_target, fetcher, keys, progress_cb,
nullptr));
310 EXPECT_EQ(http->counter, 1);
314 int main(
int argc,
char** argv) {
315 ::testing::InitGoogleTest(&argc, argv);
318 logger_set_threshold(boost::log::trivial::debug);
320 std::string port = TestUtils::getFreePort();
322 boost::process::child http_server_process(
"tests/fake_http_server/fake_test_server.py", port,
"-f");
323 TestUtils::waitForServer(server +
"/");
325 std::string treehub_port = TestUtils::getFreePort();
326 treehub_server += treehub_port;
328 boost::process::child ostree_server_process(
"tests/sota_tools/treehub_server.py", std::string(
"-p"), treehub_port,
329 std::string(
"-d"), treehub_dir.PathString(), std::string(
"-s0.5"),
330 std::string(
"--create"));
332 int r = system((std::string(
"ostree admin init-fs ") + temp_dir.PathString()).c_str());
336 r = system((std::string(
"ostree config --repo=") + temp_dir.PathString() +
337 std::string(
"/ostree/repo set core.mode bare-user-only"))
342 sysroot = temp_dir.Path().string();
343 TestUtils::waitForServer(treehub_server +
"/");
344 #endif // BUILD_OSTREE
345 return RUN_ALL_TESTS();
347 #endif // __NO_MAIN__