Skip to content
This repository was archived by the owner on Jun 29, 2022. It is now read-only.

Commit 8927640

Browse files
authored
Closing Firestore instance on FirebaseApp.delete() (firebase#227)
* Closing Firestore instance on FirebaseApp.delete() * Updated javadocs * Updated docs and tests
1 parent b80bc92 commit 8927640

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22

3-
-
3+
- [fixed] `Firestore` instances initialized by the SDK are now cleaned
4+
up, when `FirebaseApp.delete()` is called.
45

56
# v6.6.0
67

src/main/java/com/google/firebase/cloud/FirestoreClient.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import com.google.firebase.ImplFirebaseTrampolines;
1212
import com.google.firebase.internal.FirebaseService;
1313
import com.google.firebase.internal.NonNull;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
1416

1517
/**
1618
* {@code FirestoreClient} provides access to Google Cloud Firestore. Use this API to obtain a
@@ -26,6 +28,8 @@
2628
*/
2729
public class FirestoreClient {
2830

31+
private static final Logger logger = LoggerFactory.getLogger(FirestoreClient.class);
32+
2933
private final Firestore firestore;
3034

3135
private FirestoreClient(FirebaseApp app) {
@@ -48,7 +52,9 @@ private FirestoreClient(FirebaseApp app) {
4852
}
4953

5054
/**
51-
* Returns the Firestore instance associated with the default Firebase app.
55+
* Returns the Firestore instance associated with the default Firebase app. Returns the same
56+
* instance for all invocations. The Firestore instance and all references obtained from it
57+
* becomes unusable, once the default app is deleted.
5258
*
5359
* @return A non-null <a href="https://googlecloudplatform.github.io/google-cloud-java/google-cloud-clients/apidocs/com/google/cloud/firestore/Firestore.html">{@code Firestore}</a>
5460
* instance.
@@ -59,7 +65,9 @@ public static Firestore getFirestore() {
5965
}
6066

6167
/**
62-
* Returns the Firestore instance associated with the specified Firebase app.
68+
* Returns the Firestore instance associated with the specified Firebase app. For a given app,
69+
* always returns the same instance. The Firestore instance and all references obtained from it
70+
* becomes unusable, once the specified app is deleted.
6371
*
6472
* @param app A non-null {@link FirebaseApp}.
6573
* @return A non-null <a href="https://googlecloudplatform.github.io/google-cloud-java/google-cloud-clients/apidocs/com/google/cloud/firestore/Firestore.html">{@code Firestore}</a>
@@ -89,10 +97,11 @@ private static class FirestoreClientService extends FirebaseService<FirestoreCli
8997

9098
@Override
9199
public void destroy() {
92-
// NOTE: We don't explicitly tear down anything here (for now). User won't be able to call
93-
// FirestoreClient.getFirestore() any more, but already created Firestore instances will
94-
// continue to work. Request Firestore team to provide a cleanup/teardown method on the
95-
// Firestore object.
100+
try {
101+
instance.firestore.close();
102+
} catch (Exception e) {
103+
logger.warn("Error while closing the Firestore instance", e);
104+
}
96105
}
97106
}
98107

src/test/java/com/google/firebase/cloud/FirestoreClientTest.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,29 @@
77
import static org.junit.Assert.fail;
88

99
import com.google.auth.oauth2.GoogleCredentials;
10+
import com.google.cloud.firestore.DocumentReference;
1011
import com.google.cloud.firestore.Firestore;
1112
import com.google.cloud.firestore.FirestoreOptions;
1213
import com.google.firebase.FirebaseApp;
1314
import com.google.firebase.FirebaseOptions;
1415
import com.google.firebase.FirebaseOptions.Builder;
1516
import com.google.firebase.ImplFirebaseTrampolines;
1617
import com.google.firebase.TestOnlyImplFirebaseTrampolines;
18+
import com.google.firebase.auth.MockGoogleCredentials;
1719
import com.google.firebase.testing.ServiceAccount;
1820
import java.io.IOException;
1921
import org.junit.After;
2022
import org.junit.Test;
2123

2224
public class FirestoreClientTest {
2325

26+
public static final FirestoreOptions FIRESTORE_OPTIONS = FirestoreOptions.newBuilder()
27+
// Setting credentials is not required (they get overridden by Admin SDK), but without
28+
// this Firestore logs an ugly warning during tests.
29+
.setCredentials(new MockGoogleCredentials("test-token"))
30+
.setTimestampsInSnapshotsEnabled(true)
31+
.build();
32+
2433
@After
2534
public void tearDown() {
2635
TestOnlyImplFirebaseTrampolines.clearInstancesForTest();
@@ -31,9 +40,7 @@ public void testExplicitProjectId() throws IOException {
3140
FirebaseApp app = FirebaseApp.initializeApp(new FirebaseOptions.Builder()
3241
.setCredentials(GoogleCredentials.fromStream(ServiceAccount.EDITOR.asStream()))
3342
.setProjectId("explicit-project-id")
34-
.setFirestoreOptions(FirestoreOptions.newBuilder()
35-
.setTimestampsInSnapshotsEnabled(true)
36-
.build())
43+
.setFirestoreOptions(FIRESTORE_OPTIONS)
3744
.build());
3845
Firestore firestore = FirestoreClient.getFirestore(app);
3946
assertEquals("explicit-project-id", firestore.getOptions().getProjectId());
@@ -46,9 +53,7 @@ public void testExplicitProjectId() throws IOException {
4653
public void testServiceAccountProjectId() throws IOException {
4754
FirebaseApp app = FirebaseApp.initializeApp(new FirebaseOptions.Builder()
4855
.setCredentials(GoogleCredentials.fromStream(ServiceAccount.EDITOR.asStream()))
49-
.setFirestoreOptions(FirestoreOptions.newBuilder()
50-
.setTimestampsInSnapshotsEnabled(true)
51-
.build())
56+
.setFirestoreOptions(FIRESTORE_OPTIONS)
5257
.build());
5358
Firestore firestore = FirestoreClient.getFirestore(app);
5459
assertEquals("mock-project-id", firestore.getOptions().getProjectId());
@@ -62,9 +67,7 @@ public void testFirestoreOptions() throws IOException {
6267
FirebaseApp app = FirebaseApp.initializeApp(new Builder()
6368
.setCredentials(GoogleCredentials.fromStream(ServiceAccount.EDITOR.asStream()))
6469
.setProjectId("explicit-project-id")
65-
.setFirestoreOptions(FirestoreOptions.newBuilder()
66-
.setTimestampsInSnapshotsEnabled(true)
67-
.build())
70+
.setFirestoreOptions(FIRESTORE_OPTIONS)
6871
.build());
6972
Firestore firestore = FirestoreClient.getFirestore(app);
7073
assertEquals("explicit-project-id", firestore.getOptions().getProjectId());
@@ -104,12 +107,12 @@ public void testAppDelete() throws IOException {
104107
FirebaseApp app = FirebaseApp.initializeApp(new FirebaseOptions.Builder()
105108
.setCredentials(GoogleCredentials.fromStream(ServiceAccount.EDITOR.asStream()))
106109
.setProjectId("mock-project-id")
107-
.setFirestoreOptions(FirestoreOptions.newBuilder()
108-
.setTimestampsInSnapshotsEnabled(true)
109-
.build())
110+
.setFirestoreOptions(FIRESTORE_OPTIONS)
110111
.build());
111112

112-
assertNotNull(FirestoreClient.getFirestore(app));
113+
Firestore firestore = FirestoreClient.getFirestore(app);
114+
assertNotNull(firestore);
115+
DocumentReference document = firestore.collection("collection").document("doc");
113116
app.delete();
114117
try {
115118
FirestoreClient.getFirestore(app);
@@ -118,12 +121,18 @@ public void testAppDelete() throws IOException {
118121
// ignore
119122
}
120123

124+
try {
125+
document.get();
126+
fail("No error thrown for deleted app");
127+
} catch (IllegalStateException expected) {
128+
// ignore
129+
}
130+
121131
try {
122132
FirestoreClient.getFirestore();
123133
fail("No error thrown for deleted app");
124134
} catch (IllegalStateException expected) {
125135
// ignore
126136
}
127137
}
128-
129138
}

0 commit comments

Comments
 (0)