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

Commit 89c3340a authored by Chris Manton's avatar Chris Manton
Browse files

Refactor of headless test to allow additional tests

Bug: 147316415

Test: bt_headless --device=40:4e:36:56:f3:9b --loop=1 pairing
Test: bt_headless --device=40:4e:36:56:f3:9b --loop=1 --uuid=0x110e sdp

Change-Id: I202c7af885d86fd77fffeec5a87b56ffe18882da
parent 1d41507e
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -5,7 +5,13 @@ cc_test {
    srcs: [
        "get_options.cc",
        "headless.cc",
        "sdp/main.cc",
        "main.cc",
        "pairing/pairing.cc",
        "sdp/sdp.cc",
        "sdp/sdp_db.cc",
        "nop/nop.cc",
        "read/read.cc",
        "read/name.cc",
    ],
    include_dirs: [
        "packages/modules/Bluetooth/system",
+30 −18
Original line number Diff line number Diff line
@@ -24,19 +24,34 @@
#include <string>

namespace {
constexpr struct option long_options[] = {{"device", required_argument, 0, 0},
                                          {"loop", required_argument, 0, 0},
                                          {"uuid", required_argument, 0, 0},
                                          {0, 0, 0, 0}};
constexpr struct option long_options[] = {
    {"device", required_argument, 0, 0}, {"loop", required_argument, 0, 0},
    {"uuid", required_argument, 0, 0},   {"msleep", required_argument, 0, 0},
    {"stderr", no_argument, 0, 0},       {0, 0, 0, 0}};

enum OptionType {
  kOptionDevice = 0,
  kOptionLoop = 1,
  kOptionUuid = 2,
  kOptionMsleep = 3,
  kOptionStdErr = 4,
};

}  // namespace

void bluetooth::test::headless::GetOpt::Usage() const {
  fprintf(stdout, "%s: Usage:\n", name_);
  fprintf(stdout,
          "%s  --device=<device,>  Comma separated list of remote devices\n",
          name_);
  fprintf(stdout, "%s  --uuid=<uuid,>      Comma separated list of uuids\n",
          name_);
  fprintf(stdout, "%s  --loop=<loop>       Number of loops\n", name_);
  fprintf(stdout, "%s  --msleep=<msecs>    Sleep msec between loops\n", name_);
  fprintf(stdout, "%s  --stderr            Dump stderr to stdout\n", name_);
  fflush(nullptr);
}

void bluetooth::test::headless::GetOpt::ParseValue(
    char* optarg, std::list<std::string>& string_list) {
  CHECK(optarg != nullptr);
@@ -58,9 +73,9 @@ void bluetooth::test::headless::GetOpt::ProcessOption(int option_index,
  std::list<std::string> string_list;
  OptionType option_type = static_cast<OptionType>(option_index);

  if (!optarg) return;
  switch (option_type) {
    case kOptionDevice:
      if (!optarg) return;
      ParseValue(optarg, string_list);
      for (auto& entry : string_list) {
        if (RawAddress::IsValidAddress(entry)) {
@@ -74,12 +89,20 @@ void bluetooth::test::headless::GetOpt::ProcessOption(int option_index,
      loop_ = std::stoul(optarg, nullptr, 0);
      break;
    case kOptionUuid:
      if (!optarg) return;
      ParseValue(optarg, string_list);
      for (auto& entry : string_list) {
        uuid_.push_back(
            bluetooth::Uuid::From16Bit(std::stoul(entry.c_str(), nullptr, 0)));
      }
      break;
    case kOptionMsleep:
      if (!optarg) return;
      msec_ = std::stoul(optarg, nullptr, 0);
      break;
    case kOptionStdErr:
      close_stderr_ = false;
      break;
    default:
      fflush(nullptr);
      valid_ = false;
@@ -108,20 +131,9 @@ bluetooth::test::headless::GetOpt::GetOpt(int argc, char** argv)
    }
  }

  if (optind < argc) {
    printf("non-option ARGV-elements: ");
    while (optind < argc) printf("%s ", argv[optind++]);
    printf("\n");
    valid_ = false;
  while (optind < argc) {
    non_options_.push_back(argv[optind++]);
  }
  fflush(nullptr);
}
void bluetooth::test::headless::GetOpt::Usage() const {
  printf("%s: Usage:\n", name_);
  printf("%s  --device=<device,>  Comma separated list of remote devices\n",
         name_);
  printf("%s  --uuid=<uuid,>      Comma separated list of uuids\n", name_);
  printf("%s  --loop=<loop>       Number of loops\n", name_);
  fflush(nullptr);
}
+12 −1
Original line number Diff line number Diff line
@@ -33,9 +33,20 @@ class GetOpt {
  virtual void Usage() const;
  virtual bool IsValid() const { return valid_; };

  std::string GetNextSubTest() const {
    std::string test = non_options_.front();
    non_options_.pop_front();
    return test;
  }

  std::list<RawAddress> device_;
  std::list<bluetooth::Uuid> uuid_;
  int loop_;
  unsigned long loop_{1};
  unsigned long msec_{0};

  bool close_stderr_{true};

  mutable std::list<std::string> non_options_;

 private:
  void ParseValue(char* optarg, std::list<std::string>& my_list);
+6 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "base/logging.h"  // LOG() stdout and android log
#include "include/hardware/bluetooth.h"
#include "osi/include/log.h"  // android log only
#include "test/headless/get_options.h"
#include "test/headless/headless.h"

extern bt_interface_t bluetoothInterface;
@@ -137,7 +138,7 @@ bt_os_callouts_t bt_os_callouts{
};
}  // namespace

void Headless::SetUp() {
void HeadlessStack::SetUp() {
  LOG(INFO) << __func__ << " Entry";

  int status = bluetoothInterface.init(&bt_callbacks, false, false);
@@ -151,14 +152,14 @@ void Headless::SetUp() {
      : LOG(ERROR) << "Failed to set up Bluetooth OS callouts";

  bluetoothInterface.enable();
  LOG_INFO(LOG_TAG, "%s Headless stack has enabled", __func__);
  LOG_INFO(LOG_TAG, "%s HeadlessStack stack has enabled", __func__);

  std::unique_lock<std::mutex> lck(adapter_state_mutex_);
  while (bt_state_ != BT_STATE_ON) adapter_state_cv_.wait(lck);
  LOG_INFO(LOG_TAG, "%s Headless stack is operational", __func__);
  LOG_INFO(LOG_TAG, "%s HeadlessStack stack is operational", __func__);
}

void Headless::TearDown() {
void HeadlessStack::TearDown() {
  LOG_INFO(LOG_TAG, "Stack has disabled");
  int status = bluetoothInterface.disable();

@@ -169,5 +170,5 @@ void Headless::TearDown() {

  std::unique_lock<std::mutex> lck(adapter_state_mutex_);
  while (bt_state_ != BT_STATE_OFF) adapter_state_cv_.wait(lck);
  LOG_INFO(LOG_TAG, "%s Headless stack has exited", __func__);
  LOG_INFO(LOG_TAG, "%s HeadlessStack stack has exited", __func__);
}
+82 −10
Original line number Diff line number Diff line
@@ -14,32 +14,104 @@
 * limitations under the License.
 */

#pragma once

#include <unordered_map>

#include <unistd.h>

#include "base/logging.h"  // LOG() stdout and android log
#include "test/headless/get_options.h"

namespace bluetooth {
namespace test {
namespace headless {

namespace {

template <typename T>
using ExecutionUnit = std::function<T()>;

class Headless {
 public:
  Headless() = default;
  virtual ~Headless() = default;
constexpr char kHeadlessStartSentinel[] =
    " START HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
    "HEADLESS";
constexpr char kHeadlessStopSentinel[] =
    " STOP HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
    "HEADLESS";

}  // namespace

class HeadlessStack {
 protected:
  virtual void SetUp();
  virtual void TearDown();
  HeadlessStack() = default;
  virtual ~HeadlessStack() = default;

  void SetUp();
  void TearDown();
};

class Test : public Headless {
 public:
class HeadlessRun : public HeadlessStack {
 protected:
  const bluetooth::test::headless::GetOpt& options_;
  unsigned long loop_{0};

  HeadlessRun(const bluetooth::test::headless::GetOpt& options)
      : options_(options) {}

  template <typename T>
  T Run(ExecutionUnit<T> func) {
  T RunOnHeadlessStack(ExecutionUnit<T> func) {
    SetUp();
    T rc = func();
    LOG(INFO) << kHeadlessStartSentinel;

    T rc;
    for (loop_ = 0; loop_ < options_.loop_; loop_++) {
      rc = func();
      if (options_.msec_ != 0) {
        usleep(options_.msec_ * 1000);
      }
      if (rc) {
        break;
      }
    }
    if (rc) {
      LOG(ERROR) << "FAIL:" << rc << " loop/loops:" << loop_ << "/"
                 << options_.loop_;
    } else {
      LOG(INFO) << "PASS:" << rc << " loop/loops:" << loop_ << "/"
                << options_.loop_;
    }

    LOG(INFO) << kHeadlessStopSentinel;
    TearDown();
    return rc;
  }
  virtual ~HeadlessRun() = default;
};

template <typename T>
class HeadlessTest : public HeadlessRun {
 public:
  virtual T Run() {
    if (options_.non_options_.size() == 0) {
      fprintf(stdout, "Must supply at least one subtest name\n");
      return -1;
    }

    std::string subtest = options_.GetNextSubTest();
    if (test_nodes_.find(subtest) == test_nodes_.end()) {
      fprintf(stdout, "Unknown subtest module:%s\n", subtest.c_str());
      return -1;
    }
    return test_nodes_.at(subtest)->Run();
  }

  virtual ~HeadlessTest() = default;

 protected:
  HeadlessTest(const bluetooth::test::headless::GetOpt& options)
      : HeadlessRun(options) {}

  std::unordered_map<std::string, std::unique_ptr<HeadlessTest<T>>> test_nodes_;
};

}  // namespace headless
Loading