FOrderByTests.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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 "FirebaseDatabase/Tests/Integration/FOrderByTests.h"
  17. @interface FOrderByTests ()
  18. @end
  19. @implementation FOrderByTests
  20. - (void)testCanDefineAndUseAnIndex {
  21. __block FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  22. NSArray *users = @[
  23. @{@"name" : @"Andrew", @"nuggets" : @35}, @{@"name" : @"Rob", @"nuggets" : @40},
  24. @{@"name" : @"Greg", @"nuggets" : @38}
  25. ];
  26. __block int setCount = 0;
  27. [users enumerateObjectsUsingBlock:^(NSDictionary *user, NSUInteger idx, BOOL *stop) {
  28. [[ref childByAutoId] setValue:user
  29. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  30. setCount++;
  31. }];
  32. }];
  33. [self waitUntil:^BOOL {
  34. return setCount == users.count;
  35. }];
  36. __block NSMutableArray *byNuggets = [[NSMutableArray alloc] init];
  37. [[ref queryOrderedByChild:@"nuggets"] observeEventType:FIRDataEventTypeChildAdded
  38. withBlock:^(FIRDataSnapshot *snapshot) {
  39. NSDictionary *user = snapshot.value;
  40. [byNuggets addObject:user[@"name"]];
  41. }];
  42. [self waitUntil:^BOOL {
  43. return byNuggets.count == users.count;
  44. }];
  45. NSArray *expected = @[ @"Andrew", @"Greg", @"Rob" ];
  46. XCTAssertEqualObjects(byNuggets, expected, @"Correct by-nugget ordering.");
  47. }
  48. - (void)testCanDefineAndUseDeepIndex {
  49. __block FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  50. NSArray *users = @[
  51. @{@"name" : @"Andrew", @"deep" : @{@"nuggets" : @35}},
  52. @{@"name" : @"Rob", @"deep" : @{@"nuggets" : @40}},
  53. @{@"name" : @"Greg", @"deep" : @{@"nuggets" : @38}}
  54. ];
  55. __block int setCount = 0;
  56. [users enumerateObjectsUsingBlock:^(NSDictionary *user, NSUInteger idx, BOOL *stop) {
  57. [[ref childByAutoId] setValue:user
  58. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  59. setCount++;
  60. }];
  61. }];
  62. [self waitUntil:^BOOL {
  63. return setCount == users.count;
  64. }];
  65. __block NSMutableArray *byNuggets = [[NSMutableArray alloc] init];
  66. [[ref queryOrderedByChild:@"deep/nuggets"] observeEventType:FIRDataEventTypeChildAdded
  67. withBlock:^(FIRDataSnapshot *snapshot) {
  68. NSDictionary *user = snapshot.value;
  69. [byNuggets addObject:user[@"name"]];
  70. }];
  71. [self waitUntil:^BOOL {
  72. return byNuggets.count == users.count;
  73. }];
  74. NSArray *expected = @[ @"Andrew", @"Greg", @"Rob" ];
  75. XCTAssertEqualObjects(byNuggets, expected, @"Correct by-nugget ordering.");
  76. }
  77. - (void)testCanUsaAFallbackThenDefineTheSpecifiedIndex {
  78. FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
  79. FIRDatabaseReference *reader = tuple.one, *writer = tuple.two;
  80. NSDictionary *foo1 = @{
  81. @"a" : @{@"order" : @2, @"foo" : @1},
  82. @"b" : @{@"order" : @0},
  83. @"c" : @{@"order" : @1, @"foo" : @NO},
  84. @"d" : @{@"order" : @3, @"foo" : @"hello"}
  85. };
  86. NSDictionary *foo_e = @{@"order" : @1.5, @"foo" : @YES};
  87. NSDictionary *foo_f = @{@"order" : @4, @"foo" : @{@"bar" : @"baz"}};
  88. [self waitForCompletionOf:writer setValue:foo1];
  89. NSMutableArray *snaps = [[NSMutableArray alloc] init];
  90. [[[reader queryOrderedByChild:@"order"] queryLimitedToLast:2]
  91. observeEventType:FIRDataEventTypeValue
  92. withBlock:^(FIRDataSnapshot *snapshot) {
  93. [snaps addObject:snapshot.value];
  94. }];
  95. WAIT_FOR(snaps.count == 1);
  96. NSDictionary *expected =
  97. @{@"d" : @{@"order" : @3, @"foo" : @"hello"}, @"a" : @{@"order" : @2, @"foo" : @1}};
  98. XCTAssertEqualObjects(snaps[0], expected, @"Got correct result");
  99. [self waitForCompletionOf:[writer child:@"e"] setValue:foo_e];
  100. [self waitForRoundTrip:reader];
  101. NSLog(@"snaps: %@", snaps);
  102. NSLog(@"snaps.count: %ld", (unsigned long)snaps.count);
  103. XCTAssertEqual(snaps.count, (NSUInteger)1, @"Should still have one event.");
  104. [self waitForCompletionOf:[writer child:@"f"] setValue:foo_f];
  105. [self waitForRoundTrip:reader];
  106. XCTAssertEqual(snaps.count, (NSUInteger)2, @"Should have gotten another event.");
  107. expected = @{@"f" : foo_f, @"d" : @{@"order" : @3, @"foo" : @"hello"}};
  108. XCTAssertEqualObjects(snaps[1], expected, @"Correct event.");
  109. }
  110. - (void)testSnapshotsAreIteratedInOrder {
  111. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  112. NSDictionary *initial = @{
  113. @"alex" : @{@"nuggets" : @60},
  114. @"rob" : @{@"nuggets" : @56},
  115. @"vassili" : @{@"nuggets" : @55.5},
  116. @"tony" : @{@"nuggets" : @52},
  117. @"greg" : @{@"nuggets" : @52}
  118. };
  119. NSArray *expectedOrder = @[ @"greg", @"tony", @"vassili", @"rob", @"alex" ];
  120. NSArray *expectedPrevNames = @[ [NSNull null], @"greg", @"tony", @"vassili", @"rob" ];
  121. NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
  122. NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
  123. NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
  124. FIRDatabaseQuery *orderedRef = [ref queryOrderedByChild:@"nuggets"];
  125. [orderedRef observeEventType:FIRDataEventTypeValue
  126. withBlock:^(FIRDataSnapshot *snapshot) {
  127. for (FIRDataSnapshot *child in snapshot.children) {
  128. [valueOrder addObject:child.key];
  129. }
  130. }];
  131. [orderedRef observeEventType:FIRDataEventTypeChildAdded
  132. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
  133. [addedOrder addObject:snapshot.key];
  134. [addedPrevNames addObject:prevName ? prevName : [NSNull null]];
  135. }];
  136. [ref setValue:initial];
  137. WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
  138. XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
  139. XCTAssertEqualObjects(addedPrevNames, expectedPrevNames,
  140. @"Got correct prevnames for child_added events.");
  141. XCTAssertEqualObjects(valueOrder, expectedOrder,
  142. @"enumerated snapshot children in correct order.");
  143. }
  144. - (void)testSnapshotsAreIteratedInOrderForValueIndex {
  145. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  146. NSDictionary *initial =
  147. @{@"alex" : @60, @"rob" : @56, @"vassili" : @55.5, @"tony" : @52, @"greg" : @52};
  148. NSArray *expectedOrder = @[ @"greg", @"tony", @"vassili", @"rob", @"alex" ];
  149. NSArray *expectedPrevNames = @[ [NSNull null], @"greg", @"tony", @"vassili", @"rob" ];
  150. NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
  151. NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
  152. NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
  153. FIRDatabaseQuery *orderedRef = [ref queryOrderedByValue];
  154. [orderedRef observeEventType:FIRDataEventTypeValue
  155. withBlock:^(FIRDataSnapshot *snapshot) {
  156. for (FIRDataSnapshot *child in snapshot.children) {
  157. [valueOrder addObject:child.key];
  158. }
  159. }];
  160. [orderedRef observeEventType:FIRDataEventTypeChildAdded
  161. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
  162. [addedOrder addObject:snapshot.key];
  163. [addedPrevNames addObject:prevName ? prevName : [NSNull null]];
  164. }];
  165. [ref setValue:initial];
  166. WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
  167. XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
  168. XCTAssertEqualObjects(addedPrevNames, expectedPrevNames,
  169. @"Got correct prevnames for child_added events.");
  170. XCTAssertEqualObjects(valueOrder, expectedOrder,
  171. @"enumerated snapshot children in correct order.");
  172. }
  173. - (void)testFiresChildMovedEvents {
  174. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  175. NSDictionary *initial = @{
  176. @"alex" : @{@"nuggets" : @60},
  177. @"rob" : @{@"nuggets" : @56},
  178. @"vassili" : @{@"nuggets" : @55.5},
  179. @"tony" : @{@"nuggets" : @52},
  180. @"greg" : @{@"nuggets" : @52}
  181. };
  182. FIRDatabaseQuery *orderedRef = [ref queryOrderedByChild:@"nuggets"];
  183. __block BOOL moved = NO;
  184. [orderedRef observeEventType:FIRDataEventTypeChildMoved
  185. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
  186. moved = YES;
  187. XCTAssertEqualObjects(snapshot.key, @"greg", @"");
  188. XCTAssertEqualObjects(prevName, @"rob", @"");
  189. XCTAssertEqualObjects(
  190. snapshot.value,
  191. @{@"nuggets" : @57}, @"");
  192. }];
  193. [ref setValue:initial];
  194. [[ref child:@"greg/nuggets"] setValue:@57];
  195. WAIT_FOR(moved);
  196. }
  197. - (void)testDefineMultipleIndexesAtALocation {
  198. FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
  199. FIRDatabaseReference *reader = tuple.one, *writer = tuple.two;
  200. NSDictionary *foo1 = @{
  201. @"a" : @{@"order" : @2, @"foo" : @2},
  202. @"b" : @{@"order" : @0},
  203. @"c" : @{@"order" : @1, @"foo" : @NO},
  204. @"d" : @{@"order" : @3, @"foo" : @"hello"}
  205. };
  206. [self waitForCompletionOf:writer setValue:foo1];
  207. FIRDatabaseQuery *fooOrder = [reader queryOrderedByChild:@"foo"];
  208. FIRDatabaseQuery *orderOrder = [reader queryOrderedByChild:@"order"];
  209. NSMutableArray *fooSnaps = [[NSMutableArray alloc] init];
  210. NSMutableArray *orderSnaps = [[NSMutableArray alloc] init];
  211. [[[fooOrder queryStartingAtValue:nil] queryEndingAtValue:@1]
  212. observeEventType:FIRDataEventTypeValue
  213. withBlock:^(FIRDataSnapshot *snapshot) {
  214. [fooSnaps addObject:snapshot.value];
  215. }];
  216. [[orderOrder queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue
  217. withBlock:^(FIRDataSnapshot *snapshot) {
  218. [orderSnaps addObject:snapshot.value];
  219. }];
  220. WAIT_FOR(fooSnaps.count == 1 && orderSnaps.count == 1);
  221. NSDictionary *expected = @{@"b" : @{@"order" : @0}, @"c" : @{@"order" : @1, @"foo" : @NO}};
  222. XCTAssertEqualObjects(fooSnaps[0], expected, @"");
  223. expected = @{
  224. @"d" : @{@"order" : @3, @"foo" : @"hello"},
  225. @"a" : @{@"order" : @2, @"foo" : @2},
  226. };
  227. XCTAssertEqualObjects(orderSnaps[0], expected, @"");
  228. [[writer child:@"a"] setValue:@{@"order" : @-1, @"foo" : @1}];
  229. WAIT_FOR(fooSnaps.count == 2 && orderSnaps.count == 2);
  230. expected = @{
  231. @"a" : @{@"order" : @-1, @"foo" : @1},
  232. @"b" : @{@"order" : @0},
  233. @"c" : @{@"order" : @1, @"foo" : @NO}
  234. };
  235. XCTAssertEqualObjects(fooSnaps[1], expected, @"");
  236. expected = @{@"d" : @{@"order" : @3, @"foo" : @"hello"}, @"c" : @{@"order" : @1, @"foo" : @NO}};
  237. XCTAssertEqualObjects(orderSnaps[1], expected, @"");
  238. }
  239. - (void)testCallbackRemovalWorks {
  240. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  241. __block int reads = 0;
  242. FIRDatabaseHandle fooHandle, bazHandle;
  243. fooHandle = [[ref queryOrderedByChild:@"foo"] observeEventType:FIRDataEventTypeValue
  244. withBlock:^(FIRDataSnapshot *snapshot) {
  245. reads++;
  246. }];
  247. [[ref queryOrderedByChild:@"bar"] observeEventType:FIRDataEventTypeValue
  248. withBlock:^(FIRDataSnapshot *snapshot) {
  249. reads++;
  250. }];
  251. bazHandle = [[ref queryOrderedByChild:@"baz"] observeEventType:FIRDataEventTypeValue
  252. withBlock:^(FIRDataSnapshot *snapshot) {
  253. reads++;
  254. }];
  255. [ref observeEventType:FIRDataEventTypeValue
  256. withBlock:^(FIRDataSnapshot *snapshot) {
  257. reads++;
  258. }];
  259. [self waitForCompletionOf:ref setValue:@1];
  260. XCTAssertEqual(reads, 4, @"");
  261. [ref removeObserverWithHandle:fooHandle];
  262. [self waitForCompletionOf:ref setValue:@2];
  263. XCTAssertEqual(reads, 7, @"");
  264. // should be a no-op, resulting in 3 more reads.
  265. [[ref queryOrderedByChild:@"foo"] removeObserverWithHandle:bazHandle];
  266. [self waitForCompletionOf:ref setValue:@3];
  267. XCTAssertEqual(reads, 10, @"");
  268. [[ref queryOrderedByChild:@"bar"] removeAllObservers];
  269. [self waitForCompletionOf:ref setValue:@4];
  270. XCTAssertEqual(reads, 12, @"");
  271. // Now, remove everything.
  272. [ref removeAllObservers];
  273. [self waitForCompletionOf:ref setValue:@5];
  274. XCTAssertEqual(reads, 12, @"");
  275. }
  276. - (void)testChildAddedEventsAreInTheCorrectOrder {
  277. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  278. NSDictionary *initial = @{@"a" : @{@"value" : @5}, @"c" : @{@"value" : @3}};
  279. NSMutableArray *added = [[NSMutableArray alloc] init];
  280. [[ref queryOrderedByChild:@"value"] observeEventType:FIRDataEventTypeChildAdded
  281. withBlock:^(FIRDataSnapshot *snapshot) {
  282. [added addObject:snapshot.key];
  283. }];
  284. [ref setValue:initial];
  285. WAIT_FOR(added.count == 2);
  286. NSArray *expected = @[ @"c", @"a" ];
  287. XCTAssertEqualObjects(added, expected, @"");
  288. [ref updateChildValues:@{@"b" : @{@"value" : @4}, @"d" : @{@"value" : @2}}];
  289. WAIT_FOR(added.count == 4);
  290. expected = @[ @"c", @"a", @"d", @"b" ];
  291. XCTAssertEqualObjects(added, expected, @"");
  292. }
  293. - (void)testCanUseKeyIndex {
  294. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  295. NSDictionary *data = @{
  296. @"a" : @{@".priority" : @10, @".value" : @"a"},
  297. @"b" : @{@".priority" : @5, @".value" : @"b"},
  298. @"c" : @{@".priority" : @20, @".value" : @"c"},
  299. @"d" : @{@".priority" : @7, @".value" : @"d"},
  300. @"e" : @{@".priority" : @30, @".value" : @"e"},
  301. @"f" : @{@".priority" : @8, @".value" : @"f"}
  302. };
  303. [self waitForCompletionOf:ref setValue:data];
  304. __block BOOL valueDone = NO;
  305. [[[ref queryOrderedByKey] queryStartingAtValue:@"c"]
  306. observeSingleEventOfType:FIRDataEventTypeValue
  307. withBlock:^(FIRDataSnapshot *snapshot) {
  308. NSMutableArray *keys = [[NSMutableArray alloc] init];
  309. for (FIRDataSnapshot *child in snapshot.children) {
  310. [keys addObject:child.key];
  311. }
  312. NSArray *expected = @[ @"c", @"d", @"e", @"f" ];
  313. XCTAssertEqualObjects(keys, expected, @"");
  314. valueDone = YES;
  315. }];
  316. WAIT_FOR(valueDone);
  317. NSMutableArray *keys = [[NSMutableArray alloc] init];
  318. [[[ref queryOrderedByKey] queryLimitedToLast:5]
  319. observeEventType:FIRDataEventTypeValue
  320. withBlock:^(FIRDataSnapshot *snapshot) {
  321. for (FIRDataSnapshot *child in snapshot.children) {
  322. [keys addObject:child.key];
  323. }
  324. }];
  325. WAIT_FOR(keys.count == 5);
  326. NSArray *expected = @[ @"b", @"c", @"d", @"e", @"f" ];
  327. XCTAssertEqualObjects(keys, expected, @"");
  328. }
  329. - (void)testQueriesWorkOnLeafNodes {
  330. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  331. [self waitForCompletionOf:ref setValue:@"leaf-node"];
  332. __block BOOL valueDone = NO;
  333. [[[ref queryOrderedByChild:@"foo"] queryLimitedToLast:1]
  334. observeSingleEventOfType:FIRDataEventTypeValue
  335. withBlock:^(FIRDataSnapshot *snapshot) {
  336. XCTAssertEqual(snapshot.value, [NSNull null]);
  337. valueDone = YES;
  338. }];
  339. WAIT_FOR(valueDone);
  340. }
  341. - (void)testUpdatesForUnindexedQuery {
  342. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  343. FIRDatabaseReference *reader = refs.one;
  344. FIRDatabaseReference *writer = refs.two;
  345. __block BOOL done = NO;
  346. NSDictionary *value = @{
  347. @"one" : @{@"index" : @1, @"value" : @"one"},
  348. @"two" : @{@"index" : @2, @"value" : @"two"},
  349. @"three" : @{@"index" : @3, @"value" : @"three"}
  350. };
  351. [writer setValue:value
  352. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  353. done = YES;
  354. }];
  355. WAIT_FOR(done);
  356. done = NO;
  357. NSMutableArray *snapshots = [NSMutableArray array];
  358. [[[reader queryOrderedByChild:@"index"] queryLimitedToLast:2]
  359. observeEventType:FIRDataEventTypeValue
  360. withBlock:^(FIRDataSnapshot *snapshot) {
  361. [snapshots addObject:snapshot.value];
  362. done = YES;
  363. }];
  364. WAIT_FOR(done);
  365. NSDictionary *expected = @{
  366. @"two" : @{@"index" : @2, @"value" : @"two"},
  367. @"three" : @{@"index" : @3, @"value" : @"three"}
  368. };
  369. XCTAssertEqual(snapshots.count, (NSUInteger)1);
  370. XCTAssertEqualObjects(snapshots[0], expected);
  371. done = NO;
  372. [[writer child:@"one/index"] setValue:@4];
  373. WAIT_FOR(done);
  374. expected = @{
  375. @"one" : @{@"index" : @4, @"value" : @"one"},
  376. @"three" : @{@"index" : @3, @"value" : @"three"}
  377. };
  378. XCTAssertEqual(snapshots.count, (NSUInteger)2);
  379. XCTAssertEqualObjects(snapshots[1], expected);
  380. }
  381. - (void)testServerRespectsKeyIndex {
  382. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  383. FIRDatabaseReference *writer = refs.one;
  384. FIRDatabaseReference *reader = refs.two;
  385. NSDictionary *initial = @{@"a" : @1, @"b" : @2, @"c" : @3};
  386. // If the server doesn't respect the index, it will send down limited data, but with no offset, so
  387. // the expected and actual data don't match
  388. FIRDatabaseQuery *query =
  389. [[[reader queryOrderedByKey] queryStartingAtValue:@"b"] queryLimitedToFirst:2];
  390. NSArray *expectedChildren = @[ @"b", @"c" ];
  391. [self waitForCompletionOf:writer setValue:initial];
  392. NSMutableArray *children = [[NSMutableArray alloc] init];
  393. __block BOOL done = NO;
  394. [query observeEventType:FIRDataEventTypeValue
  395. withBlock:^(FIRDataSnapshot *snapshot) {
  396. for (FIRDataSnapshot *child in snapshot.children) {
  397. [children addObject:child.key];
  398. }
  399. done = YES;
  400. }];
  401. WAIT_FOR(done);
  402. XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
  403. }
  404. - (void)testServerRespectsValueIndex {
  405. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  406. FIRDatabaseReference *writer = refs.one;
  407. FIRDatabaseReference *reader = refs.two;
  408. NSDictionary *initial = @{@"a" : @1, @"c" : @2, @"b" : @3};
  409. // If the server doesn't respect the index, it will send down limited data, but with no offset, so
  410. // the expected and actual data don't match
  411. FIRDatabaseQuery *query =
  412. [[[reader queryOrderedByValue] queryStartingAtValue:@2] queryLimitedToFirst:2];
  413. NSArray *expectedChildren = @[ @"c", @"b" ];
  414. [self waitForCompletionOf:writer setValue:initial];
  415. NSMutableArray *children = [[NSMutableArray alloc] init];
  416. __block BOOL done = NO;
  417. [query observeEventType:FIRDataEventTypeValue
  418. withBlock:^(FIRDataSnapshot *snapshot) {
  419. for (FIRDataSnapshot *child in snapshot.children) {
  420. [children addObject:child.key];
  421. }
  422. done = YES;
  423. }];
  424. WAIT_FOR(done);
  425. XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
  426. }
  427. - (void)testDeepUpdatesWorkWithQueries {
  428. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  429. FIRDatabaseReference *writer = refs.one;
  430. FIRDatabaseReference *reader = refs.two;
  431. NSDictionary *initial = @{
  432. @"a" : @{@"data" : @"foo", @"idx" : @YES},
  433. @"b" : @{@"data" : @"bar", @"idx" : @YES},
  434. @"c" : @{@"data" : @"baz", @"idx" : @NO}
  435. };
  436. [self waitForCompletionOf:writer setValue:initial];
  437. FIRDatabaseQuery *query = [[reader queryOrderedByChild:@"idx"] queryEqualToValue:@YES];
  438. NSDictionary *expected =
  439. @{@"a" : @{@"data" : @"foo", @"idx" : @YES}, @"b" : @{@"data" : @"bar", @"idx" : @YES}};
  440. [self waitForExportValueOf:query toBe:expected];
  441. NSDictionary *update = @{@"a/idx" : @NO, @"b/data" : @"blah", @"c/idx" : @YES};
  442. [self waitForCompletionOf:writer updateChildValues:update];
  443. expected =
  444. @{@"b" : @{@"data" : @"blah", @"idx" : @YES}, @"c" : @{@"data" : @"baz", @"idx" : @YES}};
  445. [self waitForExportValueOf:query toBe:expected];
  446. }
  447. - (void)testServerRespectsDeepIndex {
  448. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  449. FIRDatabaseReference *writer = refs.one;
  450. FIRDatabaseReference *reader = refs.two;
  451. NSDictionary *initial = @{
  452. @"a" : @{@"deep" : @{@"index" : @1}},
  453. @"c" : @{@"deep" : @{@"index" : @2}},
  454. @"b" : @{@"deep" : @{@"index" : @3}}
  455. };
  456. // If the server doesn't respect the index, it will send down limited data, but with no offset, so
  457. // the expected and actual data don't match
  458. FIRDatabaseQuery *query =
  459. [[[reader queryOrderedByChild:@"deep/index"] queryStartingAtValue:@2] queryLimitedToFirst:2];
  460. NSArray *expectedChildren = @[ @"c", @"b" ];
  461. [self waitForCompletionOf:writer setValue:initial];
  462. NSMutableArray *children = [[NSMutableArray alloc] init];
  463. __block BOOL done = NO;
  464. [query observeEventType:FIRDataEventTypeValue
  465. withBlock:^(FIRDataSnapshot *snapshot) {
  466. for (FIRDataSnapshot *child in snapshot.children) {
  467. [children addObject:child.key];
  468. }
  469. done = YES;
  470. }];
  471. WAIT_FOR(done);
  472. XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
  473. }
  474. - (void)testStartAtEndAtWorksWithValueIndex {
  475. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  476. NSDictionary *initial =
  477. @{@"alex" : @60, @"rob" : @56, @"vassili" : @55.5, @"tony" : @52, @"greg" : @52};
  478. NSArray *expectedOrder = @[ @"tony", @"vassili", @"rob" ];
  479. NSArray *expectedPrevNames = @[ [NSNull null], @"tony", @"vassili" ];
  480. NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
  481. NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
  482. NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
  483. FIRDatabaseQuery *orderedRef =
  484. [[[ref queryOrderedByValue] queryStartingAtValue:@52
  485. childKey:@"tony"] queryEndingAtValue:@59];
  486. [orderedRef observeEventType:FIRDataEventTypeValue
  487. withBlock:^(FIRDataSnapshot *snapshot) {
  488. for (FIRDataSnapshot *child in snapshot.children) {
  489. [valueOrder addObject:child.key];
  490. }
  491. }];
  492. [orderedRef observeEventType:FIRDataEventTypeChildAdded
  493. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
  494. [addedOrder addObject:snapshot.key];
  495. [addedPrevNames addObject:prevName ? prevName : [NSNull null]];
  496. }];
  497. [ref setValue:initial];
  498. WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
  499. XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
  500. XCTAssertEqualObjects(addedPrevNames, expectedPrevNames,
  501. @"Got correct prevnames for child_added events.");
  502. XCTAssertEqualObjects(valueOrder, expectedOrder,
  503. @"enumerated snapshot children in correct order.");
  504. }
  505. - (void)testRemovingDefaultListenerRemovesNonDefaultListenWithLoadsAllData {
  506. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  507. NSDictionary *initialData = @{@"key" : @"value"};
  508. [self waitForCompletionOf:ref setValue:initialData];
  509. [[ref queryOrderedByKey] observeEventType:FIRDataEventTypeValue
  510. withBlock:^(FIRDataSnapshot *snapshot){
  511. }];
  512. [ref observeEventType:FIRDataEventTypeValue
  513. withBlock:^(FIRDataSnapshot *snapshot){
  514. }];
  515. // Should remove both listener and should remove the listen sent to the server
  516. [ref removeAllObservers];
  517. __block id result = nil;
  518. // This used to crash because a listener for [ref queryOrderedByKey] existed already
  519. [[ref queryOrderedByKey] observeSingleEventOfType:FIRDataEventTypeValue
  520. withBlock:^(FIRDataSnapshot *snapshot) {
  521. result = snapshot.value;
  522. }];
  523. WAIT_FOR(result);
  524. XCTAssertEqualObjects(result, initialData);
  525. }
  526. @end