Skip to content

Commit e5b44cf

Browse files
authored
Merge 80f6e63 into be461e5
2 parents be461e5 + 80f6e63 commit e5b44cf

File tree

9 files changed

+120
-110
lines changed

9 files changed

+120
-110
lines changed

firestore/integration_test_internal/src/android/firestore_integration_test_android.cc

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,9 @@ Local<Throwable> FirestoreAndroidIntegrationTest::CreateException(
7373
}
7474

7575
void FirestoreAndroidIntegrationTest::Await(Env& env, const Task& task) {
76-
int cycles = kTimeOutMillis / kCheckIntervalMillis;
77-
while (env.ok() && !task.IsComplete(env)) {
78-
if (ProcessEvents(kCheckIntervalMillis)) {
79-
std::cout << "WARNING: app receives an event requesting exit."
80-
<< std::endl;
81-
break;
82-
}
83-
--cycles;
84-
}
76+
bool success = WaitUntil([&] { return env.ok() && task.IsComplete(env); });
8577
if (env.ok()) {
86-
EXPECT_GT(cycles, 0) << "Waiting for Task timed out.";
78+
EXPECT_TRUE(success) << "Waiting for Task timed out.";
8779
}
8880
}
8981

firestore/integration_test_internal/src/android/promise_android_test.cc

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -122,24 +122,10 @@ class TestCompletionBase : public Promise<PublicType,
122122
// Waits for `CompleteWith()` to be invoked. Returns `true` if an invocation
123123
// occurred prior to timing out or `false` otherwise.
124124
bool AwaitCompletion() {
125-
int cycles_remaining = kTimeOutMillis / kCheckIntervalMillis;
126-
while (true) {
127-
{
128-
MutexLock lock(mutex_);
129-
if (invocation_count_ > 0) {
130-
return true;
131-
}
132-
}
133-
134-
if (ProcessEvents(kCheckIntervalMillis)) {
135-
return false;
136-
}
137-
138-
cycles_remaining--;
139-
if (cycles_remaining == 0) {
140-
return false;
141-
}
142-
}
125+
return WaitUntil([&] {
126+
MutexLock lock(mutex_);
127+
return invocation_count_ > 0;
128+
});
143129
}
144130

145131
// Returns the number of times that `CompleteWith()` has been invoked.
@@ -229,7 +215,7 @@ TEST_F(PromiseTest, FutureVoidShouldSucceedWhenTaskSucceeds) {
229215

230216
SetTaskResult(0);
231217

232-
EXPECT_GT(WaitFor(future), 0);
218+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
233219
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
234220
EXPECT_EQ(future.error(), 0);
235221
EXPECT_EQ(future.result(), nullptr);
@@ -243,7 +229,7 @@ TEST_F(PromiseTest, FutureNonVoidShouldSucceedWhenTaskSucceeds) {
243229

244230
SetTaskResult(42);
245231

246-
EXPECT_GT(WaitFor(future), 0);
232+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
247233
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
248234
EXPECT_EQ(future.error(), 0);
249235
EXPECT_EQ(*future.result(), "42");
@@ -256,7 +242,7 @@ TEST_F(PromiseTest, FutureVoidShouldFailWhenTaskFails) {
256242

257243
SetTaskException(Error::kErrorFailedPrecondition, "Simulated failure");
258244

259-
EXPECT_GT(WaitFor(future), 0);
245+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
260246
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
261247
EXPECT_EQ(future.error(), Error::kErrorFailedPrecondition);
262248
EXPECT_EQ(future.error_message(), std::string("Simulated failure"));
@@ -271,7 +257,7 @@ TEST_F(PromiseTest, FutureNonVoidShouldFailWhenTaskFails) {
271257

272258
SetTaskException(Error::kErrorFailedPrecondition, "Simulated failure");
273259

274-
EXPECT_GT(WaitFor(future), 0);
260+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
275261
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
276262
EXPECT_EQ(future.error(), Error::kErrorFailedPrecondition);
277263
EXPECT_EQ(future.error_message(), std::string("Simulated failure"));
@@ -285,7 +271,7 @@ TEST_F(PromiseTest, FutureVoidShouldCancelWhenTaskCancels) {
285271

286272
CancelTask();
287273

288-
EXPECT_GT(WaitFor(future), 0);
274+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
289275
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
290276
EXPECT_EQ(future.error(), Error::kErrorCancelled);
291277
EXPECT_EQ(future.error_message(), std::string("cancelled"));
@@ -300,7 +286,7 @@ TEST_F(PromiseTest, FutureNonVoidShouldCancelWhenTaskCancels) {
300286

301287
CancelTask();
302288

303-
EXPECT_GT(WaitFor(future), 0);
289+
EXPECT_TRUE(WaitUntilFutureCompletes(future));
304290
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete);
305291
EXPECT_EQ(future.error(), Error::kErrorCancelled);
306292
EXPECT_EQ(future.error_message(), std::string("cancelled"));

firestore/integration_test_internal/src/bundle_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ TEST_F(BundleTest, CanDeleteFirestoreFromProgressUpdate) {
187187

188188
// This future is not completed, and returns back a nullptr for result when it
189189
// times out.
190-
EXPECT_EQ(Await(result), nullptr);
190+
EXPECT_TRUE(WaitUntilFutureCompletes(result));
191+
EXPECT_EQ(result.result(), nullptr);
191192

192193
// 3 progresses will be reported: initial, document 1, document 2.
193194
// Final progress update is missing because Firestore is deleted before that.

firestore/integration_test_internal/src/firestore_integration_test.cc

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,10 @@ std::string ToFirestoreErrorCodeName(int error_code) {
9797
}
9898
}
9999

100-
int WaitFor(const FutureBase& future) {
101-
// Instead of getting a clock, we count the cycles instead.
102-
int cycles = kTimeOutMillis / kCheckIntervalMillis;
103-
while (future.status() == FutureStatus::kFutureStatusPending && cycles > 0) {
104-
if (ProcessEvents(kCheckIntervalMillis)) {
105-
std::cout << "WARNING: app receives an event requesting exit."
106-
<< std::endl;
107-
break;
108-
}
109-
--cycles;
110-
}
111-
return cycles;
100+
bool WaitUntilFutureCompletes(const FutureBase& future, int timeout_ms) {
101+
return WaitUntil(
102+
[&] { return future.status() != FutureStatus::kFutureStatusPending; },
103+
timeout_ms);
112104
}
113105

114106
FirestoreIntegrationTest::FirestoreIntegrationTest() {
@@ -280,18 +272,12 @@ FirestoreIntegrationTest::QuerySnapshotToMap(
280272
return result;
281273
}
282274

283-
/* static */
284-
void FirestoreIntegrationTest::Await(const Future<void>& future) {
285-
while (future.status() == FutureStatus::kFutureStatusPending) {
286-
if (ProcessEvents(kCheckIntervalMillis)) {
287-
std::cout << "WARNING: app received an event requesting exit."
288-
<< std::endl;
289-
break;
290-
}
291-
}
275+
void FirestoreIntegrationTest::Await(const Future<void>& future,
276+
int timeout_ms) {
277+
EXPECT_TRUE(WaitUntilFutureCompletes(future, timeout_ms))
278+
<< "Future<void> timed out.";
292279
}
293280

294-
/* static */
295281
bool FirestoreIntegrationTest::FailIfUnsuccessful(const char* operation,
296282
const FutureBase& future) {
297283
if (future.status() != FutureStatus::kFutureStatusComplete) {
@@ -307,11 +293,13 @@ bool FirestoreIntegrationTest::FailIfUnsuccessful(const char* operation,
307293
}
308294
}
309295

310-
/* static */
311296
std::string FirestoreIntegrationTest::DescribeFailedFuture(
312297
const FutureBase& future) {
313-
return "Future failed: " + ToFirestoreErrorCodeName(future.error()) + " (" +
314-
std::to_string(future.error()) + "): " + future.error_message();
298+
std::string error_message =
299+
future.error_message() ? future.error_message() : "[no additional info]";
300+
return std::string("Future failed: ") +
301+
ToFirestoreErrorCodeName(future.error()) + " (" +
302+
std::to_string(future.error()) + "): " + error_message;
315303
}
316304

317305
bool ProcessEvents(int msec) { return app_framework::ProcessEvents(msec); }

firestore/integration_test_internal/src/firestore_integration_test.h

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef FIREBASE_FIRESTORE_INTEGRATION_TEST_INTERNAL_SRC_FIRESTORE_INTEGRATION_TEST_H_
44
#define FIREBASE_FIRESTORE_INTEGRATION_TEST_INTERNAL_SRC_FIRESTORE_INTEGRATION_TEST_H_
55

6+
#include <chrono> // NOLINT(build/c++11)
67
#include <cstdio>
78
#include <iostream>
89
#include <map>
@@ -45,11 +46,16 @@ bool ProcessEvents(int msec);
4546
// enum, but this function will gracefully handle the case where it is not.
4647
std::string ToFirestoreErrorCodeName(int error_code);
4748

48-
// Waits for a Future to complete. If a timeout is reached then this method
49-
// returns as if successful; therefore, the caller should verify the status of
50-
// the given Future after this function returns. Returns the number of cycles
51-
// that were left before a timeout would have occurred.
52-
int WaitFor(const FutureBase& future);
49+
// Blocks until either the given predicate `pred` returns `true` or timeout
50+
// occurs. Returns `true` on success, `false` on timeout or if exit signal was
51+
// received.
52+
template <typename PredT>
53+
bool WaitUntil(const PredT& pred, int timeout_ms = kTimeOutMillis);
54+
55+
// Blocks until either the future completes or timeout occurs. Returns `true`
56+
// on success, `false` on timeout or if exit signal was received.
57+
bool WaitUntilFutureCompletes(const FutureBase& future,
58+
int timeout_ms = kTimeOutMillis);
5359

5460
template <typename T>
5561
class EventAccumulator;
@@ -276,37 +282,30 @@ class FirestoreIntegrationTest : public testing::Test {
276282

277283
// TODO(zxu): add a helper function to block on signal.
278284

279-
// A helper function to block until the future completes.
285+
// Blocks until the future is completed and returns the future result.
280286
template <typename T>
281-
static const T* Await(const Future<T>& future) {
282-
int cycles = WaitFor(future);
283-
EXPECT_GT(cycles, 0) << "Waiting future timed out.";
284-
if (future.status() == FutureStatus::kFutureStatusComplete) {
285-
if (future.result() == nullptr) {
286-
std::cout << "WARNING: " << DescribeFailedFuture(future) << std::endl;
287-
}
288-
} else {
289-
std::cout << "WARNING: Future is not completed." << std::endl;
290-
}
287+
static const T* Await(const Future<T>& future,
288+
int timeout_ms = kTimeOutMillis) {
289+
EXPECT_TRUE(WaitUntilFutureCompletes(future, timeout_ms))
290+
<< "Future<T> timed out.";
291+
292+
EXPECT_EQ(future.status(), FutureStatus::kFutureStatusComplete)
293+
<< DescribeFailedFuture(future);
294+
EXPECT_NE(future.result(), nullptr) << DescribeFailedFuture(future);
295+
291296
return future.result();
292297
}
293298

294-
static void Await(const Future<void>& future);
299+
// Blocks until the future completes.
300+
static void Await(const Future<void>& future,
301+
int timeout_ms = kTimeOutMillis);
295302

296-
// A helper function to block until there is at least n event.
303+
// Blocks until there is at least `event_count` events.
297304
template <typename T>
298-
static void Await(const TestEventListener<T>& listener, int n = 1) {
299-
// Instead of getting a clock, we count the cycles instead.
300-
int cycles = kTimeOutMillis / kCheckIntervalMillis;
301-
while (listener.event_count() < n && cycles > 0) {
302-
if (ProcessEvents(kCheckIntervalMillis)) {
303-
std::cout << "WARNING: app receives an event requesting exit."
304-
<< std::endl;
305-
return;
306-
}
307-
--cycles;
308-
}
309-
EXPECT_GT(cycles, 0) << "Waiting listener timed out.";
305+
static void Await(const TestEventListener<T>& listener, int event_count = 1) {
306+
bool success =
307+
WaitUntil([&] { return listener.event_count() >= event_count; });
308+
EXPECT_TRUE(success) << "Waiting for a listener timed out.";
310309
}
311310

312311
// Fails the current test if the given future did not complete or contained an
@@ -351,6 +350,24 @@ class FirestoreIntegrationTest : public testing::Test {
351350
mutable std::unordered_map<Firestore*, FirestoreInfo> firestores_;
352351
};
353352

353+
template <typename PredT>
354+
bool WaitUntil(const PredT& pred, int timeout_ms) {
355+
auto now = std::chrono::steady_clock::now();
356+
auto timeout_time = now + std::chrono::milliseconds(timeout_ms);
357+
358+
while (!pred() && now < timeout_time) {
359+
if (ProcessEvents(kCheckIntervalMillis)) {
360+
std::cout << "WARNING: app received an event requesting exit."
361+
<< std::endl;
362+
return false;
363+
}
364+
365+
now = std::chrono::steady_clock::now();
366+
}
367+
368+
return now < timeout_time;
369+
}
370+
354371
} // namespace firestore
355372
} // namespace firebase
356373

firestore/integration_test_internal/src/transaction_extra_test.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ TEST_F(TransactionExtraTest, TestReadingADocTwiceWithDifferentVersions) {
8989
transaction.Set(doc, MapFieldValue{{"count", FieldValue::Double(16.0)}});
9090
return error;
9191
});
92-
Await(future);
92+
93+
// Because the transaction retries a few times with exponential backoff, it
94+
// might time out with the default timeout time (the default timeout value is
95+
// 15 seconds and the transaction can take 11-16 seconds).
96+
Await(future, kTimeOutMillis * 2);
9397
EXPECT_EQ(Error::kErrorAborted, future.error());
9498
EXPECT_STREQ("Document version changed between two reads.",
9599
future.error_message());

firestore/integration_test_internal/src/transaction_test.cc

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ class TransactionTest : public FirestoreIntegrationTest {
3939
void RunTransactionAndExpect(
4040
Error error,
4141
const char* message,
42-
std::function<Error(Transaction&, std::string&)> update) {
42+
std::function<Error(Transaction&, std::string&)> update,
43+
int timeout_ms = kTimeOutMillis) {
4344
Future<void> future;
4445
// Re-try 5 times in case server is unavailable.
4546
for (int i = 0; i < 5; ++i) {
4647
future = TestFirestore()->RunTransaction(update);
47-
Await(future);
48+
Await(future, timeout_ms);
4849
if (future.error() == Error::kErrorUnavailable) {
4950
std::cout << "Could not reach backend. Retrying transaction test."
5051
<< std::endl;
@@ -57,10 +58,13 @@ class TransactionTest : public FirestoreIntegrationTest {
5758
}
5859

5960
void RunTransactionAndExpect(
60-
Error error, std::function<Error(Transaction&, std::string&)> update) {
61+
Error error,
62+
std::function<Error(Transaction&, std::string&)> update,
63+
int timeout_ms = kTimeOutMillis) {
6164
switch (error) {
6265
case Error::kErrorOk:
63-
RunTransactionAndExpect(Error::kErrorOk, "", std::move(update));
66+
RunTransactionAndExpect(Error::kErrorOk, "", std::move(update),
67+
timeout_ms);
6468
break;
6569
case Error::kErrorAborted:
6670
RunTransactionAndExpect(
@@ -69,15 +73,15 @@ class TransactionTest : public FirestoreIntegrationTest {
6973
#else
7074
Error::kErrorAborted,
7175
#endif
72-
"Transaction failed all retries.", std::move(update));
76+
"Transaction failed all retries.", std::move(update), timeout_ms);
7377
break;
7478
case Error::kErrorFailedPrecondition:
7579
// Here specifies error message of the most common cause. There are
7680
// other causes for FailedPrecondition as well. Use the one with message
7781
// parameter if the expected error message is different.
7882
RunTransactionAndExpect(Error::kErrorFailedPrecondition,
7983
"Can't update a document that doesn't exist.",
80-
std::move(update));
84+
std::move(update), timeout_ms);
8185
break;
8286
default:
8387
FAIL() << "Unexpected error code: " << error;
@@ -694,6 +698,10 @@ TEST_F(TransactionTest, TestCancellationOnError) {
694698
int count = 0;
695699

696700
SCOPED_TRACE("TestCancellationOnError");
701+
702+
// Because the transaction retries a few times with exponential backoff, it
703+
// might time out with the default timeout time (the default timeout value is
704+
// 15 seconds and the transaction can take up to 20 seconds).
697705
RunTransactionAndExpect(
698706
Error::kErrorDeadlineExceeded, "no",
699707
[doc, &count_locker, &count](Transaction& transaction,
@@ -705,7 +713,8 @@ TEST_F(TransactionTest, TestCancellationOnError) {
705713
transaction.Set(doc, MapFieldValue{{"foo", FieldValue::String("bar")}});
706714
error_message = "no";
707715
return Error::kErrorDeadlineExceeded;
708-
});
716+
},
717+
kTimeOutMillis * 3);
709718

710719
// TODO(varconst): uncomment. Currently, there is no way in C++ to distinguish
711720
// user error, so the transaction gets retried, and the counter goes up to 6.

0 commit comments

Comments
 (0)