aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Example
diff options
context:
space:
mode:
authorGravatar Rich Gowman <rgowman@google.com>2018-06-12 10:50:07 -0400
committerGravatar Rich Gowman <rgowman@google.com>2018-06-12 10:50:07 -0400
commit86cdae83a0b7b36d8a7c61eb3704b28f9f31a041 (patch)
treebb1dc7167d8eddb9e872780da357026f7ce1d83c /Firestore/Example
parentcf2899a085f7ceca3fad2d1fb5336be25cecd7ff (diff)
parentf5bf0a37a7dd40e7538a1aed77af05471b7fe713 (diff)
Merge remote-tracking branch 'origin/master' into rsgowman/protobuf_cpp
Diffstat (limited to 'Firestore/Example')
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj16
-rw-r--r--Firestore/Example/FuzzTests/FSTFuzzTestsPrincipal.mm14
-rw-r--r--Firestore/Example/Podfile2
-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
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