aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Example
diff options
context:
space:
mode:
Diffstat (limited to 'Firestore/Example')
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj4
-rw-r--r--Firestore/Example/SwiftBuildTest/main.swift20
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRFirestoreSourceTests.mm648
-rw-r--r--Firestore/Example/Tests/Util/FSTIntegrationTestCase.h11
-rw-r--r--Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm43
5 files changed, 716 insertions, 10 deletions
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index d20dc48..dd64351 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -131,6 +131,7 @@
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
+ 6161B5032047140C00A99DBB /* FIRFirestoreSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */; };
6ED54761B845349D43DB6B78 /* Pods_Firestore_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */; };
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */; };
@@ -356,6 +357,7 @@
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFirestoreSourceTests.mm; sourceTree = "<group>"; };
69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDispatchQueueTests.mm; sourceTree = "<group>"; };
@@ -885,6 +887,7 @@
isa = PBXGroup;
children = (
73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */,
+ 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */,
5492E070202154D600B64F25 /* FIRCursorTests.mm */,
5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */,
5492E06A202154D500B64F25 /* FIRFieldsTests.mm */,
@@ -1559,6 +1562,7 @@
buildActionMask = 2147483647;
files = (
73866AA12082B0A5009BB4FF /* FIRArrayTransformTests.mm in Sources */,
+ 6161B5032047140C00A99DBB /* FIRFirestoreSourceTests.mm in Sources */,
5492E076202154D600B64F25 /* FIRValidationTests.mm in Sources */,
5492E072202154D600B64F25 /* FIRQueryTests.mm in Sources */,
5491BC731FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */,
diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift
index 00839c4..f61da2b 100644
--- a/Firestore/Example/SwiftBuildTest/main.swift
+++ b/Firestore/Example/SwiftBuildTest/main.swift
@@ -32,8 +32,10 @@ func main() {
addDocument(to: collectionRef)
readDocument(at: documentRef)
+ readDocumentWithSource(at: documentRef)
readDocuments(matching: query)
+ readDocumentsWithSource(matching: query)
listenToDocument(at: documentRef)
@@ -230,6 +232,15 @@ func readDocument(at docRef: DocumentReference) {
}
}
+func readDocumentWithSource(at docRef: DocumentReference) {
+ docRef.getDocument(source: FirestoreSource.default) { document, error in
+ }
+ docRef.getDocument(source: .server) { document, error in
+ }
+ docRef.getDocument(source: FirestoreSource.cache) { document, error in
+ }
+}
+
func readDocuments(matching query: Query) {
query.getDocuments { querySnapshot, error in
// TODO(mikelehen): Figure out how to make "for..in" syntax work
@@ -240,6 +251,15 @@ func readDocuments(matching query: Query) {
}
}
+func readDocumentsWithSource(matching query: Query) {
+ query.getDocuments(source: FirestoreSource.default) { querySnapshot, error in
+ }
+ query.getDocuments(source: .server) { querySnapshot, error in
+ }
+ query.getDocuments(source: FirestoreSource.cache) { querySnapshot, error in
+ }
+}
+
func listenToDocument(at docRef: DocumentReference) {
let listener = docRef.addSnapshotListener { document, error in
if let error = error {
diff --git a/Firestore/Example/Tests/Integration/API/FIRFirestoreSourceTests.mm b/Firestore/Example/Tests/Integration/API/FIRFirestoreSourceTests.mm
new file mode 100644
index 0000000..0f844c6
--- /dev/null
+++ b/Firestore/Example/Tests/Integration/API/FIRFirestoreSourceTests.mm
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <FirebaseFirestore/FirebaseFirestore.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
+#import "Firestore/Source/API/FIRFirestore+Internal.h"
+#import "Firestore/Source/Core/FSTFirestoreClient.h"
+
+@interface FIRFirestoreSourceTests : FSTIntegrationTestCase
+@end
+
+@implementation FIRFirestoreSourceTests
+
+- (void)testGetDocumentWhileOnlineWithDefaultSource {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // get doc and ensure that it exists, is *not* from the cache, and matches
+ // the initialData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
+ XCTAssertTrue(result.exists);
+ XCTAssertFalse(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, initialData);
+}
+
+- (void)testGetCollectionWhileOnlineWithDefaultSource {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to known values
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"}
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // get docs and ensure they are *not* from the cache, and match the
+ // initialDocs.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col];
+ XCTAssertFalse(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(
+ FIRQuerySnapshotGetData(result),
+ (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"} ]));
+ XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
+ ]));
+}
+
+- (void)testGetDocumentWhileOfflineWithDefaultSource {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the doc (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
+ [doc setData:newData
+ completion:^(NSError *_Nullable error) {
+ XCTAssertTrue(false, "Because we're offline, this should never occur.");
+ }];
+
+ // get doc and ensure it exists, *is* from the cache, and matches the
+ // newData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
+ XCTAssertTrue(result.exists);
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, newData);
+}
+
+- (void)testGetCollectionWhileOfflineWithDefaultSource {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to known values
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"}
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the docs (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge];
+ [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
+ [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
+
+ // get docs and ensure they *are* from the cache, and matches the updated data.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col];
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
+ @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
+ ]));
+ XCTAssertEqualObjects(
+ FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
+ ]));
+}
+
+- (void)testGetDocumentWhileOnlineCacheOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // get doc and ensure that it exists, *is* from the cache, and matches
+ // the initialData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.exists);
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, initialData);
+}
+
+- (void)testGetCollectionWhileOnlineCacheOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to a known value
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"},
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // get docs and ensure they *are* from the cache, and matches the
+ // initialDocs.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"},
+ @{@"key2" : @"value2"},
+ @{@"key3" : @"value3"},
+ ]));
+ XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
+ ]));
+}
+
+- (void)testGetDocumentWhileOfflineCacheOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the doc (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
+ [doc setData:newData
+ completion:^(NSError *_Nullable error) {
+ XCTFail("Because we're offline, this should never occur.");
+ }];
+
+ // get doc and ensure it exists, *is* from the cache, and matches the
+ // newData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.exists);
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, newData);
+}
+
+- (void)testGetCollectionWhileOfflineCacheOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to a known value
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"},
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the docs (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge];
+ [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
+ [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
+
+ // get docs and ensure they *are* from the cache, and matches the updated
+ // data.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
+ @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
+ ]));
+ XCTAssertEqualObjects(
+ FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
+ ]));
+}
+
+- (void)testGetDocumentWhileOnlineServerOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // get doc and ensure that it exists, is *not* from the cache, and matches
+ // the initialData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceServer];
+ XCTAssertTrue(result.exists);
+ XCTAssertFalse(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, initialData);
+}
+
+- (void)testGetCollectionWhileOnlineServerOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to a known value
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"},
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // get docs and ensure they are *not* from the cache, and matches the
+ // initialData.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceServer];
+ XCTAssertFalse(result.metadata.fromCache);
+ XCTAssertFalse(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"},
+ @{@"key2" : @"value2"},
+ @{@"key3" : @"value3"},
+ ]));
+ XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
+ ]));
+}
+
+- (void)testGetDocumentWhileOfflineServerOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get doc and ensure it cannot be retreived
+ XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"];
+ [doc getDocumentWithSource:FIRFirestoreSourceServer
+ completion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [failedGetDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetCollectionWhileOfflineServerOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to a known value
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"},
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get docs and ensure they cannot be retreived
+ XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
+ [col getDocumentsWithSource:FIRFirestoreSourceServer
+ completion:^(FIRQuerySnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [failedGetDocsCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetDocumentWhileOfflineWithDifferentSource {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // set document to a known value
+ NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
+ [self writeDocumentRef:doc data:initialData];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the doc (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
+ [doc setData:newData
+ completion:^(NSError *_Nullable error) {
+ XCTAssertTrue(false, "Because we're offline, this should never occur.");
+ }];
+
+ // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for
+ // the listener to deliver its initial snapshot before continuing.
+ XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"];
+ [doc addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ [listenerReady fulfill];
+ }];
+ [self awaitExpectations];
+
+ // get doc (from cache) and ensure it exists, *is* from the cache, and
+ // matches the newData.
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.exists);
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, newData);
+
+ // attempt to get doc (with default get source)
+ result = [self readDocumentForRef:doc source:FIRFirestoreSourceDefault];
+ XCTAssertTrue(result.exists);
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(result.data, newData);
+
+ // attempt to get doc (from the server) and ensure it cannot be retreived
+ XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"];
+ [doc getDocumentWithSource:FIRFirestoreSourceServer
+ completion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [failedGetDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetCollectionWhileOfflineWithDifferentSource {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few documents to a known value
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
+ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"},
+ @"doc3" : @{@"key3" : @"value3"},
+ };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // update the docs (though don't wait for a server response. We're offline; so
+ // that ain't happening!). This allows us to further distinguished cached vs
+ // server responses below.
+ [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge];
+ [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
+ [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
+
+ // Create an initial listener for this query (to attempt to disrupt the gets
+ // below) and wait for the listener to deliver its initial snapshot before
+ // continuing.
+ XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"];
+ [col addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
+ [listenerReady fulfill];
+ }];
+ [self awaitExpectations];
+
+ // get docs (from cache) and ensure they *are* from the cache, and
+ // matches the updated data.
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertTrue(result.metadata.hasPendingWrites);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
+ @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
+ ]));
+ XCTAssertEqualObjects(
+ FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
+ ]));
+
+ // attempt to get docs (with default get source)
+ result = [self readDocumentSetForRef:col source:FIRFirestoreSourceDefault];
+ XCTAssertTrue(result.metadata.fromCache);
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
+ @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
+ ]));
+ XCTAssertEqualObjects(
+ FIRQuerySnapshotGetDocChangesData(result), (@[
+ @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
+ @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
+ ]));
+
+ // attempt to get docs (from the server) and ensure they cannot be retreived
+ XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
+ [col getDocumentsWithSource:FIRFirestoreSourceServer
+ completion:^(FIRQuerySnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [failedGetDocsCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetNonExistingDocWhileOnlineWithDefaultSource {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // get doc and ensure that it does not exist and is *not* from the cache.
+ FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
+ XCTAssertFalse(snapshot.exists);
+ XCTAssertFalse(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingCollectionWhileOnlineWithDefaultSource {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // get collection and ensure it's empty and that it's *not* from the cache.
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col];
+ XCTAssertEqual(snapshot.count, 0);
+ XCTAssertEqual(snapshot.documentChanges.count, 0);
+ XCTAssertFalse(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingDocWhileOfflineWithDefaultSource {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get doc. Currently, this is expected to fail. In the future, we
+ // might consider adding support for negative cache hits so that we know
+ // certain documents *don't* exist.
+ XCTestExpectation *getNonExistingDocCompletion =
+ [self expectationWithDescription:@"getNonExistingDoc"];
+ [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [getNonExistingDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetNonExistingCollectionWhileOfflineWithDefaultSource {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // get collection and ensure it's empty and that it *is* from the cache.
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col];
+ XCTAssertEqual(snapshot.count, 0);
+ XCTAssertEqual(snapshot.documentChanges.count, 0);
+ XCTAssertTrue(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingDocWhileOnlineCacheOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // attempt to get doc. Currently, this is expected to fail. In the future, we
+ // might consider adding support for negative cache hits so that we know
+ // certain documents *don't* exist.
+ XCTestExpectation *getNonExistingDocCompletion =
+ [self expectationWithDescription:@"getNonExistingDoc"];
+ [doc getDocumentWithSource:FIRFirestoreSourceCache
+ completion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [getNonExistingDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetNonExistingCollectionWhileOnlineCacheOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // get collection and ensure it's empty and that it *is* from the cache.
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
+ XCTAssertEqual(snapshot.count, 0);
+ XCTAssertEqual(snapshot.documentChanges.count, 0);
+ XCTAssertTrue(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingDocWhileOfflineCacheOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get doc. Currently, this is expected to fail. In the future, we
+ // might consider adding support for negative cache hits so that we know
+ // certain documents *don't* exist.
+ XCTestExpectation *getNonExistingDocCompletion =
+ [self expectationWithDescription:@"getNonExistingDoc"];
+ [doc getDocumentWithSource:FIRFirestoreSourceCache
+ completion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [getNonExistingDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetNonExistingCollectionWhileOfflineCacheOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // get collection and ensure it's empty and that it *is* from the cache.
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
+ XCTAssertEqual(snapshot.count, 0);
+ XCTAssertEqual(snapshot.documentChanges.count, 0);
+ XCTAssertTrue(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingDocWhileOnlineServerOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // get doc and ensure that it does not exist and is *not* from the cache.
+ FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc source:FIRFirestoreSourceServer];
+ XCTAssertFalse(snapshot.exists);
+ XCTAssertFalse(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingCollectionWhileOnlineServerOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // get collection and ensure that it's empty and that it's *not* from the cache.
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceServer];
+ XCTAssertEqual(snapshot.count, 0);
+ XCTAssertEqual(snapshot.documentChanges.count, 0);
+ XCTAssertFalse(snapshot.metadata.fromCache);
+ XCTAssertFalse(snapshot.metadata.hasPendingWrites);
+}
+
+- (void)testGetNonExistingDocWhileOfflineServerOnly {
+ FIRDocumentReference *doc = [self documentRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get doc. Currently, this is expected to fail. In the future, we
+ // might consider adding support for negative cache hits so that we know
+ // certain documents *don't* exist.
+ XCTestExpectation *getNonExistingDocCompletion =
+ [self expectationWithDescription:@"getNonExistingDoc"];
+ [doc getDocumentWithSource:FIRFirestoreSourceServer
+ completion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [getNonExistingDocCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testGetNonExistingCollectionWhileOfflineServerOnly {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // attempt to get collection and ensure that it cannot be retreived
+ XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
+ [col getDocumentsWithSource:FIRFirestoreSourceServer
+ completion:^(FIRQuerySnapshot *snapshot, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
+ [failedGetDocsCompletion fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+@end
diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
index e27491b..585d99a 100644
--- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
+++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
@@ -20,6 +20,8 @@
#import "Firestore/Example/Tests/Util/XCTestCase+Await.h"
#import "Firestore/Source/Core/FSTTypes.h"
+#import "FIRFirestoreSource.h"
+
@class FIRCollectionReference;
@class FIRDocumentSnapshot;
@class FIRDocumentReference;
@@ -71,8 +73,13 @@ extern "C" {
- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref;
+- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref
+ source:(FIRFirestoreSource)source;
+
- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query;
+- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query source:(FIRFirestoreSource)source;
+
- (FIRDocumentSnapshot *)readSnapshotForRef:(FIRDocumentReference *)query
requireOnline:(BOOL)online;
@@ -108,6 +115,10 @@ NSArray<NSDictionary<NSString *, id> *> *FIRQuerySnapshotGetData(FIRQuerySnapsho
/** Converts the FIRQuerySnapshot to an NSArray containing the document IDs in order. */
NSArray<NSString *> *FIRQuerySnapshotGetIDs(FIRQuerySnapshot *docs);
+/** Converts the FIRQuerySnapshot to an NSArray containing an NSArray containing the doc change data
+ * in order of { type, doc title, doc data }. */
+NSArray<NSArray<id> *> *FIRQuerySnapshotGetDocChangesData(FIRQuerySnapshot *docs);
+
#if __cplusplus
} // extern "C"
#endif
diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
index 9bfdb3b..1817015 100644
--- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
+++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
@@ -212,28 +212,39 @@ NS_ASSUME_NONNULL_BEGIN
}
- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref {
+ return [self readDocumentForRef:ref source:FIRFirestoreSourceDefault];
+}
+
+- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref
+ source:(FIRFirestoreSource)source {
__block FIRDocumentSnapshot *result;
XCTestExpectation *expectation = [self expectationWithDescription:@"getData"];
- [ref getDocumentWithCompletion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) {
- XCTAssertNil(error);
- result = doc;
- [expectation fulfill];
- }];
+ [ref getDocumentWithSource:source
+ completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) {
+ XCTAssertNil(error);
+ result = doc;
+ [expectation fulfill];
+ }];
[self awaitExpectations];
return result;
}
- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query {
+ return [self readDocumentSetForRef:query source:FIRFirestoreSourceDefault];
+}
+
+- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query source:(FIRFirestoreSource)source {
__block FIRQuerySnapshot *result;
XCTestExpectation *expectation = [self expectationWithDescription:@"getData"];
- [query getDocumentsWithCompletion:^(FIRQuerySnapshot *documentSet, NSError *error) {
- XCTAssertNil(error);
- result = documentSet;
- [expectation fulfill];
- }];
+ [query getDocumentsWithSource:source
+ completion:^(FIRQuerySnapshot *documentSet, NSError *error) {
+ XCTAssertNil(error);
+ result = documentSet;
+ [expectation fulfill];
+ }];
[self awaitExpectations];
return result;
@@ -329,6 +340,18 @@ extern "C" NSArray<NSString *> *FIRQuerySnapshotGetIDs(FIRQuerySnapshot *docs) {
return result;
}
+extern "C" NSArray<NSArray<id> *> *FIRQuerySnapshotGetDocChangesData(FIRQuerySnapshot *docs) {
+ NSMutableArray<NSMutableArray<id> *> *result = [NSMutableArray array];
+ for (FIRDocumentChange *docChange in docs.documentChanges) {
+ NSMutableArray<id> *docChangeData = [NSMutableArray array];
+ [docChangeData addObject:@(docChange.type)];
+ [docChangeData addObject:docChange.document.documentID];
+ [docChangeData addObject:docChange.document.data];
+ [result addObject:docChangeData];
+ }
+ return result;
+}
+
@end
NS_ASSUME_NONNULL_END