Skip to content

Commit 1f2089b

Browse files
authored
Fix a few flaky tests in several products (Auth, Analytics, Storage, RTDB, Firestore) (#1520)
* Fix flaky tests on Auth, Analytics, and GMA (with additional debug output). * Revert GMA changes, no longer needed. * Add logging for storage timestamp * Fix build error. * Change timestamp logic. * Deflake the Storage timestamp test by getting the timestamp from the remote server. * Add retries. * Increase timeout on Android FTL tests. * Handle Analytics test flakiness on Android. * Add remote timestamp verification to RTDB test as well. * Fix extra semicolon. * Change UpdateChildren test to use remote timestamp.
1 parent 7374b76 commit 1f2089b

File tree

5 files changed

+86
-17
lines changed

5 files changed

+86
-17
lines changed

.github/workflows/integration_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ jobs:
10471047
- id: ftl_test
10481048
if: steps.device-info.outputs.device_type == 'ftl'
10491049
uses: FirebaseExtended/github-actions/[email protected]
1050-
timeout-minutes: 90
1050+
timeout-minutes: 120
10511051
with:
10521052
credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIALS }}
10531053
testapp_dir: testapps

analytics/integration_test/src/integration_test.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,14 @@ TEST_F(FirebaseAnalyticsTest, TestSetSessionTimeoutDuraction) {
100100
}
101101

102102
TEST_F(FirebaseAnalyticsTest, TestGetAnalyticsInstanceID) {
103+
FLAKY_TEST_SECTION_BEGIN();
104+
103105
firebase::Future<std::string> future =
104106
firebase::analytics::GetAnalyticsInstanceId();
105107
WaitForCompletion(future, "GetAnalyticsInstanceId");
106108
EXPECT_FALSE(future.result()->empty());
109+
110+
FLAKY_TEST_SECTION_END();
107111
}
108112

109113
TEST_F(FirebaseAnalyticsTest, TestGetSessionID) {
@@ -232,10 +236,7 @@ TEST_F(FirebaseAnalyticsTest, TestLogEventWithMultipleParameters) {
232236
}
233237

234238
TEST_F(FirebaseAnalyticsTest, TestResettingGivesNewInstanceId) {
235-
// Test is flaky on iPhone due to a known issue in iOS. See b/143656277.
236-
#if TARGET_OS_IPHONE
237239
FLAKY_TEST_SECTION_BEGIN();
238-
#endif // TARGET_OS_IPHONE
239240

240241
firebase::Future<std::string> future =
241242
firebase::analytics::GetAnalyticsInstanceId();
@@ -251,9 +252,7 @@ TEST_F(FirebaseAnalyticsTest, TestResettingGivesNewInstanceId) {
251252
EXPECT_FALSE(future.result()->empty());
252253
EXPECT_NE(instance_id, new_instance_id);
253254

254-
#if TARGET_OS_IPHONE
255255
FLAKY_TEST_SECTION_END();
256-
#endif // TARGET_OS_IPHONE
257256
}
258257

259258
} // namespace firebase_testapp_automated

auth/integration_test/src/integration_test.cc

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,10 @@ TEST_F(FirebaseAuthTest, TestUpdateEmailAndPassword_DEPRECATED) {
948948
}
949949

950950
TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) {
951-
SignInAnonymously();
951+
FLAKY_TEST_SECTION_BEGIN();
952+
953+
WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously");
954+
952955
firebase::auth::User user = auth_->current_user();
953956
EXPECT_TRUE(user.is_valid());
954957
std::string email = GenerateEmailAddress();
@@ -958,7 +961,7 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) {
958961
WaitForCompletion(user.LinkWithCredential(credential), "LinkWithCredential");
959962
WaitForCompletion(user.Unlink(credential.provider().c_str()), "Unlink");
960963
SignOut();
961-
SignInAnonymously();
964+
WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously");
962965
user = auth_->current_user();
963966
EXPECT_TRUE(user.is_valid());
964967
std::string email1 = GenerateEmailAddress();
@@ -979,10 +982,16 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) {
979982
firebase::auth::kAuthErrorProviderAlreadyLinked);
980983
WaitForCompletion(user.Unlink(credential.provider().c_str()), "Unlink 2");
981984
DeleteUser();
985+
986+
// In case any operations failed, force signout before retrying the test.
987+
SignOut();
988+
FLAKY_TEST_SECTION_END();
982989
}
983990

984991
TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential_DEPRECATED) {
985-
SignInAnonymously_DEPRECATED();
992+
FLAKY_TEST_SECTION_BEGIN();
993+
994+
WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously");
986995
ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr);
987996
firebase::auth::User* user = auth_->current_user_DEPRECATED();
988997
std::string email = GenerateEmailAddress();
@@ -994,7 +1003,7 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential_DEPRECATED) {
9941003
WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()),
9951004
"Unlink");
9961005
SignOut();
997-
SignInAnonymously_DEPRECATED();
1006+
WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously");
9981007
EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr);
9991008
std::string email1 = GenerateEmailAddress();
10001009
firebase::auth::Credential credential1 =
@@ -1012,6 +1021,9 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential_DEPRECATED) {
10121021
WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()),
10131022
"Unlink_DEPRECATED 2");
10141023
DeleteUser_DEPRECATED();
1024+
1025+
SignOut();
1026+
FLAKY_TEST_SECTION_END();
10151027
}
10161028

10171029
TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithBadCredential) {

database/integration_test/src/integration_test.cc

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace firebase_testapp_automated {
4747
using app_framework::LogDebug;
4848
using app_framework::LogError;
4949
using app_framework::LogInfo;
50+
using app_framework::LogWarning;
5051

5152
using app_framework::ProcessEvents;
5253
using firebase_test_framework::FirebaseTest;
@@ -146,6 +147,8 @@ class FirebaseDatabaseTest : public FirebaseTest {
146147
// Shut down Firebase Database.
147148
void TerminateDatabase();
148149

150+
int64_t GetRemoteTimeInMilliseconds();
151+
149152
firebase::database::DatabaseReference CreateWorkingPath(
150153
bool suppress_cleanup = false);
151154

@@ -365,6 +368,30 @@ firebase::database::DatabaseReference FirebaseDatabaseTest::CreateWorkingPath(
365368
return ref;
366369
}
367370

371+
int64_t FirebaseDatabaseTest::GetRemoteTimeInMilliseconds() {
372+
firebase::database::DatabaseReference ref =
373+
CreateWorkingPath().Child("timestamp");
374+
WaitForCompletionAnyResult(
375+
ref.SetValue(firebase::database::ServerTimestamp()),
376+
"GetRemoteTime_SetValue");
377+
firebase::Future<firebase::database::DataSnapshot> future = ref.GetValue();
378+
WaitForCompletionAnyResult(future, "GetRemoteTime_GetValue");
379+
int64_t timestamp = 0;
380+
if (future.error() == 0 && future.result() &&
381+
future.result()->value().is_int64()) {
382+
timestamp = future.result()->value().int64_value();
383+
}
384+
if (timestamp > 0) {
385+
LogDebug("Got server timestamp: %lld", timestamp);
386+
LogDebug(" Local timestamp: %lld",
387+
app_framework::GetCurrentTimeInMicroseconds() / 1000L);
388+
return timestamp;
389+
} else {
390+
LogWarning("Couldn't get remote timestamp, using local time");
391+
return app_framework::GetCurrentTimeInMicroseconds() / 1000L;
392+
}
393+
}
394+
368395
// Test cases below.
369396
TEST_F(FirebaseDatabaseTest, TestInitializeAndTerminate) {
370397
// Already tested via SetUp() and TearDown().
@@ -460,8 +487,7 @@ TEST_F(FirebaseDatabaseTest, TestSetAndGetSimpleValues) {
460487
WaitForCompletion(f7, "GetLongDouble");
461488

462489
// Get the current time to compare to the Timestamp.
463-
int64_t current_time_milliseconds =
464-
static_cast<int64_t>(time(nullptr)) * 1000L;
490+
int64_t current_time_milliseconds = GetRemoteTimeInMilliseconds();
465491

466492
EXPECT_EQ(f1.result()->value().AsString(), kSimpleString);
467493
EXPECT_EQ(f2.result()->value().AsInt64(), kSimpleInt);
@@ -672,8 +698,8 @@ TEST_F(FirebaseDatabaseTest, TestUpdateChildren) {
672698
WaitForCompletion(update_future, "UpdateChildren");
673699
read_future = ref.Child(test_name).GetValue();
674700
WaitForCompletion(read_future, "GetValue 2");
675-
int64_t current_time_milliseconds =
676-
static_cast<int64_t>(time(nullptr)) * 1000L;
701+
int64_t current_time_milliseconds = GetRemoteTimeInMilliseconds();
702+
677703
EXPECT_THAT(
678704
read_future.result()->value().map(),
679705
UnorderedElementsAre(

storage/integration_test/src/integration_test.cc

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class FirebaseStorageTest : public FirebaseTest {
118118
// Create a unique working folder and return a reference to it.
119119
firebase::storage::StorageReference CreateFolder();
120120

121+
int64_t GetRemoteTimeInMilliseconds();
122+
121123
static firebase::App* shared_app_;
122124
static firebase::auth::Auth* shared_auth_;
123125

@@ -324,6 +326,30 @@ firebase::storage::StorageReference FirebaseStorageTest::CreateFolder() {
324326
return storage_->GetReference(kRootNodeName).Child(saved_url_);
325327
}
326328

329+
int64_t FirebaseStorageTest::GetRemoteTimeInMilliseconds() {
330+
SignIn();
331+
332+
firebase::storage::StorageReference ref =
333+
CreateFolder().Child("timestamp.txt");
334+
firebase::Future<firebase::storage::Metadata> future =
335+
RunWithRetry<firebase::storage::Metadata>(
336+
[&]() { return ref.PutBytes("TS00", 4); });
337+
WaitForCompletionAnyResult(future, "GetRemoteTime_PutBytes");
338+
if (future.error() == 0 && future.result() != nullptr &&
339+
future.result()->creation_time() > 0) {
340+
int64_t timestamp = future.result()->creation_time();
341+
WaitForCompletionAnyResult(RunWithRetry([&]() { return ref.Delete(); }),
342+
"GetRemoteTime_Delete");
343+
LogDebug("Got server timestamp: %lld", timestamp);
344+
LogDebug(" Local timestamp: %lld",
345+
app_framework::GetCurrentTimeInMicroseconds() / 1000L);
346+
return timestamp;
347+
} else {
348+
LogWarning("Couldn't get remote timestamp, using local time");
349+
return app_framework::GetCurrentTimeInMicroseconds() / 1000L;
350+
}
351+
}
352+
327353
// Test cases below.
328354

329355
TEST_F(FirebaseStorageTest, TestInitializeAndTerminate) {
@@ -497,17 +523,23 @@ TEST_F(FirebaseStorageTest, TestWriteAndReadFileWithCustomMetadata) {
497523
ASSERT_NE(metadata, nullptr);
498524

499525
// Get the current time to compare to the Timestamp.
500-
int64_t current_time_seconds = static_cast<int64_t>(time(nullptr));
526+
int64_t current_time_seconds = GetRemoteTimeInMilliseconds() / 1000L;
501527
int64_t updated_time_milliseconds = metadata->updated_time();
502-
int64_t updated_time_seconds = updated_time_milliseconds / 1000;
528+
int64_t updated_time_seconds = updated_time_milliseconds / 1000L;
503529
int64_t time_difference_seconds =
504530
updated_time_seconds - current_time_seconds;
531+
if (time_difference_seconds < 0)
532+
time_difference_seconds = -time_difference_seconds;
505533
// As long as our timestamp is within a day, it's correct enough for
506534
// our purposes.
507535
const int64_t kAllowedTimeDifferenceSeconds = 60L * 60L * 24L;
508536
EXPECT_TRUE(time_difference_seconds < kAllowedTimeDifferenceSeconds &&
509537
time_difference_seconds > -kAllowedTimeDifferenceSeconds)
510-
<< "Bad timestamp in metadata.";
538+
<< "Bad timestamp in metadata. Metadata timestamp is "
539+
<< updated_time_seconds << ", current time is " << current_time_seconds
540+
<< ", difference = " << time_difference_seconds
541+
<< " (allowed difference " << kAllowedTimeDifferenceSeconds << ").";
542+
511543
EXPECT_EQ(metadata->size_bytes(), kSimpleTestFile.size());
512544
EXPECT_EQ(metadata->content_type(), content_type);
513545
ASSERT_NE(metadata->custom_metadata(), nullptr);

0 commit comments

Comments
 (0)