aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Example/Tests
diff options
context:
space:
mode:
Diffstat (limited to 'Firestore/Example/Tests')
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm82
-rw-r--r--Firestore/Example/Tests/Integration/FSTStreamTests.mm73
-rw-r--r--Firestore/Example/Tests/Remote/FSTDatastoreTests.mm6
3 files changed, 159 insertions, 2 deletions
diff --git a/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm b/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
index f8091c0..e048a40 100644
--- a/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
+++ b/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
@@ -162,8 +162,10 @@
NSDictionary<NSString *, id> *initialData = @{
@"updated" : @NO,
};
- NSDictionary<NSString *, id> *mergeData =
- @{@"time" : [FIRFieldValue fieldValueForServerTimestamp]};
+ NSDictionary<NSString *, id> *mergeData = @{
+ @"time" : [FIRFieldValue fieldValueForServerTimestamp],
+ @"nested" : @{@"time" : [FIRFieldValue fieldValueForServerTimestamp]}
+ };
[self writeDocumentRef:doc data:initialData];
@@ -182,6 +184,7 @@
FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
XCTAssertEqual(document[@"updated"], @NO);
XCTAssertTrue([document[@"time"] isKindOfClass:[FIRTimestamp class]]);
+ XCTAssertTrue([document[@"nested.time"] isKindOfClass:[FIRTimestamp class]]);
}
- (void)testCanDeleteFieldUsingMerge {
@@ -218,6 +221,81 @@
XCTAssertNil(document[@"nested.foo"]);
}
+- (void)testCanDeleteFieldUsingMergeFields {
+ FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
+
+ NSDictionary<NSString *, id> *initialData = @{
+ @"untouched" : @YES,
+ @"foo" : @"bar",
+ @"inner" : @{@"removed" : @YES, @"foo" : @"bar"},
+ @"nested" : @{@"untouched" : @YES, @"foo" : @"bar"}
+ };
+ NSDictionary<NSString *, id> *mergeData = @{
+ @"foo" : [FIRFieldValue fieldValueForDelete],
+ @"inner" : @{@"foo" : [FIRFieldValue fieldValueForDelete]},
+ @"nested" : @{
+ @"untouched" : [FIRFieldValue fieldValueForDelete],
+ @"foo" : [FIRFieldValue fieldValueForDelete]
+ }
+ };
+ NSDictionary<NSString *, id> *finalData =
+ @{ @"untouched" : @YES,
+ @"inner" : @{},
+ @"nested" : @{@"untouched" : @YES} };
+
+ [self writeDocumentRef:doc data:initialData];
+
+ XCTestExpectation *completed =
+ [self expectationWithDescription:@"testCanMergeDataWithAnExistingDocumentUsingSet"];
+
+ [doc setData:mergeData
+ mergeFields:@[ @"foo", @"inner", @"nested.foo" ]
+ completion:^(NSError *error) {
+ XCTAssertNil(error);
+ [completed fulfill];
+ }];
+
+ [self awaitExpectations];
+
+ FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
+ XCTAssertEqualObjects([document data], finalData);
+}
+
+- (void)testCanSetServerTimestampsUsingMergeFields {
+ FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
+
+ NSDictionary<NSString *, id> *initialData = @{
+ @"untouched" : @YES,
+ @"foo" : @"bar",
+ @"nested" : @{@"untouched" : @YES, @"foo" : @"bar"}
+ };
+ NSDictionary<NSString *, id> *mergeData = @{
+ @"foo" : [FIRFieldValue fieldValueForServerTimestamp],
+ @"inner" : @{@"foo" : [FIRFieldValue fieldValueForServerTimestamp]},
+ @"nested" : @{@"foo" : [FIRFieldValue fieldValueForServerTimestamp]}
+ };
+
+ [self writeDocumentRef:doc data:initialData];
+
+ XCTestExpectation *completed =
+ [self expectationWithDescription:@"testCanMergeDataWithAnExistingDocumentUsingSet"];
+
+ [doc setData:mergeData
+ mergeFields:@[ @"foo", @"inner", @"nested.foo" ]
+ completion:^(NSError *error) {
+ XCTAssertNil(error);
+ [completed fulfill];
+ }];
+
+ [self awaitExpectations];
+
+ FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
+ XCTAssertTrue([document exists]);
+ XCTAssertTrue([document[@"foo"] isKindOfClass:[FIRTimestamp class]]);
+ XCTAssertTrue([document[@"inner.foo"] isKindOfClass:[FIRTimestamp class]]);
+ XCTAssertTrue([document[@"nested.foo"] isKindOfClass:[FIRTimestamp class]]);
+}
+
- (void)testMergeReplacesArrays {
FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
diff --git a/Firestore/Example/Tests/Integration/FSTStreamTests.mm b/Firestore/Example/Tests/Integration/FSTStreamTests.mm
index b944a93..3ad6868 100644
--- a/Firestore/Example/Tests/Integration/FSTStreamTests.mm
+++ b/Firestore/Example/Tests/Integration/FSTStreamTests.mm
@@ -18,8 +18,11 @@
#import <GRPCClient/GRPCCall.h>
+#import <FirebaseFirestore/FIRFirestoreErrors.h>
#import <FirebaseFirestore/FIRFirestoreSettings.h>
+#include <utility>
+
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
#import "Firestore/Source/Remote/FSTDatastore.h"
@@ -327,4 +330,74 @@ using firebase::firestore::model::SnapshotVersion;
]];
}
+class MockCredentialsProvider : public firebase::firestore::auth::EmptyCredentialsProvider {
+ public:
+ MockCredentialsProvider() {
+ observed_states_ = [NSMutableArray new];
+ }
+
+ void GetToken(firebase::firestore::auth::TokenListener completion) override {
+ [observed_states_ addObject:@"GetToken"];
+ EmptyCredentialsProvider::GetToken(std::move(completion));
+ }
+
+ void InvalidateToken() override {
+ [observed_states_ addObject:@"InvalidateToken"];
+ EmptyCredentialsProvider::InvalidateToken();
+ }
+
+ NSMutableArray<NSString *> *observed_states() const {
+ return observed_states_;
+ }
+
+ private:
+ NSMutableArray<NSString *> *observed_states_;
+};
+
+- (void)testStreamRefreshesTokenUponExpiration {
+ MockCredentialsProvider credentials;
+ FSTDatastore *datastore = [[FSTDatastore alloc] initWithDatabaseInfo:&_databaseInfo
+ workerDispatchQueue:_workerDispatchQueue
+ credentials:&credentials];
+ FSTWatchStream *watchStream = [datastore createWatchStream];
+
+ [_delegate awaitNotificationFromBlock:^{
+ [watchStream startWithDelegate:_delegate];
+ }];
+
+ // Simulate callback from GRPC with an unauthenticated error -- this should invalidate the token.
+ NSError *unauthenticatedError = [NSError errorWithDomain:FIRFirestoreErrorDomain
+ code:FIRFirestoreErrorCodeUnauthenticated
+ userInfo:nil];
+ dispatch_async(_testQueue, ^{
+ [watchStream.callbackFilter writesFinishedWithError:unauthenticatedError];
+ });
+ // Drain the queue.
+ dispatch_sync(_testQueue, ^{
+ });
+
+ // Try reconnecting.
+ [_delegate awaitNotificationFromBlock:^{
+ [watchStream startWithDelegate:_delegate];
+ }];
+ // Simulate a different error -- token should not be invalidated this time.
+ NSError *unavailableError = [NSError errorWithDomain:FIRFirestoreErrorDomain
+ code:FIRFirestoreErrorCodeUnavailable
+ userInfo:nil];
+ dispatch_async(_testQueue, ^{
+ [watchStream.callbackFilter writesFinishedWithError:unavailableError];
+ });
+ dispatch_sync(_testQueue, ^{
+ });
+
+ [_delegate awaitNotificationFromBlock:^{
+ [watchStream startWithDelegate:_delegate];
+ }];
+ dispatch_sync(_testQueue, ^{
+ });
+
+ NSArray<NSString *> *expected = @[ @"GetToken", @"InvalidateToken", @"GetToken", @"GetToken" ];
+ XCTAssertEqualObjects(credentials.observed_states(), expected);
+}
+
@end
diff --git a/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm b/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm
index 6d6e912..9783e37 100644
--- a/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm
+++ b/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm
@@ -53,6 +53,12 @@
code:FIRFirestoreErrorCodeUnavailable
userInfo:nil];
XCTAssertFalse([FSTDatastore isPermanentWriteError:error]);
+
+ // "unauthenticated" is considered a recoverable error due to expired token.
+ error = [NSError errorWithDomain:FIRFirestoreErrorDomain
+ code:FIRFirestoreErrorCodeUnauthenticated
+ userInfo:nil];
+ XCTAssertFalse([FSTDatastore isPermanentWriteError:error]);
}
@end