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

Commit 9fe430d0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "cherrypicker-L09000000956548908:N73400001298271020" into tm-qpr-dev

* changes:
  Split log_capture into android and host targets
  Wait for a string to appear in logs.
  test: log capture add fd sync
parents ed092cb8 bc8fa74a
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -351,12 +351,16 @@ cc_test {
            srcs: [
                ":BluetoothHalTestSources_hci_host",
                ":BluetoothOsTestSources_host",
                ":BluetoothHostTestingLogCapture",
                ":BluetoothHostTestingLogCaptureTest",
            ],
        },
        android: {
            srcs: [
                ":BluetoothHalTestSources_hci_android_hidl",
                ":BluetoothOsTestSources_android",
                ":BluetoothAndroidTestingLogCapture",
                ":BluetoothAndroidTestingLogCaptureTest",
            ],
            static_libs: [
                "android.system.suspend.control-V1-ndk",
+36 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "system_bt_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["system_bt_license"],
}

filegroup {
    name: "BluetoothAndroidTestingLogCapture",
    srcs: [
            "android/log_capture.cc",
  ],
}

filegroup {
    name: "BluetoothAndroidTestingLogCaptureTest",
    srcs: [
            "android/log_capture_test.cc",
    ],
}

filegroup {
    name: "BluetoothHostTestingLogCapture",
    srcs: [
            "host/log_capture.cc",
  ],
}

filegroup {
    name: "BluetoothHostTestingLogCaptureTest",
    srcs: [
            "host/log_capture_test.cc",
    ],
}
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common/testing/log_capture.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <cstddef>
#include <sstream>
#include <string>

#include "os/log.h"

namespace bluetooth {
namespace testing {

LogCapture::LogCapture() {
  LOG_INFO(
      "Log capture disabled for android build dup_fd:%d fd:%d original_stderr_fd:%d",
      dup_fd_,
      fd_,
      original_stderr_fd_);
}

LogCapture::~LogCapture() {}

LogCapture* LogCapture::Rewind() {
  return this;
}

bool LogCapture::Find(std::string to_find) {
  // For |atest| assume all log captures succeed
  return true;
}

void LogCapture::Flush() {}

void LogCapture::Sync() {}

void LogCapture::Reset() {}

std::string LogCapture::Read() {
  return std::string();
}

size_t LogCapture::Size() const {
  size_t size{0UL};
  return size;
}

void LogCapture::WaitUntilLogContains(std::promise<void>* promise, std::string text) {
  std::async([promise, text]() { promise->set_value(); });
  promise->get_future().wait();
}

std::pair<int, int> LogCapture::create_backing_store() const {
  int dup_fd = -1;
  int fd = -1;
  return std::make_pair(dup_fd, fd);
}

bool LogCapture::set_non_blocking(int fd) const {
  return true;
}

void LogCapture::clean_up() {}

}  // namespace testing
}  // namespace bluetooth
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "../log_capture.h"

#include <gtest/gtest.h>

#include <cstring>
#include <memory>
#include <string>

#include "common/init_flags.h"
#include "os/log.h"

namespace bluetooth {
namespace testing {

class LogCaptureTest : public ::testing::Test {
 protected:
  void SetUp() override {}

  void TearDown() override {}
};

TEST_F(LogCaptureTest, not_working_over_atest) {}

}  // namespace testing
}  // namespace bluetooth
+190 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common/testing/log_capture.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <cstddef>
#include <sstream>
#include <string>

#include "os/log.h"

namespace {
constexpr char kTempFilename[] = "/tmp/bt_gtest_log_capture-XXXXXX";
constexpr size_t kTempFilenameMaxSize = 64;
constexpr size_t kBufferSize = 4096;
constexpr int kStandardErrorFd = STDERR_FILENO;
}  // namespace

namespace bluetooth {
namespace testing {

LogCapture::LogCapture() {
  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(dup_fd_)) {
    LOG_ERROR("Unable to set socket non-blocking : %s", strerror(errno));
    return;
  }
  original_stderr_fd_ = fcntl(kStandardErrorFd, F_DUPFD_CLOEXEC);
  if (original_stderr_fd_ == -1) {
    LOG_ERROR("Unable to save original fd : %s", strerror(errno));
    return;
  }
  if (dup3(dup_fd_, kStandardErrorFd, O_CLOEXEC) == -1) {
    LOG_ERROR("Unable to duplicate stderr fd : %s", strerror(errno));
    return;
  }
}

LogCapture::~LogCapture() {
  Rewind()->Flush();
  clean_up();
}

LogCapture* LogCapture::Rewind() {
  if (fd_ != -1) {
    if (lseek(fd_, 0, SEEK_SET) != 0) {
      LOG_ERROR("Unable to rewind log capture : %s", strerror(errno));
    }
  }
  return this;
}

bool LogCapture::Find(std::string to_find) {
  std::string str = this->Read();
  return str.find(to_find) != std::string::npos;
}

void LogCapture::Flush() {
  if (fd_ != -1 && original_stderr_fd_ != -1) {
    ssize_t sz{-1};
    do {
      char buf[kBufferSize];
      sz = read(fd_, buf, sizeof(buf));
      if (sz > 0) {
        write(original_stderr_fd_, buf, sz);
      }
    } while (sz == kBufferSize);
  }
}

void LogCapture::Sync() {
  if (fd_ != -1) {
    fsync(fd_);
  }
}

void LogCapture::Reset() {
  if (fd_ != -1) {
    if (ftruncate(fd_, 0UL) == -1) {
      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));
      }
    }
  }
}

std::string LogCapture::Read() {
  if (fd_ == -1) {
    return std::string();
  }
  std::ostringstream oss;
  ssize_t sz{-1};
  do {
    char buf[kBufferSize];
    sz = read(fd_, buf, sizeof(buf));
    if (sz > 0) {
      oss << buf;
    }
  } while (sz == kBufferSize);
  return oss.str();
}

size_t LogCapture::Size() const {
  size_t size{0UL};
  struct stat statbuf;
  if (fd_ != -1 && fstat(fd_, &statbuf) != -1) {
    size = statbuf.st_size;
  }
  return size;
}

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 dup_fd = mkstemp(backing_store_filename);
  int fd = open(backing_store_filename, O_RDWR);
  if (dup_fd != -1) {
    unlink(backing_store_filename);
  }
  return std::make_pair(dup_fd, fd);
}

bool LogCapture::set_non_blocking(int fd) const {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1) {
    LOG_ERROR("Unable to get file descriptor flags : %s", strerror(errno));
    return false;
  }
  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
    LOG_ERROR("Unable to set file descriptor flags : %s", strerror(errno));
    return false;
  }
  return true;
}

void LogCapture::clean_up() {
  if (original_stderr_fd_ != -1) {
    if (dup3(original_stderr_fd_, kStandardErrorFd, O_CLOEXEC) != kStandardErrorFd) {
      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;
  }
}

}  // namespace testing
}  // namespace bluetooth
Loading