diff options
Diffstat (limited to 'Firestore/Example/Tests')
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 |