1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <unordered_map>
20 
21 #include <unistd.h>
22 
23 #include "base/logging.h"  // LOG() stdout and android log
24 #include "include/hardware/bluetooth.h"
25 #include "test/headless/get_options.h"
26 
27 extern bt_interface_t bluetoothInterface;
28 
29 namespace bluetooth {
30 namespace test {
31 namespace headless {
32 
33 namespace {
34 
35 template <typename T>
36 using ExecutionUnit = std::function<T()>;
37 
38 constexpr char kHeadlessInitialSentinel[] =
39     " INITIAL HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
40     "HEADLESS";
41 constexpr char kHeadlessStartSentinel[] =
42     " START HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
43     "HEADLESS";
44 constexpr char kHeadlessStopSentinel[] =
45     " STOP HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
46     "HEADLESS";
47 constexpr char kHeadlessFinalSentinel[] =
48     " FINAL HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS HEADLESS "
49     "HEADLESS";
50 
51 }  // namespace
52 
53 class HeadlessStack {
54  protected:
HeadlessStack(const char ** stack_init_flags)55   HeadlessStack(const char** stack_init_flags)
56       : stack_init_flags_(stack_init_flags) {}
57   virtual ~HeadlessStack() = default;
58 
59   void SetUp();
60   void TearDown();
StackInitFlags()61   const char** StackInitFlags() const { return stack_init_flags_; }
62 
63  private:
64   const char** stack_init_flags_;
65 };
66 
67 class HeadlessRun : public HeadlessStack {
68  protected:
69   const bluetooth::test::headless::GetOpt& options_;
70   unsigned long loop_{0};
71 
HeadlessRun(const bluetooth::test::headless::GetOpt & options)72   HeadlessRun(const bluetooth::test::headless::GetOpt& options)
73       : HeadlessStack(options.StackInitFlags()), options_(options) {}
74 
75   template <typename T>
RunOnHeadlessStack(ExecutionUnit<T> func)76   T RunOnHeadlessStack(ExecutionUnit<T> func) {
77     LOG(INFO) << kHeadlessInitialSentinel;
78     SetUp();
79     LOG(INFO) << kHeadlessStartSentinel;
80 
81     T rc;
82     for (loop_ = 0; loop_ < options_.loop_; loop_++) {
83       rc = func();
84       if (options_.msec_ != 0) {
85         usleep(options_.msec_ * 1000);
86       }
87       if (rc) {
88         break;
89       }
90     }
91     if (rc) {
92       LOG(ERROR) << "FAIL:" << rc << " loop/loops:" << loop_ << "/"
93                  << options_.loop_;
94     } else {
95       LOG(INFO) << "PASS:" << rc << " loop/loops:" << loop_ << "/"
96                 << options_.loop_;
97     }
98 
99     LOG(INFO) << kHeadlessStopSentinel;
100     TearDown();
101     LOG(INFO) << kHeadlessFinalSentinel;
102     return rc;
103   }
104   virtual ~HeadlessRun() = default;
105 };
106 
107 template <typename T>
108 class HeadlessTest : public HeadlessRun {
109  public:
Run()110   virtual T Run() {
111     if (options_.non_options_.size() == 0) {
112       fprintf(stdout, "Must supply at least one subtest name\n");
113       return -1;
114     }
115 
116     std::string subtest = options_.GetNextSubTest();
117     if (test_nodes_.find(subtest) == test_nodes_.end()) {
118       fprintf(stdout, "Unknown subtest module:%s\n", subtest.c_str());
119       return -1;
120     }
121     return test_nodes_.at(subtest)->Run();
122   }
123 
124   virtual ~HeadlessTest() = default;
125 
126  protected:
HeadlessTest(const bluetooth::test::headless::GetOpt & options)127   HeadlessTest(const bluetooth::test::headless::GetOpt& options)
128       : HeadlessRun(options) {}
129 
130   std::unordered_map<std::string, std::unique_ptr<HeadlessTest<T>>> test_nodes_;
131 };
132 
133 }  // namespace headless
134 }  // namespace test
135 }  // namespace bluetooth
136