You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
9.4 KiB
284 lines
9.4 KiB
# GTest Unit Tests
|
|
|
|
[TOC]
|
|
|
|
## GTest Unit Tests
|
|
|
|
[GTest](https://github.com/google/googletest) is a Google developed open source
|
|
unit testing framework for C++ and C code. As the majority of GD code is writeen
|
|
in C++, GTest provide the first layer of defence against bugs from the
|
|
implementation level. Used in combination with
|
|
[GMock](https://github.com/google/googlemock) developers can easily isolate
|
|
classes and functions from their code to conduct unit testing.
|
|
|
|
* [GTest Primer](https://github.com/google/googletest/blob/master/googletest/docs/primer.md)
|
|
* [GMock for Dummies](https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md)
|
|
|
|
### Test Binary
|
|
|
|
All Gd unit test classes are compiled into a single binary
|
|
[bluetooth_test_gd](https://android.googlesource.com/platform/system/bt/+/master/gd/Android.bp).
|
|
|
|
### Test Sources Definitions
|
|
|
|
* Tests should live in the same directory as the source code
|
|
* Mocks should live in the same directory as the source header so that it can
|
|
be shared among multiple tests
|
|
* Tests should not modify global states that would affect other tests, so that
|
|
all tests could be executed using the same binary
|
|
* Each module can define a filegroup() that includes all test sources. This
|
|
filegroup is then included in a single cc_test() target that produce a
|
|
single test binary
|
|
[bluetooth_test_gd](https://android.googlesource.com/platform/system/bt/+/master/gd/Android.bp).
|
|
A single test binary simplifies the configuration effort needed for
|
|
compilation, presubmit and postsubmit execution, and so on.
|
|
|
|
### How to run tests
|
|
|
|
#### Use `atest`
|
|
|
|
[ATest](https://source.android.com/compatibility/tests/development/atest) is an
|
|
Android tool that allows a developers to run multiple modes of tests from the
|
|
same `atest` command, including Java Instrumentation Tests, C/C++ GTests,
|
|
CTS/GTS tests, etc. To use `atest` with GD, simplying sync your Android tree,
|
|
run `source build/envsetup.sh` and `lunch` to a desired target. Then
|
|
|
|
* To run tests on device, the following command will automatically build,
|
|
push, and execute tests on a connected Android device
|
|
|
|
```shell
|
|
atest bluetooth_test_gd
|
|
```
|
|
|
|
* To run tests on host, the following command will automatically build and run
|
|
tests on your host machine
|
|
|
|
```shell
|
|
atest --host bluetooth_test_gd
|
|
```
|
|
|
|
* To run a single test case, use `<test_binary>:<test_class>#<test_method>`
|
|
format, such as
|
|
|
|
```shell
|
|
atest --host bluetooth_test_gd:AclManagerTest#invoke_registered_callback_connection_complete_success
|
|
```
|
|
|
|
See `atest --help` for more documentation on how to use atest to run various
|
|
tests
|
|
|
|
#### Run it yourself (Not receommended unless really needed)
|
|
|
|
Sometimes, you may want to execute the test binary directly because you want to
|
|
attach a debugger or you want to avoid the test boostrap delay in `atest`. You
|
|
can do it with the following steps
|
|
|
|
1. Sync Android tree, run `build/envsetup` and `lunch` desired target, `cd`
|
|
into Android checkout root directory
|
|
|
|
1. Make bluetooth_test_gd binary
|
|
|
|
```shell
|
|
m -j40 bluetooth_test_gd
|
|
```
|
|
|
|
1. Run the test on host {value=3}
|
|
|
|
```shell
|
|
$ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd
|
|
```
|
|
|
|
1. Run the test on device {value=4}
|
|
|
|
Push test to device
|
|
|
|
```shell
|
|
adb push $ANDROID_PRODUCT_OUT/testcases/bluetooth_test_gd/arm64/bluetooth_test_gd /data/nativetest64/bluetooth_test_gd
|
|
```
|
|
|
|
Run test using ADB
|
|
|
|
```shell
|
|
adb shell /data/nativetest64/bluetooth_test_gd
|
|
```
|
|
|
|
1. Run test with filter (Works the same way for device based test) {value=5}
|
|
|
|
```shell
|
|
$ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd --gtest_filter=AclManagerTest.invoke_registered_callback_connection_complete_success*
|
|
```
|
|
|
|
Note: the '*' wildcard is very important
|
|
|
|
1. Get command line help {value=6}
|
|
|
|
```shell
|
|
$ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd --help
|
|
```
|
|
|
|
### Example: L2capClassicFixedChannelImplTest
|
|
|
|
Note: All paths are relative to
|
|
[system/bt/gd](https://android.googlesource.com/platform/system/bt/+/master/gd)
|
|
|
|
#### Source code:
|
|
|
|
* [l2cap/classic/internal/fixed_channel_impl.h](https://android.googlesource.com/platform/system/bt/+/master/gd/l2cap/classic/internal/fixed_channel_impl.h)
|
|
|
|
```c++
|
|
#pragma once
|
|
|
|
#include "common/bidi_queue.h"
|
|
#include "l2cap/cid.h"
|
|
#include "l2cap/classic/fixed_channel.h"
|
|
#include "l2cap/internal/channel_impl.h"
|
|
#include "l2cap/l2cap_packets.h"
|
|
#include "os/handler.h"
|
|
#include "os/log.h"
|
|
|
|
namespace bluetooth {
|
|
namespace l2cap {
|
|
namespace classic {
|
|
namespace internal {
|
|
|
|
class Link;
|
|
|
|
class FixedChannelImpl : public l2cap::internal::ChannelImpl {
|
|
public:
|
|
FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
|
|
virtual ~FixedChannelImpl() = default;
|
|
hci::Address GetDevice() const;
|
|
virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
|
|
virtual void Acquire();
|
|
virtual void Release();
|
|
virtual bool IsAcquired() const;
|
|
virtual void OnClosed(hci::ErrorCode status);
|
|
virtual std::string ToString();
|
|
common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd();
|
|
common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd();
|
|
Cid GetCid() const;
|
|
Cid GetRemoteCid() const;
|
|
private:
|
|
// private fields omitted in doc ...
|
|
};
|
|
|
|
} // namespace internal
|
|
} // namespace classic
|
|
} // namespace l2cap
|
|
} // namespace bluetooth
|
|
```
|
|
|
|
* [system/bt/gd/l2cap/classic/internal/fixed_channel_impl.cc](https://android.googlesource.com/platform/system/bt/+/master/gd/l2cap/classic/internal/fixed_channel_impl.cc)
|
|
|
|
#### Mocks for dependencies' unit tests
|
|
|
|
* [l2cap/classic/internal/fixed_channel_impl_mock.h](https://android.googlesource.com/platform/system/bt/+/master/gd/l2cap/classic/internal/fixed_channel_impl_mock.h)
|
|
|
|
```c++
|
|
#pragma once
|
|
|
|
#include "l2cap/classic/internal/fixed_channel_impl.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
|
|
// Unit test interfaces
|
|
namespace bluetooth {
|
|
namespace l2cap {
|
|
namespace classic {
|
|
namespace internal {
|
|
namespace testing {
|
|
|
|
class MockFixedChannelImpl : public FixedChannelImpl {
|
|
public:
|
|
MockFixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler) : FixedChannelImpl(cid, link, l2cap_handler) {}
|
|
MOCK_METHOD(void, RegisterOnCloseCallback,
|
|
(os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
|
|
MOCK_METHOD(void, Acquire, (), (override));
|
|
MOCK_METHOD(void, Release, (), (override));
|
|
MOCK_METHOD(bool, IsAcquired, (), (override, const));
|
|
MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
|
|
};
|
|
|
|
} // namespace testing
|
|
} // namespace internal
|
|
} // namespace classic
|
|
} // namespace l2cap
|
|
} // namespace bluetooth
|
|
```
|
|
|
|
#### Tests
|
|
|
|
* [l2cap/classic/internal/fixed_channel_impl_test.cc](https://android.googlesource.com/platform/system/bt/+/master/gd/l2cap/classic/internal/fixed_channel_impl_test.cc)
|
|
|
|
```c++
|
|
#include "l2cap/classic/internal/fixed_channel_impl.h"
|
|
|
|
#include "common/testing/bind_test_util.h"
|
|
#include "l2cap/cid.h"
|
|
#include "l2cap/classic/internal/link_mock.h"
|
|
#include "l2cap/internal/parameter_provider_mock.h"
|
|
#include "os/handler.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace bluetooth {
|
|
namespace l2cap {
|
|
namespace classic {
|
|
namespace internal {
|
|
|
|
using l2cap::internal::testing::MockParameterProvider;
|
|
using ::testing::_;
|
|
using testing::MockLink;
|
|
using ::testing::Return;
|
|
|
|
class L2capClassicFixedChannelImplTest : public ::testing::Test {
|
|
public:
|
|
static void SyncHandler(os::Handler* handler) {
|
|
std::promise<void> promise;
|
|
auto future = promise.get_future();
|
|
handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
|
|
future.wait_for(std::chrono::seconds(1));
|
|
}
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
|
|
l2cap_handler_ = new os::Handler(thread_);
|
|
}
|
|
|
|
void TearDown() override {
|
|
l2cap_handler_->Clear();
|
|
delete l2cap_handler_;
|
|
delete thread_;
|
|
}
|
|
|
|
os::Thread* thread_ = nullptr;
|
|
os::Handler* l2cap_handler_ = nullptr;
|
|
};
|
|
|
|
TEST_F(L2capClassicFixedChannelImplTest, get_device) {
|
|
MockParameterProvider mock_parameter_provider;
|
|
EXPECT_CALL(mock_parameter_provider, GetClassicLinkIdleDisconnectTimeout())
|
|
.WillRepeatedly(Return(std::chrono::seconds(5)));
|
|
testing::MockClassicAclConnection* mock_acl_connection = new testing::MockClassicAclConnection();
|
|
EXPECT_CALL(*mock_acl_connection, GetAddress()).Times(1);
|
|
EXPECT_CALL(*mock_acl_connection, RegisterCallbacks(_, l2cap_handler_)).Times(1);
|
|
EXPECT_CALL(*mock_acl_connection, UnregisterCallbacks(_)).Times(1);
|
|
MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider,
|
|
std::unique_ptr<testing::MockClassicAclConnection>(mock_acl_connection));
|
|
hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
|
|
hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
|
|
EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
|
|
FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
|
|
EXPECT_EQ(device.GetAddress(), fixed_channel_impl.GetDevice());
|
|
}
|
|
|
|
// Other test cases omitted in doc ...
|
|
|
|
} // namespace internal
|
|
} // namespace classic
|
|
} // namespace l2cap
|
|
} // namespace bluetooth
|
|
```
|