FOrderByTests.m 24 KB

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