| // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "p2p/common/testutil.h" |
| |
| #include <attr/xattr.h> |
| #include <fcntl.h> |
| #include <stdarg.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <glib-object.h> |
| |
| #include <cctype> |
| #include <cinttypes> |
| #include <cstdlib> |
| |
| #include <base/logging.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <gtest/gtest.h> |
| |
| using std::string; |
| |
| using base::FilePath; |
| |
| namespace p2p { |
| |
| namespace testutil { |
| |
| // This is the message to be displayed if the TimeBombAbort timeout is |
| // reached. |
| static const char* time_bomb_abort_message_ = NULL; |
| |
| TimeBombAbort::TimeBombAbort(int timeout_seconds, const char* message) { |
| CHECK(time_bomb_abort_message_ == NULL); |
| time_bomb_abort_message_ = message; |
| // Install the signal handler keeping the previous one. |
| struct sigaction time_bomb_action; |
| time_bomb_action.sa_flags = 0; |
| time_bomb_action.sa_handler = TimeoutHandler; |
| sigaction(SIGALRM, &time_bomb_action, &previous_); |
| alarm(timeout_seconds); |
| } |
| |
| TimeBombAbort::~TimeBombAbort() { |
| // Restore the previous sigaction. |
| alarm(0); |
| sigaction(SIGALRM, &previous_, NULL); |
| time_bomb_abort_message_ = NULL; |
| } |
| |
| void TimeBombAbort::TimeoutHandler(int signal) { |
| // Does a "best-effort" write. |
| const char* msg = "\n\nTimeBombAbort::TimeoutHandler reached.\n"; |
| if (write(STDERR_FILENO, msg, strlen(msg))) {} // Ignore the return value. |
| if (write(STDERR_FILENO, time_bomb_abort_message_, |
| strlen(time_bomb_abort_message_))) {} // Ignore the return value. |
| exit(1); |
| } |
| |
| FilePath SetupTestDir(const string& test_name) { |
| // Create testing directory |
| FilePath ret; |
| string dir_name = string("/tmp/p2p-testing-") + test_name + ".XXXXXX"; |
| char* buf = strdup(dir_name.c_str()); |
| EXPECT_TRUE(mkdtemp(buf) != NULL); |
| ret = FilePath(buf); |
| free(buf); |
| return ret; |
| } |
| |
| void TeardownTestDir(const FilePath& dir_path) { |
| // Sanity check |
| EXPECT_EQ(0, dir_path.value().find("/tmp/p2p-testing-")); |
| EXPECT_COMMAND(0, "rm -rf %s", dir_path.value().c_str()); |
| } |
| |
| static gboolean RunGMainLoopOnTimeout(gpointer user_data) { |
| bool* timeout = static_cast<bool*>(user_data); |
| *timeout = true; |
| return FALSE; // Remove timeout source |
| } |
| |
| void RunGMainLoopUntil(int timeout_msec, |
| base::Callback<bool()> terminate) { |
| GMainLoop* loop = g_main_loop_new(NULL, FALSE); |
| GMainContext* context = g_main_context_default(); |
| |
| bool timeout = false; |
| guint source_id = g_timeout_add( |
| timeout_msec, p2p::testutil::RunGMainLoopOnTimeout, &timeout); |
| |
| while (!timeout && (terminate.is_null() || !terminate.Run())) |
| g_main_context_iteration(context, TRUE); |
| |
| g_source_remove(source_id); |
| g_main_loop_unref(loop); |
| } |
| |
| int RunGMainLoopMaxIterations(int iterations) { |
| int result; |
| GMainContext* context = g_main_context_default(); |
| for (result = 0; |
| result < iterations && g_main_context_iteration(context, FALSE); |
| result++) {} |
| return result; |
| } |
| |
| size_t FileSize(const FilePath& dir, |
| const string& file_name) { |
| struct stat stat_buf; |
| FilePath path = dir.Append(file_name); |
| if (stat(path.value().c_str(), &stat_buf) != 0) { |
| return 0; |
| } |
| return stat_buf.st_size; |
| } |
| |
| void ExpectFileSize(const FilePath& dir, |
| const string& file_name, |
| size_t expected_size) { |
| EXPECT_EQ(FileSize(dir, file_name), expected_size); |
| } |
| |
| bool SetExpectedFileSize(const FilePath& filename, size_t size) { |
| int fd = open(filename.value().c_str(), O_RDWR); |
| if (fd == -1) |
| return false; |
| |
| string decimal_size = base::UintToString(size); |
| if (fsetxattr(fd, "user.cros-p2p-filesize", |
| decimal_size.c_str(), decimal_size.size(), 0) != 0) { |
| close(fd); |
| return false; |
| } |
| close(fd); |
| return true; |
| } |
| |
| } // namespace testutil |
| |
| } // namespace p2p |