Loading system/gd/common/testing/log_capture.cc +30 −8 Original line number Diff line number Diff line Loading @@ -37,12 +37,12 @@ namespace bluetooth { namespace testing { LogCapture::LogCapture() { fd_ = create_backing_store(); if (fd_ == -1) { std::tie(dup_fd_, fd_) = create_backing_store(); if (dup_fd_ == -1 || fd_ == -1) { LOG_ERROR("Unable to create backing storage : %s", strerror(errno)); return; } if (!set_non_blocking(fd_)) { if (!set_non_blocking(dup_fd_)) { LOG_ERROR("Unable to set socket non-blocking : %s", strerror(errno)); return; } Loading @@ -51,7 +51,7 @@ LogCapture::LogCapture() { LOG_ERROR("Unable to save original fd : %s", strerror(errno)); return; } if (dup3(fd_, kStandardErrorFd, O_CLOEXEC) == -1) { if (dup3(dup_fd_, kStandardErrorFd, O_CLOEXEC) == -1) { LOG_ERROR("Unable to duplicate stderr fd : %s", strerror(errno)); return; } Loading Loading @@ -95,6 +95,12 @@ void LogCapture::Reset() { LOG_ERROR("Unable to truncate backing storage : %s", strerror(errno)); } this->Rewind(); // The only time we rewind the dup()'ed fd is during Reset() if (dup_fd_ != -1) { if (lseek(dup_fd_, 0, SEEK_SET) != 0) { LOG_ERROR("Unable to rewind log capture : %s", strerror(errno)); } } } } Loading Loading @@ -123,14 +129,26 @@ size_t LogCapture::Size() const { return size; } int LogCapture::create_backing_store() const { void LogCapture::WaitUntilLogContains(std::promise<void>* promise, std::string text) { std::async([this, promise, text]() { bool found = false; do { found = this->Rewind()->Find(text); } while (!found); promise->set_value(); }); promise->get_future().wait(); } std::pair<int, int> LogCapture::create_backing_store() const { char backing_store_filename[kTempFilenameMaxSize]; strncpy(backing_store_filename, kTempFilename, kTempFilenameMaxSize); int fd = mkstemp(backing_store_filename); if (fd != -1) { int dup_fd = mkstemp(backing_store_filename); int fd = open(backing_store_filename, O_RDWR); if (dup_fd != -1) { unlink(backing_store_filename); } return fd; return std::make_pair(dup_fd, fd); } bool LogCapture::set_non_blocking(int fd) const { Loading @@ -152,6 +170,10 @@ void LogCapture::clean_up() { LOG_ERROR("Unable to restore original fd : %s", strerror(errno)); } } if (dup_fd_ != -1) { close(dup_fd_); dup_fd_ = -1; } if (fd_ != -1) { close(fd_); fd_ = -1; Loading system/gd/common/testing/log_capture.h +5 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <cstddef> #include <future> #include <string> namespace bluetooth { Loading @@ -39,12 +40,15 @@ class LogCapture { size_t Size() const; // Truncates and resets the file pointer discarding all logs up to this point void Reset(); // Wait until the provided string shows up in the logs void WaitUntilLogContains(std::promise<void>* promise, std::string text); private: int create_backing_store() const; std::pair<int, int> create_backing_store() const; bool set_non_blocking(int fd) const; void clean_up(); int dup_fd_{-1}; int fd_{-1}; int original_stderr_fd_{-1}; }; Loading system/gd/common/testing/log_capture_test.cc +10 −0 Original line number Diff line number Diff line Loading @@ -135,5 +135,15 @@ TEST_F(LogCaptureTest, with_logging_debug_enabled_for_all) { bluetooth::common::InitFlags::Load(nullptr); } TEST_F(LogCaptureTest, wait_until_log_contains) { bluetooth::common::InitFlags::Load(test_flags); std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>(); LOG_DEBUG("%s", kLogDebug); std::promise<void> promise; log_capture->WaitUntilLogContains(&promise, kLogDebug); bluetooth::common::InitFlags::Load(nullptr); } } // namespace testing } // namespace bluetooth Loading
system/gd/common/testing/log_capture.cc +30 −8 Original line number Diff line number Diff line Loading @@ -37,12 +37,12 @@ namespace bluetooth { namespace testing { LogCapture::LogCapture() { fd_ = create_backing_store(); if (fd_ == -1) { std::tie(dup_fd_, fd_) = create_backing_store(); if (dup_fd_ == -1 || fd_ == -1) { LOG_ERROR("Unable to create backing storage : %s", strerror(errno)); return; } if (!set_non_blocking(fd_)) { if (!set_non_blocking(dup_fd_)) { LOG_ERROR("Unable to set socket non-blocking : %s", strerror(errno)); return; } Loading @@ -51,7 +51,7 @@ LogCapture::LogCapture() { LOG_ERROR("Unable to save original fd : %s", strerror(errno)); return; } if (dup3(fd_, kStandardErrorFd, O_CLOEXEC) == -1) { if (dup3(dup_fd_, kStandardErrorFd, O_CLOEXEC) == -1) { LOG_ERROR("Unable to duplicate stderr fd : %s", strerror(errno)); return; } Loading Loading @@ -95,6 +95,12 @@ void LogCapture::Reset() { LOG_ERROR("Unable to truncate backing storage : %s", strerror(errno)); } this->Rewind(); // The only time we rewind the dup()'ed fd is during Reset() if (dup_fd_ != -1) { if (lseek(dup_fd_, 0, SEEK_SET) != 0) { LOG_ERROR("Unable to rewind log capture : %s", strerror(errno)); } } } } Loading Loading @@ -123,14 +129,26 @@ size_t LogCapture::Size() const { return size; } int LogCapture::create_backing_store() const { void LogCapture::WaitUntilLogContains(std::promise<void>* promise, std::string text) { std::async([this, promise, text]() { bool found = false; do { found = this->Rewind()->Find(text); } while (!found); promise->set_value(); }); promise->get_future().wait(); } std::pair<int, int> LogCapture::create_backing_store() const { char backing_store_filename[kTempFilenameMaxSize]; strncpy(backing_store_filename, kTempFilename, kTempFilenameMaxSize); int fd = mkstemp(backing_store_filename); if (fd != -1) { int dup_fd = mkstemp(backing_store_filename); int fd = open(backing_store_filename, O_RDWR); if (dup_fd != -1) { unlink(backing_store_filename); } return fd; return std::make_pair(dup_fd, fd); } bool LogCapture::set_non_blocking(int fd) const { Loading @@ -152,6 +170,10 @@ void LogCapture::clean_up() { LOG_ERROR("Unable to restore original fd : %s", strerror(errno)); } } if (dup_fd_ != -1) { close(dup_fd_); dup_fd_ = -1; } if (fd_ != -1) { close(fd_); fd_ = -1; Loading
system/gd/common/testing/log_capture.h +5 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <cstddef> #include <future> #include <string> namespace bluetooth { Loading @@ -39,12 +40,15 @@ class LogCapture { size_t Size() const; // Truncates and resets the file pointer discarding all logs up to this point void Reset(); // Wait until the provided string shows up in the logs void WaitUntilLogContains(std::promise<void>* promise, std::string text); private: int create_backing_store() const; std::pair<int, int> create_backing_store() const; bool set_non_blocking(int fd) const; void clean_up(); int dup_fd_{-1}; int fd_{-1}; int original_stderr_fd_{-1}; }; Loading
system/gd/common/testing/log_capture_test.cc +10 −0 Original line number Diff line number Diff line Loading @@ -135,5 +135,15 @@ TEST_F(LogCaptureTest, with_logging_debug_enabled_for_all) { bluetooth::common::InitFlags::Load(nullptr); } TEST_F(LogCaptureTest, wait_until_log_contains) { bluetooth::common::InitFlags::Load(test_flags); std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>(); LOG_DEBUG("%s", kLogDebug); std::promise<void> promise; log_capture->WaitUntilLogContains(&promise, kLogDebug); bluetooth::common::InitFlags::Load(nullptr); } } // namespace testing } // namespace bluetooth