Skip to content

Commit 1044299

Browse files
committed
Merge branch 'master' into codable-master
2 parents 16885d2 + 3185ff6 commit 1044299

18 files changed

+282
-200
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,6 @@
14781478
B6FB467B208E9A8200554BA2 /* async_queue_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = async_queue_test.cc; sourceTree = "<group>"; };
14791479
B6FB4680208EA0BE00554BA2 /* async_queue_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = async_queue_libdispatch_test.mm; sourceTree = "<group>"; };
14801480
B6FB4681208EA0BE00554BA2 /* async_queue_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = async_queue_std_test.cc; sourceTree = "<group>"; };
1481-
B6FB4686208F9B9100554BA2 /* async_tests_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = async_tests_util.h; sourceTree = "<group>"; };
14821481
B6FB4687208F9B9100554BA2 /* executor_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = executor_std_test.cc; sourceTree = "<group>"; };
14831482
B6FB4688208F9B9100554BA2 /* executor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = executor_test.cc; sourceTree = "<group>"; };
14841483
B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = executor_libdispatch_test.mm; sourceTree = "<group>"; };
@@ -1726,7 +1725,6 @@
17261725
B6FB4681208EA0BE00554BA2 /* async_queue_std_test.cc */,
17271726
B6FB467B208E9A8200554BA2 /* async_queue_test.cc */,
17281727
B6FB467A208E9A8200554BA2 /* async_queue_test.h */,
1729-
B6FB4686208F9B9100554BA2 /* async_tests_util.h */,
17301728
54740A521FC913E500713A1A /* autoid_test.cc */,
17311729
AB380D01201BC69F00D97691 /* bits_test.cc */,
17321730
548DB928200D59F600E00ABC /* comparison_test.cc */,

Firestore/Example/GoogleTest.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
Pod::Spec.new do |s|
1919
s.name = 'GoogleTest'
20-
s.version = '1.8.0'
20+
s.version = '1.8.1'
2121
s.summary = 'Google Test'
2222

2323
s.description = <<-DESC

Firestore/core/test/firebase/firestore/remote/exponential_backoff_test.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include "Firestore/core/src/firebase/firestore/util/async_queue.h"
2121
#include "Firestore/core/src/firebase/firestore/util/executor.h"
2222
#include "Firestore/core/test/firebase/firestore/testutil/async_testing.h"
23-
#include "Firestore/core/test/firebase/firestore/util/async_tests_util.h"
2423
#include "absl/memory/memory.h"
2524
#include "gtest/gtest.h"
2625

@@ -30,13 +29,13 @@ namespace firebase {
3029
namespace firestore {
3130
namespace remote {
3231

32+
using testutil::Expectation;
3333
using util::AsyncQueue;
3434
using util::Executor;
35-
using util::TestWithTimeoutMixin;
3635
using util::TimerId;
3736

38-
class ExponentialBackoffTest : public TestWithTimeoutMixin,
39-
public testing::Test {
37+
class ExponentialBackoffTest : public testing::Test,
38+
public testutil::AsyncTest {
4039
public:
4140
ExponentialBackoffTest()
4241
: queue{testutil::AsyncQueueForTesting()},
@@ -51,12 +50,13 @@ class ExponentialBackoffTest : public TestWithTimeoutMixin,
5150
TEST_F(ExponentialBackoffTest, CanScheduleOperations) {
5251
EXPECT_FALSE(queue->IsScheduled(timer_id));
5352

53+
Expectation finished;
5454
queue->EnqueueBlocking([&] {
55-
backoff.BackoffAndRun([&] { signal_finished(); });
55+
backoff.BackoffAndRun(finished.AsCallback());
5656
EXPECT_TRUE(queue->IsScheduled(timer_id));
5757
});
5858

59-
EXPECT_TRUE(WaitForTestToFinish());
59+
Await(finished);
6060
EXPECT_FALSE(queue->IsScheduled(timer_id));
6161
}
6262

@@ -75,16 +75,17 @@ TEST_F(ExponentialBackoffTest, CanCancelOperations) {
7575
}
7676

7777
TEST_F(ExponentialBackoffTest, SequentialCallsToBackoffAndRun) {
78+
Expectation finished;
7879
queue->EnqueueBlocking([&] {
7980
backoff.BackoffAndRun([] {});
8081
backoff.BackoffAndRun([] {});
81-
backoff.BackoffAndRun([&] { signal_finished(); });
82+
backoff.BackoffAndRun(finished.AsCallback());
8283
});
8384

8485
// The chosen value of initial_delay is large enough that it shouldn't be
8586
// realistically possible for backoff to finish already.
8687
queue->RunScheduledOperationsUntil(timer_id);
87-
EXPECT_TRUE(WaitForTestToFinish());
88+
Await(finished);
8889
}
8990

9091
} // namespace remote

Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ cc_library(
4343
firebase_firestore_nanopb
4444

4545
${TESTUTIL_DEPENDS}
46+
GTest::GTest
4647
absl_time
4748
firebase_firestore_core
4849
firebase_firestore_model

Firestore/core/test/firebase/firestore/testutil/async_testing.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#include "Firestore/core/test/firebase/firestore/testutil/async_testing.h"
1818

1919
#include <string>
20+
#include <utility>
2021

2122
#include "Firestore/core/src/firebase/firestore/util/async_queue.h"
2223
#include "Firestore/core/src/firebase/firestore/util/executor.h"
2324
#include "absl/strings/str_cat.h"
25+
#include "gtest/gtest.h"
2426

2527
namespace firebase {
2628
namespace firestore {
@@ -38,6 +40,65 @@ std::shared_ptr<util::AsyncQueue> AsyncQueueForTesting() {
3840
return std::make_shared<AsyncQueue>(ExecutorForTesting("worker"));
3941
}
4042

43+
// MARK: - Expectation
44+
45+
Expectation::Expectation()
46+
: promise_(std::make_shared<std::promise<void>>()),
47+
future_(promise_->get_future().share()) {
48+
}
49+
50+
void Expectation::Fulfill() {
51+
promise_->set_value();
52+
}
53+
54+
std::function<void()> Expectation::AsCallback() const {
55+
// Additional copy required because putting `promise_` in the capture list
56+
// is not allowed. Generalized capture in C++14 would allow direct
57+
// initialization.
58+
auto promise = promise_;
59+
return [promise] { promise->set_value(); };
60+
}
61+
62+
// MARK: - AsyncTest
63+
64+
std::future<void> AsyncTest::Async(std::function<void()> action) const {
65+
std::packaged_task<void()> task(std::move(action));
66+
auto future = task.get_future();
67+
68+
std::thread thread(std::move(task));
69+
thread.detach();
70+
return future;
71+
}
72+
73+
void AsyncTest::Await(const std::future<void>& future,
74+
std::chrono::milliseconds timeout) const {
75+
std::future_status result = future.wait_for(timeout);
76+
if (result == std::future_status::ready) {
77+
return;
78+
}
79+
80+
ADD_FAILURE() << "Test timed out after " << timeout.count() << " ms";
81+
}
82+
83+
void AsyncTest::Await(const std::shared_future<void>& future,
84+
std::chrono::milliseconds timeout) const {
85+
std::future_status result = future.wait_for(timeout);
86+
if (result == std::future_status::ready) {
87+
return;
88+
}
89+
90+
ADD_FAILURE() << "Test timed out after " << timeout.count() << " ms";
91+
}
92+
93+
void AsyncTest::Await(Expectation& expectation,
94+
std::chrono::milliseconds timeout) const {
95+
return Await(expectation.get_future(), timeout);
96+
}
97+
98+
void AsyncTest::SleepFor(int millis) const {
99+
std::this_thread::sleep_for(std::chrono::milliseconds(millis));
100+
}
101+
41102
} // namespace testutil
42103
} // namespace firestore
43104
} // namespace firebase

Firestore/core/test/firebase/firestore/testutil/async_testing.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
#ifndef FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_TESTUTIL_ASYNC_TESTING_H_
1818
#define FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_TESTUTIL_ASYNC_TESTING_H_
1919

20+
#include <chrono> // NOLINT(build/c++11)
21+
#include <functional>
22+
#include <future> // NOLINT(build/c++11)
2023
#include <memory>
24+
#include <thread> // NOLINT(build/c++11)
25+
26+
#include "gtest/gtest.h"
2127

2228
namespace firebase {
2329
namespace firestore {
@@ -46,6 +52,89 @@ std::unique_ptr<util::Executor> ExecutorForTesting(const char* name);
4652
*/
4753
std::shared_ptr<util::AsyncQueue> AsyncQueueForTesting();
4854

55+
constexpr auto kTimeout = std::chrono::seconds(5);
56+
57+
/**
58+
* An expected outcome of an asynchronous test.
59+
*/
60+
class Expectation {
61+
public:
62+
Expectation();
63+
64+
/**
65+
* Marks this expectation as fulfilled.
66+
*
67+
* Only a single call to `Fulfill` is allowed for any given `Expectaction`. An
68+
* exception is thrown if `Fulfill` is called more than once.
69+
*/
70+
void Fulfill();
71+
72+
/**
73+
* Returns a callback function, that when invoked, fullfills the expectation.
74+
*
75+
* The returned function has a lifetime that's independent of the Expectation
76+
* that created it.
77+
*/
78+
std::function<void()> AsCallback() const;
79+
80+
/**
81+
* Returns a `shared_future` that represents the completion of this
82+
* Expectation.
83+
*/
84+
const std::shared_future<void>& get_future() const {
85+
return future_;
86+
}
87+
88+
private:
89+
std::shared_ptr<std::promise<void>> promise_;
90+
std::shared_future<void> future_;
91+
};
92+
93+
/**
94+
* A mixin that supplies utilities for safely writing asynchronous tests.
95+
*/
96+
class AsyncTest {
97+
public:
98+
AsyncTest() = default;
99+
100+
std::future<void> Async(std::function<void()> action) const;
101+
102+
/**
103+
* Waits for the future to become ready.
104+
*
105+
* Fails the current test if the timeout occurs.
106+
*/
107+
void Await(const std::future<void>& future,
108+
std::chrono::milliseconds timeout = kTimeout) const;
109+
110+
/**
111+
* Waits for the shared future to become ready.
112+
*
113+
* Fails the current test if the timeout occurs.
114+
*/
115+
void Await(const std::shared_future<void>& future,
116+
std::chrono::milliseconds timeout = kTimeout) const;
117+
118+
/**
119+
* Waits for the expectation to become fulfilled.
120+
*
121+
* Fails the current test if the timeout occurs.
122+
*/
123+
void Await(Expectation& expectation, // NOLINT(runtime/references)
124+
std::chrono::milliseconds timeout = kTimeout) const;
125+
126+
/**
127+
* Sleeps the current thread for the given number of milliseconds.
128+
*/
129+
void SleepFor(int millis) const;
130+
131+
private:
132+
testing::ScopedTrace trace_{
133+
"Test case name", 1,
134+
testing::Message()
135+
<< testing::UnitTest::GetInstance()->current_test_info()->name()};
136+
};
137+
49138
} // namespace testutil
50139
} // namespace firestore
51140
} // namespace firebase

Firestore/core/test/firebase/firestore/util/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ cc_test(
2828
async_queue_std_test.cc
2929
async_queue_test.cc
3030
async_queue_test.h
31-
async_tests_util.h
3231
executor_std_test.cc
3332
executor_test.cc
3433
executor_test.h
@@ -44,7 +43,6 @@ if(HAVE_LIBDISPATCH)
4443
async_queue_libdispatch_test.mm
4544
async_queue_test.cc
4645
async_queue_test.h
47-
async_tests_util.h
4846
executor_libdispatch_test.mm
4947
executor_test.cc
5048
executor_test.h
@@ -189,6 +187,7 @@ cc_library(
189187
firebase_firestore_auth
190188
firebase_firestore_core
191189
firebase_firestore_remote
190+
firebase_firestore_testutil
192191
firebase_firestore_util
193192
grpc++
194193
)

Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
namespace firebase {
2626
namespace firestore {
2727
namespace util {
28-
2928
namespace {
3029

30+
using testutil::Expectation;
31+
3132
dispatch_queue_t CreateDispatchQueue() {
3233
return dispatch_queue_create("AsyncQueueTests", DISPATCH_QUEUE_SERIAL);
3334
}
@@ -47,8 +48,8 @@ dispatch_queue_t CreateDispatchQueue() {
4748
AsyncQueueTest,
4849
::testing::Values(CreateExecutorLibdispatch));
4950

50-
class AsyncQueueTestLibdispatchOnly : public TestWithTimeoutMixin,
51-
public ::testing::Test {
51+
class AsyncQueueTestLibdispatchOnly : public ::testing::Test,
52+
public testutil::AsyncTest {
5253
public:
5354
AsyncQueueTestLibdispatchOnly()
5455
: underlying_queue{CreateDispatchQueue()},
@@ -63,10 +64,10 @@ dispatch_queue_t CreateDispatchQueue() {
6364
// interacts with raw usage of libdispatch.
6465

6566
TEST_F(AsyncQueueTestLibdispatchOnly, SameQueueIsAllowedForUnownedActions) {
66-
internal::DispatchAsync(underlying_queue, [this] {
67-
queue.Enqueue([this] { signal_finished(); });
68-
});
69-
EXPECT_TRUE(WaitForTestToFinish());
67+
Expectation ran;
68+
internal::DispatchAsync(underlying_queue,
69+
[&] { queue.Enqueue(ran.AsCallback()); });
70+
Await(ran);
7071
}
7172

7273
TEST_F(AsyncQueueTestLibdispatchOnly,

0 commit comments

Comments
 (0)