FSTLocalSerializerTests.mm 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Local/FSTLocalSerializer.h"
  17. #import <FirebaseFirestore/FIRTimestamp.h>
  18. #import <XCTest/XCTest.h>
  19. #include <utility>
  20. #include <vector>
  21. #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h"
  22. #import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
  23. #import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
  24. #import "Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h"
  25. #import "Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h"
  26. #import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h"
  27. #import "Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h"
  28. #import "Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h"
  29. #import "Firestore/Protos/objc/google/type/Latlng.pbobjc.h"
  30. #import "Firestore/Source/Remote/FSTSerializerBeta.h"
  31. #import "Firestore/Example/Tests/Util/FSTHelpers.h"
  32. #include "Firestore/core/include/firebase/firestore/timestamp.h"
  33. #include "Firestore/core/src/firebase/firestore/local/query_data.h"
  34. #include "Firestore/core/src/firebase/firestore/model/database_id.h"
  35. #include "Firestore/core/src/firebase/firestore/model/document.h"
  36. #include "Firestore/core/src/firebase/firestore/model/field_mask.h"
  37. #include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
  38. #include "Firestore/core/src/firebase/firestore/model/precondition.h"
  39. #include "Firestore/core/src/firebase/firestore/model/unknown_document.h"
  40. #include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h"
  41. #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
  42. #include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
  43. namespace testutil = firebase::firestore::testutil;
  44. using firebase::Timestamp;
  45. using firebase::firestore::local::QueryData;
  46. using firebase::firestore::local::QueryPurpose;
  47. using firebase::firestore::model::DatabaseId;
  48. using firebase::firestore::model::Document;
  49. using firebase::firestore::model::DocumentState;
  50. using firebase::firestore::model::FieldMask;
  51. using firebase::firestore::model::MaybeDocument;
  52. using firebase::firestore::model::Mutation;
  53. using firebase::firestore::model::MutationBatch;
  54. using firebase::firestore::model::NoDocument;
  55. using firebase::firestore::model::PatchMutation;
  56. using firebase::firestore::model::Precondition;
  57. using firebase::firestore::model::SnapshotVersion;
  58. using firebase::firestore::model::TargetId;
  59. using firebase::firestore::model::UnknownDocument;
  60. using firebase::firestore::nanopb::ByteString;
  61. using firebase::firestore::nanopb::MakeNSData;
  62. using firebase::firestore::testutil::Field;
  63. using firebase::firestore::testutil::Query;
  64. using firebase::firestore::testutil::Version;
  65. using testutil::DeletedDoc;
  66. using testutil::Doc;
  67. using testutil::Key;
  68. using testutil::Map;
  69. using testutil::UnknownDoc;
  70. using testutil::WrapObject;
  71. NS_ASSUME_NONNULL_BEGIN
  72. @interface FSTLocalSerializerTests : XCTestCase
  73. @property(nonatomic, strong) FSTLocalSerializer *serializer;
  74. @property(nonatomic, strong) FSTSerializerBeta *remoteSerializer;
  75. @end
  76. @implementation FSTLocalSerializerTests
  77. - (void)setUp {
  78. self.remoteSerializer = [[FSTSerializerBeta alloc] initWithDatabaseID:DatabaseId("p", "d")];
  79. self.serializer = [[FSTLocalSerializer alloc] initWithRemoteSerializer:self.remoteSerializer];
  80. }
  81. - (void)testEncodesMutationBatch {
  82. Mutation base = PatchMutation(Key("bar/baz"), WrapObject("a", "b"), FieldMask{Field("a")},
  83. Precondition::Exists(true));
  84. Mutation set = testutil::SetMutation("foo/bar", Map("a", "b", "num", 1));
  85. Mutation patch = PatchMutation(Key("bar/baz"), WrapObject("a", "b", "num", 1),
  86. FieldMask{Field("a")}, Precondition::Exists(true));
  87. Mutation del = testutil::DeleteMutation("baz/quux");
  88. Timestamp writeTime = Timestamp::Now();
  89. MutationBatch model = MutationBatch(42, writeTime, {base}, {set, patch, del});
  90. GCFSWrite *baseProto = [GCFSWrite message];
  91. baseProto.update.name = @"projects/p/databases/d/documents/bar/baz";
  92. [baseProto.update.fields addEntriesFromDictionary:@{
  93. @"a" : [self.remoteSerializer encodedString:"b"],
  94. }];
  95. [baseProto.updateMask.fieldPathsArray addObjectsFromArray:@[ @"a" ]];
  96. baseProto.currentDocument.exists = YES;
  97. GCFSWrite *setProto = [GCFSWrite message];
  98. setProto.update.name = @"projects/p/databases/d/documents/foo/bar";
  99. [setProto.update.fields addEntriesFromDictionary:@{
  100. @"a" : [self.remoteSerializer encodedString:"b"],
  101. @"num" : [self.remoteSerializer encodedInteger:1]
  102. }];
  103. GCFSWrite *patchProto = [GCFSWrite message];
  104. patchProto.update.name = @"projects/p/databases/d/documents/bar/baz";
  105. [patchProto.update.fields addEntriesFromDictionary:@{
  106. @"a" : [self.remoteSerializer encodedString:"b"],
  107. @"num" : [self.remoteSerializer encodedInteger:1]
  108. }];
  109. [patchProto.updateMask.fieldPathsArray addObjectsFromArray:@[ @"a" ]];
  110. patchProto.currentDocument.exists = YES;
  111. GCFSWrite *delProto = [GCFSWrite message];
  112. delProto.delete_p = @"projects/p/databases/d/documents/baz/quux";
  113. GPBTimestamp *writeTimeProto = [GPBTimestamp message];
  114. writeTimeProto.seconds = writeTime.seconds();
  115. writeTimeProto.nanos = writeTime.nanoseconds();
  116. FSTPBWriteBatch *batchProto = [FSTPBWriteBatch message];
  117. batchProto.batchId = 42;
  118. [batchProto.baseWritesArray addObject:baseProto];
  119. [batchProto.writesArray addObjectsFromArray:@[ setProto, patchProto, delProto ]];
  120. batchProto.localWriteTime = writeTimeProto;
  121. XCTAssertEqualObjects([self.serializer encodedMutationBatch:model], batchProto);
  122. MutationBatch decoded = [self.serializer decodedMutationBatch:batchProto];
  123. XCTAssertEqual(decoded.batch_id(), model.batch_id());
  124. XCTAssertEqual(decoded.local_write_time(), model.local_write_time());
  125. XCTAssertEqual(decoded.base_mutations(), model.base_mutations());
  126. XCTAssertEqual(decoded.mutations(), model.mutations());
  127. XCTAssertEqual(decoded.keys(), model.keys());
  128. }
  129. - (void)testEncodesDocumentAsMaybeDocument {
  130. Document doc = Doc("some/path", 42, Map("foo", "bar"));
  131. FSTPBMaybeDocument *maybeDocProto = [FSTPBMaybeDocument message];
  132. maybeDocProto.document = [GCFSDocument message];
  133. maybeDocProto.document.name = @"projects/p/databases/d/documents/some/path";
  134. [maybeDocProto.document.fields addEntriesFromDictionary:@{
  135. @"foo" : [self.remoteSerializer encodedString:"bar"],
  136. }];
  137. maybeDocProto.document.updateTime.seconds = 0;
  138. maybeDocProto.document.updateTime.nanos = 42000;
  139. XCTAssertEqualObjects([self.serializer encodedMaybeDocument:doc], maybeDocProto);
  140. MaybeDocument decoded = [self.serializer decodedMaybeDocument:maybeDocProto];
  141. XCTAssertEqual(decoded, doc);
  142. }
  143. - (void)testEncodesUnknownDocumentAsMaybeDocument {
  144. UnknownDocument doc = UnknownDoc("some/path", 42);
  145. FSTPBMaybeDocument *maybeDocProto = [FSTPBMaybeDocument message];
  146. maybeDocProto.unknownDocument = [FSTPBUnknownDocument message];
  147. maybeDocProto.unknownDocument.name = @"projects/p/databases/d/documents/some/path";
  148. maybeDocProto.unknownDocument.version.seconds = 0;
  149. maybeDocProto.unknownDocument.version.nanos = 42000;
  150. maybeDocProto.hasCommittedMutations = true;
  151. XCTAssertEqualObjects([self.serializer encodedMaybeDocument:doc], maybeDocProto);
  152. MaybeDocument decoded = [self.serializer decodedMaybeDocument:maybeDocProto];
  153. XCTAssertEqual(decoded, doc);
  154. }
  155. - (void)testEncodesDeletedDocumentAsMaybeDocument {
  156. NoDocument deletedDoc = DeletedDoc("some/path", 42);
  157. FSTPBMaybeDocument *maybeDocProto = [FSTPBMaybeDocument message];
  158. maybeDocProto.noDocument = [FSTPBNoDocument message];
  159. maybeDocProto.noDocument.name = @"projects/p/databases/d/documents/some/path";
  160. maybeDocProto.noDocument.readTime.seconds = 0;
  161. maybeDocProto.noDocument.readTime.nanos = 42000;
  162. XCTAssertEqualObjects([self.serializer encodedMaybeDocument:deletedDoc], maybeDocProto);
  163. MaybeDocument decoded = [self.serializer decodedMaybeDocument:maybeDocProto];
  164. XCTAssertEqual(decoded, deletedDoc);
  165. }
  166. - (void)testEncodesQueryData {
  167. core::Query query = Query("room");
  168. TargetId targetID = 42;
  169. SnapshotVersion version = Version(1039);
  170. ByteString resumeToken = testutil::ResumeToken(1039);
  171. QueryData queryData(query, targetID, 10, QueryPurpose::Listen, version, resumeToken);
  172. // Let the RPC serializer test various permutations of query serialization.
  173. GCFSTarget_QueryTarget *queryTarget = [self.remoteSerializer encodedQueryTarget:query];
  174. FSTPBTarget *expected = [FSTPBTarget message];
  175. expected.targetId = targetID;
  176. expected.lastListenSequenceNumber = 10;
  177. expected.snapshotVersion.nanos = 1039000;
  178. expected.resumeToken = MakeNullableNSData(resumeToken);
  179. expected.query.parent = queryTarget.parent;
  180. expected.query.structuredQuery = queryTarget.structuredQuery;
  181. XCTAssertEqualObjects([self.serializer encodedQueryData:queryData], expected);
  182. QueryData decoded = [self.serializer decodedQueryData:expected];
  183. XCTAssertEqual(decoded, queryData);
  184. }
  185. @end
  186. NS_ASSUME_NONNULL_END