| /* |
| * Copyright 2019 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 "module.h" |
| |
| #include <unistd.h> |
| |
| #include <functional> |
| #include <sstream> |
| #include <string> |
| |
| #include "dumpsys_data_generated.h" |
| #include "gtest/gtest.h" |
| #include "module_dumper.h" |
| #include "module_unittest_generated.h" |
| #include "os/handler.h" |
| #include "os/thread.h" |
| |
| using ::bluetooth::os::Thread; |
| |
| namespace bluetooth { |
| namespace { |
| |
| class ModuleTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| thread_ = new Thread("test_thread", Thread::Priority::NORMAL); |
| registry_ = new ModuleRegistry(); |
| } |
| |
| void TearDown() override { |
| delete registry_; |
| delete thread_; |
| } |
| |
| ModuleRegistry* registry_; |
| Thread* thread_; |
| }; |
| |
| os::Handler* test_module_no_dependency_handler = nullptr; |
| |
| class TestModuleNoDependency : public Module { |
| public: |
| static const ModuleFactory Factory; |
| |
| protected: |
| void ListDependencies(ModuleList* /* list */) const {} |
| |
| void Start() override { |
| // A module is not considered started until Start() finishes |
| EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| test_module_no_dependency_handler = GetHandler(); |
| } |
| |
| void Stop() override { |
| // A module is not considered stopped until after Stop() finishes |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| } |
| |
| std::string ToString() const override { |
| return std::string("TestModuleNoDependency"); |
| } |
| }; |
| |
| const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() { |
| return new TestModuleNoDependency(); |
| }); |
| |
| os::Handler* test_module_one_dependency_handler = nullptr; |
| |
| class TestModuleOneDependency : public Module { |
| public: |
| static const ModuleFactory Factory; |
| |
| protected: |
| void ListDependencies(ModuleList* list) const { |
| list->add<TestModuleNoDependency>(); |
| } |
| |
| void Start() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| |
| // A module is not considered started until Start() finishes |
| EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>()); |
| test_module_one_dependency_handler = GetHandler(); |
| } |
| |
| void Stop() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| |
| // A module is not considered stopped until after Stop() finishes |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>()); |
| } |
| |
| std::string ToString() const override { |
| return std::string("TestModuleOneDependency"); |
| } |
| }; |
| |
| const ModuleFactory TestModuleOneDependency::Factory = ModuleFactory([]() { |
| return new TestModuleOneDependency(); |
| }); |
| |
| |
| class TestModuleNoDependencyTwo : public Module { |
| public: |
| static const ModuleFactory Factory; |
| |
| protected: |
| void ListDependencies(ModuleList* /* list */) const {} |
| |
| void Start() override { |
| // A module is not considered started until Start() finishes |
| EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>()); |
| } |
| |
| void Stop() override { |
| // A module is not considered stopped until after Stop() finishes |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>()); |
| } |
| |
| std::string ToString() const override { |
| return std::string("TestModuleNoDependencyTwo"); |
| } |
| }; |
| |
| const ModuleFactory TestModuleNoDependencyTwo::Factory = ModuleFactory([]() { |
| return new TestModuleNoDependencyTwo(); |
| }); |
| |
| class TestModuleTwoDependencies : public Module { |
| public: |
| static const ModuleFactory Factory; |
| |
| protected: |
| void ListDependencies(ModuleList* list) const { |
| list->add<TestModuleOneDependency>(); |
| list->add<TestModuleNoDependencyTwo>(); |
| } |
| |
| void Start() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>()); |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>()); |
| |
| // A module is not considered started until Start() finishes |
| EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>()); |
| } |
| |
| void Stop() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>()); |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>()); |
| |
| // A module is not considered stopped until after Stop() finishes |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>()); |
| } |
| |
| std::string ToString() const override { |
| return std::string("TestModuleTwoDependencies"); |
| } |
| }; |
| |
| const ModuleFactory TestModuleTwoDependencies::Factory = ModuleFactory([]() { |
| return new TestModuleTwoDependencies(); |
| }); |
| |
| // To generate module unittest flatbuffer headers: |
| // $ flatc --cpp module_unittest.fbs |
| class TestModuleDumpState : public Module { |
| public: |
| static const ModuleFactory Factory; |
| |
| std::string test_string_{"Initial Test String"}; |
| |
| protected: |
| void ListDependencies(ModuleList* list) const { |
| list->add<TestModuleNoDependency>(); |
| } |
| |
| void Start() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| |
| // A module is not considered started until Start() finishes |
| EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleDumpState>()); |
| test_module_one_dependency_handler = GetHandler(); |
| } |
| |
| void Stop() override { |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>()); |
| |
| // A module is not considered stopped until after Stop() finishes |
| EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleDumpState>()); |
| } |
| |
| std::string ToString() const override { |
| return std::string("TestModuleDumpState"); |
| } |
| |
| DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const override { |
| auto string = fb_builder->CreateString(test_string_.c_str()); |
| |
| auto builder = ModuleUnitTestDataBuilder(*fb_builder); |
| builder.add_title(string); |
| auto table = builder.Finish(); |
| |
| return [table](DumpsysDataBuilder* builder) { builder->add_module_unittest_data(table); }; |
| } |
| }; |
| |
| const ModuleFactory TestModuleDumpState::Factory = ModuleFactory([]() { return new TestModuleDumpState(); }); |
| |
| TEST_F(ModuleTest, no_dependency) { |
| ModuleList list; |
| list.add<TestModuleNoDependency>(); |
| registry_->Start(&list, thread_); |
| |
| EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| |
| registry_->StopAll(); |
| |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| } |
| |
| TEST_F(ModuleTest, one_dependency) { |
| ModuleList list; |
| list.add<TestModuleOneDependency>(); |
| registry_->Start(&list, thread_); |
| |
| EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| |
| registry_->StopAll(); |
| |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| } |
| |
| TEST_F(ModuleTest, two_dependencies) { |
| ModuleList list; |
| list.add<TestModuleTwoDependencies>(); |
| registry_->Start(&list, thread_); |
| |
| EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_TRUE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| |
| registry_->StopAll(); |
| |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>()); |
| EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>()); |
| } |
| |
| void post_to_module_one_handler() { |
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| test_module_one_dependency_handler->Post(common::BindOnce([] { FAIL(); })); |
| } |
| |
| TEST_F(ModuleTest, shutdown_with_unhandled_callback) { |
| ModuleList list; |
| list.add<TestModuleOneDependency>(); |
| registry_->Start(&list, thread_); |
| test_module_no_dependency_handler->Post(common::BindOnce(&post_to_module_one_handler)); |
| registry_->StopAll(); |
| } |
| |
| TEST_F(ModuleTest, dump_state) { |
| static const char* title = "Test Dump Title"; |
| ModuleList list; |
| list.add<TestModuleDumpState>(); |
| registry_->Start(&list, thread_); |
| |
| ModuleDumper dumper(STDOUT_FILENO, *registry_, title); |
| |
| std::string output; |
| std::ostringstream oss; |
| dumper.DumpState(&output, oss); |
| |
| auto data = flatbuffers::GetRoot<DumpsysData>(output.data()); |
| EXPECT_STREQ(title, data->title()->c_str()); |
| |
| auto test_data = data->module_unittest_data(); |
| EXPECT_STREQ("Initial Test String", test_data->title()->c_str()); |
| |
| TestModuleDumpState* test_module = |
| static_cast<TestModuleDumpState*>(registry_->Start(&TestModuleDumpState::Factory, nullptr)); |
| test_module->test_string_ = "A Second Test String"; |
| |
| oss.clear(); |
| output.clear(); |
| dumper.DumpState(&output, oss); |
| |
| data = flatbuffers::GetRoot<DumpsysData>(output.data()); |
| test_data = data->module_unittest_data(); |
| EXPECT_STREQ("A Second Test String", test_data->title()->c_str()); |
| |
| registry_->StopAll(); |
| } |
| |
| } // namespace |
| } // namespace bluetooth |