Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b72c64c0 authored by Qasim Javed's avatar Qasim Javed
Browse files

Wait for a string to appear in logs.

Currently, we have to wait for arbitrary amount of time before we check
the log for a particular string. Instead of that, add functionality to
wait for a provided string to appear in the logs.

When an fd is dup?()'ed, the oldfd and the newfd share the offset.
So when the offset is changed on the oldfd using lseek, that change in
offset is applied to the newfd as well. In the context of this change,
it means that when we Rewind(), that also changes where the logs will be
written in the backing store. It can cause problems if we are
Rewind()'ing while logs are being written.

This change keeps the dup'ed fd since its needed to create a backing
store. However, it creates adds a new fd which uses the open system call
to get a new fd to the underlying backing store file. Since this is a
separate fd, an lseek on this fd will not result in a change in offset
on the newfd and oldfd provided to dup3 system call.

Bug: 246955322
Tag: #gd-refactor
Test: atest bluetooth_test_gd_unit

Change-Id: Ib2fcfeef82d3419f4c02e1815b907b0b6ac499a9
parent a21f10ff
Loading
Loading
Loading
Loading
+30 −8
Original line number Diff line number Diff line
@@ -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;
  }
@@ -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;
  }
@@ -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));
      }
    }
  }
}

@@ -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 {
@@ -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;
+5 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <cstddef>
#include <future>
#include <string>

namespace bluetooth {
@@ -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};
};
+10 −0
Original line number Diff line number Diff line
@@ -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