FIRDatabaseQueryTests.m 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256
  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/FIRDatabaseQueryTests.h"
  17. #import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h"
  18. #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h"
  19. #import "FirebaseDatabase/Sources/Constants/FConstants.h"
  20. #import "FirebaseDatabase/Sources/Core/FQuerySpec.h"
  21. #import "FirebaseDatabase/Sources/Utilities/FUtilities.h"
  22. #import "FirebaseDatabase/Tests/Helpers/FIRFakeApp.h"
  23. #import "FirebaseDatabase/Tests/Helpers/FTestExpectations.h"
  24. @implementation FIRDatabaseQueryTests
  25. - (void)testCanCreateBasicQueries {
  26. // Just make sure none of these throw anything
  27. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  28. [ref queryLimitedToFirst:10];
  29. [ref queryLimitedToLast:10];
  30. [[ref queryOrderedByKey] queryStartingAtValue:@"foo"];
  31. [[ref queryOrderedByKey] queryEndingAtValue:@"foo"];
  32. [[ref queryOrderedByKey] queryEqualToValue:@"foo"];
  33. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@YES];
  34. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@1];
  35. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@"foo"];
  36. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:nil];
  37. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@YES];
  38. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@1];
  39. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@"foo"];
  40. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:nil];
  41. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@YES];
  42. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@1];
  43. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@"foo"];
  44. [[ref queryOrderedByChild:@"index"] queryEqualToValue:nil];
  45. [[ref queryOrderedByPriority] queryStartingAtValue:@1];
  46. [[ref queryOrderedByPriority] queryStartingAtValue:@"foo"];
  47. [[ref queryOrderedByPriority] queryStartingAtValue:nil];
  48. [[ref queryOrderedByPriority] queryEndingAtValue:@1];
  49. [[ref queryOrderedByPriority] queryEndingAtValue:@"foo"];
  50. [[ref queryOrderedByPriority] queryEndingAtValue:nil];
  51. [[ref queryOrderedByPriority] queryEqualToValue:@1];
  52. [[ref queryOrderedByPriority] queryEqualToValue:@"foo"];
  53. [[ref queryOrderedByPriority] queryEqualToValue:nil];
  54. }
  55. - (void)testInvalidQueryParams {
  56. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  57. XCTAssertThrows([[ref queryLimitedToFirst:100] queryLimitedToFirst:100]);
  58. XCTAssertThrows([[ref queryLimitedToFirst:100] queryLimitedToLast:100]);
  59. XCTAssertThrows([[ref queryLimitedToLast:100] queryLimitedToFirst:100]);
  60. XCTAssertThrows([[ref queryLimitedToLast:100] queryLimitedToLast:100]);
  61. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByPriority]);
  62. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByKey]);
  63. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByChild:@"foo"]);
  64. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByValue]);
  65. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByPriority]);
  66. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByKey]);
  67. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByChild:@"foo"]);
  68. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByValue]);
  69. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByPriority]);
  70. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByKey]);
  71. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByChild:@"foo"]);
  72. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByValue]);
  73. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByPriority]);
  74. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByKey]);
  75. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByChild:@"foo"]);
  76. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByValue]);
  77. XCTAssertThrows([[ref queryStartingAtValue:@"foo"] queryStartingAtValue:@"foo"]);
  78. XCTAssertThrows([[ref queryStartingAtValue:@"foo"] queryEqualToValue:@"foo"]);
  79. XCTAssertThrows([[ref queryEndingAtValue:@"foo"] queryEndingAtValue:@"foo"]);
  80. XCTAssertThrows([[ref queryEndingAtValue:@"foo"] queryEqualToValue:@"foo"]);
  81. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryStartingAtValue:@"foo"]);
  82. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryEndingAtValue:@"foo"]);
  83. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryEqualToValue:@"foo"]);
  84. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@"foo" childKey:@"foo"]);
  85. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@"foo" childKey:@"foo"]);
  86. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:@"foo" childKey:@"foo"]);
  87. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@1 childKey:@"foo"]);
  88. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@YES]);
  89. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@1]);
  90. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@YES]);
  91. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:nil]);
  92. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:nil]);
  93. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:nil]);
  94. XCTAssertThrows([[ref queryStartingAtValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  95. XCTAssertThrows([[ref queryEndingAtValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  96. XCTAssertThrows([[ref queryEqualToValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  97. XCTAssertThrows([[ref queryStartingAtValue:@1] queryOrderedByKey]);
  98. XCTAssertThrows([[ref queryStartingAtValue:@YES] queryOrderedByKey]);
  99. XCTAssertThrows([[ref queryEndingAtValue:@1] queryOrderedByKey]);
  100. XCTAssertThrows([[ref queryEndingAtValue:@YES] queryOrderedByKey]);
  101. XCTAssertThrows([ref queryStartingAtValue:@[]]);
  102. XCTAssertThrows([ref queryStartingAtValue:@{}]);
  103. XCTAssertThrows([ref queryEndingAtValue:@[]]);
  104. XCTAssertThrows([ref queryEndingAtValue:@{}]);
  105. XCTAssertThrows([ref queryEqualToValue:@[]]);
  106. XCTAssertThrows([ref queryEqualToValue:@{}]);
  107. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByPriority],
  108. @"Cannot call orderBy multiple times");
  109. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByPriority],
  110. @"Cannot call orderBy multiple times");
  111. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByKey],
  112. @"Cannot call orderBy multiple times");
  113. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByKey],
  114. @"Cannot call orderBy multiple times");
  115. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByChild:@"foo"],
  116. @"Cannot call orderBy multiple times");
  117. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByChild:@"foo"],
  118. @"Cannot call orderBy multiple times");
  119. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@"a" childKey:@"b"],
  120. @"Cannot specify starting child name when ordering by key.");
  121. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@"a" childKey:@"b"],
  122. @"Cannot specify ending child name when ordering by key.");
  123. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:@"a" childKey:@"b"],
  124. @"Cannot specify equalTo child name when ordering by key.");
  125. XCTAssertThrows([[ref queryOrderedByPriority] queryStartingAtValue:@YES],
  126. @"Can't pass booleans as start/end when using priority index.");
  127. XCTAssertThrows([[ref queryOrderedByPriority] queryEndingAtValue:@NO],
  128. @"Can't pass booleans as start/end when using priority index.");
  129. XCTAssertThrows([[ref queryOrderedByPriority] queryEqualToValue:@YES],
  130. @"Can't pass booleans as start/end when using priority index.");
  131. }
  132. - (void)testLimitRanges {
  133. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  134. XCTAssertThrows([ref queryLimitedToLast:0], @"Can't pass zero as limit");
  135. XCTAssertThrows([ref queryLimitedToFirst:0], @"Can't pass zero as limit");
  136. XCTAssertThrows([ref queryLimitedToLast:0], @"Can't pass zero as limit");
  137. uint64_t MAX_ALLOWED_VALUE = (uint64_t)(1l << 31) - 1;
  138. [ref queryLimitedToFirst:(NSUInteger)MAX_ALLOWED_VALUE];
  139. [ref queryLimitedToLast:(NSUInteger)MAX_ALLOWED_VALUE];
  140. XCTAssertThrows([ref queryLimitedToFirst:(NSUInteger)(MAX_ALLOWED_VALUE + 1)],
  141. @"Can't pass limits that don't fit into 32 bit signed integer range");
  142. XCTAssertThrows([ref queryLimitedToLast:(NSUInteger)(MAX_ALLOWED_VALUE + 1)],
  143. @"Can't pass limits that don't fit into 32 bit signed integer range");
  144. }
  145. - (void)testInvalidKeys {
  146. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  147. NSArray* badKeys = @[
  148. @".test", @"test.", @"fo$o", @"[what", @"ever]", @"ha#sh", @"/thing", @"th/ing", @"thing/"
  149. ];
  150. for (NSString* badKey in badKeys) {
  151. XCTAssertThrows([[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:badKey],
  152. @"Setting bad key");
  153. XCTAssertThrows([[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:badKey],
  154. @"Setting bad key");
  155. }
  156. }
  157. - (void)testOffCanBeCalledOnDefault {
  158. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  159. __block BOOL called = NO;
  160. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  161. [query observeEventType:FIRDataEventTypeValue
  162. withBlock:^(FIRDataSnapshot* snapshot) {
  163. if (called) {
  164. XCTFail(@"Should not be called twice");
  165. } else {
  166. called = YES;
  167. }
  168. }];
  169. [ref setValue:@{@"a" : @5, @"b" : @6}];
  170. [self waitUntil:^BOOL {
  171. return called;
  172. }];
  173. called = NO;
  174. [ref removeAllObservers];
  175. __block BOOL complete = NO;
  176. [ref setValue:@{@"a" : @6, @"b" : @7}
  177. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  178. complete = YES;
  179. }];
  180. [self waitUntil:^BOOL {
  181. return complete;
  182. }];
  183. XCTAssertFalse(called, @"Should not have been called again");
  184. }
  185. - (void)testOffCanBeCalledOnHandle {
  186. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  187. __block BOOL called = NO;
  188. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  189. FIRDatabaseHandle handle = [query observeEventType:FIRDataEventTypeValue
  190. withBlock:^(FIRDataSnapshot* snapshot) {
  191. if (called) {
  192. XCTFail(@"Should not be called twice");
  193. } else {
  194. called = YES;
  195. }
  196. }];
  197. [ref setValue:@{@"a" : @5, @"b" : @6}];
  198. [self waitUntil:^BOOL {
  199. return called;
  200. }];
  201. called = NO;
  202. [ref removeObserverWithHandle:handle];
  203. __block BOOL complete = NO;
  204. [ref setValue:@{@"a" : @6, @"b" : @7}
  205. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  206. complete = YES;
  207. }];
  208. [self waitUntil:^BOOL {
  209. return complete;
  210. }];
  211. XCTAssertFalse(called, @"Should not have been called again");
  212. }
  213. - (void)testOffCanBeCalledOnSpecificQuery {
  214. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  215. __block BOOL called = NO;
  216. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  217. FIRDatabaseHandle handle = [query observeEventType:FIRDataEventTypeValue
  218. withBlock:^(FIRDataSnapshot* snapshot) {
  219. if (called) {
  220. XCTFail(@"Should not be called twice");
  221. } else {
  222. called = YES;
  223. }
  224. }];
  225. [ref setValue:@{@"a" : @5, @"b" : @6}];
  226. [self waitUntil:^BOOL {
  227. return called;
  228. }];
  229. called = NO;
  230. [query removeObserverWithHandle:handle];
  231. __block BOOL complete = NO;
  232. [ref setValue:@{@"a" : @6, @"b" : @7}
  233. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  234. complete = YES;
  235. }];
  236. [self waitUntil:^BOOL {
  237. return complete;
  238. }];
  239. XCTAssertFalse(called, @"Should not have been called again");
  240. }
  241. - (void)testOffCanBeCalledOnMultipleQueries {
  242. FIRDatabaseQuery* query = [[FTestHelpers getRandomNode] queryLimitedToFirst:10];
  243. FIRDatabaseHandle handle1 = [query observeEventType:FIRDataEventTypeValue
  244. withBlock:^(FIRDataSnapshot* snapshot){
  245. }];
  246. FIRDatabaseHandle handle2 = [query observeEventType:FIRDataEventTypeValue
  247. withBlock:^(FIRDataSnapshot* snapshot){
  248. }];
  249. [query removeObserverWithHandle:handle1];
  250. [query removeObserverWithHandle:handle2];
  251. }
  252. - (void)testOffCanBeCalledWithoutHandle {
  253. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  254. __block BOOL called1 = NO;
  255. __block BOOL called2 = NO;
  256. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  257. [ref observeEventType:FIRDataEventTypeValue
  258. withBlock:^(FIRDataSnapshot* snapshot) {
  259. called1 = YES;
  260. }];
  261. [query observeEventType:FIRDataEventTypeValue
  262. withBlock:^(FIRDataSnapshot* snapshot) {
  263. called2 = YES;
  264. }];
  265. [ref setValue:@{@"a" : @5, @"b" : @6}];
  266. [self waitUntil:^BOOL {
  267. return called1 && called2;
  268. }];
  269. called1 = NO;
  270. called2 = NO;
  271. [ref removeAllObservers];
  272. __block BOOL complete = NO;
  273. [ref setValue:@{@"a" : @6, @"b" : @7}
  274. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  275. complete = YES;
  276. }];
  277. [self waitUntil:^BOOL {
  278. return complete;
  279. }];
  280. XCTAssertFalse(called1 || called2, @"Should not have called either callback");
  281. }
  282. - (void)testEnsureOnly5ItemsAreKept {
  283. __block FIRDataSnapshot* snap = nil;
  284. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  285. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  286. __block int count = 0;
  287. [query observeEventType:FIRDataEventTypeValue
  288. withBlock:^(FIRDataSnapshot* snapshot) {
  289. snap = snapshot;
  290. count++;
  291. }];
  292. [ref setValue:nil];
  293. for (int i = 0; i < 10; ++i) {
  294. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]];
  295. }
  296. [self waitUntil:^BOOL {
  297. // The initial set triggers the callback, so we need to wait for 11 events
  298. return count == 11;
  299. }];
  300. count = 5;
  301. for (FIRDataSnapshot* snapshot in snap.children) {
  302. NSNumber* num = [snapshot value];
  303. NSNumber* current = [NSNumber numberWithInt:count];
  304. XCTAssertTrue([num isEqualToNumber:current], @"Expect children in order");
  305. count++;
  306. }
  307. XCTAssertTrue(count == 10, @"Expected 5 children");
  308. }
  309. - (void)testOnlyLast5SentFromServer {
  310. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  311. __block int count = 0;
  312. [ref setValue:nil];
  313. for (int i = 0; i < 10; ++i) {
  314. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]
  315. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  316. count++;
  317. }];
  318. }
  319. [self waitUntil:^BOOL {
  320. return count == 10;
  321. }];
  322. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  323. count = 5;
  324. [query observeEventType:FIRDataEventTypeValue
  325. withBlock:^(FIRDataSnapshot* snapshot) {
  326. for (FIRDataSnapshot* child in snapshot.children) {
  327. NSNumber* num = [child value];
  328. NSNumber* current = [NSNumber numberWithInt:count];
  329. XCTAssertTrue([num isEqualToNumber:current], @"Expect children to be in order");
  330. count++;
  331. }
  332. }];
  333. [self waitUntil:^BOOL {
  334. return count == 10;
  335. }];
  336. }
  337. - (void)testVariousLimits {
  338. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  339. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  340. [expectations addQuery:[ref queryLimitedToLast:1] withExpectation:@{@"c" : @3}];
  341. [expectations
  342. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:1]
  343. withExpectation:@{@"c" : @3}];
  344. [expectations
  345. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:2]
  346. withExpectation:@{@"b" : @2, @"c" : @3}];
  347. [expectations
  348. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:3]
  349. withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3}];
  350. [expectations
  351. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:4]
  352. withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3}];
  353. __block BOOL ready = NO;
  354. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  355. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  356. ready = YES;
  357. }];
  358. [self waitUntil:^BOOL {
  359. return ready;
  360. }];
  361. [expectations validate];
  362. }
  363. - (void)testSetLimitsWithStartAt {
  364. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  365. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  366. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil]
  367. queryLimitedToFirst:1]
  368. withExpectation:@{@"a" : @1}];
  369. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"c"]
  370. queryLimitedToFirst:1]
  371. withExpectation:@{@"c" : @3}];
  372. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  373. queryLimitedToFirst:1]
  374. withExpectation:@{@"b" : @2}];
  375. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  376. queryLimitedToFirst:2]
  377. withExpectation:@{@"b" : @2, @"c" : @3}];
  378. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  379. queryLimitedToFirst:3]
  380. withExpectation:@{@"b" : @2, @"c" : @3}];
  381. __block BOOL ready = NO;
  382. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  383. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  384. ready = YES;
  385. }];
  386. [self waitUntil:^BOOL {
  387. return ready;
  388. }];
  389. [expectations validate];
  390. }
  391. - (void)testLimitsAndStartAtWithServerData {
  392. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  393. __block BOOL ready = NO;
  394. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  395. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  396. ready = YES;
  397. }];
  398. [self waitUntil:^BOOL {
  399. return ready;
  400. }];
  401. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  402. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil]
  403. queryLimitedToFirst:1]
  404. withExpectation:@{@"a" : @1}];
  405. /*params = [[FQueryParams alloc] init];
  406. params = [params setStartPriority:nil andName:@"c"];
  407. params = [params limitTo:1];
  408. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"c": @3}];
  409. params = [[FQueryParams alloc] init];
  410. params = [params setStartPriority:nil andName:@"b"];
  411. params = [params limitTo:1];
  412. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2}];
  413. params = [[FQueryParams alloc] init];
  414. params = [params setStartPriority:nil andName:@"b"];
  415. params = [params limitTo:2];
  416. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2, @"c": @3}];
  417. params = [[FQueryParams alloc] init];
  418. params = [params setStartPriority:nil andName:@"b"];
  419. params = [params limitTo:3];
  420. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2, @"c": @3}];*/
  421. [self waitUntil:^BOOL {
  422. return expectations.isReady;
  423. }];
  424. [expectations validate];
  425. [ref removeAllObservers];
  426. }
  427. - (void)testChildEventsAreFiredWhenLimitIsHit {
  428. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  429. NSMutableArray* added = [[NSMutableArray alloc] init];
  430. NSMutableArray* removed = [[NSMutableArray alloc] init];
  431. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded
  432. withBlock:^(FIRDataSnapshot* snapshot) {
  433. [added addObject:[snapshot key]];
  434. }];
  435. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildRemoved
  436. withBlock:^(FIRDataSnapshot* snapshot) {
  437. [removed addObject:[snapshot key]];
  438. }];
  439. __block BOOL ready = NO;
  440. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  441. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  442. ready = YES;
  443. }];
  444. [self waitUntil:^BOOL {
  445. return ready;
  446. }];
  447. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  448. NSArray* expected = @[ @"b", @"c" ];
  449. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  450. [added removeAllObjects];
  451. ready = NO;
  452. [[ref child:@"d"] setValue:@4
  453. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  454. ready = YES;
  455. }];
  456. [self waitUntil:^BOOL {
  457. return ready;
  458. }];
  459. expected = @[ @"b" ];
  460. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  461. expected = @[ @"d" ];
  462. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add d");
  463. [ref removeAllObservers];
  464. }
  465. - (void)testChildEventsAreFiredWhenLimitIsHitWithServerData {
  466. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  467. __block BOOL ready = NO;
  468. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  469. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  470. ready = YES;
  471. }];
  472. [self waitUntil:^BOOL {
  473. return ready;
  474. }];
  475. NSMutableArray* added = [[NSMutableArray alloc] init];
  476. NSMutableArray* removed = [[NSMutableArray alloc] init];
  477. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  478. [query observeEventType:FIRDataEventTypeChildAdded
  479. withBlock:^(FIRDataSnapshot* snapshot) {
  480. [added addObject:[snapshot key]];
  481. }];
  482. [query observeEventType:FIRDataEventTypeChildRemoved
  483. withBlock:^(FIRDataSnapshot* snapshot) {
  484. [removed addObject:[snapshot key]];
  485. }];
  486. [self waitUntil:^BOOL {
  487. return [added count] == 2;
  488. }];
  489. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  490. NSArray* expected = @[ @"b", @"c" ];
  491. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  492. [added removeAllObjects];
  493. ready = NO;
  494. [[ref child:@"d"] setValue:@4
  495. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  496. ready = YES;
  497. }];
  498. [self waitUntil:^BOOL {
  499. return ready;
  500. }];
  501. expected = @[ @"b" ];
  502. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  503. expected = @[ @"d" ];
  504. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add d");
  505. [ref removeAllObservers];
  506. }
  507. - (void)testChildEventsAreFiredWhenLimitIsHitWithStart {
  508. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  509. FIRDatabaseQuery* query =
  510. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  511. NSMutableArray* added = [[NSMutableArray alloc] init];
  512. NSMutableArray* removed = [[NSMutableArray alloc] init];
  513. [query observeEventType:FIRDataEventTypeChildAdded
  514. withBlock:^(FIRDataSnapshot* snapshot) {
  515. [added addObject:[snapshot key]];
  516. }];
  517. [query observeEventType:FIRDataEventTypeChildRemoved
  518. withBlock:^(FIRDataSnapshot* snapshot) {
  519. [removed addObject:[snapshot key]];
  520. }];
  521. __block BOOL ready = NO;
  522. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  523. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  524. ready = YES;
  525. }];
  526. [self waitUntil:^BOOL {
  527. return ready;
  528. }];
  529. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  530. NSArray* expected = @[ @"a", @"b" ];
  531. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  532. [added removeAllObjects];
  533. ready = NO;
  534. [[ref child:@"aa"] setValue:@4
  535. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  536. ready = YES;
  537. }];
  538. [self waitUntil:^BOOL {
  539. return ready;
  540. }];
  541. expected = @[ @"b" ];
  542. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  543. expected = @[ @"aa" ];
  544. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add aa");
  545. [ref removeAllObservers];
  546. }
  547. - (void)testChildEventsAreFiredWhenLimitIsHitWithStartAndServerData {
  548. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  549. __block BOOL ready = NO;
  550. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  551. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  552. ready = YES;
  553. }];
  554. [self waitUntil:^BOOL {
  555. return ready;
  556. }];
  557. FIRDatabaseQuery* query =
  558. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  559. NSMutableArray* added = [[NSMutableArray alloc] init];
  560. NSMutableArray* removed = [[NSMutableArray alloc] init];
  561. [query observeEventType:FIRDataEventTypeChildAdded
  562. withBlock:^(FIRDataSnapshot* snapshot) {
  563. [added addObject:[snapshot key]];
  564. }];
  565. [query observeEventType:FIRDataEventTypeChildRemoved
  566. withBlock:^(FIRDataSnapshot* snapshot) {
  567. [removed addObject:[snapshot key]];
  568. }];
  569. [self waitUntil:^BOOL {
  570. return [added count] == 2;
  571. }];
  572. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  573. NSArray* expected = @[ @"a", @"b" ];
  574. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  575. [added removeAllObjects];
  576. ready = NO;
  577. [[ref child:@"aa"] setValue:@4
  578. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  579. ready = YES;
  580. }];
  581. [self waitUntil:^BOOL {
  582. return ready;
  583. }];
  584. expected = @[ @"b" ];
  585. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  586. expected = @[ @"aa" ];
  587. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add aa");
  588. [ref removeAllObservers];
  589. }
  590. - (void)testStartAndLimitWithIncompleteWindow {
  591. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  592. FIRDatabaseQuery* query =
  593. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  594. NSMutableArray* added = [[NSMutableArray alloc] init];
  595. NSMutableArray* removed = [[NSMutableArray alloc] init];
  596. [query observeEventType:FIRDataEventTypeChildAdded
  597. withBlock:^(FIRDataSnapshot* snapshot) {
  598. [added addObject:[snapshot key]];
  599. }];
  600. [query observeEventType:FIRDataEventTypeChildRemoved
  601. withBlock:^(FIRDataSnapshot* snapshot) {
  602. [removed addObject:[snapshot key]];
  603. }];
  604. __block BOOL ready = NO;
  605. [ref setValue:@{@"c" : @3}
  606. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  607. ready = YES;
  608. }];
  609. [self waitUntil:^BOOL {
  610. return ready && [added count] >= 1;
  611. }];
  612. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  613. NSArray* expected = @[ @"c" ];
  614. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  615. [added removeAllObjects];
  616. ready = NO;
  617. [[ref child:@"b"] setValue:@4
  618. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  619. ready = YES;
  620. }];
  621. [self waitUntil:^BOOL {
  622. return ready;
  623. }];
  624. XCTAssertTrue([removed count] == 0, @"Expected to remove nothing");
  625. expected = @[ @"b" ];
  626. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add b");
  627. [ref removeAllObservers];
  628. }
  629. - (void)testStartAndLimitWithIncompleteWindowAndServerData {
  630. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  631. __block BOOL ready = NO;
  632. [ref setValue:@{@"c" : @3}
  633. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  634. ready = YES;
  635. }];
  636. [self waitUntil:^BOOL {
  637. return ready;
  638. }];
  639. FIRDatabaseQuery* query =
  640. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  641. NSMutableArray* added = [[NSMutableArray alloc] init];
  642. NSMutableArray* removed = [[NSMutableArray alloc] init];
  643. [query observeEventType:FIRDataEventTypeChildAdded
  644. withBlock:^(FIRDataSnapshot* snapshot) {
  645. [added addObject:[snapshot key]];
  646. }];
  647. [query observeEventType:FIRDataEventTypeChildRemoved
  648. withBlock:^(FIRDataSnapshot* snapshot) {
  649. [removed addObject:[snapshot key]];
  650. }];
  651. [self waitUntil:^BOOL {
  652. return [added count] == 1;
  653. }];
  654. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  655. NSArray* expected = @[ @"c" ];
  656. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  657. [added removeAllObjects];
  658. ready = NO;
  659. [[ref child:@"b"] setValue:@4
  660. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  661. ready = YES;
  662. }];
  663. [self waitUntil:^BOOL {
  664. return ready;
  665. }];
  666. XCTAssertTrue([removed count] == 0, @"Expected to remove nothing");
  667. expected = @[ @"b" ];
  668. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add b");
  669. [ref removeAllObservers];
  670. }
  671. - (void)testChildEventsFiredWhenItemDeleted {
  672. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  673. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  674. NSMutableArray* added = [[NSMutableArray alloc] init];
  675. NSMutableArray* removed = [[NSMutableArray alloc] init];
  676. [query observeEventType:FIRDataEventTypeChildAdded
  677. withBlock:^(FIRDataSnapshot* snapshot) {
  678. [added addObject:[snapshot key]];
  679. }];
  680. [query observeEventType:FIRDataEventTypeChildRemoved
  681. withBlock:^(FIRDataSnapshot* snapshot) {
  682. [removed addObject:[snapshot key]];
  683. }];
  684. __block BOOL ready = NO;
  685. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  686. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  687. ready = YES;
  688. }];
  689. [self waitUntil:^BOOL {
  690. return ready && [added count] >= 1;
  691. }];
  692. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  693. NSArray* expected = @[ @"b", @"c" ];
  694. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  695. [added removeAllObjects];
  696. ready = NO;
  697. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  698. ready = YES;
  699. }];
  700. [self waitUntil:^BOOL {
  701. return ready;
  702. }];
  703. expected = @[ @"b" ];
  704. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  705. expected = @[ @"a" ];
  706. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add a");
  707. [ref removeAllObservers];
  708. }
  709. - (void)testChildEventsAreFiredWhenItemDeletedAtServer {
  710. FIRDatabaseReference* ref = [FTestHelpers getRandomNodeWithoutPersistence];
  711. __block BOOL ready = NO;
  712. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  713. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  714. ready = YES;
  715. }];
  716. [self waitUntil:^BOOL {
  717. return ready;
  718. }];
  719. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  720. NSMutableArray* added = [[NSMutableArray alloc] init];
  721. NSMutableArray* removed = [[NSMutableArray alloc] init];
  722. [query observeEventType:FIRDataEventTypeChildAdded
  723. withBlock:^(FIRDataSnapshot* snapshot) {
  724. [added addObject:[snapshot key]];
  725. }];
  726. [query observeEventType:FIRDataEventTypeChildRemoved
  727. withBlock:^(FIRDataSnapshot* snapshot) {
  728. [removed addObject:[snapshot key]];
  729. }];
  730. [self waitUntil:^BOOL {
  731. return [added count] == 2;
  732. }];
  733. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  734. NSArray* expected = @[ @"b", @"c" ];
  735. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  736. [added removeAllObjects];
  737. ready = NO;
  738. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  739. ready = YES;
  740. }];
  741. [self waitUntil:^BOOL {
  742. return ready;
  743. }];
  744. XCTAssertEqualObjects(removed, (@[ @"b" ]), @"Expected to remove b");
  745. XCTAssertEqualObjects(added, (@[ @"a" ]), @"Expected to add a");
  746. [ref removeAllObservers];
  747. }
  748. - (void)testRemoveFiredWhenItemDeleted {
  749. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  750. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  751. NSMutableArray* added = [[NSMutableArray alloc] init];
  752. NSMutableArray* removed = [[NSMutableArray alloc] init];
  753. [query observeEventType:FIRDataEventTypeChildAdded
  754. withBlock:^(FIRDataSnapshot* snapshot) {
  755. [added addObject:[snapshot key]];
  756. }];
  757. [query observeEventType:FIRDataEventTypeChildRemoved
  758. withBlock:^(FIRDataSnapshot* snapshot) {
  759. [removed addObject:[snapshot key]];
  760. }];
  761. __block BOOL ready = NO;
  762. [ref setValue:@{@"b" : @2, @"c" : @3}
  763. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  764. ready = YES;
  765. }];
  766. [self waitUntil:^BOOL {
  767. return ready && [added count] >= 1;
  768. }];
  769. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  770. NSArray* expected = @[ @"b", @"c" ];
  771. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  772. [added removeAllObjects];
  773. ready = NO;
  774. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  775. ready = YES;
  776. }];
  777. [self waitUntil:^BOOL {
  778. return ready;
  779. }];
  780. expected = @[ @"b" ];
  781. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  782. XCTAssertTrue([added count] == 0, @"Expected to add nothing");
  783. [ref removeAllObservers];
  784. }
  785. - (void)testRemoveFiredWhenItemDeletedAtServer {
  786. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  787. __block BOOL ready = NO;
  788. [ref setValue:@{@"b" : @2, @"c" : @3}
  789. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  790. ready = YES;
  791. }];
  792. [self waitUntil:^BOOL {
  793. return ready;
  794. }];
  795. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  796. NSMutableArray* added = [[NSMutableArray alloc] init];
  797. NSMutableArray* removed = [[NSMutableArray alloc] init];
  798. [query observeEventType:FIRDataEventTypeChildAdded
  799. withBlock:^(FIRDataSnapshot* snapshot) {
  800. [added addObject:[snapshot key]];
  801. }];
  802. [query observeEventType:FIRDataEventTypeChildRemoved
  803. withBlock:^(FIRDataSnapshot* snapshot) {
  804. [removed addObject:[snapshot key]];
  805. }];
  806. [self waitUntil:^BOOL {
  807. return [added count] == 2;
  808. }];
  809. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  810. NSArray* expected = @[ @"b", @"c" ];
  811. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  812. [added removeAllObjects];
  813. ready = NO;
  814. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  815. ready = YES;
  816. }];
  817. [self waitUntil:^BOOL {
  818. return ready;
  819. }];
  820. expected = @[ @"b" ];
  821. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  822. XCTAssertTrue([added count] == 0, @"Expected to add nothing");
  823. [ref removeAllObservers];
  824. }
  825. - (void)testStartAtPriorityAndEndAtPriorityWork {
  826. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  827. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  828. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  829. queryEndingAtValue:@"y"]
  830. withExpectation:@{@"b" : @2, @"c" : @3, @"d" : @4}];
  831. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  832. queryEndingAtValue:@"w"]
  833. withExpectation:@{@"d" : @4}];
  834. __block id nullSnap = @"dummy";
  835. [[[[ref queryOrderedByPriority] queryStartingAtValue:@"a"] queryEndingAtValue:@"c"]
  836. observeEventType:FIRDataEventTypeValue
  837. withBlock:^(FIRDataSnapshot* snapshot) {
  838. nullSnap = [snapshot value];
  839. }];
  840. [ref setValue:@{
  841. @"a" : @{@".value" : @1, @".priority" : @"z"},
  842. @"b" : @{@".value" : @2, @".priority" : @"y"},
  843. @"c" : @{@".value" : @3, @".priority" : @"x"},
  844. @"d" : @{@".value" : @4, @".priority" : @"w"}
  845. }];
  846. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  847. [expectations validate];
  848. }
  849. - (void)testStartAtPriorityAndEndAtPriorityWorkWithServerData {
  850. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  851. __block BOOL ready = NO;
  852. [ref setValue:@{
  853. @"a" : @{@".value" : @1, @".priority" : @"z"},
  854. @"b" : @{@".value" : @2, @".priority" : @"y"},
  855. @"c" : @{@".value" : @3, @".priority" : @"x"},
  856. @"d" : @{@".value" : @4, @".priority" : @"w"}
  857. }
  858. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  859. ready = YES;
  860. }];
  861. WAIT_FOR(ready);
  862. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  863. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  864. queryEndingAtValue:@"y"]
  865. withExpectation:@{@"b" : @2, @"c" : @3, @"d" : @4}];
  866. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  867. queryEndingAtValue:@"w"]
  868. withExpectation:@{@"d" : @4}];
  869. __block id nullSnap = @"dummy";
  870. [[[[ref queryOrderedByPriority] queryStartingAtValue:@"a"] queryEndingAtValue:@"c"]
  871. observeEventType:FIRDataEventTypeValue
  872. withBlock:^(FIRDataSnapshot* snapshot) {
  873. nullSnap = [snapshot value];
  874. }];
  875. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  876. [expectations validate];
  877. }
  878. - (void)testStartAtAndEndAtPriorityAndNameWork {
  879. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  880. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  881. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"a"]
  882. queryEndingAtValue:@2
  883. childKey:@"d"];
  884. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  885. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  886. childKey:@"b"] queryEndingAtValue:@2
  887. childKey:@"c"];
  888. [expectations addQuery:query withExpectation:@{@"b" : @2, @"c" : @3}];
  889. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  890. childKey:@"c"] queryEndingAtValue:@2];
  891. [expectations addQuery:query withExpectation:@{@"c" : @3, @"d" : @4}];
  892. [ref setValue:@{
  893. @"a" : @{@".value" : @1, @".priority" : @1},
  894. @"b" : @{@".value" : @2, @".priority" : @1},
  895. @"c" : @{@".value" : @3, @".priority" : @2},
  896. @"d" : @{@".value" : @4, @".priority" : @2}
  897. }];
  898. WAIT_FOR(expectations.isReady);
  899. [expectations validate];
  900. }
  901. - (void)testStartAtAndEndAtPriorityAndNameWorkWithServerData {
  902. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  903. __block BOOL ready = NO;
  904. [ref setValue:@{
  905. @"a" : @{@".value" : @1, @".priority" : @1},
  906. @"b" : @{@".value" : @2, @".priority" : @1},
  907. @"c" : @{@".value" : @3, @".priority" : @2},
  908. @"d" : @{@".value" : @4, @".priority" : @2}
  909. }
  910. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  911. ready = YES;
  912. }];
  913. WAIT_FOR(ready);
  914. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  915. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"a"]
  916. queryEndingAtValue:@2
  917. childKey:@"d"];
  918. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  919. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  920. childKey:@"b"] queryEndingAtValue:@2
  921. childKey:@"c"];
  922. [expectations addQuery:query withExpectation:@{@"b" : @2, @"c" : @3}];
  923. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  924. childKey:@"c"] queryEndingAtValue:@2];
  925. [expectations addQuery:query withExpectation:@{@"c" : @3, @"d" : @4}];
  926. WAIT_FOR(expectations.isReady);
  927. [expectations validate];
  928. }
  929. - (void)testStartAtAndEndAtPriorityAndNameWork2 {
  930. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  931. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  932. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"c"]
  933. queryEndingAtValue:@2
  934. childKey:@"b"];
  935. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  936. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  937. childKey:@"d"] queryEndingAtValue:@2
  938. childKey:@"a"];
  939. [expectations addQuery:query withExpectation:@{@"d" : @4, @"a" : @1}];
  940. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  941. childKey:@"e"] queryEndingAtValue:@2];
  942. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2}];
  943. [ref setValue:@{
  944. @"c" : @{@".value" : @3, @".priority" : @1},
  945. @"d" : @{@".value" : @4, @".priority" : @1},
  946. @"a" : @{@".value" : @1, @".priority" : @2},
  947. @"b" : @{@".value" : @2, @".priority" : @2}
  948. }];
  949. WAIT_FOR(expectations.isReady);
  950. [expectations validate];
  951. }
  952. - (void)testStartAtAndEndAtPriorityAndNameWorkWithServerData2 {
  953. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  954. __block BOOL ready = NO;
  955. [ref setValue:@{
  956. @"c" : @{@".value" : @3, @".priority" : @1},
  957. @"d" : @{@".value" : @4, @".priority" : @1},
  958. @"a" : @{@".value" : @1, @".priority" : @2},
  959. @"b" : @{@".value" : @2, @".priority" : @2}
  960. }
  961. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  962. ready = YES;
  963. }];
  964. WAIT_FOR(ready);
  965. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  966. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"c"]
  967. queryEndingAtValue:@2
  968. childKey:@"b"];
  969. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  970. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  971. childKey:@"d"] queryEndingAtValue:@2
  972. childKey:@"a"];
  973. [expectations addQuery:query withExpectation:@{@"d" : @4, @"a" : @1}];
  974. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  975. childKey:@"e"] queryEndingAtValue:@2];
  976. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2}];
  977. WAIT_FOR(expectations.isReady);
  978. [expectations validate];
  979. }
  980. - (void)testEqualToPriorityWorks {
  981. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  982. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  983. [expectations addQuery:[[ref queryOrderedByPriority] queryEqualToValue:@"w"]
  984. withExpectation:@{@"d" : @4}];
  985. __block id nullSnap = @"dummy";
  986. [[[ref queryOrderedByPriority] queryEqualToValue:@"c"]
  987. observeEventType:FIRDataEventTypeValue
  988. withBlock:^(FIRDataSnapshot* snapshot) {
  989. nullSnap = [snapshot value];
  990. }];
  991. [ref setValue:@{
  992. @"a" : @{@".value" : @1, @".priority" : @"z"},
  993. @"b" : @{@".value" : @2, @".priority" : @"y"},
  994. @"c" : @{@".value" : @3, @".priority" : @"x"},
  995. @"d" : @{@".value" : @4, @".priority" : @"w"}
  996. }];
  997. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  998. [expectations validate];
  999. }
  1000. - (void)testEqualToPriorityWorksWithServerData {
  1001. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1002. __block BOOL ready = NO;
  1003. [ref setValue:@{
  1004. @"a" : @{@".value" : @1, @".priority" : @"z"},
  1005. @"b" : @{@".value" : @2, @".priority" : @"y"},
  1006. @"c" : @{@".value" : @3, @".priority" : @"x"},
  1007. @"d" : @{@".value" : @4, @".priority" : @"w"}
  1008. }
  1009. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1010. ready = YES;
  1011. }];
  1012. WAIT_FOR(ready);
  1013. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1014. [expectations addQuery:[[ref queryOrderedByPriority] queryEqualToValue:@"w"]
  1015. withExpectation:@{@"d" : @4}];
  1016. __block id nullSnap = @"dummy";
  1017. [[[ref queryOrderedByPriority] queryEqualToValue:@"c"]
  1018. observeEventType:FIRDataEventTypeValue
  1019. withBlock:^(FIRDataSnapshot* snapshot) {
  1020. nullSnap = [snapshot value];
  1021. }];
  1022. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1023. [expectations validate];
  1024. }
  1025. - (void)testEqualToPriorityAndNameWorks {
  1026. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1027. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1028. FIRDatabaseQuery* query = [[ref queryOrderedByPriority] queryEqualToValue:@1 childKey:@"a"];
  1029. [expectations addQuery:query withExpectation:@{@"a" : @1}];
  1030. __block id nullSnap = @"dummy";
  1031. [[[ref queryOrderedByPriority] queryEqualToValue:@"1" childKey:@"z"]
  1032. observeEventType:FIRDataEventTypeValue
  1033. withBlock:^(FIRDataSnapshot* snapshot) {
  1034. nullSnap = [snapshot value];
  1035. }];
  1036. [ref setValue:@{
  1037. @"a" : @{@".value" : @1, @".priority" : @1},
  1038. @"b" : @{@".value" : @2, @".priority" : @1},
  1039. @"c" : @{@".value" : @3, @".priority" : @2},
  1040. @"d" : @{@".value" : @4, @".priority" : @2}
  1041. }];
  1042. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1043. [expectations validate];
  1044. }
  1045. - (void)testEqualToPriorityAndNameWorksWithServerData {
  1046. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1047. __block BOOL ready = NO;
  1048. [ref setValue:@{
  1049. @"a" : @{@".value" : @1, @".priority" : @1},
  1050. @"b" : @{@".value" : @2, @".priority" : @1},
  1051. @"c" : @{@".value" : @3, @".priority" : @2},
  1052. @"d" : @{@".value" : @4, @".priority" : @2}
  1053. }
  1054. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1055. ready = YES;
  1056. }];
  1057. WAIT_FOR(ready);
  1058. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1059. FIRDatabaseQuery* query = [[ref queryOrderedByPriority] queryEqualToValue:@1 childKey:@"a"];
  1060. [expectations addQuery:query withExpectation:@{@"a" : @1}];
  1061. __block id nullSnap = @"dummy";
  1062. [[[ref queryOrderedByPriority] queryEqualToValue:@"1" childKey:@"z"]
  1063. observeEventType:FIRDataEventTypeValue
  1064. withBlock:^(FIRDataSnapshot* snapshot) {
  1065. nullSnap = [snapshot value];
  1066. }];
  1067. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1068. [expectations validate];
  1069. }
  1070. - (void)testPrevNameWorks {
  1071. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1072. NSMutableArray* added = [[NSMutableArray alloc] init];
  1073. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded
  1074. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot* snapshot, NSString* prevName) {
  1075. [added addObject:snapshot.key];
  1076. if (prevName) {
  1077. [added addObject:prevName];
  1078. } else {
  1079. [added addObject:@"null"];
  1080. }
  1081. }];
  1082. [[ref child:@"a"] setValue:@1];
  1083. [self waitUntil:^BOOL {
  1084. NSArray* expected = @[ @"a", @"null" ];
  1085. return [added isEqualToArray:expected];
  1086. }];
  1087. [added removeAllObjects];
  1088. [[ref child:@"c"] setValue:@3];
  1089. [self waitUntil:^BOOL {
  1090. NSArray* expected = @[ @"c", @"a" ];
  1091. return [added isEqualToArray:expected];
  1092. }];
  1093. [added removeAllObjects];
  1094. [[ref child:@"b"] setValue:@2];
  1095. [self waitUntil:^BOOL {
  1096. NSArray* expected = @[ @"b", @"null" ];
  1097. return [added isEqualToArray:expected];
  1098. }];
  1099. [added removeAllObjects];
  1100. [[ref child:@"d"] setValue:@3];
  1101. [self waitUntil:^BOOL {
  1102. NSArray* expected = @[ @"d", @"c" ];
  1103. return [added isEqualToArray:expected];
  1104. }];
  1105. }
  1106. // Dropping some of the server data tests here, around prevName. They don't really test anything
  1107. // new, and mostly don't even test server data
  1108. - (void)testPrevNameWorksWithMoves {
  1109. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1110. NSMutableArray* moved = [[NSMutableArray alloc] init];
  1111. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildMoved
  1112. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot* snapshot, NSString* prevName) {
  1113. [moved addObject:snapshot.key];
  1114. if (prevName) {
  1115. [moved addObject:prevName];
  1116. } else {
  1117. [moved addObject:@"null"];
  1118. }
  1119. }];
  1120. [ref setValue:@{
  1121. @"a" : @{@".value" : @"a", @".priority" : @10},
  1122. @"b" : @{@".value" : @"b", @".priority" : @20},
  1123. @"c" : @{@".value" : @"c", @".priority" : @30},
  1124. @"d" : @{@".value" : @"d", @".priority" : @40}
  1125. }];
  1126. __block BOOL ready = NO;
  1127. [[ref child:@"c"] setPriority:@50
  1128. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1129. ready = YES;
  1130. }];
  1131. [self waitUntil:^BOOL {
  1132. return ready;
  1133. }];
  1134. NSArray* expected = @[ @"c", @"d" ];
  1135. XCTAssertTrue([moved isEqualToArray:expected], @"Expected changed node and prevChild");
  1136. [moved removeAllObjects];
  1137. ready = NO;
  1138. [[ref child:@"c"] setPriority:@35
  1139. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1140. ready = YES;
  1141. }];
  1142. [self waitUntil:^BOOL {
  1143. return ready;
  1144. }];
  1145. expected = @[ @"c", @"null" ];
  1146. XCTAssertTrue([moved isEqualToArray:expected], @"Expected changed node and prevChild");
  1147. [moved removeAllObjects];
  1148. ready = NO;
  1149. [[ref child:@"b"] setPriority:@33
  1150. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1151. ready = YES;
  1152. }];
  1153. [self waitUntil:^BOOL {
  1154. return ready;
  1155. }];
  1156. expected = @[];
  1157. XCTAssertTrue([moved isEqualToArray:expected],
  1158. @"Expected changed node and prevChild to be empty");
  1159. }
  1160. - (void)testLocalEvents {
  1161. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1162. NSMutableArray* events = [[NSMutableArray alloc] init];
  1163. [[ref queryLimitedToLast:2]
  1164. observeEventType:FIRDataEventTypeChildAdded
  1165. withBlock:^(FIRDataSnapshot* snapshot) {
  1166. NSString* eventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1167. [events addObject:eventString];
  1168. }];
  1169. [[ref queryLimitedToLast:2]
  1170. observeEventType:FIRDataEventTypeChildRemoved
  1171. withBlock:^(FIRDataSnapshot* snapshot) {
  1172. NSString* eventString = [NSString stringWithFormat:@"%@ removed", [snapshot value]];
  1173. [events addObject:eventString];
  1174. }];
  1175. __block BOOL ready = NO;
  1176. for (int i = 0; i < 5; ++i) {
  1177. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]
  1178. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1179. if (i == 4) {
  1180. ready = YES;
  1181. }
  1182. }];
  1183. }
  1184. [self waitUntil:^BOOL {
  1185. return ready;
  1186. }];
  1187. NSArray* expected = @[
  1188. @"0 added", @"1 added", @"0 removed", @"2 added", @"1 removed", @"3 added", @"2 removed",
  1189. @"4 added"
  1190. ];
  1191. XCTAssertTrue([events isEqualToArray:expected], @"Expecting window to stay at two nodes");
  1192. }
  1193. - (void)testRemoteEvents {
  1194. FTupleFirebase* pair = [FTestHelpers getRandomNodePair];
  1195. FIRDatabaseReference* writer = pair.one;
  1196. FIRDatabaseReference* reader = pair.two;
  1197. NSMutableArray* events = [[NSMutableArray alloc] init];
  1198. [[reader queryLimitedToLast:2]
  1199. observeEventType:FIRDataEventTypeChildAdded
  1200. withBlock:^(FIRDataSnapshot* snapshot) {
  1201. NSString* eventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1202. [events addObject:eventString];
  1203. }];
  1204. [[reader queryLimitedToLast:2]
  1205. observeEventType:FIRDataEventTypeChildRemoved
  1206. withBlock:^(FIRDataSnapshot* snapshot) {
  1207. NSString* oldEventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1208. [events removeObject:oldEventString];
  1209. }];
  1210. for (int i = 0; i < 5; ++i) {
  1211. [[writer childByAutoId] setValue:[NSNumber numberWithInt:i]];
  1212. }
  1213. NSArray* expected = @[ @"3 added", @"4 added" ];
  1214. [self waitUntil:^BOOL {
  1215. return [events isEqualToArray:expected];
  1216. }];
  1217. }
  1218. - (void)testLimitOnEmptyNodeFiresValue {
  1219. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1220. __block BOOL ready = NO;
  1221. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1222. withBlock:^(FIRDataSnapshot* snapshot) {
  1223. ready = YES;
  1224. }];
  1225. [self waitUntil:^BOOL {
  1226. return ready;
  1227. }];
  1228. }
  1229. - (void)testFilteringToNullPriorities {
  1230. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1231. // Note: cannot set nil in a dictionary, just leave out priority
  1232. [ref setValue:@{
  1233. @"a" : @0,
  1234. @"b" : @1,
  1235. @"c" : @{@".priority" : @2, @".value" : @2},
  1236. @"d" : @{@".priority" : @3, @".value" : @3},
  1237. @"e" : @{@".priority" : @"hi", @".value" : @4}
  1238. }];
  1239. __block BOOL ready = NO;
  1240. [[[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryEndingAtValue:nil]
  1241. observeEventType:FIRDataEventTypeValue
  1242. withBlock:^(FIRDataSnapshot* snapshot) {
  1243. NSDictionary* expected = @{@"a" : @0, @"b" : @1};
  1244. NSDictionary* val = [snapshot value];
  1245. XCTAssertTrue([val isEqualToDictionary:expected],
  1246. @"Expected only null priority keys");
  1247. ready = YES;
  1248. }];
  1249. [self waitUntil:^BOOL {
  1250. return ready;
  1251. }];
  1252. }
  1253. - (void)testNullPrioritiesIncludedInEndAt {
  1254. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1255. // Note: cannot set nil in a dictionary, just leave out priority
  1256. [ref setValue:@{
  1257. @"a" : @0,
  1258. @"b" : @1,
  1259. @"c" : @{@".priority" : @2, @".value" : @2},
  1260. @"d" : @{@".priority" : @3, @".value" : @3},
  1261. @"e" : @{@".priority" : @"hi", @".value" : @4}
  1262. }];
  1263. __block BOOL ready = NO;
  1264. [[[ref queryOrderedByPriority] queryEndingAtValue:@2]
  1265. observeEventType:FIRDataEventTypeValue
  1266. withBlock:^(FIRDataSnapshot* snapshot) {
  1267. NSDictionary* expected = @{@"a" : @0, @"b" : @1, @"c" : @2};
  1268. NSDictionary* val = [snapshot value];
  1269. XCTAssertTrue([val isEqualToDictionary:expected], @"Expected up to priority 2");
  1270. ready = YES;
  1271. }];
  1272. [self waitUntil:^BOOL {
  1273. return ready;
  1274. }];
  1275. }
  1276. - (NSSet*)dumpListensForRef:(FIRDatabaseReference*)ref {
  1277. NSMutableSet* dumpPieces = [[NSMutableSet alloc] init];
  1278. NSDictionary* listens = [ref.repo dumpListens];
  1279. FPath* nodePath = ref.path;
  1280. [listens enumerateKeysAndObjectsUsingBlock:^(FQuerySpec* spec, id obj, BOOL* stop) {
  1281. if ([nodePath contains:spec.path]) {
  1282. FPath* relative = [FPath relativePathFrom:nodePath to:spec.path];
  1283. [dumpPieces addObject:[[FQuerySpec alloc] initWithPath:relative params:spec.params]];
  1284. }
  1285. }];
  1286. return dumpPieces;
  1287. }
  1288. - (NSSet*)expectDefaultListenerAtPath:(FPath*)path {
  1289. return [self expectParams:[FQueryParams defaultInstance] atPath:path];
  1290. }
  1291. - (NSSet*)expectParamssetValue:(NSSet*)paramsSet atPath:(FPath*)path {
  1292. NSMutableSet* all = [NSMutableSet set];
  1293. [paramsSet enumerateObjectsUsingBlock:^(FQueryParams* params, BOOL* stop) {
  1294. [all addObject:[[FQuerySpec alloc] initWithPath:path params:params]];
  1295. }];
  1296. return all;
  1297. }
  1298. - (NSSet*)expectParams:(FQueryParams*)params atPath:(FPath*)path {
  1299. return [self expectParamssetValue:[NSSet setWithObject:params] atPath:path];
  1300. }
  1301. - (void)testDedupesListensOnChild {
  1302. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1303. __block NSSet* listens = [self dumpListensForRef:ref];
  1304. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1305. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1306. withBlock:^(FIRDataSnapshot* snapshot){
  1307. }];
  1308. __block BOOL ready = NO;
  1309. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1310. listens = [self dumpListensForRef:ref];
  1311. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"a")]];
  1312. XCTAssertTrue([expected isEqualToSet:listens], @"Expected child listener");
  1313. ready = YES;
  1314. });
  1315. [self waitUntil:^BOOL {
  1316. return ready;
  1317. }];
  1318. [ref observeEventType:FIRDataEventTypeValue
  1319. withBlock:^(FIRDataSnapshot* snapshot){
  1320. }];
  1321. ready = NO;
  1322. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1323. listens = [self dumpListensForRef:ref];
  1324. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"")]];
  1325. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener");
  1326. ready = YES;
  1327. });
  1328. [self waitUntil:^BOOL {
  1329. return ready;
  1330. }];
  1331. [ref removeAllObservers];
  1332. ready = NO;
  1333. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1334. listens = [self dumpListensForRef:ref];
  1335. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"a")]];
  1336. XCTAssertTrue([expected isEqualToSet:listens], @"Child listener should be back");
  1337. ready = YES;
  1338. });
  1339. [self waitUntil:^BOOL {
  1340. return ready;
  1341. }];
  1342. [[ref child:@"a"] removeAllObservers];
  1343. ready = NO;
  1344. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1345. listens = [self dumpListensForRef:ref];
  1346. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1347. ready = YES;
  1348. });
  1349. [self waitUntil:^BOOL {
  1350. return ready;
  1351. }];
  1352. }
  1353. - (void)testDedupeListensOnGrandchild {
  1354. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1355. __block NSSet* listens;
  1356. __block BOOL ready = NO;
  1357. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1358. listens = [self dumpListensForRef:ref];
  1359. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1360. ready = YES;
  1361. });
  1362. WAIT_FOR(ready);
  1363. [ref observeEventType:FIRDataEventTypeValue
  1364. withBlock:^(FIRDataSnapshot* snapshot){
  1365. }];
  1366. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1367. listens = [self dumpListensForRef:ref];
  1368. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1369. XCTAssertTrue([expected isEqualToSet:listens], @"Expected one listener");
  1370. ready = YES;
  1371. });
  1372. WAIT_FOR(ready);
  1373. [[ref child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  1374. withBlock:^(FIRDataSnapshot* snapshot){
  1375. }];
  1376. ready = NO;
  1377. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1378. listens = [self dumpListensForRef:ref];
  1379. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1380. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener to override");
  1381. ready = YES;
  1382. });
  1383. WAIT_FOR(ready);
  1384. [ref removeAllObservers];
  1385. [[ref child:@"a/aa"] removeAllObservers];
  1386. ready = NO;
  1387. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1388. listens = [self dumpListensForRef:ref];
  1389. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1390. ready = YES;
  1391. });
  1392. WAIT_FOR(ready);
  1393. }
  1394. - (void)testListenOnGrandparentOfTwoChildren {
  1395. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1396. __block NSSet* listens = [self dumpListensForRef:ref];
  1397. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1398. [[ref child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  1399. withBlock:^(FIRDataSnapshot* snapshot){
  1400. }];
  1401. __block BOOL ready = NO;
  1402. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1403. listens = [self dumpListensForRef:ref];
  1404. NSSet* expected = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1405. XCTAssertTrue([expected isEqualToSet:listens], @"Expected grandchild");
  1406. ready = YES;
  1407. });
  1408. [self waitUntil:^BOOL {
  1409. return ready;
  1410. }];
  1411. [[ref child:@"a/bb"] observeEventType:FIRDataEventTypeValue
  1412. withBlock:^(FIRDataSnapshot* snapshot){
  1413. }];
  1414. ready = NO;
  1415. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1416. listens = [self dumpListensForRef:ref];
  1417. NSSet* expecteda = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1418. NSSet* expectedb = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1419. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1420. [expected unionSet:expectedb];
  1421. XCTAssertTrue([expected isEqualToSet:listens], @"Expected two grandchildren");
  1422. ready = YES;
  1423. });
  1424. [self waitUntil:^BOOL {
  1425. return ready;
  1426. }];
  1427. [ref observeEventType:FIRDataEventTypeValue
  1428. withBlock:^(FIRDataSnapshot* snapshot){
  1429. }];
  1430. ready = NO;
  1431. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1432. listens = [self dumpListensForRef:ref];
  1433. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1434. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener to override");
  1435. ready = YES;
  1436. });
  1437. [self waitUntil:^BOOL {
  1438. return ready;
  1439. }];
  1440. [ref removeAllObservers];
  1441. ready = NO;
  1442. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1443. listens = [self dumpListensForRef:ref];
  1444. NSSet* expecteda = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1445. NSSet* expectedb = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1446. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1447. [expected unionSet:expectedb];
  1448. XCTAssertTrue([expected isEqualToSet:listens], @"Expected grandchild listeners to return");
  1449. ready = YES;
  1450. });
  1451. [self waitUntil:^BOOL {
  1452. return ready;
  1453. }];
  1454. [[ref child:@"a/aa"] removeAllObservers];
  1455. ready = NO;
  1456. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1457. listens = [self dumpListensForRef:ref];
  1458. NSSet* expected = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1459. XCTAssertTrue([expected isEqualToSet:listens], @"Expected one listener");
  1460. ready = YES;
  1461. });
  1462. [self waitUntil:^BOOL {
  1463. return ready;
  1464. }];
  1465. [[ref child:@"a/bb"] removeAllObservers];
  1466. ready = NO;
  1467. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1468. listens = [self dumpListensForRef:ref];
  1469. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1470. ready = YES;
  1471. });
  1472. [self waitUntil:^BOOL {
  1473. return ready;
  1474. }];
  1475. }
  1476. - (void)testDedupingMultipleListenQueries {
  1477. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1478. __block NSSet* listens = [self dumpListensForRef:ref];
  1479. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1480. __block BOOL ready = NO;
  1481. FIRDatabaseQuery* aLim1 = [[ref child:@"a"] queryLimitedToLast:1];
  1482. FIRDatabaseHandle handle1 = [aLim1 observeEventType:FIRDataEventTypeValue
  1483. withBlock:^(FIRDataSnapshot* snapshot){
  1484. }];
  1485. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1486. listens = [self dumpListensForRef:ref];
  1487. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1488. expectedParams = [expectedParams limitTo:1];
  1489. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1490. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1491. ready = YES;
  1492. });
  1493. [self waitUntil:^BOOL {
  1494. return ready;
  1495. }];
  1496. ready = NO;
  1497. FIRDatabaseQuery* rootLim1 = [ref queryLimitedToLast:1];
  1498. FIRDatabaseHandle handle2 = [rootLim1 observeEventType:FIRDataEventTypeValue
  1499. withBlock:^(FIRDataSnapshot* snapshot){
  1500. }];
  1501. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1502. listens = [self dumpListensForRef:ref];
  1503. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1504. expectedParams = [expectedParams limitTo:1];
  1505. NSSet* rootExpected = [self expectParams:expectedParams atPath:[FPath empty]];
  1506. NSSet* childExpected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1507. NSMutableSet* expected = [NSMutableSet setWithSet:rootExpected];
  1508. [expected unionSet:childExpected];
  1509. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1510. ready = YES;
  1511. });
  1512. [self waitUntil:^BOOL {
  1513. return ready;
  1514. }];
  1515. ready = NO;
  1516. FIRDatabaseQuery* aLim5 = [[ref child:@"a"] queryLimitedToLast:5];
  1517. FIRDatabaseHandle handle3 = [aLim5 observeEventType:FIRDataEventTypeValue
  1518. withBlock:^(FIRDataSnapshot* snapshot){
  1519. }];
  1520. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1521. listens = [self dumpListensForRef:ref];
  1522. FQueryParams* expectedParams1 = [[FQueryParams alloc] init];
  1523. expectedParams1 = [expectedParams1 limitTo:1];
  1524. NSSet* rootExpected = [self expectParams:expectedParams1 atPath:[FPath empty]];
  1525. FQueryParams* expectedParams2 = [[FQueryParams alloc] init];
  1526. expectedParams2 = [expectedParams2 limitTo:5];
  1527. NSSet* childExpected =
  1528. [self expectParamssetValue:[NSSet setWithObjects:expectedParams1, expectedParams2, nil]
  1529. atPath:[FPath pathWithString:@"/a"]];
  1530. NSMutableSet* expected = [NSMutableSet setWithSet:childExpected];
  1531. [expected unionSet:rootExpected];
  1532. XCTAssertTrue([expected isEqualToSet:listens], @"Three queries");
  1533. ready = YES;
  1534. });
  1535. [self waitUntil:^BOOL {
  1536. return ready;
  1537. }];
  1538. [ref removeObserverWithHandle:handle2];
  1539. ready = NO;
  1540. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1541. listens = [self dumpListensForRef:ref];
  1542. FQueryParams* expectedParams1 = [[FQueryParams alloc] init];
  1543. expectedParams1 = [expectedParams1 limitTo:1];
  1544. FQueryParams* expectedParams2 = [[FQueryParams alloc] init];
  1545. expectedParams2 = [expectedParams2 limitTo:5];
  1546. NSSet* expected =
  1547. [self expectParamssetValue:[NSSet setWithObjects:expectedParams1, expectedParams2, nil]
  1548. atPath:[FPath pathWithString:@"/a"]];
  1549. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1550. ready = YES;
  1551. });
  1552. [self waitUntil:^BOOL {
  1553. return ready;
  1554. }];
  1555. [aLim1 removeObserverWithHandle:handle1];
  1556. [aLim5 removeObserverWithHandle:handle3];
  1557. ready = NO;
  1558. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1559. listens = [self dumpListensForRef:ref];
  1560. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1561. ready = YES;
  1562. });
  1563. [self waitUntil:^BOOL {
  1564. return ready;
  1565. }];
  1566. }
  1567. - (void)testListenOnParentOfQueriedChildren {
  1568. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1569. __block NSSet* listens = [self dumpListensForRef:ref];
  1570. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1571. __block BOOL ready = NO;
  1572. FIRDatabaseQuery* aLim1 = [[ref child:@"a"] queryLimitedToLast:1];
  1573. FIRDatabaseHandle handle1 = [aLim1 observeEventType:FIRDataEventTypeValue
  1574. withBlock:^(FIRDataSnapshot* snapshot){
  1575. }];
  1576. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1577. listens = [self dumpListensForRef:ref];
  1578. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1579. expectedParams = [expectedParams limitTo:1];
  1580. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1581. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1582. ready = YES;
  1583. });
  1584. [self waitUntil:^BOOL {
  1585. return ready;
  1586. }];
  1587. ready = NO;
  1588. FIRDatabaseQuery* bLim1 = [[ref child:@"b"] queryLimitedToLast:1];
  1589. FIRDatabaseHandle handle2 = [bLim1 observeEventType:FIRDataEventTypeValue
  1590. withBlock:^(FIRDataSnapshot* snapshot){
  1591. }];
  1592. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1593. listens = [self dumpListensForRef:ref];
  1594. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1595. expectedParams = [expectedParams limitTo:1];
  1596. NSSet* expecteda = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1597. NSSet* expectedb = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/b"]];
  1598. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1599. [expected unionSet:expectedb];
  1600. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1601. ready = YES;
  1602. });
  1603. [self waitUntil:^BOOL {
  1604. return ready;
  1605. }];
  1606. ready = NO;
  1607. FIRDatabaseHandle handle3 = [ref observeEventType:FIRDataEventTypeValue
  1608. withBlock:^(FIRDataSnapshot* snapshot){
  1609. }];
  1610. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1611. listens = [self dumpListensForRef:ref];
  1612. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1613. XCTAssertTrue([expected isEqualToSet:listens], @"Parent should override");
  1614. ready = YES;
  1615. });
  1616. [self waitUntil:^BOOL {
  1617. return ready;
  1618. }];
  1619. // remove in slightly random order
  1620. [aLim1 removeObserverWithHandle:handle1];
  1621. ready = NO;
  1622. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1623. listens = [self dumpListensForRef:ref];
  1624. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1625. XCTAssertTrue([expected isEqualToSet:listens], @"Parent should override");
  1626. ready = YES;
  1627. });
  1628. [self waitUntil:^BOOL {
  1629. return ready;
  1630. }];
  1631. [ref removeObserverWithHandle:handle3];
  1632. ready = NO;
  1633. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1634. listens = [self dumpListensForRef:ref];
  1635. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1636. expectedParams = [expectedParams limitTo:1];
  1637. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/b"]];
  1638. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1639. ready = YES;
  1640. });
  1641. [self waitUntil:^BOOL {
  1642. return ready;
  1643. }];
  1644. ready = NO;
  1645. [bLim1 removeObserverWithHandle:handle2];
  1646. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1647. listens = [self dumpListensForRef:ref];
  1648. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1649. ready = YES;
  1650. });
  1651. [self waitUntil:^BOOL {
  1652. return ready;
  1653. }];
  1654. }
  1655. - (void)testLimitWithMixOfNullAndNonNullPriorities {
  1656. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1657. NSMutableArray* children = [[NSMutableArray alloc] init];
  1658. [[ref queryLimitedToLast:5] observeEventType:FIRDataEventTypeChildAdded
  1659. withBlock:^(FIRDataSnapshot* snapshot) {
  1660. [children addObject:[snapshot key]];
  1661. }];
  1662. __block BOOL ready = NO;
  1663. NSDictionary* toSet = @{
  1664. @"Vikrum" : @{@".priority" : @1000, @"score" : @1000, @"name" : @"Vikrum"},
  1665. @"Mike" : @{@".priority" : @500, @"score" : @500, @"name" : @"Mike"},
  1666. @"Andrew" : @{@".priority" : @50, @"score" : @50, @"name" : @"Andrew"},
  1667. @"James" : @{@".priority" : @7, @"score" : @7, @"name" : @"James"},
  1668. @"Sally" : @{@".priority" : @-7, @"score" : @-7, @"name" : @"Sally"},
  1669. @"Fred" : @{@"score" : @0, @"name" : @"Fred"}
  1670. };
  1671. [ref setValue:toSet
  1672. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1673. ready = YES;
  1674. }];
  1675. [self waitUntil:^BOOL {
  1676. return ready;
  1677. }];
  1678. NSArray* expected = @[ @"Sally", @"James", @"Andrew", @"Mike", @"Vikrum" ];
  1679. XCTAssertTrue([children isEqualToArray:expected], @"Null priority should be left out");
  1680. }
  1681. - (void)testLimitWithMixOfNullAndNonNullPrioritiesOnServerData {
  1682. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1683. __block BOOL ready = NO;
  1684. NSDictionary* toSet = @{
  1685. @"Vikrum" : @{@".priority" : @1000, @"score" : @1000, @"name" : @"Vikrum"},
  1686. @"Mike" : @{@".priority" : @500, @"score" : @500, @"name" : @"Mike"},
  1687. @"Andrew" : @{@".priority" : @50, @"score" : @50, @"name" : @"Andrew"},
  1688. @"James" : @{@".priority" : @7, @"score" : @7, @"name" : @"James"},
  1689. @"Sally" : @{@".priority" : @-7, @"score" : @-7, @"name" : @"Sally"},
  1690. @"Fred" : @{@"score" : @0, @"name" : @"Fred"}
  1691. };
  1692. [ref setValue:toSet
  1693. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1694. ready = YES;
  1695. }];
  1696. [self waitUntil:^BOOL {
  1697. return ready;
  1698. }];
  1699. __block int count = 0;
  1700. NSMutableArray* children = [[NSMutableArray alloc] init];
  1701. [[ref queryLimitedToLast:5] observeEventType:FIRDataEventTypeChildAdded
  1702. withBlock:^(FIRDataSnapshot* snapshot) {
  1703. [children addObject:[snapshot key]];
  1704. count++;
  1705. }];
  1706. [self waitUntil:^BOOL {
  1707. return count == 5;
  1708. }];
  1709. NSArray* expected = @[ @"Sally", @"James", @"Andrew", @"Mike", @"Vikrum" ];
  1710. XCTAssertTrue([children isEqualToArray:expected], @"Null priority should be left out");
  1711. }
  1712. // Skipping context tests. Context is not implemented on iOS
  1713. /* DISABLING for now, since I'm not 100% sure what the right behavior is.
  1714. Perhaps a merge at /foo should shadow server updates at /foo instead of
  1715. just the modified children? Not sure.
  1716. - (void) testHandleUpdateThatDeletesEntireWindow {
  1717. Firebase* ref = [FTestHelpers getRandomNode];
  1718. NSMutableArray* snaps = [[NSMutableArray alloc] init];
  1719. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot
  1720. *snapshot) { id val = [snapshot value]; if (val == nil) { [snaps addObject:[NSNull null]]; } else {
  1721. [snaps addObject:val];
  1722. }
  1723. }];
  1724. NSDictionary* toSet = @{
  1725. @"a": @{@".priority": @1, @".value": @1},
  1726. @"b": @{@".priority": @2, @".value": @2},
  1727. @"c": @{@".priority": @3, @".value": @3}
  1728. };
  1729. [ref setValue:toSet];
  1730. __block BOOL ready = NO;
  1731. toSet = @{@"b": [NSNull null], @"c": [NSNull null]};
  1732. [ref updateChildValues:toSet withCompletionBlock:^(NSError* err, Firebase* ref) {
  1733. ready = YES;
  1734. }];
  1735. [self waitUntil:^BOOL{
  1736. return ready;
  1737. }];
  1738. NSArray* expected = @[@{@"b": @2, @"c": @3}, [NSNull null], @{@"a": @1}];
  1739. STAssertTrue([snaps isEqualToArray:expected], @"Expected %@ to equal %@", snaps, expected);
  1740. }
  1741. */
  1742. - (void)testHandlesAnOutOfViewQueryOnAChild {
  1743. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1744. __block NSDictionary* parent = nil;
  1745. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1746. withBlock:^(FIRDataSnapshot* snapshot) {
  1747. parent = [snapshot value];
  1748. }];
  1749. __block NSNumber* child = nil;
  1750. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1751. withBlock:^(FIRDataSnapshot* snapshot) {
  1752. child = [snapshot value];
  1753. }];
  1754. __block BOOL ready = NO;
  1755. NSDictionary* toSet = @{@"a" : @1, @"b" : @2};
  1756. [ref setValue:toSet
  1757. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1758. ready = YES;
  1759. }];
  1760. [self waitUntil:^BOOL {
  1761. return ready;
  1762. }];
  1763. NSDictionary* parentExpected = @{@"b" : @2};
  1764. NSNumber* childExpected = [NSNumber numberWithInt:1];
  1765. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1766. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1767. ready = NO;
  1768. [ref updateChildValues:@{@"c" : @3}
  1769. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1770. ready = YES;
  1771. }];
  1772. [self waitUntil:^BOOL {
  1773. return ready;
  1774. }];
  1775. parentExpected = @{@"c" : @3};
  1776. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1777. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1778. }
  1779. - (void)testHandlesAChildQueryGoingOutOfViewOfTheParent {
  1780. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1781. __block NSDictionary* parent = nil;
  1782. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1783. withBlock:^(FIRDataSnapshot* snapshot) {
  1784. parent = [snapshot value];
  1785. }];
  1786. __block NSNumber* child = nil;
  1787. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1788. withBlock:^(FIRDataSnapshot* snapshot) {
  1789. child = [snapshot value];
  1790. }];
  1791. __block BOOL ready = NO;
  1792. NSDictionary* toSet = @{@"a" : @1};
  1793. [ref setValue:toSet
  1794. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1795. ready = YES;
  1796. }];
  1797. WAIT_FOR(ready);
  1798. NSDictionary* parentExpected = @{@"a" : @1};
  1799. NSNumber* childExpected = [NSNumber numberWithInt:1];
  1800. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1801. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1802. ready = NO;
  1803. [[ref child:@"b"] setValue:@2
  1804. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1805. ready = YES;
  1806. }];
  1807. WAIT_FOR(ready);
  1808. parentExpected = @{@"b" : @2};
  1809. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1810. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1811. ready = NO;
  1812. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1813. ready = YES;
  1814. }];
  1815. [self waitUntil:^BOOL {
  1816. return ready;
  1817. }];
  1818. parentExpected = @{@"a" : @1};
  1819. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1820. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1821. }
  1822. - (void)testHandlesDivergingViews {
  1823. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1824. __block NSDictionary* cVal = nil;
  1825. FIRDatabaseQuery* query =
  1826. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"c"] queryLimitedToLast:1];
  1827. [query observeEventType:FIRDataEventTypeValue
  1828. withBlock:^(FIRDataSnapshot* snapshot) {
  1829. cVal = [snapshot value];
  1830. }];
  1831. __block NSDictionary* dVal = nil;
  1832. query = [[[ref queryOrderedByPriority] queryEndingAtValue:nil
  1833. childKey:@"d"] queryLimitedToLast:1];
  1834. [query observeEventType:FIRDataEventTypeValue
  1835. withBlock:^(FIRDataSnapshot* snapshot) {
  1836. dVal = [snapshot value];
  1837. }];
  1838. __block BOOL ready = NO;
  1839. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3};
  1840. [ref setValue:toSet
  1841. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1842. ready = YES;
  1843. }];
  1844. [self waitUntil:^BOOL {
  1845. return ready;
  1846. }];
  1847. NSDictionary* expected = @{@"c" : @3};
  1848. XCTAssertTrue([cVal isEqualToDictionary:expected], @"should be c");
  1849. XCTAssertTrue([dVal isEqualToDictionary:expected], @"should be c");
  1850. ready = NO;
  1851. [[ref child:@"d"] setValue:@4
  1852. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1853. ready = YES;
  1854. }];
  1855. [self waitUntil:^BOOL {
  1856. return ready;
  1857. }];
  1858. XCTAssertTrue([cVal isEqualToDictionary:expected], @"should be c");
  1859. expected = @{@"d" : @4};
  1860. XCTAssertTrue([dVal isEqualToDictionary:expected], @"should be d");
  1861. }
  1862. - (void)testHandlesRemovingAQueriedElement {
  1863. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1864. __block NSNumber* val = nil;
  1865. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeChildAdded
  1866. withBlock:^(FIRDataSnapshot* snapshot) {
  1867. id newVal = [snapshot value];
  1868. if (newVal != nil) {
  1869. val = [snapshot value];
  1870. }
  1871. }];
  1872. __block BOOL ready = NO;
  1873. [ref setValue:@{@"a" : @1, @"b" : @2}
  1874. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1875. ready = YES;
  1876. }];
  1877. [self waitUntil:^BOOL {
  1878. return ready;
  1879. }];
  1880. XCTAssertTrue([val isEqualToNumber:@2], @"Expected last element in window");
  1881. ready = NO;
  1882. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1883. ready = YES;
  1884. }];
  1885. [self waitUntil:^BOOL {
  1886. return ready;
  1887. }];
  1888. XCTAssertTrue([val isEqualToNumber:@1], @"Should now be the next element in the window");
  1889. }
  1890. - (void)testStartAtAndLimit1Works {
  1891. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1892. __block NSNumber* val = nil;
  1893. FIRDatabaseQuery* query =
  1894. [[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryLimitedToFirst:1];
  1895. [query observeEventType:FIRDataEventTypeChildAdded
  1896. withBlock:^(FIRDataSnapshot* snapshot) {
  1897. id newVal = [snapshot value];
  1898. if (newVal != nil) {
  1899. val = [snapshot value];
  1900. }
  1901. }];
  1902. __block BOOL ready = NO;
  1903. [ref setValue:@{@"a" : @1, @"b" : @2}
  1904. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1905. ready = YES;
  1906. }];
  1907. [self waitUntil:^BOOL {
  1908. return ready;
  1909. }];
  1910. XCTAssertTrue([val isEqualToNumber:@1], @"Expected first element in window");
  1911. }
  1912. // See case 1664
  1913. - (void)testStartAtAndLimit1AndRemoveFirstChild {
  1914. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1915. __block NSNumber* val = nil;
  1916. FIRDatabaseQuery* query =
  1917. [[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryLimitedToFirst:1];
  1918. [query observeEventType:FIRDataEventTypeChildAdded
  1919. withBlock:^(FIRDataSnapshot* snapshot) {
  1920. id newVal = [snapshot value];
  1921. if (newVal != nil) {
  1922. val = [snapshot value];
  1923. }
  1924. }];
  1925. __block BOOL ready = NO;
  1926. [ref setValue:@{@"a" : @1, @"b" : @2}
  1927. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1928. ready = YES;
  1929. }];
  1930. [self waitUntil:^BOOL {
  1931. return ready;
  1932. }];
  1933. XCTAssertTrue([val isEqualToNumber:@1], @"Expected first element in window");
  1934. ready = NO;
  1935. [[ref child:@"a"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1936. ready = YES;
  1937. }];
  1938. [self waitUntil:^BOOL {
  1939. return ready;
  1940. }];
  1941. XCTAssertTrue([val isEqualToNumber:@2], @"Expected next element in window");
  1942. }
  1943. // See case 1169
  1944. - (void)testStartAtWithTwoArgumentsWorks {
  1945. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1946. __block BOOL ready = NO;
  1947. NSMutableArray* children = [[NSMutableArray alloc] init];
  1948. NSDictionary* toSet = @{
  1949. @"Walker" : @{@"name" : @"Walker", @"score" : @20, @".priority" : @20},
  1950. @"Michael" : @{@"name" : @"Michael", @"score" : @100, @".priority" : @100}
  1951. };
  1952. [ref setValue:toSet
  1953. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1954. ready = YES;
  1955. }];
  1956. [self waitUntil:^BOOL {
  1957. return ready;
  1958. }];
  1959. ready = NO;
  1960. FIRDatabaseQuery* query =
  1961. [[[ref queryOrderedByPriority] queryStartingAtValue:@20
  1962. childKey:@"Walker"] queryLimitedToFirst:2];
  1963. [query observeEventType:FIRDataEventTypeValue
  1964. withBlock:^(FIRDataSnapshot* snapshot) {
  1965. for (FIRDataSnapshot* child in snapshot.children) {
  1966. [children addObject:child.key];
  1967. }
  1968. ready = YES;
  1969. }];
  1970. [self waitUntil:^BOOL {
  1971. return ready;
  1972. }];
  1973. NSArray* expected = @[ @"Walker", @"Michael" ];
  1974. XCTAssertTrue([children isEqualToArray:expected], @"Expected both children");
  1975. }
  1976. - (void)testHandlesMultipleQueriesOnSameNode {
  1977. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1978. __block BOOL ready = NO;
  1979. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4, @"e" : @5, @"f" : @6};
  1980. [ref setValue:toSet
  1981. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1982. ready = YES;
  1983. }];
  1984. [self waitUntil:^BOOL {
  1985. return ready;
  1986. }];
  1987. ready = NO;
  1988. __block BOOL called = NO;
  1989. [[ref queryLimitedToLast:2]
  1990. observeEventType:FIRDataEventTypeValue
  1991. withBlock:^(FIRDataSnapshot* snapshot) {
  1992. // we got the initial data
  1993. XCTAssertFalse(called,
  1994. @"This should only get called once, we don't update data after this");
  1995. called = YES;
  1996. ready = YES;
  1997. }];
  1998. [self waitUntil:^BOOL {
  1999. return ready;
  2000. }];
  2001. ready = NO;
  2002. __block NSDictionary* snap = nil;
  2003. // now do nested once calls
  2004. [[ref queryLimitedToLast:1]
  2005. observeSingleEventOfType:FIRDataEventTypeValue
  2006. withBlock:^(FIRDataSnapshot* snapshot) {
  2007. [[ref queryLimitedToLast:1]
  2008. observeSingleEventOfType:FIRDataEventTypeValue
  2009. withBlock:^(FIRDataSnapshot* snapshot) {
  2010. snap = [snapshot value];
  2011. ready = YES;
  2012. }];
  2013. }];
  2014. [self waitUntil:^BOOL {
  2015. return ready;
  2016. }];
  2017. NSDictionary* expected = @{@"f" : @6};
  2018. XCTAssertTrue([snap isEqualToDictionary:expected], @"Expected the correct data");
  2019. }
  2020. - (void)testHandlesOnceCalledOnNodeWithDefaultListener {
  2021. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2022. __block BOOL ready = NO;
  2023. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4, @"e" : @5, @"f" : @6};
  2024. [ref setValue:toSet
  2025. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2026. ready = YES;
  2027. }];
  2028. [self waitUntil:^BOOL {
  2029. return ready;
  2030. }];
  2031. ready = NO;
  2032. [ref observeEventType:FIRDataEventTypeValue
  2033. withBlock:^(FIRDataSnapshot* snapshot) {
  2034. // we got the initial data
  2035. ready = YES;
  2036. }];
  2037. [self waitUntil:^BOOL {
  2038. return ready;
  2039. }];
  2040. ready = NO;
  2041. __block NSNumber* snap = nil;
  2042. [[ref queryLimitedToLast:1] observeSingleEventOfType:FIRDataEventTypeChildAdded
  2043. withBlock:^(FIRDataSnapshot* snapshot) {
  2044. snap = [snapshot value];
  2045. ready = YES;
  2046. }];
  2047. [self waitUntil:^BOOL {
  2048. return ready;
  2049. }];
  2050. XCTAssertTrue([snap isEqualToNumber:@6], @"Got once response");
  2051. }
  2052. - (void)testHandlesOnceCalledOnNodeWithDefaultListenerAndNonCompleteLimit {
  2053. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2054. __block BOOL ready = NO;
  2055. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3};
  2056. [ref setValue:toSet
  2057. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2058. ready = YES;
  2059. }];
  2060. [self waitUntil:^BOOL {
  2061. return ready;
  2062. }];
  2063. ready = NO;
  2064. // do first listen
  2065. [ref observeEventType:FIRDataEventTypeValue
  2066. withBlock:^(FIRDataSnapshot* snapshot) {
  2067. ready = YES;
  2068. }];
  2069. [self waitUntil:^BOOL {
  2070. return ready;
  2071. }];
  2072. ready = NO;
  2073. __block NSDictionary* snap = nil;
  2074. [[ref queryLimitedToLast:5] observeSingleEventOfType:FIRDataEventTypeValue
  2075. withBlock:^(FIRDataSnapshot* snapshot) {
  2076. snap = [snapshot value];
  2077. ready = YES;
  2078. }];
  2079. [self waitUntil:^BOOL {
  2080. return ready;
  2081. }];
  2082. NSDictionary* expected = @{@"a" : @1, @"b" : @2, @"c" : @3};
  2083. XCTAssertTrue([snap isEqualToDictionary:expected], @"Got once response");
  2084. }
  2085. - (void)testRemoveTriggersRemoteEvents {
  2086. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  2087. FIRDatabaseReference* writer = tuple.one;
  2088. FIRDatabaseReference* reader = tuple.two;
  2089. __block BOOL ready = NO;
  2090. NSDictionary* toSet = @{@"a" : @"a", @"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e"};
  2091. [writer setValue:toSet
  2092. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2093. ready = YES;
  2094. }];
  2095. [self waitUntil:^BOOL {
  2096. return ready;
  2097. }];
  2098. ready = NO;
  2099. __block int count = 0;
  2100. [[reader queryLimitedToLast:5]
  2101. observeEventType:FIRDataEventTypeValue
  2102. withBlock:^(FIRDataSnapshot* snapshot) {
  2103. count++;
  2104. if (count == 1) {
  2105. NSDictionary* val = [snapshot value];
  2106. NSDictionary* expected =
  2107. @{@"a" : @"a", @"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e"};
  2108. XCTAssertTrue([val isEqualToDictionary:expected],
  2109. @"First callback, expect all the data");
  2110. [[writer child:@"c"] removeValue];
  2111. } else {
  2112. XCTAssertTrue(count == 2, @"Should only get called twice");
  2113. NSDictionary* val = [snapshot value];
  2114. NSDictionary* expected = @{@"a" : @"a", @"b" : @"b", @"d" : @"d", @"e" : @"e"};
  2115. XCTAssertTrue([val isEqualToDictionary:expected],
  2116. @"Second callback, expect all the remaining data");
  2117. ready = YES;
  2118. }
  2119. }];
  2120. [self waitUntil:^BOOL {
  2121. return ready;
  2122. }];
  2123. }
  2124. - (void)testEndingAtNameReturnsCorrectChildren {
  2125. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2126. NSDictionary* toSet = @{
  2127. @"a" : @"a",
  2128. @"b" : @"b",
  2129. @"c" : @"c",
  2130. @"d" : @"d",
  2131. @"e" : @"e",
  2132. @"f" : @"f",
  2133. @"g" : @"g",
  2134. @"h" : @"h"
  2135. };
  2136. [self waitForCompletionOf:ref setValue:toSet];
  2137. __block NSDictionary* snap = nil;
  2138. __block BOOL done = NO;
  2139. FIRDatabaseQuery* query =
  2140. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"f"] queryLimitedToLast:5];
  2141. [query observeEventType:FIRDataEventTypeValue
  2142. withBlock:^(FIRDataSnapshot* snapshot) {
  2143. snap = [snapshot value];
  2144. done = YES;
  2145. }];
  2146. [self waitUntil:^BOOL {
  2147. return done;
  2148. }];
  2149. NSDictionary* expected = @{@"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e", @"f" : @"f"};
  2150. XCTAssertTrue([snap isEqualToDictionary:expected], @"Expected 5 elements, ending at f");
  2151. }
  2152. - (void)testListenForChildAddedWithLimitEnsureEventsFireProperly {
  2153. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2154. FIRDatabaseReference* writer = refs.one;
  2155. FIRDatabaseReference* reader = refs.two;
  2156. __block BOOL done = NO;
  2157. NSDictionary* toSet =
  2158. @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2159. [writer setValue:toSet
  2160. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2161. done = YES;
  2162. }];
  2163. WAIT_FOR(done);
  2164. __block int count = 0;
  2165. [[reader queryLimitedToLast:3]
  2166. observeEventType:FIRDataEventTypeChildAdded
  2167. withBlock:^(FIRDataSnapshot* snapshot) {
  2168. count++;
  2169. if (count == 1) {
  2170. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2171. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2172. } else if (count == 2) {
  2173. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2174. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2175. } else if (count == 3) {
  2176. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2177. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2178. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2179. } else {
  2180. XCTFail(@"wrong event count");
  2181. }
  2182. }];
  2183. WAIT_FOR(count == 3);
  2184. }
  2185. #ifdef FLAKY_TEST
  2186. - (void)testListenForChildChangedWithLimitEnsureEventsFireProperly {
  2187. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2188. FIRDatabaseReference* writer = refs.one;
  2189. FIRDatabaseReference* reader = refs.two;
  2190. __block BOOL done = NO;
  2191. NSDictionary* toSet = @{@"a" : @"something", @"b" : @"we'll", @"c" : @"overwrite"};
  2192. [writer setValue:toSet
  2193. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2194. done = YES;
  2195. }];
  2196. WAIT_FOR(done);
  2197. __block int count = 0;
  2198. [reader
  2199. observeEventType:FIRDataEventTypeChildChanged
  2200. withBlock:^(FIRDataSnapshot* snapshot) {
  2201. count++;
  2202. if (count == 1) {
  2203. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2204. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2205. } else if (count == 2) {
  2206. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2207. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2208. } else if (count == 3) {
  2209. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2210. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2211. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2212. } else {
  2213. XCTFail(@"wrong event count");
  2214. }
  2215. }];
  2216. toSet = @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2217. [writer setValue:toSet];
  2218. WAIT_FOR(count == 3);
  2219. }
  2220. #endif
  2221. - (void)testListenForChildRemovedWithLimitEnsureEventsFireProperly {
  2222. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2223. FIRDatabaseReference* writer = refs.one;
  2224. FIRDatabaseReference* reader = refs.two;
  2225. __block BOOL done = NO;
  2226. NSDictionary* toSet =
  2227. @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2228. [writer setValue:toSet
  2229. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2230. done = YES;
  2231. }];
  2232. WAIT_FOR(done);
  2233. __block int count = 0;
  2234. [reader
  2235. observeEventType:FIRDataEventTypeChildRemoved
  2236. withBlock:^(FIRDataSnapshot* snapshot) {
  2237. count++;
  2238. if (count == 1) {
  2239. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2240. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2241. } else if (count == 2) {
  2242. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2243. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2244. } else if (count == 3) {
  2245. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2246. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2247. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2248. } else {
  2249. XCTFail(@"wrong event count");
  2250. }
  2251. }];
  2252. done = NO;
  2253. [reader observeEventType:FIRDataEventTypeValue
  2254. withBlock:^(FIRDataSnapshot* snapshot) {
  2255. // Load the data first
  2256. done = snapshot.value != [NSNull null] &&
  2257. [snapshot.value isEqualToDictionary:toSet];
  2258. }];
  2259. WAIT_FOR(done);
  2260. // Now do the removes
  2261. [[writer child:@"a"] removeValue];
  2262. [[writer child:@"b"] removeValue];
  2263. [[writer child:@"c"] removeValue];
  2264. WAIT_FOR(count == 3);
  2265. }
  2266. - (void)testQueriesBehaveProperlyAfterOnceCall {
  2267. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2268. FIRDatabaseReference* writer = refs.one;
  2269. FIRDatabaseReference* reader = refs.two;
  2270. __block BOOL done = NO;
  2271. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4};
  2272. [writer setValue:toSet
  2273. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2274. done = YES;
  2275. }];
  2276. WAIT_FOR(done);
  2277. done = NO;
  2278. [reader observeSingleEventOfType:FIRDataEventTypeValue
  2279. withBlock:^(FIRDataSnapshot* snapshot) {
  2280. done = YES;
  2281. }];
  2282. WAIT_FOR(done);
  2283. // Ok, now do some queries
  2284. __block int startCount = 0;
  2285. __block int defaultCount = 0;
  2286. [[[reader queryOrderedByPriority] queryStartingAtValue:nil childKey:@"d"]
  2287. observeEventType:FIRDataEventTypeChildAdded
  2288. withBlock:^(FIRDataSnapshot* snapshot) {
  2289. startCount++;
  2290. }];
  2291. [reader observeEventType:FIRDataEventTypeChildAdded
  2292. withBlock:^(FIRDataSnapshot* snapshot) {
  2293. defaultCount++;
  2294. }];
  2295. [reader observeEventType:FIRDataEventTypeChildRemoved
  2296. withBlock:^(FIRDataSnapshot* snapshot) {
  2297. XCTFail(@"Should not remove any children");
  2298. }];
  2299. WAIT_FOR(startCount == 1 && defaultCount == 4);
  2300. }
  2301. - (void)testIntegerKeysBehaveNumerically1 {
  2302. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2303. NSDictionary* toSet = @{
  2304. @"1" : @YES,
  2305. @"50" : @YES,
  2306. @"550" : @YES,
  2307. @"6" : @YES,
  2308. @"600" : @YES,
  2309. @"70" : @YES,
  2310. @"8" : @YES,
  2311. @"80" : @YES
  2312. };
  2313. __block BOOL done = NO;
  2314. [ref setValue:toSet
  2315. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2316. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"80"]
  2317. observeSingleEventOfType:FIRDataEventTypeValue
  2318. withBlock:^(FIRDataSnapshot* snapshot) {
  2319. NSDictionary* expected = @{@"80" : @YES, @"550" : @YES, @"600" : @YES};
  2320. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2321. @"Got correct result.");
  2322. done = YES;
  2323. }];
  2324. }];
  2325. WAIT_FOR(done);
  2326. }
  2327. - (void)testIntegerKeysBehaveNumerically2 {
  2328. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2329. NSDictionary* toSet = @{
  2330. @"1" : @YES,
  2331. @"50" : @YES,
  2332. @"550" : @YES,
  2333. @"6" : @YES,
  2334. @"600" : @YES,
  2335. @"70" : @YES,
  2336. @"8" : @YES,
  2337. @"80" : @YES
  2338. };
  2339. __block BOOL done = NO;
  2340. [ref setValue:toSet
  2341. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2342. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"50"]
  2343. observeSingleEventOfType:FIRDataEventTypeValue
  2344. withBlock:^(FIRDataSnapshot* snapshot) {
  2345. NSDictionary* expected =
  2346. @{@"1" : @YES,
  2347. @"6" : @YES,
  2348. @"8" : @YES,
  2349. @"50" : @YES};
  2350. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2351. @"Got correct result.");
  2352. done = YES;
  2353. }];
  2354. }];
  2355. WAIT_FOR(done);
  2356. }
  2357. - (void)testIntegerKeysBehaveNumerically3 {
  2358. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2359. NSDictionary* toSet = @{
  2360. @"1" : @YES,
  2361. @"50" : @YES,
  2362. @"550" : @YES,
  2363. @"6" : @YES,
  2364. @"600" : @YES,
  2365. @"70" : @YES,
  2366. @"8" : @YES,
  2367. @"80" : @YES
  2368. };
  2369. __block BOOL done = NO;
  2370. [ref setValue:toSet
  2371. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2372. [[[[ref queryOrderedByPriority] queryStartingAtValue:nil
  2373. childKey:@"50"] queryEndingAtValue:nil
  2374. childKey:@"80"]
  2375. observeSingleEventOfType:FIRDataEventTypeValue
  2376. withBlock:^(FIRDataSnapshot* snapshot) {
  2377. NSDictionary* expected = @{@"50" : @YES, @"70" : @YES, @"80" : @YES};
  2378. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2379. @"Got correct result.");
  2380. done = YES;
  2381. }];
  2382. }];
  2383. WAIT_FOR(done);
  2384. }
  2385. - (void)testItemsPulledIntoLimitCorrectly {
  2386. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2387. NSMutableArray* snaps = [[NSMutableArray alloc] init];
  2388. // Just so everything is cached locally.
  2389. [ref observeEventType:FIRDataEventTypeValue
  2390. withBlock:^(FIRDataSnapshot* snapshot){
  2391. }];
  2392. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue
  2393. withBlock:^(FIRDataSnapshot* snapshot) {
  2394. id val = [snapshot value];
  2395. [snaps addObject:val];
  2396. }];
  2397. [ref setValue:@{
  2398. @"a" : @{@".value" : @1, @".priority" : @1},
  2399. @"b" : @{@".value" : @2, @".priority" : @2},
  2400. @"c" : @{@".value" : @3, @".priority" : @3}
  2401. }];
  2402. __block BOOL ready = NO;
  2403. [[ref child:@"b"] setValue:[NSNull null]
  2404. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2405. ready = YES;
  2406. }];
  2407. WAIT_FOR(ready);
  2408. NSArray* expected = @[ @{@"b" : @2, @"c" : @3}, @{@"a" : @1, @"c" : @3} ];
  2409. XCTAssertEqualObjects(snaps, expected, @"Incorrect snapshots.");
  2410. }
  2411. - (void)testChildChangedCausesChildRemovedEvent {
  2412. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2413. [[ref child:@"l/a"] setValue:@"1" andPriority:@"a"];
  2414. [[ref child:@"l/b"] setValue:@"2" andPriority:@"b"];
  2415. FIRDatabaseQuery* query = [[[[ref child:@"l"] queryOrderedByPriority] queryStartingAtValue:@"b"]
  2416. queryEndingAtValue:@"d"];
  2417. __block BOOL removed = NO;
  2418. [query observeEventType:FIRDataEventTypeChildRemoved
  2419. withBlock:^(FIRDataSnapshot* snapshot) {
  2420. XCTAssertEqualObjects(snapshot.value, @"2", @"Incorrect snapshot");
  2421. removed = YES;
  2422. }];
  2423. [[ref child:@"l/b"] setValue:@"4" andPriority:@"a"];
  2424. WAIT_FOR(removed);
  2425. }
  2426. - (void)testQueryHasRef {
  2427. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2428. FIRDatabaseQuery* query = [ref queryOrderedByKey];
  2429. XCTAssertEqualObjects([query.ref path], [ref path], @"Should have same path");
  2430. }
  2431. - (void)testQuerySnapshotChildrenRespectDefaultOrdering {
  2432. FTupleFirebase* pair = [FTestHelpers getRandomNodePair];
  2433. FIRDatabaseReference* writer = pair.one;
  2434. FIRDatabaseReference* reader = pair.two;
  2435. __block BOOL done = NO;
  2436. NSDictionary* list = @{
  2437. @"a" : @{
  2438. @"thisvaluefirst" : @{@".value" : @true, @".priority" : @1},
  2439. @"name" : @{@".value" : @"Michael", @".priority" : @2},
  2440. @"thisvaluelast" : @{@".value" : @true, @".priority" : @3},
  2441. },
  2442. @"b" : @{
  2443. @"thisvaluefirst" : @{@".value" : @true},
  2444. @"name" : @{@".value" : @"Rob", @".priority" : @2},
  2445. @"thisvaluelast" : @{@".value" : @true, @".priority" : @3},
  2446. },
  2447. @"c" : @{
  2448. @"thisvaluefirst" : @{@".value" : @true, @".priority" : @1},
  2449. @"name" : @{@".value" : @"Jonny", @".priority" : @2},
  2450. @"thisvaluelast" : @{@".value" : @true, @".priority" : @"somestring"},
  2451. }
  2452. };
  2453. [writer setValue:list
  2454. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2455. done = YES;
  2456. }];
  2457. WAIT_FOR(done);
  2458. done = NO;
  2459. [[reader queryOrderedByChild:@"name"]
  2460. observeSingleEventOfType:FIRDataEventTypeValue
  2461. withBlock:^(FIRDataSnapshot* snapshot) {
  2462. NSArray* expectedKeys = @[ @"thisvaluefirst", @"name", @"thisvaluelast" ];
  2463. NSArray* expectedNames = @[ @"Jonny", @"Michael", @"Rob" ];
  2464. // Validate that snap.child() resets order to default for child snaps
  2465. NSMutableArray* orderedKeys = [[NSMutableArray alloc] init];
  2466. for (FIRDataSnapshot* childSnap in [snapshot childSnapshotForPath:@"b"]
  2467. .children) {
  2468. [orderedKeys addObject:childSnap.key];
  2469. }
  2470. XCTAssertEqualObjects(expectedKeys, orderedKeys,
  2471. @"Should have matching ordered lists of keys");
  2472. // Validate that snap.forEach() resets ordering to default for child snaps
  2473. NSMutableArray* orderedNames = [[NSMutableArray alloc] init];
  2474. for (FIRDataSnapshot* childSnap in snapshot.children) {
  2475. [orderedNames addObject:[childSnap childSnapshotForPath:@"name"].value];
  2476. [orderedKeys removeAllObjects];
  2477. for (FIRDataSnapshot* grandchildSnap in childSnap.children) {
  2478. [orderedKeys addObject:grandchildSnap.key];
  2479. }
  2480. XCTAssertEqualObjects(expectedKeys, orderedKeys,
  2481. @"Should have matching ordered lists of keys");
  2482. }
  2483. XCTAssertEqualObjects(expectedNames, orderedNames,
  2484. @"Should have matching ordered lists of names");
  2485. done = YES;
  2486. }];
  2487. WAIT_FOR(done);
  2488. }
  2489. - (void)testAddingListensForTheSamePathDoesNotCheckFail {
  2490. // This bug manifests itself if there's a hierarchy of query listener, default listener and
  2491. // one-time listener underneath. In Java implementation, during one-time listener registration,
  2492. // sync-tree traversal stopped as soon as it found a complete server cache (this is the case for
  2493. // not indexed query view). The problem is that the same traversal was looking for a ancestor
  2494. // default view, and the early exit prevented from finding the default listener above the one-time
  2495. // listener. Event removal code path wasn't removing the listener because it stopped as soon as it
  2496. // found the default view. This left the zombie one-time listener and check failed on the second
  2497. // attempt to create a listener for the same path (asana#61028598952586).
  2498. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2499. __block BOOL done = NO;
  2500. [[ref child:@"child"] setValue:@{@"name" : @"John"}];
  2501. [[[ref queryOrderedByChild:@"name"] queryEqualToValue:@"John"]
  2502. observeEventType:FIRDataEventTypeValue
  2503. withBlock:^(FIRDataSnapshot* snapshot) {
  2504. done = YES;
  2505. }];
  2506. WAIT_FOR(done);
  2507. done = NO;
  2508. [[[ref child:@"child"] child:@"favoriteToy"]
  2509. observeSingleEventOfType:FIRDataEventTypeValue
  2510. withBlock:^(FIRDataSnapshot* snapshot) {
  2511. done = YES;
  2512. }];
  2513. WAIT_FOR(done);
  2514. done = NO;
  2515. [[[ref child:@"child"] child:@"favoriteToy"]
  2516. observeSingleEventOfType:FIRDataEventTypeValue
  2517. withBlock:^(FIRDataSnapshot* snapshot) {
  2518. done = YES;
  2519. }];
  2520. WAIT_FOR(done);
  2521. }
  2522. - (void)testEmptyQueryGet {
  2523. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2524. __block BOOL done = NO;
  2525. [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2526. XCTAssert([snapshot.value isEqual:[NSNull null]]);
  2527. done = YES;
  2528. }];
  2529. WAIT_FOR(done);
  2530. }
  2531. - (void)testOfflineQueryGet {
  2532. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2533. FIRDatabase* db = [ref database];
  2534. __block BOOL done = NO;
  2535. @try {
  2536. [db goOffline];
  2537. [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2538. XCTAssertNotNil(err);
  2539. XCTAssertEqualObjects([err localizedFailureReason], kPersistentConnectionOffline);
  2540. done = YES;
  2541. }];
  2542. WAIT_FOR(done);
  2543. } @finally {
  2544. [db goOnline];
  2545. }
  2546. }
  2547. - (void)testGetQueryBasic {
  2548. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2549. __block BOOL done = NO;
  2550. [ref setValue:@42
  2551. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2552. XCTAssertNil(error);
  2553. done = YES;
  2554. }];
  2555. WAIT_FOR(done);
  2556. [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2557. XCTAssertNil(err);
  2558. XCTAssertEqualObjects(snapshot.value, @42);
  2559. done = YES;
  2560. }];
  2561. WAIT_FOR(done);
  2562. }
  2563. - (void)testQueryGetCached {
  2564. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2565. FIRDatabase* db = [ref database];
  2566. __block BOOL done = NO;
  2567. [ref observeEventType:FIRDataEventTypeValue
  2568. withBlock:^(FIRDataSnapshot* snapshot) {
  2569. id value = [snapshot value];
  2570. if (value != nil && [value isEqualToNumber:@42]) {
  2571. done = YES;
  2572. }
  2573. }];
  2574. [self waitForCompletionOf:ref setValue:@42];
  2575. WAIT_FOR(done);
  2576. done = NO;
  2577. @try {
  2578. [db goOffline];
  2579. [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2580. XCTAssertNil(err);
  2581. XCTAssertEqualObjects(snapshot.value, @42);
  2582. done = YES;
  2583. }];
  2584. WAIT_FOR(done);
  2585. } @finally {
  2586. [db goOnline];
  2587. }
  2588. }
  2589. - (FIRDatabase*)databaseForURL:(NSString*)url name:(NSString*)name {
  2590. NSString* defaultDatabaseURL = [NSString stringWithFormat:@"url:%@", self.databaseURL];
  2591. if ([url isEqualToString:self.databaseURL] && [name isEqualToString:defaultDatabaseURL]) {
  2592. // Use the default app for the default URL to avoid getting out of sync with FRepoManager
  2593. // when calling ensureRepo during tests that don't create their own FIRFakeApp.
  2594. return [FTestHelpers defaultDatabase];
  2595. } else {
  2596. id app = [[FIRFakeApp alloc] initWithName:name URL:url];
  2597. return [FIRDatabase databaseForApp:app];
  2598. }
  2599. }
  2600. - (void)testGetRetrievesLatestValueEvenIfCached {
  2601. FIRDatabase* db = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]];
  2602. FIRDatabase* db2 = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]];
  2603. XCTAssertNotEqual(db, db2);
  2604. NSString* uuidPath = [[NSUUID UUID] UUIDString];
  2605. FIRDatabaseReference* readRef = [db referenceWithPath:uuidPath];
  2606. FIRDatabaseReference* writeRef = [db2 referenceWithPath:uuidPath];
  2607. XCTAssertNotEqual(readRef, writeRef);
  2608. __block BOOL done = NO;
  2609. [self waitForCompletionOf:writeRef setValue:@42];
  2610. [readRef observeEventType:FIRDataEventTypeValue
  2611. withBlock:^(FIRDataSnapshot* snapshot) {
  2612. NSNumber* value = [snapshot value];
  2613. if (value != nil && [value isEqualToNumber:@42]) {
  2614. done = YES;
  2615. }
  2616. }];
  2617. WAIT_FOR(done);
  2618. done = NO;
  2619. [writeRef setValue:@43
  2620. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2621. XCTAssertNil(error);
  2622. done = YES;
  2623. }];
  2624. WAIT_FOR(done);
  2625. done = NO;
  2626. [readRef getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2627. XCTAssertNil(err);
  2628. XCTAssertEqualObjects(snapshot.value, @43);
  2629. done = YES;
  2630. }];
  2631. WAIT_FOR(done);
  2632. }
  2633. - (void)testGetUpdatesPersistenceCacheWhenEnabled {
  2634. FIRDatabase* db = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]];
  2635. FIRDatabase* db2 = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]];
  2636. [db2 setPersistenceEnabled:true];
  2637. NSString* uuidPath = [[NSUUID UUID] UUIDString];
  2638. FIRDatabaseReference* writeRef = [db referenceWithPath:uuidPath];
  2639. FIRDatabaseReference* readRef = [db2 referenceWithPath:uuidPath];
  2640. __block BOOL done = NO;
  2641. [writeRef setValue:@42
  2642. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2643. XCTAssertNil(error);
  2644. done = YES;
  2645. }];
  2646. WAIT_FOR(done);
  2647. done = NO;
  2648. [readRef getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
  2649. XCTAssertNil(err);
  2650. XCTAssertEqualObjects(snapshot.value, @42);
  2651. done = YES;
  2652. }];
  2653. WAIT_FOR(done);
  2654. done = NO;
  2655. @try {
  2656. [db2 goOffline];
  2657. [readRef observeEventType:FIRDataEventTypeValue
  2658. withBlock:^(FIRDataSnapshot* snapshot) {
  2659. XCTAssertEqualObjects(snapshot.value, @42);
  2660. done = YES;
  2661. }];
  2662. WAIT_FOR(done);
  2663. } @finally {
  2664. [db2 goOnline];
  2665. }
  2666. }
  2667. @end