Skip to content

Commit 40945cd

Browse files
authored
Merge branch 'master' into firebase-kotlin-format
2 parents 7b34780 + 1320a47 commit 40945cd

File tree

15 files changed

+381
-34
lines changed

15 files changed

+381
-34
lines changed

firebase-appdistribution/firebase-appdistribution.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dependencies {
5252
implementation 'com.google.firebase:firebase-common:20.3.1'
5353
testImplementation project(path: ':firebase-appdistribution')
5454
testImplementation project(':integ-testing')
55-
runtimeOnly 'com.google.firebase:firebase-installations:17.1.2'
55+
runtimeOnly 'com.google.firebase:firebase-installations:17.1.3'
5656

5757
implementation libs.javax.inject
5858
vendor (libs.dagger.dagger) {

firebase-config/src/main/java/com/google/firebase/remoteconfig/ConfigUpdate.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@
1818
import com.google.auto.value.AutoValue;
1919
import java.util.Set;
2020

21-
/**
22-
* Information about the updated config passed to the {@code onUpdate} callback of {@link
23-
* ConfigUpdateListener}.
24-
*/
21+
/** Information about the updated config passed to {@link ConfigUpdateListener#onUpdate}. */
2522
@AutoValue
2623
public abstract class ConfigUpdate {
2724
@NonNull

firebase-config/src/main/java/com/google/firebase/remoteconfig/ConfigUpdateListener.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,23 @@
1818
import javax.annotation.Nonnull;
1919

2020
/**
21-
* Event listener interface for real-time RC updates. Implement {@code ConfigUpdateListner} to call
22-
* {@link com.google.firebase.remoteconfig.FirebaseRemoteConfig#addOnConfigUpdateListener}.
21+
* Event listener interface for real-time Remote Config updates. Implement {@link
22+
* ConfigUpdateListener} to call {@link
23+
* com.google.firebase.remoteconfig.FirebaseRemoteConfig#addOnConfigUpdateListener}.
2324
*/
2425
public interface ConfigUpdateListener {
2526
/**
26-
* Callback for when a new config has been automatically fetched from the backend and has changed
27-
* from the activated config.
27+
* Callback for when a new config version has been automatically fetched from the backend and has
28+
* changed from the activated config.
2829
*
29-
* @param configUpdate A {@link ConfigUpdate} with information about the updated config, including
30-
* the set of updated parameters.
30+
* @param configUpdate A {@link ConfigUpdate} with information about the updated config version,
31+
* including the set of updated parameters.
3132
*/
3233
void onUpdate(@NonNull ConfigUpdate configUpdate);
3334

3435
/**
35-
* Callback for when an error occurs while listening or fetching a config update.
36+
* Callback for when an error occurs while listening for updates or fetching the latest version of
37+
* the config.
3638
*
3739
* @param error A {@link FirebaseRemoteConfigException} with information about the error.
3840
*/

firebase-config/src/main/java/com/google/firebase/remoteconfig/FirebaseRemoteConfig.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -549,21 +549,21 @@ public Task<Void> reset() {
549549
}
550550

551551
/**
552-
* Start listening for real-time config updates from the Remote Config backend and automatically
553-
* fetch updates from the RC backend when they are available.
552+
* Starts listening for real-time config updates from the Remote Config backend and automatically
553+
* fetches updates from the RC backend when they are available.
554554
*
555555
* <p>If a connection to the Remote Config backend is not already open, calling this method will
556556
* open it. Multiple listeners can be added by calling this method again, but subsequent calls
557557
* re-use the same connection to the backend.
558558
*
559559
* <p>Note: Real-time Remote Config requires the Firebase Remote Config Realtime API. See the <a
560-
* href="https://firebase.google.com/docs/remote-config/get-started">Remote Config Get Started
561-
* </a> guide to enable the API.
560+
* href="https://firebase.google.com/docs/remote-config/get-started#add-real-time-listener">Remote
561+
* Config Get Started </a> guide to enable the API.
562562
*
563563
* @param configUpdateListener A {@link ConfigUpdateListener} that can be used to respond to
564564
* config updates when they're fetched.
565-
* @return A {@link ConfigUpdateListenerRegistration} that allows the user to remove the added
566-
* {@code configUpdateListener} and close the connection when there are no more listeners.
565+
* @return A {@link ConfigUpdateListenerRegistration} that allows you to remove the added {@code
566+
* configUpdateListener} and close the connection when there are no more listeners.
567567
*/
568568
@NonNull
569569
public ConfigUpdateListenerRegistration addOnConfigUpdateListener(

firebase-config/src/main/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public FirebaseRemoteConfigClientException(@NonNull String detailMessage, @NonNu
4545

4646
/**
4747
* Creates a Firebase Remote Config client exception with the given message, exception cause, and
48-
* FirebaseRemoteConfigException code.
48+
* {@code FirebaseRemoteConfigException} code.
4949
*/
5050
public FirebaseRemoteConfigClientException(
5151
@NonNull String detailMessage, @Nullable Throwable cause, @NonNull Code code) {

firebase-config/src/main/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigServerException.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public FirebaseRemoteConfigServerException(
4545
}
4646

4747
/**
48-
* Creates a Firebase Remote Config server exception with the given message and
49-
* FirebaseRemoteConfigException code.
48+
* Creates a Firebase Remote Config server exception with the given message and {@code
49+
* FirebaseRemoteConfigException} code.
5050
*/
5151
public FirebaseRemoteConfigServerException(@NonNull String detailMessage, @Nonnull Code code) {
5252
super(detailMessage, code);
@@ -55,7 +55,7 @@ public FirebaseRemoteConfigServerException(@NonNull String detailMessage, @Nonnu
5555

5656
/**
5757
* Creates a Firebase Remote Config server exception with the HTTP status code, given message, and
58-
* FirebaseRemoteConfigException code.
58+
* {@code FirebaseRemoteConfigException} code.
5959
*/
6060
public FirebaseRemoteConfigServerException(
6161
int httpStatusCode, @NonNull String detailMessage, @Nonnull Code code) {
@@ -65,7 +65,7 @@ public FirebaseRemoteConfigServerException(
6565

6666
/**
6767
* Creates a Firebase Remote Config server exception with the given message, exception cause, and
68-
* FirebaseRemoteConfigException code.
68+
* {@code FirebaseRemoteConfigException} code.
6969
*/
7070
public FirebaseRemoteConfigServerException(
7171
@NonNull String detailMessage, @Nullable Throwable cause, @NonNull Code code) {
@@ -75,7 +75,7 @@ public FirebaseRemoteConfigServerException(
7575

7676
/**
7777
* Creates a Firebase Remote Config server exception with the HTTP status code, given message,
78-
* exception cause, and FirebaseRemoteConfigException code.
78+
* exception cause, and {@code FirebaseRemoteConfigException} code.
7979
*/
8080
public FirebaseRemoteConfigServerException(
8181
int httpStatusCode,

firebase-crashlytics-ndk/firebase-crashlytics-ndk.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ plugins {
1818
}
1919

2020
firebaseLibrary {
21-
testLab.enabled = true
21+
testLab {
22+
enabled = true
23+
device 'model=panther,version=33' // Pixel7
24+
}
2225
publishJavadoc = false
2326
}
2427

firebase-crashlytics/CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# Unreleased
2+
* [changed] Added support for reporting GWP-ASan crashes on supported API levels.(#4721)
23
* [changed] Improved crash reporting reliability for crashes that occur early in the app's
3-
lifecycle.
4-
* [changed] Add improved support capturing build ids for Native ANRs on older
5-
Android versions.
6-
4+
lifecycle.(#4608, #4786)
75

86
# 18.3.5
97
* [fixed] Updated `firebase-common` to its latest version (v20.3.0) to fix an

firebase-crashlytics/firebase-crashlytics.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ dependencies {
6868
implementation project(':transport:transport-runtime')
6969
implementation project(':transport:transport-backend-cct')
7070
implementation 'com.google.firebase:firebase-installations-interop:17.1.0'
71-
runtimeOnly project(':firebase-installations')
71+
runtimeOnly 'com.google.firebase:firebase-installations:17.1.3'
7272
implementation 'com.google.firebase:firebase-measurement-connector:18.0.2'
7373
implementation "com.google.android.gms:play-services-tasks:18.0.1"
7474

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.google.android.gms.tasks.Task;
3838
import com.google.common.collect.Lists;
3939
import com.google.firebase.firestore.Query.Direction;
40+
import com.google.firebase.firestore.remote.ExistenceFilterMismatchListener;
4041
import com.google.firebase.firestore.testutil.EventAccumulator;
4142
import com.google.firebase.firestore.testutil.IntegrationTestUtil;
4243
import java.util.ArrayList;
@@ -1053,6 +1054,7 @@ public void resumingAQueryShouldUseExistenceFilterToDetectDeletes() throws Excep
10531054
createdDocuments.add(documentSnapshot.getReference());
10541055
}
10551056
}
1057+
assertWithMessage("createdDocuments").that(createdDocuments).hasSize(100);
10561058

10571059
// Delete 50 of the 100 documents. Do this in a transaction, rather than
10581060
// DocumentReference.delete(), to avoid affecting the local cache.
@@ -1069,13 +1071,33 @@ public void resumingAQueryShouldUseExistenceFilterToDetectDeletes() throws Excep
10691071
}
10701072
return null;
10711073
}));
1074+
assertWithMessage("deletedDocumentIds").that(deletedDocumentIds).hasSize(50);
10721075

10731076
// Wait for 10 seconds, during which Watch will stop tracking the query and will send an
10741077
// existence filter rather than "delete" events when the query is resumed.
10751078
Thread.sleep(10000);
10761079

1077-
// Resume the query and save the resulting snapshot for verification.
1078-
QuerySnapshot snapshot2 = waitFor(collection.get());
1080+
// Resume the query and save the resulting snapshot for verification. Use some internal testing
1081+
// hooks to "capture" the existence filter mismatches to verify them.
1082+
ExistenceFilterMismatchListener existenceFilterMismatchListener =
1083+
new ExistenceFilterMismatchListener();
1084+
QuerySnapshot snapshot2;
1085+
ExistenceFilterMismatchListener.ExistenceFilterMismatchInfo existenceFilterMismatchInfo;
1086+
try {
1087+
existenceFilterMismatchListener.startListening();
1088+
snapshot2 = waitFor(collection.get());
1089+
// TODO(b/270731363): Remove the "if" condition below once the Firestore Emulator is fixed
1090+
// to send an existence filter.
1091+
if (isRunningAgainstEmulator()) {
1092+
existenceFilterMismatchInfo = null;
1093+
} else {
1094+
existenceFilterMismatchInfo =
1095+
existenceFilterMismatchListener.getOrWaitForExistenceFilterMismatch(
1096+
/*timeoutMillis=*/ 5000);
1097+
}
1098+
} finally {
1099+
existenceFilterMismatchListener.stopListening();
1100+
}
10791101

10801102
// Verify that the snapshot from the resumed query contains the expected documents; that is,
10811103
// that it contains the 50 documents that were _not_ deleted.
@@ -1098,6 +1120,26 @@ public void resumingAQueryShouldUseExistenceFilterToDetectDeletes() throws Excep
10981120
.that(actualDocumentIds)
10991121
.containsExactlyElementsIn(expectedDocumentIds);
11001122
}
1123+
1124+
// Skip the verification of the existence filter mismatch when testing against the Firestore
1125+
// emulator because the Firestore emulator fails to to send an existence filter at all.
1126+
// TODO(b/270731363): Enable the verification of the existence filter mismatch once the
1127+
// Firestore emulator is fixed to send an existence filter.
1128+
if (isRunningAgainstEmulator()) {
1129+
return;
1130+
}
1131+
1132+
// Verify that Watch sent an existence filter with the correct counts when the query was
1133+
// resumed.
1134+
assertWithMessage("Watch should have sent an existence filter")
1135+
.that(existenceFilterMismatchInfo)
1136+
.isNotNull();
1137+
assertWithMessage("localCacheCount")
1138+
.that(existenceFilterMismatchInfo.localCacheCount())
1139+
.isEqualTo(100);
1140+
assertWithMessage("existenceFilterCount")
1141+
.that(existenceFilterMismatchInfo.existenceFilterCount())
1142+
.isEqualTo(50);
11011143
}
11021144

11031145
@Test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.remote;
16+
17+
import android.os.SystemClock;
18+
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
20+
import com.google.firebase.firestore.ListenerRegistration;
21+
import java.util.ArrayList;
22+
23+
/**
24+
* Provides a mechanism for tests to listen for existence filter mismatches in the Watch "listen"
25+
* stream.
26+
*/
27+
public final class ExistenceFilterMismatchListener {
28+
29+
private TestingHooksExistenceFilterMismatchListenerImpl listener;
30+
private ListenerRegistration listenerRegistration;
31+
32+
/**
33+
* Starts listening for existence filter mismatches.
34+
*
35+
* @throws IllegalStateException if this object is already started.
36+
* @see #stopListening
37+
*/
38+
public synchronized void startListening() {
39+
if (listener != null) {
40+
throw new IllegalStateException("already registered");
41+
}
42+
listener = new TestingHooksExistenceFilterMismatchListenerImpl();
43+
listenerRegistration = TestingHooks.getInstance().addExistenceFilterMismatchListener(listener);
44+
}
45+
46+
/**
47+
* Stops listening for existence filter mismatches.
48+
*
49+
* <p>If listening has not been started then this method does nothing.
50+
*
51+
* @see #startListening
52+
*/
53+
public synchronized void stopListening() {
54+
if (listenerRegistration != null) {
55+
listenerRegistration.remove();
56+
}
57+
listenerRegistration = null;
58+
listener = null;
59+
}
60+
61+
/**
62+
* Returns the oldest existence filter mismatch observed, waiting if none has yet been observed.
63+
*
64+
* <p>The oldest existence filter mismatch observed since the most recent successful invocation of
65+
* {@link #startListening} will be returned. A subsequent invocation of this method will return
66+
* the second-oldest existence filter mismatch observed, and so on. An invocation of {@link
67+
* #stopListening} followed by another invocation of {@link #startListening} will discard any
68+
* existence filter mismatches that occurred while previously started and will start observing
69+
* afresh.
70+
*
71+
* @param timeoutMillis the maximum amount of time, in milliseconds, to wait for an existence
72+
* filter mismatch to occur.
73+
* @return information about the existence filter mismatch that occurred.
74+
* @throws InterruptedException if waiting is interrupted.
75+
* @throws IllegalStateException if this object has not been started by {@link #startListening}.
76+
* @throws IllegalArgumentException if the given timeout is less than or equal to zero.
77+
*/
78+
@Nullable
79+
public ExistenceFilterMismatchInfo getOrWaitForExistenceFilterMismatch(long timeoutMillis)
80+
throws InterruptedException {
81+
if (timeoutMillis <= 0) {
82+
throw new IllegalArgumentException("invalid timeout: " + timeoutMillis);
83+
}
84+
85+
TestingHooksExistenceFilterMismatchListenerImpl registeredListener;
86+
synchronized (this) {
87+
registeredListener = listener;
88+
}
89+
90+
if (registeredListener == null) {
91+
throw new IllegalStateException(
92+
"must be registered before waiting for an existence filter mismatch");
93+
}
94+
95+
return registeredListener.getOrWaitForExistenceFilterMismatch(timeoutMillis);
96+
}
97+
98+
private static final class TestingHooksExistenceFilterMismatchListenerImpl
99+
implements TestingHooks.ExistenceFilterMismatchListener {
100+
101+
private final ArrayList<ExistenceFilterMismatchInfo> existenceFilterMismatches =
102+
new ArrayList<>();
103+
104+
@Override
105+
public synchronized void onExistenceFilterMismatch(
106+
@NonNull TestingHooks.ExistenceFilterMismatchInfo info) {
107+
existenceFilterMismatches.add(new ExistenceFilterMismatchInfo(info));
108+
notifyAll();
109+
}
110+
111+
@Nullable
112+
synchronized ExistenceFilterMismatchInfo getOrWaitForExistenceFilterMismatch(long timeoutMillis)
113+
throws InterruptedException {
114+
if (timeoutMillis <= 0) {
115+
throw new IllegalArgumentException("invalid timeout: " + timeoutMillis);
116+
}
117+
118+
long endTimeMillis = SystemClock.uptimeMillis() + timeoutMillis;
119+
while (true) {
120+
if (existenceFilterMismatches.size() > 0) {
121+
return existenceFilterMismatches.remove(0);
122+
}
123+
long currentWaitMillis = endTimeMillis - SystemClock.uptimeMillis();
124+
if (currentWaitMillis <= 0) {
125+
return null;
126+
}
127+
128+
wait(currentWaitMillis);
129+
}
130+
}
131+
}
132+
133+
/** @see TestingHooks.ExistenceFilterMismatchInfo */
134+
public static final class ExistenceFilterMismatchInfo {
135+
136+
private final TestingHooks.ExistenceFilterMismatchInfo info;
137+
138+
ExistenceFilterMismatchInfo(@NonNull TestingHooks.ExistenceFilterMismatchInfo info) {
139+
this.info = info;
140+
}
141+
142+
public int localCacheCount() {
143+
return info.localCacheCount();
144+
}
145+
146+
public int existenceFilterCount() {
147+
return info.existenceFilterCount();
148+
}
149+
}
150+
}

0 commit comments

Comments
 (0)