diff options
author | Rich Gowman <rgowman@google.com> | 2018-06-12 10:50:07 -0400 |
---|---|---|
committer | Rich Gowman <rgowman@google.com> | 2018-06-12 10:50:07 -0400 |
commit | 86cdae83a0b7b36d8a7c61eb3704b28f9f31a041 (patch) | |
tree | bb1dc7167d8eddb9e872780da357026f7ce1d83c /Firestore/Example | |
parent | cf2899a085f7ceca3fad2d1fb5336be25cecd7ff (diff) | |
parent | f5bf0a37a7dd40e7538a1aed77af05471b7fe713 (diff) |
Merge remote-tracking branch 'origin/master' into rsgowman/protobuf_cpp
Diffstat (limited to 'Firestore/Example')
-rw-r--r-- | Firestore/Example/Firestore.xcodeproj/project.pbxproj | 16 | ||||
-rw-r--r-- | Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm | 14 | ||||
-rw-r--r-- | Firestore/Example/Podfile | 2 | ||||
-rw-r--r-- | Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm | 82 | ||||
-rw-r--r-- | Firestore/Example/Tests/Integration/FSTStreamTests.mm | 73 | ||||
-rw-r--r-- | Firestore/Example/Tests/Remote/FSTDatastoreTests.mm | 6 |
6 files changed, 188 insertions, 5 deletions
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index eadf4e2..d38dba0 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ 54DA12AE1F315EE100DD57A1 /* resume_token_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A41F315EE100DD57A1 /* resume_token_spec_test.json */; }; 54DA12AF1F315EE100DD57A1 /* write_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A51F315EE100DD57A1 /* write_spec_test.json */; }; 54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */; }; + 5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 403DBF6EFB541DFD01582AA3 /* path_test.cc */; }; 5D405BE298CE4692CB00790A /* Pods_Firestore_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */; }; 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; @@ -286,6 +287,7 @@ 3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; }; 3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.release.xcconfig"; sourceTree = "<group>"; }; 4280A9CD97BB27955F81042C /* struct.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = struct.pb.cc; sourceTree = "<group>"; }; + 403DBF6EFB541DFD01582AA3 /* path_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = path_test.cc; sourceTree = "<group>"; }; 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = "<group>"; }; 54131E9620ADE678001DF3FF /* string_format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_format_test.cc; sourceTree = "<group>"; }; 54511E8D209805F8005BD28F /* hashing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashing_test.cc; sourceTree = "<group>"; }; @@ -636,6 +638,7 @@ 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */, 54C2294E1FECABAE007D065B /* log_test.cc */, AB380D03201BC6E400D97691 /* ordered_code_test.cc */, + 403DBF6EFB541DFD01582AA3 /* path_test.cc */, 54740A531FC913E500713A1A /* secure_random_test.cc */, 54A0352C20A3B3D7003E0143 /* status_test.cc */, 54A0352B20A3B3D7003E0143 /* status_test_util.h */, @@ -1935,6 +1938,7 @@ 618BBEA820B89AAC00B5BCE7 /* mutation.pb.cc in Sources */, AB6B908820322E8800CC290A /* no_document_test.cc in Sources */, AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */, + 5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */, 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, 618BBEAB20B89AAC00B5BCE7 /* query.pb.cc in Sources */, B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */, @@ -2468,6 +2472,12 @@ "COCOAPODS=1", "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1", ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_ROOT}/../../..\"", + "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"", + "\"${PODS_ROOT}/nanopb\"", + ); INFOPLIST_FILE = "FuzzTests/Firestore_FuzzTests_iOS-Info.plist"; OTHER_CFLAGS = ( "$(inherited)", @@ -2498,6 +2508,12 @@ "COCOAPODS=1", "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1", ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_ROOT}/../../..\"", + "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"", + "\"${PODS_ROOT}/nanopb\"", + ); INFOPLIST_FILE = "FuzzTests/Firestore_FuzzTests_iOS-Info.plist"; OTHER_CFLAGS = ( "$(inherited)", diff --git a/Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm b/Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm index 63f6db0..038e687 100644 --- a/Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm +++ b/Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm @@ -18,12 +18,22 @@ #include "LibFuzzer/FuzzerDefs.h" +#include "Firestore/core/src/firebase/firestore/remote/serializer.h" + +using firebase::firestore::remote::Serializer; + namespace { +// Fuzz-test the deserialization process in Firestore. The Serializer reads raw +// bytes and converts them to a model object. +void FuzzTestDeserialization(const uint8_t *data, size_t size) { + // TODO(minafarid): fuzz-test Serializer. +} + // Contains the code to be fuzzed. Called by the fuzzing library with // different argument values for `data` and `size`. int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - // Code to be fuzz-tested here. + FuzzTestDeserialization(data, size); return 0; } @@ -32,7 +42,7 @@ int RunFuzzTestingMain() { // Arguments to libFuzzer main() function should be added to this array, // e.g., dictionaries, corpus, number of runs, jobs, etc. char *program_args[] = { - const_cast<char *>("RunFuzzTestingMain") // First argument is program name. + const_cast<char *>("RunFuzzTestingMain") // First arg is program name. }; char **argv = program_args; int argc = sizeof(program_args) / sizeof(program_args[0]); diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile index 2241582..110c676 100644 --- a/Firestore/Example/Podfile +++ b/Firestore/Example/Podfile @@ -10,7 +10,7 @@ target 'Firestore_Example_iOS' do # The next line is the forcing function for the Firebase pod. The Firebase # version's subspecs should depend on the component versions in their # corresponding podspec's. - pod 'Firebase/Core', '5.1.0' + pod 'Firebase/Core', '5.2.0' pod 'FirebaseAuth', :path => '../../' pod 'FirebaseCore', :path => '../../' 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 |