FIRFirestoreSourceTests.mm 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * Copyright 2018 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 <FirebaseFirestore/FirebaseFirestore.h>
  17. #import <XCTest/XCTest.h>
  18. #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
  19. #import "Firestore/Source/API/FIRFirestore+Internal.h"
  20. @interface FIRFirestoreSourceTests : FSTIntegrationTestCase
  21. @end
  22. @implementation FIRFirestoreSourceTests
  23. - (void)testGetDocumentWhileOnlineWithDefaultSource {
  24. FIRDocumentReference *doc = [self documentRef];
  25. // set document to a known value
  26. NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
  27. [self writeDocumentRef:doc data:initialData];
  28. // get doc and ensure that it exists, is *not* from the cache, and matches
  29. // the initialData.
  30. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  31. XCTAssertTrue(result.exists);
  32. XCTAssertFalse(result.metadata.fromCache);
  33. XCTAssertFalse(result.metadata.hasPendingWrites);
  34. XCTAssertEqualObjects(result.data, initialData);
  35. }
  36. - (void)testGetCollectionWhileOnlineWithDefaultSource {
  37. FIRCollectionReference *col = [self collectionRef];
  38. // set a few documents to known values
  39. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  40. @"doc1" : @{@"key1" : @"value1"},
  41. @"doc2" : @{@"key2" : @"value2"},
  42. @"doc3" : @{@"key3" : @"value3"}
  43. };
  44. [self writeAllDocuments:initialDocs toCollection:col];
  45. // get docs and ensure they are *not* from the cache, and match the
  46. // initialDocs.
  47. FIRQuerySnapshot *result = [self readDocumentSetForRef:col];
  48. XCTAssertFalse(result.metadata.fromCache);
  49. XCTAssertFalse(result.metadata.hasPendingWrites);
  50. XCTAssertEqualObjects(
  51. FIRQuerySnapshotGetData(result),
  52. (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"} ]));
  53. XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
  54. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  55. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
  56. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
  57. ]));
  58. }
  59. - (void)testGetDocumentError {
  60. FIRDocumentReference *doc = [self.db documentWithPath:@"foo/__invalid__"];
  61. XCTestExpectation *completed = [self expectationWithDescription:@"get completed"];
  62. [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *, NSError *error) {
  63. XCTAssertNotNil(error);
  64. [completed fulfill];
  65. }];
  66. [self awaitExpectations];
  67. }
  68. - (void)testGetCollectionError {
  69. FIRCollectionReference *col = [self.db collectionWithPath:@"__invalid__"];
  70. XCTestExpectation *completed = [self expectationWithDescription:@"get completed"];
  71. [col getDocumentsWithCompletion:^(FIRQuerySnapshot *, NSError *error) {
  72. XCTAssertNotNil(error);
  73. [completed fulfill];
  74. }];
  75. [self awaitExpectations];
  76. }
  77. - (void)testGetDocumentWhileOfflineWithDefaultSource {
  78. FIRDocumentReference *doc = [self documentRef];
  79. // set document to a known value
  80. NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
  81. [self writeDocumentRef:doc data:initialData];
  82. // go offline for the rest of this test
  83. [self disableNetwork];
  84. // update the doc (though don't wait for a server response. We're offline; so
  85. // that ain't happening!). This allows us to further distinguished cached vs
  86. // server responses below.
  87. NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
  88. [doc setData:newData
  89. completion:^(NSError *) {
  90. XCTAssertTrue(false, "Because we're offline, this should never occur.");
  91. }];
  92. // get doc and ensure it exists, *is* from the cache, and matches the
  93. // newData.
  94. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  95. XCTAssertTrue(result.exists);
  96. XCTAssertTrue(result.metadata.fromCache);
  97. XCTAssertTrue(result.metadata.hasPendingWrites);
  98. XCTAssertEqualObjects(result.data, newData);
  99. }
  100. - (void)testGetCollectionWhileOfflineWithDefaultSource {
  101. FIRCollectionReference *col = [self collectionRef];
  102. // set a few documents to known values
  103. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  104. @"doc1" : @{@"key1" : @"value1"},
  105. @"doc2" : @{@"key2" : @"value2"},
  106. @"doc3" : @{@"key3" : @"value3"}
  107. };
  108. [self writeAllDocuments:initialDocs toCollection:col];
  109. // go offline for the rest of this test
  110. [self disableNetwork];
  111. // update the docs (though don't wait for a server response. We're offline; so
  112. // that ain't happening!). This allows us to further distinguished cached vs
  113. // server responses below.
  114. [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} merge:YES];
  115. [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
  116. [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
  117. // get docs and ensure they *are* from the cache, and matches the updated data.
  118. FIRQuerySnapshot *result = [self readDocumentSetForRef:col];
  119. XCTAssertTrue(result.metadata.fromCache);
  120. XCTAssertTrue(result.metadata.hasPendingWrites);
  121. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  122. @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
  123. @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
  124. ]));
  125. XCTAssertEqualObjects(
  126. FIRQuerySnapshotGetDocChangesData(result), (@[
  127. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  128. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
  129. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
  130. @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
  131. ]));
  132. }
  133. - (void)testGetDocumentWhileOnlineCacheOnly {
  134. FIRDocumentReference *doc = [self documentRef];
  135. // set document to a known value
  136. NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
  137. [self writeDocumentRef:doc data:initialData];
  138. // get doc and ensure that it exists, *is* from the cache, and matches
  139. // the initialData.
  140. FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
  141. XCTAssertTrue(result.exists);
  142. XCTAssertTrue(result.metadata.fromCache);
  143. XCTAssertFalse(result.metadata.hasPendingWrites);
  144. XCTAssertEqualObjects(result.data, initialData);
  145. }
  146. - (void)testGetCollectionWhileOnlineCacheOnly {
  147. FIRCollectionReference *col = [self collectionRef];
  148. // set a few documents to a known value
  149. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  150. @"doc1" : @{@"key1" : @"value1"},
  151. @"doc2" : @{@"key2" : @"value2"},
  152. @"doc3" : @{@"key3" : @"value3"},
  153. };
  154. [self writeAllDocuments:initialDocs toCollection:col];
  155. // get docs and ensure they *are* from the cache, and matches the
  156. // initialDocs.
  157. FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
  158. XCTAssertTrue(result.metadata.fromCache);
  159. XCTAssertFalse(result.metadata.hasPendingWrites);
  160. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  161. @{@"key1" : @"value1"},
  162. @{@"key2" : @"value2"},
  163. @{@"key3" : @"value3"},
  164. ]));
  165. XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
  166. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  167. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
  168. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
  169. ]));
  170. }
  171. - (void)testGetDocumentWhileOfflineCacheOnly {
  172. FIRDocumentReference *doc = [self documentRef];
  173. // set document to a known value
  174. NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
  175. [self writeDocumentRef:doc data:initialData];
  176. // go offline for the rest of this test
  177. [self disableNetwork];
  178. // update the doc (though don't wait for a server response. We're offline; so
  179. // that ain't happening!). This allows us to further distinguished cached vs
  180. // server responses below.
  181. NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
  182. [doc setData:newData
  183. completion:^(NSError *) {
  184. XCTFail("Because we're offline, this should never occur.");
  185. }];
  186. // get doc and ensure it exists, *is* from the cache, and matches the
  187. // newData.
  188. FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
  189. XCTAssertTrue(result.exists);
  190. XCTAssertTrue(result.metadata.fromCache);
  191. XCTAssertTrue(result.metadata.hasPendingWrites);
  192. XCTAssertEqualObjects(result.data, newData);
  193. }
  194. - (void)testGetCollectionWhileOfflineCacheOnly {
  195. FIRCollectionReference *col = [self collectionRef];
  196. // set a few documents to a known value
  197. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  198. @"doc1" : @{@"key1" : @"value1"},
  199. @"doc2" : @{@"key2" : @"value2"},
  200. @"doc3" : @{@"key3" : @"value3"},
  201. };
  202. [self writeAllDocuments:initialDocs toCollection:col];
  203. // go offline for the rest of this test
  204. [self disableNetwork];
  205. // update the docs (though don't wait for a server response. We're offline; so
  206. // that ain't happening!). This allows us to further distinguished cached vs
  207. // server responses below.
  208. [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} merge:YES];
  209. [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
  210. [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
  211. // get docs and ensure they *are* from the cache, and matches the updated
  212. // data.
  213. FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
  214. XCTAssertTrue(result.metadata.fromCache);
  215. XCTAssertTrue(result.metadata.hasPendingWrites);
  216. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  217. @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
  218. @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
  219. ]));
  220. XCTAssertEqualObjects(
  221. FIRQuerySnapshotGetDocChangesData(result), (@[
  222. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  223. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
  224. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
  225. @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
  226. ]));
  227. }
  228. - (void)testGetDocumentWhileOnlineServerOnly {
  229. FIRDocumentReference *doc = [self documentRef];
  230. // set document to a known value
  231. NSDictionary<NSString *, id> *initialData = @{@"key" : @"value"};
  232. [self writeDocumentRef:doc data:initialData];
  233. // get doc and ensure that it exists, is *not* from the cache, and matches
  234. // the initialData.
  235. FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceServer];
  236. XCTAssertTrue(result.exists);
  237. XCTAssertFalse(result.metadata.fromCache);
  238. XCTAssertFalse(result.metadata.hasPendingWrites);
  239. XCTAssertEqualObjects(result.data, initialData);
  240. }
  241. - (void)testGetCollectionWhileOnlineServerOnly {
  242. FIRCollectionReference *col = [self collectionRef];
  243. // set a few documents to a known value
  244. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  245. @"doc1" : @{@"key1" : @"value1"},
  246. @"doc2" : @{@"key2" : @"value2"},
  247. @"doc3" : @{@"key3" : @"value3"},
  248. };
  249. [self writeAllDocuments:initialDocs toCollection:col];
  250. // get docs and ensure they are *not* from the cache, and matches the
  251. // initialData.
  252. FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceServer];
  253. XCTAssertFalse(result.metadata.fromCache);
  254. XCTAssertFalse(result.metadata.hasPendingWrites);
  255. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  256. @{@"key1" : @"value1"},
  257. @{@"key2" : @"value2"},
  258. @{@"key3" : @"value3"},
  259. ]));
  260. XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[
  261. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  262. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ],
  263. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ]
  264. ]));
  265. }
  266. - (void)testGetDocumentWhileOfflineServerOnly {
  267. FIRDocumentReference *doc = [self documentRef];
  268. // set document to a known value
  269. NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
  270. [self writeDocumentRef:doc data:initialData];
  271. // go offline for the rest of this test
  272. [self disableNetwork];
  273. // attempt to get doc and ensure it cannot be retrieved
  274. XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"];
  275. [doc getDocumentWithSource:FIRFirestoreSourceServer
  276. completion:^(FIRDocumentSnapshot *, NSError *error) {
  277. XCTAssertNotNil(error);
  278. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  279. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  280. [failedGetDocCompletion fulfill];
  281. }];
  282. [self awaitExpectations];
  283. }
  284. - (void)testGetCollectionWhileOfflineServerOnly {
  285. FIRCollectionReference *col = [self collectionRef];
  286. // set a few documents to a known value
  287. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  288. @"doc1" : @{@"key1" : @"value1"},
  289. @"doc2" : @{@"key2" : @"value2"},
  290. @"doc3" : @{@"key3" : @"value3"},
  291. };
  292. [self writeAllDocuments:initialDocs toCollection:col];
  293. // go offline for the rest of this test
  294. [self disableNetwork];
  295. // attempt to get docs and ensure they cannot be retrieved
  296. XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
  297. [col getDocumentsWithSource:FIRFirestoreSourceServer
  298. completion:^(FIRQuerySnapshot *, NSError *error) {
  299. XCTAssertNotNil(error);
  300. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  301. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  302. [failedGetDocsCompletion fulfill];
  303. }];
  304. [self awaitExpectations];
  305. }
  306. - (void)testGetDocumentWhileOfflineWithDifferentSource {
  307. FIRDocumentReference *doc = [self documentRef];
  308. // set document to a known value
  309. NSDictionary<NSString *, id> *initialData = @{@"key1" : @"value1"};
  310. [self writeDocumentRef:doc data:initialData];
  311. // go offline for the rest of this test
  312. [self disableNetwork];
  313. // update the doc (though don't wait for a server response. We're offline; so
  314. // that ain't happening!). This allows us to further distinguished cached vs
  315. // server responses below.
  316. NSDictionary<NSString *, id> *newData = @{@"key2" : @"value2"};
  317. [doc setData:newData
  318. completion:^(NSError *) {
  319. XCTAssertTrue(false, "Because we're offline, this should never occur.");
  320. }];
  321. // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for
  322. // the listener to deliver its initial snapshot before continuing.
  323. XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"];
  324. [doc addSnapshotListener:^(FIRDocumentSnapshot *, NSError *) {
  325. [listenerReady fulfill];
  326. }];
  327. [self awaitExpectations];
  328. // get doc (from cache) and ensure it exists, *is* from the cache, and
  329. // matches the newData.
  330. FIRDocumentSnapshot *result = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
  331. XCTAssertTrue(result.exists);
  332. XCTAssertTrue(result.metadata.fromCache);
  333. XCTAssertTrue(result.metadata.hasPendingWrites);
  334. XCTAssertEqualObjects(result.data, newData);
  335. // attempt to get doc (with default get source)
  336. result = [self readDocumentForRef:doc source:FIRFirestoreSourceDefault];
  337. XCTAssertTrue(result.exists);
  338. XCTAssertTrue(result.metadata.fromCache);
  339. XCTAssertTrue(result.metadata.hasPendingWrites);
  340. XCTAssertEqualObjects(result.data, newData);
  341. // attempt to get doc (from the server) and ensure it cannot be retrieved
  342. XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"];
  343. [doc getDocumentWithSource:FIRFirestoreSourceServer
  344. completion:^(FIRDocumentSnapshot *, NSError *error) {
  345. XCTAssertNotNil(error);
  346. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  347. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  348. [failedGetDocCompletion fulfill];
  349. }];
  350. [self awaitExpectations];
  351. }
  352. - (void)testGetCollectionWhileOfflineWithDifferentSource {
  353. FIRCollectionReference *col = [self collectionRef];
  354. // set a few documents to a known value
  355. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *initialDocs = @{
  356. @"doc1" : @{@"key1" : @"value1"},
  357. @"doc2" : @{@"key2" : @"value2"},
  358. @"doc3" : @{@"key3" : @"value3"},
  359. };
  360. [self writeAllDocuments:initialDocs toCollection:col];
  361. // go offline for the rest of this test
  362. [self disableNetwork];
  363. // update the docs (though don't wait for a server response. We're offline; so
  364. // that ain't happening!). This allows us to further distinguished cached vs
  365. // server responses below.
  366. [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} merge:YES];
  367. [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}];
  368. [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}];
  369. // Create an initial listener for this query (to attempt to disrupt the gets
  370. // below) and wait for the listener to deliver its initial snapshot before
  371. // continuing.
  372. XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"];
  373. [col addSnapshotListener:^(FIRQuerySnapshot *, NSError *) {
  374. [listenerReady fulfill];
  375. }];
  376. [self awaitExpectations];
  377. // get docs (from cache) and ensure they *are* from the cache, and
  378. // matches the updated data.
  379. FIRQuerySnapshot *result = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
  380. XCTAssertTrue(result.metadata.fromCache);
  381. XCTAssertTrue(result.metadata.hasPendingWrites);
  382. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  383. @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
  384. @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
  385. ]));
  386. XCTAssertEqualObjects(
  387. FIRQuerySnapshotGetDocChangesData(result), (@[
  388. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  389. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
  390. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
  391. @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
  392. ]));
  393. // attempt to get docs (with default get source)
  394. result = [self readDocumentSetForRef:col source:FIRFirestoreSourceDefault];
  395. XCTAssertTrue(result.metadata.fromCache);
  396. XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
  397. @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"},
  398. @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"}
  399. ]));
  400. XCTAssertEqualObjects(
  401. FIRQuerySnapshotGetDocChangesData(result), (@[
  402. @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ],
  403. @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ],
  404. @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ],
  405. @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ]
  406. ]));
  407. // attempt to get docs (from the server) and ensure they cannot be retrieved
  408. XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
  409. [col getDocumentsWithSource:FIRFirestoreSourceServer
  410. completion:^(FIRQuerySnapshot *, NSError *error) {
  411. XCTAssertNotNil(error);
  412. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  413. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  414. [failedGetDocsCompletion fulfill];
  415. }];
  416. [self awaitExpectations];
  417. }
  418. - (void)testGetNonExistingDocWhileOnlineWithDefaultSource {
  419. FIRDocumentReference *doc = [self documentRef];
  420. // get doc and ensure that it does not exist and is *not* from the cache.
  421. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
  422. XCTAssertFalse(snapshot.exists);
  423. XCTAssertFalse(snapshot.metadata.fromCache);
  424. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  425. }
  426. - (void)testGetNonExistingCollectionWhileOnlineWithDefaultSource {
  427. FIRCollectionReference *col = [self collectionRef];
  428. // get collection and ensure it's empty and that it's *not* from the cache.
  429. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col];
  430. XCTAssertEqual(snapshot.count, 0);
  431. XCTAssertEqual(snapshot.documentChanges.count, 0ul);
  432. XCTAssertFalse(snapshot.metadata.fromCache);
  433. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  434. }
  435. - (void)testGetNonExistingDocWhileOfflineWithDefaultSource {
  436. FIRDocumentReference *doc = [self documentRef];
  437. // go offline for the rest of this test
  438. [self disableNetwork];
  439. // Attempt to get doc. This will fail since there's nothing in cache.
  440. XCTestExpectation *getNonExistingDocCompletion =
  441. [self expectationWithDescription:@"getNonExistingDoc"];
  442. [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *, NSError *error) {
  443. XCTAssertNotNil(error);
  444. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  445. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  446. [getNonExistingDocCompletion fulfill];
  447. }];
  448. [self awaitExpectations];
  449. }
  450. // TODO(b/112267729): We should raise a fromCache=true event with a nonexistent snapshot, but
  451. // because the default source goes through a normal listener, we do not.
  452. - (void)xtestGetDeletedDocWhileOfflineWithDefaultSource {
  453. FIRDocumentReference *doc = [self documentRef];
  454. // Delete the doc to get a deleted document into our cache.
  455. [self deleteDocumentRef:doc];
  456. // Go offline for the rest of this test
  457. [self disableNetwork];
  458. // Should get a FIRDocumentSnapshot with exists=false, fromCache=true
  459. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc source:FIRFirestoreSourceDefault];
  460. XCTAssertNotNil(snapshot);
  461. XCTAssertFalse(snapshot.exists);
  462. XCTAssertNil(snapshot.data);
  463. XCTAssertTrue(snapshot.metadata.fromCache);
  464. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  465. }
  466. - (void)testGetNonExistingCollectionWhileOfflineWithDefaultSource {
  467. FIRCollectionReference *col = [self collectionRef];
  468. // go offline for the rest of this test
  469. [self disableNetwork];
  470. // get collection and ensure it's empty and that it *is* from the cache.
  471. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col];
  472. XCTAssertEqual(snapshot.count, 0);
  473. XCTAssertEqual(snapshot.documentChanges.count, 0ul);
  474. XCTAssertTrue(snapshot.metadata.fromCache);
  475. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  476. }
  477. - (void)testGetNonExistingDocWhileOnlineCacheOnly {
  478. FIRDocumentReference *doc = [self documentRef];
  479. // Attempt to get doc. This will fail since there's nothing in cache.
  480. XCTestExpectation *getNonExistingDocCompletion =
  481. [self expectationWithDescription:@"getNonExistingDoc"];
  482. [doc getDocumentWithSource:FIRFirestoreSourceCache
  483. completion:^(FIRDocumentSnapshot *, NSError *error) {
  484. XCTAssertNotNil(error);
  485. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  486. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  487. [getNonExistingDocCompletion fulfill];
  488. }];
  489. [self awaitExpectations];
  490. }
  491. - (void)testGetNonExistingCollectionWhileOnlineCacheOnly {
  492. FIRCollectionReference *col = [self collectionRef];
  493. // get collection and ensure it's empty and that it *is* from the cache.
  494. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
  495. XCTAssertEqual(snapshot.count, 0);
  496. XCTAssertEqual(snapshot.documentChanges.count, 0ul);
  497. XCTAssertTrue(snapshot.metadata.fromCache);
  498. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  499. }
  500. - (void)testGetNonExistingDocWhileOfflineCacheOnly {
  501. FIRDocumentReference *doc = [self documentRef];
  502. // go offline for the rest of this test
  503. [self disableNetwork];
  504. // Attempt to get doc. This will fail since there's nothing in cache.
  505. XCTestExpectation *getNonExistingDocCompletion =
  506. [self expectationWithDescription:@"getNonExistingDoc"];
  507. [doc getDocumentWithSource:FIRFirestoreSourceCache
  508. completion:^(FIRDocumentSnapshot *, NSError *error) {
  509. XCTAssertNotNil(error);
  510. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  511. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  512. [getNonExistingDocCompletion fulfill];
  513. }];
  514. [self awaitExpectations];
  515. }
  516. - (void)testGetDeletedDocWhileOfflineCacheOnly {
  517. FIRDocumentReference *doc = [self documentRef];
  518. // Delete the doc to get a deleted document into our cache.
  519. [self deleteDocumentRef:doc];
  520. // Go offline for the rest of this test
  521. [self disableNetwork];
  522. // Should get a FIRDocumentSnapshot with exists=false, fromCache=true
  523. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc source:FIRFirestoreSourceCache];
  524. XCTAssertNotNil(snapshot);
  525. XCTAssertFalse(snapshot.exists);
  526. XCTAssertNil(snapshot.data);
  527. XCTAssertTrue(snapshot.metadata.fromCache);
  528. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  529. }
  530. - (void)testGetNonExistingCollectionWhileOfflineCacheOnly {
  531. FIRCollectionReference *col = [self collectionRef];
  532. // go offline for the rest of this test
  533. [self disableNetwork];
  534. // get collection and ensure it's empty and that it *is* from the cache.
  535. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceCache];
  536. XCTAssertEqual(snapshot.count, 0);
  537. XCTAssertEqual(snapshot.documentChanges.count, 0ul);
  538. XCTAssertTrue(snapshot.metadata.fromCache);
  539. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  540. }
  541. - (void)testGetNonExistingDocWhileOnlineServerOnly {
  542. FIRDocumentReference *doc = [self documentRef];
  543. // get doc and ensure that it does not exist and is *not* from the cache.
  544. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc source:FIRFirestoreSourceServer];
  545. XCTAssertFalse(snapshot.exists);
  546. XCTAssertFalse(snapshot.metadata.fromCache);
  547. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  548. }
  549. - (void)testGetNonExistingCollectionWhileOnlineServerOnly {
  550. FIRCollectionReference *col = [self collectionRef];
  551. // get collection and ensure that it's empty and that it's *not* from the cache.
  552. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col source:FIRFirestoreSourceServer];
  553. XCTAssertEqual(snapshot.count, 0);
  554. XCTAssertEqual(snapshot.documentChanges.count, 0ul);
  555. XCTAssertFalse(snapshot.metadata.fromCache);
  556. XCTAssertFalse(snapshot.metadata.hasPendingWrites);
  557. }
  558. - (void)testGetNonExistingDocWhileOfflineServerOnly {
  559. FIRDocumentReference *doc = [self documentRef];
  560. // go offline for the rest of this test
  561. [self disableNetwork];
  562. // attempt to get doc. Currently, this is expected to fail. In the future, we
  563. // might consider adding support for negative cache hits so that we know
  564. // certain documents *don't* exist.
  565. XCTestExpectation *getNonExistingDocCompletion =
  566. [self expectationWithDescription:@"getNonExistingDoc"];
  567. [doc getDocumentWithSource:FIRFirestoreSourceServer
  568. completion:^(FIRDocumentSnapshot *, NSError *error) {
  569. XCTAssertNotNil(error);
  570. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  571. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  572. [getNonExistingDocCompletion fulfill];
  573. }];
  574. [self awaitExpectations];
  575. }
  576. - (void)testGetNonExistingCollectionWhileOfflineServerOnly {
  577. FIRCollectionReference *col = [self collectionRef];
  578. // go offline for the rest of this test
  579. [self disableNetwork];
  580. // attempt to get collection and ensure that it cannot be retrieved
  581. XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"];
  582. [col getDocumentsWithSource:FIRFirestoreSourceServer
  583. completion:^(FIRQuerySnapshot *, NSError *error) {
  584. XCTAssertNotNil(error);
  585. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  586. XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable);
  587. [failedGetDocsCompletion fulfill];
  588. }];
  589. [self awaitExpectations];
  590. }
  591. @end