Migrate fake functions to third_party/nearby to help unit test

PiperOrigin-RevId: 517433481
This commit is contained in:
Qin Wang
2023-03-17 09:34:58 -07:00
committed by Copybara-Service
parent 94ff506d1e
commit 86ca85b85a
16 changed files with 1248 additions and 0 deletions
+5
View File
@@ -422,6 +422,7 @@ let package = Package(
"internal/flags/BUILD",
"internal/network/BUILD",
"internal/base/BUILD",
"internal/test/BUILD",
// tests
"connections/listeners_test.cc",
"connections/strategy_test.cc",
@@ -538,6 +539,10 @@ let package = Package(
"internal/network/http_request_test.cc",
"internal/network/http_client_impl_test.cc",
"internal/network/http_status_code_test.cc",
"internal/test/fake_clock_test.cc",
"internal/test/fake_timer_test.cc",
"internal/test/fake_device_info_test.cc",
"internal/test/fake_task_runner_test.cc",
// simulation
"connections/implementation/offline_simulation_user.cc",
"connections/implementation/simulation_user.cc",
+1
View File
@@ -354,6 +354,7 @@ cc_library(
"//fastpair:__subpackages__",
"//internal/flags:__subpackages__",
"//internal/platform/implementation/windows:__subpackages__",
"//internal/test:__subpackages__",
"//location/nearby/cpp:__subpackages__",
"//location/nearby/testing/nearby_native:__subpackages__",
"//presence:__subpackages__",
+1
View File
@@ -42,6 +42,7 @@ cc_library(
"//fastpair:__subpackages__",
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//internal/test:__subpackages__",
"//location/nearby/analytics/cpp:__subpackages__",
"//presence:__subpackages__",
],
@@ -132,6 +132,7 @@ cc_library(
"//internal/network:__subpackages__",
"//internal/platform:__subpackages__",
"//internal/proto/analytics:__subpackages__",
"//internal/test:__subpackages__",
"//location/nearby/cpp:__subpackages__",
"//presence:__subpackages__",
],
+56
View File
@@ -0,0 +1,56 @@
licenses(["notice"])
cc_library(
name = "test",
srcs = [
"fake_clock.cc",
"fake_task_runner.cc",
"fake_timer.cc",
],
hdrs = [
"fake_clock.h",
"fake_device_info.h",
"fake_task_runner.h",
"fake_timer.h",
],
copts = [
"-Ithird_party",
],
visibility = ["//visibility:public"],
deps = [
"//internal/base:bluetooth_address",
"//internal/platform:types",
"//internal/platform/implementation:types",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span", # fixdeps: keep
],
)
cc_test(
name = "test_test",
size = "small",
timeout = "short",
srcs = [
"fake_clock_test.cc",
"fake_device_info_test.cc",
"fake_task_runner_test.cc",
"fake_timer_test.cc",
],
copts = [
"-Ithird_party",
],
shard_count = 8,
deps = [
":test",
"//internal/platform:types",
"//internal/platform/implementation:types",
"//internal/platform/implementation/g3",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
+71
View File
@@ -0,0 +1,71 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 "internal/test/fake_clock.h"
#include <functional>
#include <string>
#include <utility>
#include <vector>
namespace nearby {
absl::Time FakeClock::Now() const { return now_; }
void FakeClock::AddObserver(absl::string_view name,
std::function<void()> observer) {
absl::MutexLock lock(&mutex_);
observers_.emplace(name, std::move(observer));
}
void FakeClock::RemoveObserver(absl::string_view name) {
absl::MutexLock lock(&mutex_);
observers_.erase(name);
}
void FakeClock::FastForward(absl::Duration duration) {
std::vector<std::string> timer_callback_ids;
now_ += duration;
{
absl::MutexLock lock(&mutex_);
for (const auto& observer : observers_) {
timer_callback_ids.push_back(observer.first);
}
}
for (const auto& timer_callback_id : timer_callback_ids) {
// Timer may be closed during other timer running, so only run callback
// on available timers.
bool is_alive_timer = true;
std::function<void()> callback;
{
absl::MutexLock lock(&mutex_);
is_alive_timer = observers_.contains(timer_callback_id);
if (!is_alive_timer) {
continue;
}
callback = observers_[timer_callback_id];
}
callback();
}
}
int FakeClock::GetObserversCount() {
absl::MutexLock lock(&mutex_);
return observers_.size();
}
} // namespace nearby
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_CLOCK_H_
#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_CLOCK_H_
#include <functional>
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/clock.h"
namespace nearby {
class FakeClock : public Clock {
public:
FakeClock() { now_ = absl::Now(); }
FakeClock(FakeClock&&) = default;
FakeClock& operator=(FakeClock&&) = default;
absl::Time Now() const override;
void AddObserver(absl::string_view name, std::function<void()> observer)
ABSL_LOCKS_EXCLUDED(mutex_);
void RemoveObserver(absl::string_view name) ABSL_LOCKS_EXCLUDED(mutex_);
void FastForward(absl::Duration duration);
int GetObserversCount() ABSL_LOCKS_EXCLUDED(mutex_);
private:
absl::Time now_;
mutable absl::Mutex mutex_;
absl::flat_hash_map<std::string, std::function<void()>> observers_
ABSL_GUARDED_BY(mutex_);
};
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_CLOCK_H_
+53
View File
@@ -0,0 +1,53 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 "internal/test/fake_clock.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
namespace nearby {
namespace {
TEST(FakeClock, TestGetCurrentTime) {
FakeClock clock;
EXPECT_GT(absl::ToUnixNanos(clock.Now()), 0);
}
TEST(FakeClock, TestFastForward) {
FakeClock clock;
absl::Time time1 = clock.Now();
clock.FastForward(absl::Nanoseconds(1500));
absl::Time time2 = clock.Now();
EXPECT_EQ(absl::ToUnixNanos(time1) + 1500, absl::ToUnixNanos(time2));
EXPECT_EQ(clock.GetObserversCount(), 0);
}
TEST(FakeClock, TestObserver) {
FakeClock clock;
int count = 0;
auto observer = [&count]() { count++; };
clock.AddObserver("test", observer);
clock.FastForward(absl::Nanoseconds(1500));
EXPECT_EQ(count, 1);
clock.FastForward(absl::Nanoseconds(1500));
EXPECT_EQ(count, 2);
clock.RemoveObserver("test");
clock.FastForward(absl::Nanoseconds(1500));
EXPECT_EQ(count, 2);
}
} // namespace
} // namespace nearby
+179
View File
@@ -0,0 +1,179 @@
// Copyright 2022 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_DEVICE_INFO_H_
#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_DEVICE_INFO_H_
#include <filesystem>
#include <functional>
#include <limits>
#include <optional>
#include <string>
#include <string_view>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/device_info.h"
#include "internal/platform/implementation/device_info.h"
namespace nearby {
class FakeDeviceInfo : public DeviceInfo {
public:
std::u16string GetOsDeviceName() const override { return device_name_; }
api::DeviceInfo::DeviceType GetDeviceType() const override {
return device_type_;
}
api::DeviceInfo::OsType GetOsType() const override { return os_type_; }
std::optional<std::u16string> GetFullName() const override {
return full_name_;
}
std::optional<std::u16string> GetGivenName() const override {
return given_name_;
}
std::optional<std::u16string> GetLastName() const override {
return last_name_;
}
std::optional<std::string> GetProfileUserName() const override {
return profile_user_name_;
}
std::filesystem::path GetDownloadPath() const override {
return download_path_;
}
std::filesystem::path GetAppDataPath() const override {
return app_data_path_;
}
std::filesystem::path GetTemporaryPath() const override { return temp_path_; }
std::optional<size_t> GetAvailableDiskSpaceInBytes(
const std::filesystem::path& path) const override {
std::wstring path_key = path.wstring();
auto it = available_space_map_.find(path_key);
if (it != available_space_map_.end()) {
return it->second;
}
return std::numeric_limits<int64_t>::max();
}
bool IsScreenLocked() const override { return is_screen_locked_; }
void RegisterScreenLockedListener(
absl::string_view listener_name,
std::function<void(api::DeviceInfo::ScreenStatus)> callback) override {
screen_locked_listeners_.emplace(listener_name, callback);
}
void UnregisterScreenLockedListener(
absl::string_view listener_name) override {
screen_locked_listeners_.erase(listener_name);
}
int GetScreenLockedListenerCount() { return screen_locked_listeners_.size(); }
// Mock methods.
void SetOsDeviceName(std::u16string_view device_name) {
device_name_ = device_name;
}
void SetDeviceType(api::DeviceInfo::DeviceType device_type) {
device_type_ = device_type;
}
void SetOsType(api::DeviceInfo::OsType os_type) { os_type_ = os_type; }
void SetFullName(std::optional<std::u16string> full_name) {
if (full_name.has_value() && !full_name->empty()) {
full_name_ = full_name;
} else {
full_name_ = std::nullopt;
}
}
void SetGivenName(std::optional<std::u16string> given_name) {
if (given_name.has_value() && !given_name->empty()) {
given_name_ = given_name;
} else {
given_name_ = std::nullopt;
}
}
void SetLastName(std::optional<std::u16string> last_name) {
if (last_name.has_value() && !last_name->empty()) {
last_name_ = last_name;
} else {
last_name_ = std::nullopt;
}
}
void SetProfileUserName(std::optional<std::string> profile_user_name) {
if (profile_user_name.has_value() && !profile_user_name->empty()) {
profile_user_name_ = profile_user_name;
} else {
profile_user_name_ = std::nullopt;
}
}
void SetDownloadPath(std::filesystem::path path) { download_path_ = path; }
void SetAppDataPath(std::filesystem::path path) { app_data_path_ = path; }
void SetTemporaryPath(std::filesystem::path path) { temp_path_ = path; }
void SetAvailableDiskSpaceInBytes(const std::filesystem::path& path,
size_t available_bytes) {
available_space_map_.emplace(path.wstring(), available_bytes);
}
void ResetDiskSpace() { available_space_map_.clear(); }
void SetScreenLocked(bool locked) {
is_screen_locked_ = locked;
for (auto& listener : screen_locked_listeners_) {
if (locked) {
listener.second(api::DeviceInfo::ScreenStatus::kLocked);
} else {
listener.second(api::DeviceInfo::ScreenStatus::kUnlocked);
}
}
}
private:
std::u16string device_name_ = u"nearby";
api::DeviceInfo::DeviceType device_type_ =
api::DeviceInfo::DeviceType::kLaptop;
api::DeviceInfo::OsType os_type_ = api::DeviceInfo::OsType::kWindows;
std::optional<std::u16string> full_name_ = u"Nearby";
std::optional<std::u16string> given_name_ = u"Nearby";
std::optional<std::u16string> last_name_ = u"Nearby";
std::optional<std::string> profile_user_name_ = "nearby";
std::filesystem::path download_path_ = std::filesystem::temp_directory_path();
std::filesystem::path app_data_path_ = std::filesystem::temp_directory_path();
std::filesystem::path temp_path_ = std::filesystem::temp_directory_path();
absl::flat_hash_map<std::wstring, size_t> available_space_map_;
absl::flat_hash_map<std::string,
std::function<void(api::DeviceInfo::ScreenStatus)>>
screen_locked_listeners_;
bool is_screen_locked_ = false;
};
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_DEVICE_INFO_H_
+192
View File
@@ -0,0 +1,192 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 "internal/test/fake_device_info.h"
#include <array>
#include <filesystem>
#include <functional>
#include <optional>
#include "gtest/gtest.h"
#include "internal/platform/implementation/device_info.h"
namespace nearby {
namespace {
TEST(FakeDeviceInfo, DeviceName) {
FakeDeviceInfo device_info;
device_info.SetOsDeviceName(u"windows");
EXPECT_EQ(device_info.GetOsDeviceName(), u"windows");
}
TEST(FakeDeviceInfo, DeviceType) {
FakeDeviceInfo device_info;
device_info.SetDeviceType(api::DeviceInfo::DeviceType::kPhone);
EXPECT_EQ(device_info.GetDeviceType(), api::DeviceInfo::DeviceType::kPhone);
}
TEST(FakeDeviceInfo, OsType) {
FakeDeviceInfo device_info;
device_info.SetOsType(api::DeviceInfo::OsType::kWindows);
EXPECT_EQ(device_info.GetOsType(), api::DeviceInfo::OsType::kWindows);
}
TEST(FakeDeviceInfo, FullName) {
FakeDeviceInfo device_info;
device_info.SetFullName(u"windows");
EXPECT_EQ(device_info.GetFullName(), u"windows");
device_info.SetFullName(std::nullopt);
EXPECT_FALSE(device_info.GetFullName().has_value());
}
TEST(FakeDeviceInfo, GivenName) {
FakeDeviceInfo device_info;
device_info.SetGivenName(u"windows");
EXPECT_EQ(device_info.GetGivenName(), u"windows");
device_info.SetGivenName(std::nullopt);
EXPECT_FALSE(device_info.GetGivenName().has_value());
}
TEST(FakeDeviceInfo, LastName) {
FakeDeviceInfo device_info;
device_info.SetLastName(u"windows");
EXPECT_EQ(device_info.GetLastName(), u"windows");
device_info.SetLastName(std::nullopt);
EXPECT_FALSE(device_info.GetLastName().has_value());
}
TEST(FakeDeviceInfo, ProfileUserName) {
FakeDeviceInfo device_info;
device_info.SetProfileUserName("windows");
EXPECT_EQ(device_info.GetProfileUserName(), "windows");
device_info.SetProfileUserName(std::nullopt);
EXPECT_FALSE(device_info.GetProfileUserName().has_value());
}
TEST(FakeDeviceInfo, GetDownloadPath) {
FakeDeviceInfo device_info;
EXPECT_EQ(device_info.GetDownloadPath(),
std::filesystem::temp_directory_path());
device_info.SetDownloadPath(std::filesystem::temp_directory_path() / "test");
EXPECT_EQ(device_info.GetDownloadPath(),
std::filesystem::temp_directory_path() / "test");
}
TEST(FakeDeviceInfo, GetAppDataPath) {
FakeDeviceInfo device_info;
EXPECT_EQ(device_info.GetAppDataPath(),
std::filesystem::temp_directory_path());
device_info.SetAppDataPath(std::filesystem::temp_directory_path() / "test");
EXPECT_EQ(device_info.GetAppDataPath(),
std::filesystem::temp_directory_path() / "test");
}
TEST(FakeDeviceInfo, GetTemporaryPath) {
FakeDeviceInfo device_info;
EXPECT_EQ(device_info.GetTemporaryPath(),
std::filesystem::temp_directory_path());
device_info.SetTemporaryPath(std::filesystem::temp_directory_path() / "test");
EXPECT_EQ(device_info.GetTemporaryPath(),
std::filesystem::temp_directory_path() / "test");
}
TEST(FakeDeviceInfo, GetAvailableDiskSpaceInBytes) {
FakeDeviceInfo device_info;
device_info.SetDownloadPath("download");
device_info.SetAppDataPath("appdata");
device_info.SetTemporaryPath("temp");
device_info.SetAvailableDiskSpaceInBytes(device_info.GetDownloadPath(), 10);
device_info.SetAvailableDiskSpaceInBytes(device_info.GetAppDataPath(), 100);
device_info.SetAvailableDiskSpaceInBytes(device_info.GetTemporaryPath(),
1000);
EXPECT_EQ(
device_info.GetAvailableDiskSpaceInBytes(device_info.GetDownloadPath()),
10);
EXPECT_EQ(
device_info.GetAvailableDiskSpaceInBytes(device_info.GetAppDataPath()),
100);
EXPECT_EQ(
device_info.GetAvailableDiskSpaceInBytes(device_info.GetTemporaryPath()),
1000);
}
TEST(FakeDeviceInfo, RegisterScreenLockedListener) {
std::function<void(api::DeviceInfo::ScreenStatus)> listener_1 =
[](api::DeviceInfo::ScreenStatus) {};
std::function<void(api::DeviceInfo::ScreenStatus)> listener_2 =
[](api::DeviceInfo::ScreenStatus) {};
FakeDeviceInfo device_info;
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 0);
device_info.RegisterScreenLockedListener("listener_1", listener_1);
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 1);
device_info.RegisterScreenLockedListener("listener_2", listener_2);
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 2);
}
TEST(FakeDeviceInfo, UnregisterScreenLockedListener) {
std::function<void(api::DeviceInfo::ScreenStatus)> listener_1 =
[](api::DeviceInfo::ScreenStatus) {};
std::function<void(api::DeviceInfo::ScreenStatus)> listener_2 =
[](api::DeviceInfo::ScreenStatus) {};
FakeDeviceInfo device_info;
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 0);
device_info.RegisterScreenLockedListener("listener_1", listener_1);
device_info.RegisterScreenLockedListener("listener_2", listener_2);
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 2);
device_info.UnregisterScreenLockedListener("listener_1");
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 1);
device_info.UnregisterScreenLockedListener("listener_2");
EXPECT_EQ(device_info.GetScreenLockedListenerCount(), 0);
}
TEST(FakeDeviceInfo, UpdateScreenLockedListener) {
api::DeviceInfo::ScreenStatus screen_locked_tracker_1 =
api::DeviceInfo::ScreenStatus::kUndetermined;
api::DeviceInfo::ScreenStatus screen_locked_tracker_2 =
api::DeviceInfo::ScreenStatus::kUndetermined;
std::function<void(api::DeviceInfo::ScreenStatus)> listener_1 =
[&screen_locked_tracker_1](api::DeviceInfo::ScreenStatus status) {
screen_locked_tracker_1 = status;
};
std::function<void(api::DeviceInfo::ScreenStatus)> listener_2 =
[&screen_locked_tracker_2](api::DeviceInfo::ScreenStatus status) {
screen_locked_tracker_2 = status;
};
FakeDeviceInfo device_info;
device_info.RegisterScreenLockedListener("listener_1", listener_1);
device_info.RegisterScreenLockedListener("listener_2", listener_2);
device_info.SetScreenLocked(true);
EXPECT_EQ(screen_locked_tracker_1, api::DeviceInfo::ScreenStatus::kLocked);
EXPECT_EQ(screen_locked_tracker_2, api::DeviceInfo::ScreenStatus::kLocked);
device_info.SetScreenLocked(false);
EXPECT_EQ(screen_locked_tracker_1, api::DeviceInfo::ScreenStatus::kUnlocked);
EXPECT_EQ(screen_locked_tracker_2, api::DeviceInfo::ScreenStatus::kUnlocked);
}
} // namespace
} // namespace nearby
+123
View File
@@ -0,0 +1,123 @@
// Copyright 2022 Google LLC
//
// 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
//
// https://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 "internal/test/fake_task_runner.h"
#include <functional>
#include <future> // NOLINT
#include <memory>
#include <utility>
#include <vector>
#include "absl/time/time.h"
namespace nearby {
std::atomic_uint FakeTaskRunner::running_thread_count_ = 0;
bool FakeTaskRunner::PostTask(absl::AnyInvocable<void()> task) {
if (mode_ == Mode::kNoPending) {
run(std::move(task));
return true;
}
pending_tasks_.push_back(std::move(task));
return true;
}
bool FakeTaskRunner::PostDelayedTask(absl::Duration delay,
absl::AnyInvocable<void()> task) {
std::unique_ptr<Timer> timer = std::make_unique<FakeTimer>(clock_);
Timer* timer_ptr = timer.get();
uint32_t id = GenerateId();
pending_delayed_tasks_.emplace(id, std::move(timer));
timer_ptr->Start(delay / absl::Milliseconds(1), 0,
[this, task = std::move(task), id]() mutable {
PostTask(std::move(task));
completed_delayed_tasks_.push_back(id);
});
return true;
}
void FakeTaskRunner::RunNextTask() {
if (pending_tasks_.empty()) {
return;
}
run(std::move(pending_tasks_.front()));
pending_tasks_.erase(pending_tasks_.begin());
}
void FakeTaskRunner::RunAllPendingTasks() {
while (!pending_tasks_.empty()) {
RunNextTask();
}
}
const std::vector<absl::AnyInvocable<void()>>& FakeTaskRunner::GetPendingTasks()
const {
return pending_tasks_;
}
const absl::flat_hash_map<uint32_t, std::unique_ptr<Timer>>&
FakeTaskRunner::GetPendingDelayedTask() {
if (!completed_delayed_tasks_.empty()) {
for (uint32_t id : completed_delayed_tasks_) {
pending_delayed_tasks_.erase(id);
}
}
return pending_delayed_tasks_;
}
bool FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Duration timeout) {
int i = (timeout / absl::Milliseconds(1)) / 50;
while (running_thread_count_ != 0 && i > 0) {
absl::SleepFor(absl::Milliseconds(50));
--i;
}
return running_thread_count_ == 0;
}
uint32_t FakeTaskRunner::GenerateId() {
++current_id_;
return current_id_;
}
void FakeTaskRunner::CleanThreads() {
auto it = threads_.begin();
while (it != threads_.end()) {
// Delete the thread if it is ready
auto status = it->wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
it = threads_.erase(it);
} else {
++it;
}
}
}
void FakeTaskRunner::run(absl::AnyInvocable<void()> task) {
absl::MutexLock lock(&mutex_);
CleanThreads();
++running_thread_count_;
// Run the task in a new thread, to simulate the real environment.
std::future<void> thread =
std::async(std::launch::async, [&, task = std::move(task)]() mutable {
task();
--running_thread_count_;
});
threads_.push_back(std::move(thread));
}
} // namespace nearby
+87
View File
@@ -0,0 +1,87 @@
// Copyright 2022 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TASK_RUNNER_H_
#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TASK_RUNNER_H_
#include <atomic>
#include <cstdint>
#include <future> //NOLINT
#include <memory>
#include <thread> //NOLINT
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/time/time.h"
#include "internal/platform/task_runner.h"
#include "internal/test/fake_clock.h"
#include "internal/test/fake_timer.h"
namespace nearby {
class FakeTaskRunner : public TaskRunner {
public:
enum class Mode { kNoPending, kPending };
FakeTaskRunner(FakeClock* clock, uint32_t count)
: clock_(clock), count_(count) {}
~FakeTaskRunner() override = default;
bool PostTask(absl::AnyInvocable<void()> task) override;
// No matter the mode is pending or not, always put the task in timer control.
// Caller can move forward time to trigger it.
bool PostDelayedTask(absl::Duration delay,
absl::AnyInvocable<void()> task) override;
// Mocked methods.
void SetMode(Mode mode) { mode_ = mode; }
Mode GetMode() const { return mode_; }
void RunNextTask();
void RunAllPendingTasks();
const std::vector<absl::AnyInvocable<void()>>& GetPendingTasks() const;
const absl::flat_hash_map<uint32_t, std::unique_ptr<Timer>>&
GetPendingDelayedTask();
int GetConcurrentCount() const { return count_; }
// In some testcases, we needs to make sure all running tasks completion
// before go to next task. This method can be used for the purpose.
static bool WaitForRunningTasksWithTimeout(absl::Duration timeout);
private:
uint32_t GenerateId();
void CleanThreads() ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void run(absl::AnyInvocable<void()> task) ABSL_LOCKS_EXCLUDED(mutex_);
Mode mode_ = Mode::kNoPending;
std::atomic_uint current_id_ = 0;
FakeClock* clock_ = nullptr;
uint32_t count_;
std::vector<absl::AnyInvocable<void()>> pending_tasks_;
std::vector<uint32_t> completed_delayed_tasks_;
absl::flat_hash_map<uint32_t, std::unique_ptr<Timer>> pending_delayed_tasks_;
absl::Mutex mutex_;
std::vector<std::future<void>> threads_ ABSL_GUARDED_BY(mutex_);
static std::atomic_uint running_thread_count_;
};
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TASK_RUNNER_H_
+115
View File
@@ -0,0 +1,115 @@
// Copyright 2022 Google LLC
//
// 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
//
// https://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 "internal/test/fake_task_runner.h"
#include "gtest/gtest.h"
#include "absl/time/time.h"
#include "internal/test/fake_clock.h"
namespace nearby {
namespace {
TEST(FakeTaskRunner, PostTask) {
FakeClock clock;
int count = 0;
FakeTaskRunner task_runner{&clock, 1};
task_runner.PostTask([&count] { ++count; });
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(task_runner.GetPendingTasks().size(), 0);
EXPECT_EQ(count, 1);
}
TEST(FakeTaskRunner, PostDelayedTask) {
FakeClock clock;
int count = 0;
FakeTaskRunner task_runner{&clock, 1};
task_runner.PostDelayedTask(absl::Seconds(10), [&count] { ++count; });
EXPECT_EQ(task_runner.GetPendingTasks().size(), 0);
EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 1);
EXPECT_EQ(count, 0);
clock.FastForward(absl::Seconds(10));
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(count, 1);
EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 0);
}
TEST(FakeTaskRunner, PostTasksInPendingMode) {
FakeClock clock;
FakeTaskRunner task_runner{&clock, 1};
task_runner.SetMode(FakeTaskRunner::Mode::kPending);
EXPECT_EQ(task_runner.GetConcurrentCount(), 1);
task_runner.PostTask([]() {});
task_runner.PostTask([]() {});
EXPECT_EQ(task_runner.GetPendingTasks().size(), 2);
task_runner.RunNextTask();
EXPECT_EQ(task_runner.GetPendingTasks().size(), 1);
task_runner.RunNextTask();
EXPECT_EQ(task_runner.GetPendingTasks().size(), 0);
}
TEST(FakeTaskRunner, RunAllPostedTasksInPendingMode) {
FakeClock clock;
FakeTaskRunner task_runner{&clock, 1};
task_runner.SetMode(FakeTaskRunner::Mode::kPending);
task_runner.PostTask([]() {});
task_runner.PostTask([]() {});
EXPECT_EQ(task_runner.GetPendingTasks().size(), 2);
task_runner.RunAllPendingTasks();
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(task_runner.GetPendingTasks().size(), 0);
}
TEST(FakeTaskRunner, PostDelayedTaskInPendingMode) {
FakeClock clock;
bool called = false;
FakeTaskRunner task_runner{&clock, 1};
task_runner.SetMode(FakeTaskRunner::Mode::kPending);
task_runner.PostDelayedTask(absl::Seconds(1), [&called]() { called = true; });
EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 1);
clock.FastForward(absl::Seconds(1));
EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 0);
EXPECT_EQ(task_runner.GetPendingTasks().size(), 1);
task_runner.RunAllPendingTasks();
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(task_runner.GetPendingTasks().size(), 0);
EXPECT_TRUE(called);
}
TEST(FakeTaskRunner, PostDelayedTaskInDelayedTask) {
FakeClock clock;
int called_count = 0;
FakeTaskRunner task_runner{&clock, 1};
task_runner.PostDelayedTask(
absl::Seconds(1), [&called_count, &task_runner]() {
++called_count;
task_runner.PostDelayedTask(absl::Seconds(1),
[&called_count]() { ++called_count; });
});
clock.FastForward(absl::Seconds(1));
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(called_count, 1);
clock.FastForward(absl::Seconds(1));
ASSERT_TRUE(
FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100)));
EXPECT_EQ(called_count, 2);
}
} // namespace
} // namespace nearby
+93
View File
@@ -0,0 +1,93 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 "internal/test/fake_timer.h"
#include <functional>
#include <future> // NOLINT
#include <string>
#include <thread> // NOLINT
#include <utility>
#include "absl/time/clock.h"
#include "absl/time/time.h"
namespace nearby {
FakeTimer::FakeTimer(FakeClock* clock) : clock_(clock) {
id_ = std::to_string(absl::ToUnixNanos(absl::Now()));
clock_->AddObserver(id_, [this]() { ClockUpdated(); });
}
FakeTimer::~FakeTimer() { clock_->RemoveObserver(id_); }
bool FakeTimer::Start(int delay, int period,
absl::AnyInvocable<void()> callback) {
if (is_started_ || delay < 0 || period < 0) {
return false;
}
delay_ = delay;
period_ = period;
callback_ = std::move(callback);
start_time_ = clock_->Now();
fired_count_ = 0;
is_started_ = true;
return true;
}
bool FakeTimer::Stop() {
is_started_ = false;
return true;
}
bool FakeTimer::IsRunning() { return is_started_; }
void FakeTimer::ClockUpdated() {
if (!is_started_) {
return;
}
absl::Time now = clock_->Now();
int64_t duration = absl::ToInt64Milliseconds(now - start_time_);
FakeClock* clock = clock_;
if (duration >= delay_ && fired_count_ == 0) {
++fired_count_;
callback_();
}
if (period_ == 0 || duration < delay_ ||
((clock_ != nullptr) && (clock_ != clock))) {
return;
}
int count = (duration - delay_) / period_;
int should_fire_count = count - fired_count_ + 1;
for (int i = 0; i < should_fire_count; ++i) {
++fired_count_;
callback_();
}
}
bool FakeTimer::FireNow() {
if (IsRunning() && callback_) {
callback_();
return true;
}
return false;
}
} // namespace nearby
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TIMER_H_
#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TIMER_H_
#include <string>
#include "internal/platform/timer.h"
#include "internal/test/fake_clock.h"
namespace nearby {
class FakeTimer : public Timer {
public:
explicit FakeTimer(FakeClock* clock);
~FakeTimer() override;
FakeTimer(FakeTimer&&) = default;
FakeTimer& operator=(FakeTimer&&) = default;
bool Start(int delay, int period,
absl::AnyInvocable<void()> callback) override;
bool Stop() override;
bool IsRunning() override;
bool FireNow() override;
private:
void ClockUpdated();
std::string id_;
int delay_ = 0;
int period_ = false;
int fired_count_ = 0;
absl::Time start_time_;
bool is_started_ = false;
absl::AnyInvocable<void()> callback_;
FakeClock* clock_ = nullptr;
};
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_TIMER_H_
+164
View File
@@ -0,0 +1,164 @@
// Copyright 2021 Google LLC
//
// 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
//
// https://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 "internal/test/fake_timer.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/time/time.h"
namespace nearby {
namespace {
TEST(FakeTimer, TestOneTimeTimer) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(100, 0, callback);
EXPECT_TRUE(timer.IsRunning());
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 1);
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
}
TEST(FakeTimer, TestRepeatTimer) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(100, 100, callback);
EXPECT_TRUE(timer.IsRunning());
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 10);
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
}
TEST(FakeTimer, TestInvalidInput) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(-100, 100, callback);
EXPECT_FALSE(timer.IsRunning());
EXPECT_TRUE(timer.Stop());
}
TEST(FakeTimer, TestStopTimerBeforeClockUpdate) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(100, 100, callback);
EXPECT_TRUE(timer.IsRunning());
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 0);
}
TEST(FakeTimer, TestUpdateMultipleTimesClockForOnetimeTimer) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(100, 0, callback);
EXPECT_TRUE(timer.IsRunning());
clock.FastForward(absl::Nanoseconds(50));
EXPECT_EQ(count, 0);
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 1);
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 1);
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
}
TEST(FakeTimer, TestInstantRunTimer) {
FakeClock clock;
FakeTimer timer(&clock);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(0, 100, callback);
EXPECT_TRUE(timer.IsRunning());
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 11);
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
}
TEST(FakeTimer, TestTimerDestructor) {
FakeClock clock;
{
FakeTimer timer(&clock);
EXPECT_EQ(clock.GetObserversCount(), 1);
int count = 0;
auto callback = [&count]() { ++count; };
timer.Start(100, 0, callback);
EXPECT_TRUE(timer.IsRunning());
EXPECT_EQ(count, 0);
EXPECT_TRUE(timer.Stop());
EXPECT_FALSE(timer.IsRunning());
}
EXPECT_EQ(clock.GetObserversCount(), 0);
}
TEST(FakeTimer, TestTimerFireNow) {
FakeClock clock;
int count = 0;
FakeTimer timer(&clock);
auto callback = [&count]() { ++count; };
timer.Start(200, 100, callback);
timer.FireNow();
timer.Stop();
EXPECT_EQ(count, 1);
}
TEST(FakeTimer, CloseTimerInTimerProc) {
int count = 0;
FakeClock clock;
FakeTimer timer1(&clock);
FakeTimer timer2(&clock);
timer1.Start(100, 0, [&]() { ++count; });
timer2.Start(50, 0, [&]() {
++count;
timer1.Stop();
});
clock.FastForward(absl::Milliseconds(50));
EXPECT_EQ(count, 1);
clock.FastForward(absl::Milliseconds(50));
EXPECT_EQ(count, 1);
}
TEST(FakeTimer, StartTimerInTimerProc) {
int count = 0;
FakeClock clock;
FakeTimer timer1(&clock);
timer1.Start(1000, 0, [&]() {
++count;
timer1.Stop();
timer1.Start(1000, 0, [&]() { ++count; });
});
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 1);
clock.FastForward(absl::Milliseconds(1000));
EXPECT_EQ(count, 2);
}
} // namespace
} // namespace nearby