FData.m 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285
  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/FData.h"
  17. #import <limits.h>
  18. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  19. #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h"
  20. #import "FirebaseDatabase/Sources/Core/FRepo_Private.h"
  21. #import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h"
  22. #import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h"
  23. #import "FirebaseDatabase/Tests/Helpers/FEventTester.h"
  24. #import "FirebaseDatabase/Tests/Helpers/FTestHelpers.h"
  25. #import "FirebaseDatabase/Tests/Helpers/FTupleEventTypeString.h"
  26. @implementation FData
  27. - (void)testGetNode {
  28. __unused FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  29. XCTAssertTrue(YES, @"Properly created node without throwing error");
  30. }
  31. - (void)testWriteData {
  32. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  33. [node setValue:@42];
  34. XCTAssertTrue(YES, @"Properly write to node without throwing error");
  35. }
  36. - (void)testWriteDataWithDebugLogging {
  37. [FIRDatabase setLoggingEnabled:YES];
  38. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  39. [node setValue:@42];
  40. [FIRDatabase setLoggingEnabled:NO];
  41. XCTAssertTrue(YES, @"Properly write to node without throwing error");
  42. }
  43. - (void)testWriteAndReadData {
  44. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  45. [node setValue:@42];
  46. [self snapWaiter:node
  47. withBlock:^(FIRDataSnapshot *snapshot) {
  48. XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw correct value");
  49. }];
  50. }
  51. - (void)testProperParamChecking {
  52. // ios doesn't have an equivalent of this test
  53. }
  54. - (void)testNamespaceCaseInsensitivityWithinARepo {
  55. FIRDatabaseReference *ref1 =
  56. [[FTestHelpers defaultDatabase] referenceFromURL:[self.databaseURL uppercaseString]];
  57. FIRDatabaseReference *ref2 =
  58. [[FTestHelpers defaultDatabase] referenceFromURL:[self.databaseURL lowercaseString]];
  59. XCTAssertTrue([ref1.description isEqualToString:ref2.description], @"Descriptions should match");
  60. }
  61. - (void)testRootProperty {
  62. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  63. FIRDatabaseReference *root = node.root;
  64. XCTAssertTrue(root != nil, @"Should get a root");
  65. XCTAssertTrue([[root description] isEqualToString:self.databaseURL],
  66. @"Root is actually the root");
  67. }
  68. - (void)testValReturnsCompoundObjectWithChildren {
  69. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  70. [node setValue:@{@"foo" : @{@"bar" : @5}}];
  71. [self snapWaiter:node
  72. withBlock:^(FIRDataSnapshot *snapshot) {
  73. XCTAssertEqualObjects([[[snapshot value] objectForKey:@"foo"] objectForKey:@"bar"], @5,
  74. @"Properly saw compound object");
  75. }];
  76. }
  77. - (void)testWriteDataAndWaitForServerConfirmation {
  78. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  79. [self waitForCompletionOf:node setValue:@42];
  80. }
  81. - (void)testWriteAValueAndRead {
  82. // dupe of FEvent testWriteLeafExpectValueChanged
  83. }
  84. - (void)testWriteABunchOfDataAndRead {
  85. FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
  86. FIRDatabaseReference *writeNode = tuple.one;
  87. FIRDatabaseReference *readNode = tuple.two;
  88. __block BOOL done = NO;
  89. [[[[writeNode child:@"a"] child:@"b"] child:@"c"] setValue:@1];
  90. [[[[writeNode child:@"a"] child:@"d"] child:@"e"] setValue:@2];
  91. [[[[writeNode child:@"a"] child:@"d"] child:@"f"] setValue:@3];
  92. [[writeNode child:@"g"] setValue:@4
  93. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  94. done = YES;
  95. }];
  96. [self waitUntil:^BOOL {
  97. return done;
  98. }];
  99. [super snapWaiter:readNode
  100. withBlock:^(FIRDataSnapshot *s) {
  101. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"b"]
  102. childSnapshotForPath:@"c"] value],
  103. @1, @"Proper child value");
  104. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"d"]
  105. childSnapshotForPath:@"e"] value],
  106. @2, @"Proper child value");
  107. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"d"]
  108. childSnapshotForPath:@"f"] value],
  109. @3, @"Proper child value");
  110. XCTAssertEqualObjects([[s childSnapshotForPath:@"g"] value], @4, @"Proper child value");
  111. }];
  112. }
  113. - (void)testWriteABunchOfDataWithLeadingZeroesAndRead {
  114. FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
  115. FIRDatabaseReference *writeNode = tuple.one;
  116. FIRDatabaseReference *readNode = tuple.two;
  117. [self waitForCompletionOf:[writeNode child:@"1"] setValue:@1];
  118. [self waitForCompletionOf:[writeNode child:@"01"] setValue:@2];
  119. [self waitForCompletionOf:[writeNode child:@"001"] setValue:@3];
  120. [self waitForCompletionOf:[writeNode child:@"0001"] setValue:@4];
  121. [super
  122. snapWaiter:readNode
  123. withBlock:^(FIRDataSnapshot *s) {
  124. XCTAssertEqualObjects([[s childSnapshotForPath:@"1"] value], @1, @"Proper child value");
  125. XCTAssertEqualObjects([[s childSnapshotForPath:@"01"] value], @2, @"Proper child value");
  126. XCTAssertEqualObjects([[s childSnapshotForPath:@"001"] value], @3, @"Proper child value");
  127. XCTAssertEqualObjects([[s childSnapshotForPath:@"0001"] value], @4, @"Proper child value");
  128. }];
  129. }
  130. - (void)testLeadingZeroesTurnIntoDictionary {
  131. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  132. [self waitForCompletionOf:[ref child:@"1"] setValue:@1];
  133. [self waitForCompletionOf:[ref child:@"01"] setValue:@2];
  134. __block BOOL done = NO;
  135. __block FIRDataSnapshot *snap = nil;
  136. [ref observeEventType:FIRDataEventTypeValue
  137. withBlock:^(FIRDataSnapshot *snapshot) {
  138. snap = snapshot;
  139. done = YES;
  140. }];
  141. WAIT_FOR(done);
  142. XCTAssertTrue([snap.value isKindOfClass:[NSDictionary class]], @"Should be dictionary");
  143. XCTAssertEqualObjects([snap.value objectForKey:@"1"], @1, @"Proper child value");
  144. XCTAssertEqualObjects([snap.value objectForKey:@"01"], @2, @"Proper child value");
  145. }
  146. - (void)testLeadingZerosDontCollapseLocally {
  147. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  148. __block BOOL done = NO;
  149. __block FIRDataSnapshot *snap = nil;
  150. [ref observeEventType:FIRDataEventTypeValue
  151. withBlock:^(FIRDataSnapshot *snapshot) {
  152. snap = snapshot;
  153. done = (snapshot.childrenCount == 2);
  154. }];
  155. [[ref child:@"3"] setValue:@YES];
  156. [[ref child:@"03"] setValue:@NO];
  157. WAIT_FOR(done);
  158. XCTAssertEqualObjects([[snap childSnapshotForPath:@"3"] value], @YES, @"Proper child value");
  159. XCTAssertEqualObjects([[snap childSnapshotForPath:@"03"] value], @NO, @"Proper child value");
  160. }
  161. - (void)testSnapshotRef {
  162. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  163. __block BOOL done = NO;
  164. [ref observeEventType:FIRDataEventTypeValue
  165. withBlock:^(FIRDataSnapshot *snapshot) {
  166. [snapshot.ref observeSingleEventOfType:FIRDataEventTypeValue
  167. withBlock:^(FIRDataSnapshot *snapshot) {
  168. done = YES;
  169. }];
  170. }];
  171. WAIT_FOR(done);
  172. }
  173. - (void)testWriteLeafNodeOverwriteAtParentVerifyExpectedEvents {
  174. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  175. FIRDatabaseReference *connected =
  176. [[[FTestHelpers defaultDatabase] reference] child:@".info/connected"];
  177. __block BOOL ready = NO;
  178. [connected observeEventType:FIRDataEventTypeValue
  179. withBlock:^(FIRDataSnapshot *snapshot) {
  180. NSNumber *val = [snapshot value];
  181. ready = [val boolValue];
  182. }];
  183. WAIT_FOR(ready);
  184. NSArray *lookingFor = @[
  185. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  186. withEvent:FIRDataEventTypeValue
  187. withString:nil], // 4
  188. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  189. withEvent:FIRDataEventTypeChildAdded
  190. withString:@"aa"], // 0
  191. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  192. withEvent:FIRDataEventTypeValue
  193. withString:nil], // 4
  194. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  195. withEvent:FIRDataEventTypeChildChanged
  196. withString:@"aa"], // 2
  197. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  198. withEvent:FIRDataEventTypeValue
  199. withString:nil], // 4
  200. ];
  201. [[node repo]
  202. interrupt]; // Going offline ensures that local events get queued up before server events
  203. FEventTester *et = [[FEventTester alloc] initFrom:self];
  204. [et addLookingFor:lookingFor];
  205. [[node child:@"a/aa"] setValue:@1];
  206. [[node child:@"a"] setValue:@{@"aa" : @2}];
  207. [[node repo] resume];
  208. [et wait];
  209. }
  210. - (void)testWriteLeafNodeOverwriteAtParentMultipleTimesVerifyExpectedEvents {
  211. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  212. NSArray *lookingFor = @[
  213. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  214. withEvent:FIRDataEventTypeValue
  215. withString:nil],
  216. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  217. withEvent:FIRDataEventTypeChildAdded
  218. withString:@"aa"],
  219. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  220. withEvent:FIRDataEventTypeValue
  221. withString:nil],
  222. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/bb"]
  223. withEvent:FIRDataEventTypeValue
  224. withString:nil],
  225. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  226. withEvent:FIRDataEventTypeChildChanged
  227. withString:@"aa"],
  228. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  229. withEvent:FIRDataEventTypeValue
  230. withString:nil],
  231. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  232. withEvent:FIRDataEventTypeValue
  233. withString:nil],
  234. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  235. withEvent:FIRDataEventTypeChildChanged
  236. withString:@"aa"],
  237. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  238. withEvent:FIRDataEventTypeValue
  239. withString:nil],
  240. ];
  241. [[node repo]
  242. interrupt]; // Going offline ensures that local events get queued up before server events
  243. FEventTester *et = [[FEventTester alloc] initFrom:self];
  244. [et addLookingFor:lookingFor];
  245. [[node child:@"a/aa"] setValue:@1];
  246. [[node child:@"a"] setValue:@{@"aa" : @2}];
  247. [[node child:@"a"] setValue:@{@"aa" : @3}];
  248. [[node child:@"a"] setValue:@{@"aa" : @3}];
  249. [[node repo] resume];
  250. [et wait];
  251. }
  252. #ifdef FLAKY_TEST
  253. This test flakes frequently on the emulator on travis and almost always on GHA with
  254. testWriteLeafNodeRemoveLeafVerifyExpectedEvents,
  255. failed
  256. : caught "NSInternalInconsistencyException",
  257. "Unable to report test assertion failure '(([target isEqualTo:recvd]) is true) failed: throwing
  258. "Unable to report test assertion failure '(([target isEqualTo:recvd]) is true) failed - Expected
  259. http : // localhost:9000/-M8IJYWb68MuqQKKz2IY/a aa (0) to match
  260. http : // localhost:9000/-M8IJYWb68MuqQKKz2IY/a (null) (4)' from
  261. /
  262. Users / runner / runners / 2.262.1 / work / firebase -
  263. ios - sdk / firebase - ios -
  264. sdk / Example / Database / Tests / Helpers /
  265. FEventTester
  266. .m : 123 because it was raised inside test case -
  267. [FEventTester(
  268. null)] which has no associated XCTestRun object.This may happen when test cases
  269. are constructed and invoked independently of standard XCTest infrastructure,
  270. or when the test has already finished
  271. ." - Expected http://localhost:9000/-M8IJYWb68MuqQKKz2IY/a aa (0) to match "
  272. "http://localhost:9000/-M8IJYWb68MuqQKKz2IY/a (null) (4)' from "
  273. "/Users/runner/runners/2.262.1/work/firebase-ios-sdk/firebase-ios-sdk/"
  274. "Example/Database/Tests/Helpers/FEventTester.m:123 because it was raised "
  275. "inside test case -[FEventTester (null)] which has no associated XCTestRun "
  276. "object. This may happen when test cases are constructed and invoked "
  277. "independently of standard XCTest infrastructure, or when the test has "
  278. "already finished." /
  279. Users / runner / runners / 2.262.1 / work / firebase -
  280. ios - sdk / firebase - ios -
  281. sdk / Example / Database / Tests / Helpers / FEventTester.m:
  282. 123
  283. ``` FTupleEventTypeString *recvd = [self.actualPathsAndEvents objectAtIndex:i];
  284. XCTAssertTrue([target isEqualTo:recvd], @"Expected %@ to match %@", target, recvd);
  285. - (void)testWriteParentNodeOverwriteAtLeafVerifyExpectedEvents {
  286. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  287. NSArray *lookingFor = @[
  288. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  289. withEvent:FIRDataEventTypeValue
  290. withString:nil],
  291. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  292. withEvent:FIRDataEventTypeChildAdded
  293. withString:@"aa"],
  294. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  295. withEvent:FIRDataEventTypeValue
  296. withString:nil],
  297. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  298. withEvent:FIRDataEventTypeValue
  299. withString:nil],
  300. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  301. withEvent:FIRDataEventTypeChildChanged
  302. withString:@"aa"],
  303. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  304. withEvent:FIRDataEventTypeValue
  305. withString:nil],
  306. ];
  307. [[node repo]
  308. interrupt]; // Going offline ensures that local events get queued up before server events
  309. FEventTester *et = [[FEventTester alloc] initFrom:self];
  310. [et addLookingFor:lookingFor];
  311. [[node child:@"a"] setValue:@{@"aa" : @2}];
  312. [[node child:@"a/aa"] setValue:@1];
  313. [[node repo] resume];
  314. [et wait];
  315. }
  316. - (void)testWriteLeafNodeRemoveParentNodeVerifyExpectedEvents {
  317. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  318. FIRDatabaseReference *writer = refs.one;
  319. FIRDatabaseReference *reader = refs.two;
  320. NSArray *lookingFor = @[
  321. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"]
  322. withEvent:FIRDataEventTypeValue
  323. withString:nil],
  324. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  325. withEvent:FIRDataEventTypeChildAdded
  326. withString:@"aa"],
  327. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  328. withEvent:FIRDataEventTypeValue
  329. withString:nil],
  330. [[FTupleEventTypeString alloc] initWithFirebase:writer
  331. withEvent:FIRDataEventTypeChildAdded
  332. withString:@"a"],
  333. [[FTupleEventTypeString alloc] initWithFirebase:writer
  334. withEvent:FIRDataEventTypeValue
  335. withString:nil],
  336. ];
  337. FEventTester *et = [[FEventTester alloc] initFrom:self];
  338. [et addLookingFor:lookingFor];
  339. [[writer child:@"a/aa"] setValue:@42];
  340. // the local events
  341. [et wait];
  342. // the reader should get all of the events intermingled
  343. FEventTester *readerEvents = [[FEventTester alloc] initFrom:self];
  344. lookingFor = @[
  345. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"]
  346. withEvent:FIRDataEventTypeValue
  347. withString:nil],
  348. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  349. withEvent:FIRDataEventTypeChildAdded
  350. withString:@"aa"],
  351. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  352. withEvent:FIRDataEventTypeValue
  353. withString:nil],
  354. [[FTupleEventTypeString alloc] initWithFirebase:reader
  355. withEvent:FIRDataEventTypeChildAdded
  356. withString:@"a"],
  357. [[FTupleEventTypeString alloc] initWithFirebase:reader
  358. withEvent:FIRDataEventTypeValue
  359. withString:nil]
  360. ];
  361. [readerEvents addLookingFor:lookingFor];
  362. [readerEvents wait];
  363. lookingFor = @[
  364. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"]
  365. withEvent:FIRDataEventTypeValue
  366. withString:nil],
  367. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  368. withEvent:FIRDataEventTypeChildRemoved
  369. withString:@"aa"],
  370. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  371. withEvent:FIRDataEventTypeValue
  372. withString:nil],
  373. [[FTupleEventTypeString alloc] initWithFirebase:reader
  374. withEvent:FIRDataEventTypeChildRemoved
  375. withString:@"a"],
  376. [[FTupleEventTypeString alloc] initWithFirebase:reader
  377. withEvent:FIRDataEventTypeValue
  378. withString:nil]
  379. ];
  380. [readerEvents addLookingFor:lookingFor];
  381. lookingFor = @[
  382. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"]
  383. withEvent:FIRDataEventTypeValue
  384. withString:nil],
  385. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  386. withEvent:FIRDataEventTypeChildRemoved
  387. withString:@"aa"],
  388. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  389. withEvent:FIRDataEventTypeValue
  390. withString:nil],
  391. [[FTupleEventTypeString alloc] initWithFirebase:writer
  392. withEvent:FIRDataEventTypeChildRemoved
  393. withString:@"a"],
  394. [[FTupleEventTypeString alloc] initWithFirebase:writer
  395. withEvent:FIRDataEventTypeValue
  396. withString:nil]
  397. ];
  398. [et addLookingFor:lookingFor];
  399. [[writer child:@"a"] removeValue];
  400. [et wait];
  401. [readerEvents wait];
  402. [et unregister];
  403. [readerEvents unregister];
  404. // Ensure we can write a new value
  405. __block NSNumber *readVal = @0.0;
  406. __block NSNumber *writeVal = @0.0;
  407. [[reader child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  408. withBlock:^(FIRDataSnapshot *snapshot) {
  409. id val = [snapshot value];
  410. if (val != [NSNull null]) {
  411. readVal = val;
  412. }
  413. }];
  414. [[writer child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  415. withBlock:^(FIRDataSnapshot *snapshot) {
  416. id val = [snapshot value];
  417. if (val != [NSNull null]) {
  418. writeVal = val;
  419. }
  420. }];
  421. [[writer child:@"a/aa"] setValue:@3.1415];
  422. [self waitUntil:^BOOL {
  423. return fabs([readVal doubleValue] - 3.1415) < 0.001 &&
  424. fabs([writeVal doubleValue] - 3.1415) < 0.001;
  425. // return [readVal isEqualToNumber:@3.1415] && [writeVal isEqualToNumber:@3.1415];
  426. }];
  427. }
  428. - (void)testWriteLeafNodeRemoveLeafVerifyExpectedEvents {
  429. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  430. FIRDatabaseReference *writer = refs.one;
  431. FIRDatabaseReference *reader = refs.two;
  432. NSArray *lookingFor = @[
  433. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"]
  434. withEvent:FIRDataEventTypeValue
  435. withString:nil],
  436. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  437. withEvent:FIRDataEventTypeChildAdded
  438. withString:@"aa"],
  439. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  440. withEvent:FIRDataEventTypeValue
  441. withString:nil],
  442. [[FTupleEventTypeString alloc] initWithFirebase:writer
  443. withEvent:FIRDataEventTypeChildAdded
  444. withString:@"a"],
  445. [[FTupleEventTypeString alloc] initWithFirebase:writer
  446. withEvent:FIRDataEventTypeValue
  447. withString:nil],
  448. ];
  449. FEventTester *et = [[FEventTester alloc] initFrom:self];
  450. [et addLookingFor:lookingFor];
  451. [[writer child:@"a/aa"] setValue:@42];
  452. // the local events
  453. [et wait];
  454. // the reader should get all of the events intermingled
  455. FEventTester *readerEvents = [[FEventTester alloc] initFrom:self];
  456. lookingFor = @[
  457. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"]
  458. withEvent:FIRDataEventTypeValue
  459. withString:nil],
  460. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  461. withEvent:FIRDataEventTypeChildAdded
  462. withString:@"aa"],
  463. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  464. withEvent:FIRDataEventTypeValue
  465. withString:nil],
  466. [[FTupleEventTypeString alloc] initWithFirebase:reader
  467. withEvent:FIRDataEventTypeChildAdded
  468. withString:@"a"],
  469. [[FTupleEventTypeString alloc] initWithFirebase:reader
  470. withEvent:FIRDataEventTypeValue
  471. withString:nil]
  472. ];
  473. [readerEvents addLookingFor:lookingFor];
  474. [readerEvents wait];
  475. lookingFor = @[
  476. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"]
  477. withEvent:FIRDataEventTypeValue
  478. withString:nil],
  479. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  480. withEvent:FIRDataEventTypeChildRemoved
  481. withString:@"aa"],
  482. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  483. withEvent:FIRDataEventTypeValue
  484. withString:nil],
  485. [[FTupleEventTypeString alloc] initWithFirebase:reader
  486. withEvent:FIRDataEventTypeChildRemoved
  487. withString:@"a"],
  488. [[FTupleEventTypeString alloc] initWithFirebase:reader
  489. withEvent:FIRDataEventTypeValue
  490. withString:nil]
  491. ];
  492. [readerEvents addLookingFor:lookingFor];
  493. lookingFor = @[
  494. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"]
  495. withEvent:FIRDataEventTypeValue
  496. withString:nil],
  497. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  498. withEvent:FIRDataEventTypeChildRemoved
  499. withString:@"aa"],
  500. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"]
  501. withEvent:FIRDataEventTypeValue
  502. withString:nil],
  503. [[FTupleEventTypeString alloc] initWithFirebase:writer
  504. withEvent:FIRDataEventTypeChildRemoved
  505. withString:@"a"],
  506. [[FTupleEventTypeString alloc] initWithFirebase:writer
  507. withEvent:FIRDataEventTypeValue
  508. withString:nil]
  509. ];
  510. [et addLookingFor:lookingFor];
  511. // remove just the leaf
  512. [[writer child:@"a/aa"] removeValue];
  513. [et wait];
  514. [readerEvents wait];
  515. [et unregister];
  516. [readerEvents unregister];
  517. // Ensure we can write a new value
  518. __block NSNumber *readVal = @0.0;
  519. __block NSNumber *writeVal = @0.0;
  520. [[reader child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  521. withBlock:^(FIRDataSnapshot *snapshot) {
  522. id val = [snapshot value];
  523. if (val != [NSNull null]) {
  524. readVal = val;
  525. }
  526. }];
  527. [[writer child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  528. withBlock:^(FIRDataSnapshot *snapshot) {
  529. id val = [snapshot value];
  530. if (val != [NSNull null]) {
  531. writeVal = val;
  532. }
  533. }];
  534. [[writer child:@"a/aa"] setValue:@3.1415];
  535. [self waitUntil:^BOOL {
  536. // NSLog(@"readVal: %@, writeVal: %@, vs %@", readVal, writeVal, @3.1415);
  537. // return [readVal isEqualToNumber:@3.1415] && [writeVal isEqualToNumber:@3.1415];
  538. return fabs([readVal doubleValue] - 3.1415) < 0.001 &&
  539. fabs([writeVal doubleValue] - 3.1415) < 0.001;
  540. }];
  541. }
  542. #endif
  543. - (void)testWriteMultipleLeafNodesRemoveOnlyOneVerifyExpectedEvents {
  544. // XXX impl
  545. }
  546. - (void)testVerifyNodeNamesCantStartWithADot {
  547. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  548. XCTAssertThrows([ref child:@".foo"], @"not a valid .prefix");
  549. XCTAssertThrows([ref child:@"foo/.foo"], @"not a valid path");
  550. // Should not throw
  551. [[ref parent] child:@".info"];
  552. }
  553. - (void)testVerifyWritingToDotLengthAndDotKeysThrows {
  554. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  555. XCTAssertThrows([[ref child:@".keys"] setValue:@42], @"not a valid .prefix");
  556. XCTAssertThrows([[ref child:@".length"] setValue:@42], @"not a valid path");
  557. }
  558. - (void)testNumericKeysGetTurnedIntoArrays {
  559. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  560. [[ref child:@"0"] setValue:@"alpha"];
  561. [[ref child:@"1"] setValue:@"bravo"];
  562. [[ref child:@"2"] setValue:@"charlie"];
  563. [[ref child:@"3"] setValue:@"delta"];
  564. [[ref child:@"4"] setValue:@"echo"];
  565. __block BOOL ready = NO;
  566. [ref observeEventType:FIRDataEventTypeValue
  567. withBlock:^(FIRDataSnapshot *snapshot) {
  568. id val = [snapshot value];
  569. XCTAssertTrue([val isKindOfClass:[NSArray class]], @"Expected an array");
  570. NSArray *expected = @[ @"alpha", @"bravo", @"charlie", @"delta", @"echo" ];
  571. XCTAssertTrue([expected isEqualToArray:val], @"Did not get the correct array");
  572. ready = YES;
  573. }];
  574. [self waitUntil:^{
  575. return ready;
  576. }];
  577. }
  578. // This was an issue on 64-bit.
  579. - (void)testLargeNumericKeysDontGetTurnedIntoArrays {
  580. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  581. [[ref child:@"100003354884401"] setValue:@"alpha"];
  582. __block BOOL ready = NO;
  583. [ref observeSingleEventOfType:FIRDataEventTypeValue
  584. withBlock:^(FIRDataSnapshot *snapshot) {
  585. id val = [snapshot value];
  586. XCTAssertTrue([val isKindOfClass:[NSDictionary class]],
  587. @"Expected a dictionary.");
  588. ready = YES;
  589. }];
  590. [self waitUntil:^{
  591. return ready;
  592. }];
  593. }
  594. - (void)testWriteCompoundObjectAndGetItBack {
  595. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  596. NSDictionary *data = @{
  597. @"a" : @{@"aa" : @5, @"ab" : @3},
  598. @"b" : @{@"ba" : @"hey there!", @"bb" : @{@"bba" : @NO}},
  599. @"c" : @[ @0, @{@"c_1" : @4}, @"hey", @YES, @NO, @"dude" ]
  600. };
  601. __block FIRDataSnapshot *snap = nil;
  602. [node observeEventType:FIRDataEventTypeValue
  603. withBlock:^(FIRDataSnapshot *snapshot) {
  604. snap = snapshot;
  605. }];
  606. __block BOOL done = NO;
  607. [node setValue:data
  608. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  609. done = YES;
  610. }];
  611. [self waitUntil:^BOOL {
  612. return done;
  613. }];
  614. [self snapWaiter:node
  615. withBlock:^(FIRDataSnapshot *snapshot) {
  616. XCTAssertTrue([[[[snapshot value] objectForKey:@"c"] objectAtIndex:3] boolValue],
  617. @"Got proper boolean");
  618. }];
  619. }
  620. - (void)testCanPassValueToPush {
  621. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  622. FIRDatabaseReference *pushA = [node childByAutoId];
  623. [pushA setValue:@5];
  624. [self snapWaiter:pushA
  625. withBlock:^(FIRDataSnapshot *snapshot) {
  626. XCTAssertEqualObjects(@5, [snapshot value], @"Got proper value");
  627. }];
  628. FIRDatabaseReference *pushB = [node childByAutoId];
  629. [pushB setValue:@{@"a" : @5, @"b" : @6}];
  630. [self snapWaiter:pushB
  631. withBlock:^(FIRDataSnapshot *snapshot) {
  632. XCTAssertEqualObjects(@5, [[snapshot value] objectForKey:@"a"], @"Got proper value");
  633. XCTAssertEqualObjects(@6, [[snapshot value] objectForKey:@"b"], @"Got proper value");
  634. }];
  635. }
  636. // Dropped test that tested callbacks to push. Support was removed.
  637. - (void)testRemoveCallbackHit {
  638. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  639. __block BOOL setDone = NO;
  640. __block BOOL removeDone = NO;
  641. __block BOOL readDone = NO;
  642. [node setValue:@42
  643. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  644. setDone = YES;
  645. }];
  646. [self waitUntil:^BOOL {
  647. return setDone;
  648. }];
  649. [node observeEventType:FIRDataEventTypeValue
  650. withBlock:^(FIRDataSnapshot *snapshot) {
  651. id val = [snapshot value];
  652. if (val == [NSNull null]) {
  653. readDone = YES;
  654. }
  655. }];
  656. [node removeValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  657. XCTAssertTrue(error == nil, @"Should not be an error removing");
  658. removeDone = YES;
  659. }];
  660. [self waitUntil:^BOOL {
  661. return readDone && removeDone;
  662. }];
  663. }
  664. - (void)testRemoveCallbackIsHitForNodesThatAreAlreadyRemoved {
  665. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  666. __block int removes = 0;
  667. [node removeValueWithCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  668. removes = removes + 1;
  669. }];
  670. [node removeValueWithCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  671. removes = removes + 1;
  672. }];
  673. [self waitUntil:^BOOL {
  674. return removes == 2;
  675. }];
  676. }
  677. - (void)testUsingNumbersAsKeysDoesntCreateHugeSparseArrays {
  678. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  679. [[ref child:@"3024"] setValue:@5];
  680. __block BOOL ready = NO;
  681. [ref observeEventType:FIRDataEventTypeValue
  682. withBlock:^(FIRDataSnapshot *snapshot) {
  683. id val = [snapshot value];
  684. XCTAssertTrue(![val isKindOfClass:[NSArray class]], @"Should not be an array");
  685. ready = YES;
  686. }];
  687. [self waitUntil:^BOOL {
  688. return ready;
  689. }];
  690. }
  691. - (void)testOnceWithACallbackHitsServer {
  692. FTupleFirebase *tuple = [FTestHelpers getRandomNodeTriple];
  693. FIRDatabaseReference *writeNode = tuple.one;
  694. FIRDatabaseReference *readNode = tuple.two;
  695. FIRDatabaseReference *readNodeB = tuple.three;
  696. __block BOOL initialReadDone = NO;
  697. [readNode observeSingleEventOfType:FIRDataEventTypeValue
  698. withBlock:^(FIRDataSnapshot *snapshot) {
  699. XCTAssertTrue([[snapshot value] isEqual:[NSNull null]],
  700. @"First callback is null");
  701. initialReadDone = YES;
  702. }];
  703. [self waitUntil:^BOOL {
  704. return initialReadDone;
  705. }];
  706. __block BOOL writeDone = NO;
  707. [writeNode setValue:@42
  708. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  709. writeDone = YES;
  710. }];
  711. [self waitUntil:^BOOL {
  712. return writeDone;
  713. }];
  714. __block BOOL readDone = NO;
  715. [readNodeB observeSingleEventOfType:FIRDataEventTypeValue
  716. withBlock:^(FIRDataSnapshot *snapshot) {
  717. XCTAssertEqualObjects(@42, [snapshot value], @"Proper second read");
  718. readDone = YES;
  719. }];
  720. [self waitUntil:^BOOL {
  721. return readDone;
  722. }];
  723. }
  724. // Removed test of forEach aborting iteration. Support dropped, use for .. in syntax
  725. - (void)testSetAndThenListenForValueEventsAreCorrect {
  726. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  727. __block BOOL setDone = NO;
  728. [node setValue:@"moo"
  729. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  730. setDone = YES;
  731. }];
  732. __block int calls = 0;
  733. [node observeEventType:FIRDataEventTypeValue
  734. withBlock:^(FIRDataSnapshot *snapshot) {
  735. calls = calls + 1;
  736. XCTAssertTrue(calls == 1, @"Only called once");
  737. XCTAssertEqualObjects([snapshot value], @"moo", @"Proper snapshot value");
  738. }];
  739. [self waitUntil:^BOOL {
  740. return setDone && calls == 1;
  741. }];
  742. [node removeAllObservers];
  743. }
  744. - (void)testHasChildrenWorksCorrectly {
  745. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  746. [node setValue:@{@"one" : @42, @"two" : @{@"a" : @5}, @"three" : @{@"a" : @5, @"b" : @6}}];
  747. __block BOOL removedTwo = NO;
  748. __block BOOL done = NO;
  749. [node observeEventType:FIRDataEventTypeValue
  750. withBlock:^(FIRDataSnapshot *snapshot) {
  751. if (!removedTwo) {
  752. XCTAssertFalse([[snapshot childSnapshotForPath:@"one"] hasChildren], @"nope");
  753. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] hasChildren], @"nope");
  754. XCTAssertTrue([[snapshot childSnapshotForPath:@"three"] hasChildren], @"nope");
  755. XCTAssertFalse([[snapshot childSnapshotForPath:@"four"] hasChildren], @"nope");
  756. removedTwo = YES;
  757. [[node child:@"two"] removeValue];
  758. } else {
  759. XCTAssertFalse([[snapshot childSnapshotForPath:@"two"] hasChildren],
  760. @"Second time around");
  761. done = YES;
  762. }
  763. }];
  764. [self waitUntil:^BOOL {
  765. return done;
  766. }];
  767. }
  768. - (void)testNumChildrenWorksCorrectly {
  769. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  770. [node setValue:@{@"one" : @42, @"two" : @{@"a" : @5}, @"three" : @{@"a" : @5, @"b" : @6}}];
  771. __block BOOL removedTwo = NO;
  772. __block BOOL done = NO;
  773. [node observeEventType:FIRDataEventTypeValue
  774. withBlock:^(FIRDataSnapshot *snapshot) {
  775. if (!removedTwo) {
  776. XCTAssertTrue([snapshot childrenCount] == 3, @"Total children");
  777. XCTAssertTrue([[snapshot childSnapshotForPath:@"one"] childrenCount] == 0,
  778. @"Two's children");
  779. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] childrenCount] == 1,
  780. @"Two's children");
  781. XCTAssertTrue([[snapshot childSnapshotForPath:@"three"] childrenCount] == 2,
  782. @"Two's children");
  783. XCTAssertTrue([[snapshot childSnapshotForPath:@"four"] childrenCount] == 0,
  784. @"Two's children");
  785. removedTwo = YES;
  786. [[node child:@"two"] removeValue];
  787. } else {
  788. XCTAssertTrue([snapshot childrenCount] == 2, @"Total children");
  789. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] childrenCount] == 0,
  790. @"Two's children");
  791. done = YES;
  792. }
  793. }];
  794. [self waitUntil:^BOOL {
  795. return done;
  796. }];
  797. }
  798. #ifdef FLAKY_TEST
  799. - (void)testSettingANodeWithChildrenToAPrimitiveAndBack {
  800. // Can't tolerate stale data; so disable persistence.
  801. FTupleFirebase *tuple = [FTestHelpers getRandomNodePairWithoutPersistence];
  802. FIRDatabaseReference *writeNode = tuple.one;
  803. FIRDatabaseReference *readNode = tuple.two;
  804. __block BOOL done = NO;
  805. NSDictionary *compound = @{@"a" : @5, @"b" : @6};
  806. NSNumber *number = @76;
  807. [writeNode setValue:compound];
  808. [self snapWaiter:writeNode
  809. withBlock:^(FIRDataSnapshot *snapshot) {
  810. XCTAssertTrue([snapshot hasChildren], @"Has children");
  811. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  812. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  813. done = YES;
  814. }];
  815. [self waitUntil:^BOOL {
  816. return done;
  817. }];
  818. done = NO;
  819. [self snapWaiter:readNode
  820. withBlock:^(FIRDataSnapshot *snapshot) {
  821. XCTAssertTrue([snapshot hasChildren], @"has children");
  822. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  823. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  824. done = YES;
  825. }];
  826. [self waitUntil:^BOOL {
  827. return done;
  828. }];
  829. done = NO;
  830. [writeNode setValue:number
  831. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  832. done = YES;
  833. }];
  834. [self waitUntil:^BOOL {
  835. return done;
  836. }];
  837. done = NO;
  838. [self snapWaiter:readNode
  839. withBlock:^(FIRDataSnapshot *snapshot) {
  840. XCTAssertFalse([snapshot hasChildren], @"No more children");
  841. XCTAssertEqualObjects(number, [snapshot value], @"Proper non compound value");
  842. done = YES;
  843. }];
  844. [self waitUntil:^BOOL {
  845. return done;
  846. }];
  847. done = NO;
  848. [writeNode setValue:compound
  849. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  850. done = YES;
  851. }];
  852. [self waitUntil:^BOOL {
  853. return done;
  854. }];
  855. done = NO;
  856. [self snapWaiter:readNode
  857. withBlock:^(FIRDataSnapshot *snapshot) {
  858. XCTAssertTrue([snapshot hasChildren], @"Has children");
  859. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  860. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  861. done = YES;
  862. }];
  863. [self waitUntil:^BOOL {
  864. return done;
  865. }];
  866. XCTAssertTrue(done, @"Properly finished");
  867. }
  868. #endif
  869. - (void)testWriteLeafRemoveLeafAddChildToRemovedNode {
  870. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  871. FIRDatabaseReference *writer = refs.one;
  872. FIRDatabaseReference *reader = refs.two;
  873. __block BOOL ready = NO;
  874. [writer setValue:@5];
  875. [writer removeValue];
  876. [[writer child:@"abc"] setValue:@5
  877. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  878. ready = YES;
  879. }];
  880. [self waitUntil:^BOOL {
  881. return ready;
  882. }];
  883. __block NSDictionary *readVal = nil;
  884. [reader observeEventType:FIRDataEventTypeValue
  885. withBlock:^(FIRDataSnapshot *snapshot) {
  886. readVal = [snapshot value];
  887. }];
  888. [self waitUntil:^BOOL {
  889. return readVal != nil;
  890. }];
  891. NSNumber *five = [readVal objectForKey:@"abc"];
  892. XCTAssertTrue([five isEqualToNumber:@5], @"Should get 5");
  893. }
  894. - (void)testListenForValueAndThenWriteOnANodeWithExistingData {
  895. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  896. FIRDatabaseReference *writer = refs.one;
  897. FIRDatabaseReference *reader = refs.two;
  898. [self waitForCompletionOf:writer setValue:@{@"a" : @5, @"b" : @2}];
  899. __block int calls = 0;
  900. [reader observeEventType:FIRDataEventTypeValue
  901. withBlock:^(FIRDataSnapshot *snapshot) {
  902. calls++;
  903. if (calls == 1) {
  904. NSDictionary *val = [snapshot value];
  905. NSDictionary *expected = @{@"a" : @10, @"b" : @2};
  906. XCTAssertTrue([val isEqualToDictionary:expected], @"Got the correct value");
  907. } else {
  908. XCTFail(@"Should only be called once");
  909. }
  910. }];
  911. [[reader child:@"a"] setValue:@10];
  912. [self waitUntil:^BOOL {
  913. return calls == 1;
  914. }];
  915. [reader removeAllObservers];
  916. }
  917. - (void)testSetPriorityOnNonexistentNodeFails {
  918. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  919. __block BOOL ready = NO;
  920. [ref setPriority:@5
  921. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  922. XCTAssertTrue(error != nil, @"This should not succeed");
  923. ready = YES;
  924. }];
  925. [self waitUntil:^BOOL {
  926. return ready;
  927. }];
  928. }
  929. - (void)testSetPriorityOnExistentNodeSucceeds {
  930. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  931. __block BOOL ready = NO;
  932. [ref setValue:@"hello!"];
  933. [ref setPriority:@5
  934. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  935. XCTAssertTrue(error == nil, @"This should succeed");
  936. ready = YES;
  937. }];
  938. [self waitUntil:^BOOL {
  939. return ready;
  940. }];
  941. }
  942. - (void)testSetWithPrioritySetsValueAndPriority {
  943. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  944. FIRDatabaseReference *writer = refs.one;
  945. FIRDatabaseReference *reader = refs.two;
  946. [self waitForCompletionOf:writer setValue:@"hello" andPriority:@5];
  947. __block FIRDataSnapshot *writeSnap = nil;
  948. __block FIRDataSnapshot *readSnap = nil;
  949. [writer observeEventType:FIRDataEventTypeValue
  950. withBlock:^(FIRDataSnapshot *snapshot) {
  951. writeSnap = snapshot;
  952. }];
  953. [reader observeEventType:FIRDataEventTypeValue
  954. withBlock:^(FIRDataSnapshot *snapshot) {
  955. readSnap = snapshot;
  956. }];
  957. [self waitUntil:^BOOL {
  958. return readSnap != nil && writeSnap != nil;
  959. }];
  960. XCTAssertTrue([@"hello" isEqualToString:[readSnap value]], @"Got the value on the reader");
  961. XCTAssertTrue([@"hello" isEqualToString:[writeSnap value]], @"Got the value on the writer");
  962. XCTAssertTrue([@5 isEqualToNumber:[readSnap priority]], @"Got the priority on the reader");
  963. XCTAssertTrue([@5 isEqualToNumber:[writeSnap priority]], @"Got the priority on the writer");
  964. }
  965. - (void)testEffectsOfSetPriorityIsImmediatelyEvident {
  966. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  967. NSMutableArray *values = [[NSMutableArray alloc] init];
  968. NSMutableArray *priorities = [[NSMutableArray alloc] init];
  969. [ref observeSingleEventOfType:FIRDataEventTypeValue
  970. withBlock:^(FIRDataSnapshot *snapshot) {
  971. [values addObject:[snapshot value]];
  972. [priorities addObject:[snapshot priority]];
  973. }];
  974. [ref setValue:@5];
  975. [ref setPriority:@10];
  976. __block BOOL ready = NO;
  977. [ref observeEventType:FIRDataEventTypeValue
  978. withBlock:^(FIRDataSnapshot *snapshot) {
  979. [values addObject:[snapshot value]];
  980. [priorities addObject:[snapshot priority]];
  981. ready = YES;
  982. }];
  983. [self waitUntil:^BOOL {
  984. return ready;
  985. }];
  986. NSArray *expectedValues = @[ @5, @5 ];
  987. NSArray *expectedPriorities = @[ [NSNull null], @10 ];
  988. XCTAssertTrue([values isEqualToArray:expectedValues],
  989. @"Expected both listeners to get 5, got %@ instead", values);
  990. XCTAssertTrue([priorities isEqualToArray:expectedPriorities],
  991. @"The first listener should have missed the priority, got %@ instead", priorities);
  992. }
  993. - (void)testSetOverwritesPriorityOfTopLevelNodeAndSubnodes {
  994. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  995. FIRDatabaseReference *writer = refs.one;
  996. FIRDatabaseReference *reader = refs.two;
  997. __block BOOL ready = NO;
  998. [writer setValue:@{@"a" : @5}];
  999. [writer setPriority:@10];
  1000. [[writer child:@"a"] setPriority:@18];
  1001. [writer setValue:@{@"a" : @7}
  1002. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1003. ready = YES;
  1004. }];
  1005. [self waitUntil:^BOOL {
  1006. return ready;
  1007. }];
  1008. ready = NO;
  1009. [reader observeEventType:FIRDataEventTypeValue
  1010. withBlock:^(FIRDataSnapshot *snapshot) {
  1011. id pri = [snapshot priority];
  1012. XCTAssertTrue([NSNull null] == pri, @"Expected null priority");
  1013. FIRDataSnapshot *child = [snapshot childSnapshotForPath:@"a"];
  1014. XCTAssertTrue([NSNull null] == [child priority],
  1015. @"Child priority should be null too");
  1016. ready = YES;
  1017. }];
  1018. [self waitUntil:^BOOL {
  1019. return ready;
  1020. }];
  1021. }
  1022. - (void)testSetPriorityOfLeafSavesCorrectly {
  1023. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1024. FIRDatabaseReference *writer = refs.one;
  1025. FIRDatabaseReference *reader = refs.two;
  1026. __block BOOL ready = NO;
  1027. [writer setValue:@"testleaf"
  1028. andPriority:@992
  1029. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1030. ready = YES;
  1031. }];
  1032. [self waitUntil:^BOOL {
  1033. return ready;
  1034. }];
  1035. ready = NO;
  1036. [reader observeEventType:FIRDataEventTypeValue
  1037. withBlock:^(FIRDataSnapshot *snapshot) {
  1038. id pri = [snapshot priority];
  1039. XCTAssertTrue([@992 isEqualToNumber:pri], @"Expected non-null priority");
  1040. ready = YES;
  1041. }];
  1042. [self waitUntil:^BOOL {
  1043. return ready;
  1044. }];
  1045. }
  1046. - (void)testSetPriorityOfObjectSavesCorrectly {
  1047. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1048. FIRDatabaseReference *writer = refs.one;
  1049. FIRDatabaseReference *reader = refs.two;
  1050. __block BOOL ready = NO;
  1051. [writer setValue:@{@"a" : @5}
  1052. andPriority:@991
  1053. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1054. ready = YES;
  1055. }];
  1056. [self waitUntil:^BOOL {
  1057. return ready;
  1058. }];
  1059. ready = NO;
  1060. [reader observeEventType:FIRDataEventTypeValue
  1061. withBlock:^(FIRDataSnapshot *snapshot) {
  1062. id pri = [snapshot priority];
  1063. XCTAssertTrue([@991 isEqualToNumber:pri], @"Expected non-null priority");
  1064. ready = YES;
  1065. }];
  1066. [self waitUntil:^BOOL {
  1067. return ready;
  1068. }];
  1069. }
  1070. - (void)testSetWithPriorityFollowedBySetClearsPriority {
  1071. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1072. FIRDatabaseReference *writer = refs.one;
  1073. FIRDatabaseReference *reader = refs.two;
  1074. __block BOOL ready = NO;
  1075. [writer setValue:@{@"a" : @5}
  1076. andPriority:@991
  1077. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1078. ready = YES;
  1079. }];
  1080. [self waitUntil:^BOOL {
  1081. return ready;
  1082. }];
  1083. ready = NO;
  1084. [reader setValue:@{@"a" : @19}
  1085. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1086. ready = YES;
  1087. }];
  1088. [self waitUntil:^BOOL {
  1089. return ready;
  1090. }];
  1091. ready = NO;
  1092. [reader observeEventType:FIRDataEventTypeValue
  1093. withBlock:^(FIRDataSnapshot *snapshot) {
  1094. id pri = [snapshot priority];
  1095. XCTAssertTrue([NSNull null] == pri, @"Expected null priority");
  1096. ready = YES;
  1097. }];
  1098. [self waitUntil:^BOOL {
  1099. return ready;
  1100. }];
  1101. }
  1102. - (void)testGetPriorityReturnsCorrectType {
  1103. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1104. __block FIRDataSnapshot *snap = nil;
  1105. [ref observeEventType:FIRDataEventTypeValue
  1106. withBlock:^(FIRDataSnapshot *snapshot) {
  1107. snap = snapshot;
  1108. }];
  1109. [ref setValue:@"a"];
  1110. [self waitUntil:^BOOL {
  1111. return snap != nil;
  1112. }];
  1113. XCTAssertTrue([snap priority] == [NSNull null], @"Expect null priority");
  1114. snap = nil;
  1115. [ref setValue:@"b" andPriority:@5];
  1116. [self waitUntil:^BOOL {
  1117. return snap != nil;
  1118. }];
  1119. XCTAssertTrue([[snap priority] isEqualToNumber:@5], @"Expect priority");
  1120. snap = nil;
  1121. [ref setValue:@"c" andPriority:@"6"];
  1122. [self waitUntil:^BOOL {
  1123. return snap != nil;
  1124. }];
  1125. XCTAssertTrue([[snap priority] isEqualToString:@"6"], @"Expect priority");
  1126. snap = nil;
  1127. [ref setValue:@"d" andPriority:@7];
  1128. [self waitUntil:^BOOL {
  1129. return snap != nil;
  1130. }];
  1131. XCTAssertTrue([[snap priority] isEqualToNumber:@7], @"Expect priority");
  1132. snap = nil;
  1133. [ref setValue:@{@".value" : @"e", @".priority" : @8}];
  1134. [self waitUntil:^BOOL {
  1135. return snap != nil;
  1136. }];
  1137. XCTAssertTrue([[snap priority] isEqualToNumber:@8], @"Expect priority");
  1138. snap = nil;
  1139. [ref setValue:@{@".value" : @"f", @".priority" : @"8"}];
  1140. [self waitUntil:^BOOL {
  1141. return snap != nil;
  1142. }];
  1143. XCTAssertTrue([[snap priority] isEqualToString:@"8"], @"Expect priority");
  1144. snap = nil;
  1145. [ref setValue:@{@".value" : @"e", @".priority" : [NSNull null]}];
  1146. [self waitUntil:^BOOL {
  1147. return snap != nil;
  1148. }];
  1149. XCTAssertTrue([snap priority] == [NSNull null], @"Expect priority");
  1150. snap = nil;
  1151. }
  1152. - (void)testExportValIncludesPriorities {
  1153. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1154. NSDictionary *contents =
  1155. @{@"foo" : @{@"bar" : @{@".value" : @5, @".priority" : @7}, @".priority" : @"hi"}};
  1156. __block FIRDataSnapshot *snap = nil;
  1157. [ref observeEventType:FIRDataEventTypeValue
  1158. withBlock:^(FIRDataSnapshot *snapshot) {
  1159. snap = snapshot;
  1160. }];
  1161. [ref setValue:contents];
  1162. [self waitUntil:^BOOL {
  1163. return snap != nil;
  1164. }];
  1165. XCTAssertTrue([contents isEqualToDictionary:[snap valueInExportFormat]],
  1166. @"Expected priorities in snapshot");
  1167. }
  1168. - (void)testPriorityIsOverwrittenByServer {
  1169. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1170. FIRDatabaseReference *reader = refs.one;
  1171. FIRDatabaseReference *writer = refs.two;
  1172. __block int event = 0;
  1173. __block BOOL done = NO;
  1174. [reader observeEventType:FIRDataEventTypeValue
  1175. withBlock:^(FIRDataSnapshot *snapshot) {
  1176. NSLog(@"%@ Snapshot", snapshot);
  1177. id pri = [snapshot priority];
  1178. if (event == 0) {
  1179. XCTAssertTrue([@100 isEqualToNumber:pri],
  1180. @"Expect local priority. Got %@ instead.", pri);
  1181. } else if (event == 1) {
  1182. XCTAssertTrue(pri == [NSNull null], @"Expect remote priority. Got %@ instead.",
  1183. pri);
  1184. } else {
  1185. XCTFail(@"Extra event");
  1186. }
  1187. event++;
  1188. if (event == 2) {
  1189. done = YES;
  1190. }
  1191. }];
  1192. [writer
  1193. observeEventType:FIRDataEventTypeValue
  1194. withBlock:^(FIRDataSnapshot *snapshot) {
  1195. id pri = [snapshot priority];
  1196. if ([[pri class] isSubclassOfClass:[NSNumber class]] && [@100 isEqualToNumber:pri]) {
  1197. [writer setValue:@"whatever"];
  1198. }
  1199. }];
  1200. [reader setValue:@"hi" andPriority:@100];
  1201. [self waitUntil:^BOOL {
  1202. return done;
  1203. }];
  1204. }
  1205. - (void)testLargeNumericPrioritiesWork {
  1206. NSNumber *bigPriority = @1356721306842;
  1207. __block BOOL ready = NO;
  1208. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1209. FIRDatabaseReference *reader = refs.one;
  1210. FIRDatabaseReference *writer = refs.two;
  1211. [self waitForCompletionOf:writer setValue:@5 andPriority:bigPriority];
  1212. __block NSNumber *serverPriority = @0;
  1213. [reader observeEventType:FIRDataEventTypeValue
  1214. withBlock:^(FIRDataSnapshot *snapshot) {
  1215. serverPriority = [snapshot priority];
  1216. ready = YES;
  1217. }];
  1218. [self waitUntil:^BOOL {
  1219. return ready;
  1220. }];
  1221. XCTAssertTrue([bigPriority isEqualToNumber:serverPriority], @"Expect big priority back");
  1222. }
  1223. - (void)testToString {
  1224. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1225. FIRDatabaseReference *parent = [ref parent];
  1226. XCTAssertEqualObjects([parent description], self.databaseURL);
  1227. FIRDatabaseReference *child = [parent child:@"a/b/c"];
  1228. NSString *expected = [NSString stringWithFormat:@"%@/a/b/c", self.databaseURL];
  1229. XCTAssertEqualObjects([child description], expected);
  1230. }
  1231. - (void)testURLEncodingOfDescriptionAndURLDecodingOfNewFirebase {
  1232. __block BOOL ready = NO;
  1233. NSString *test1 =
  1234. [NSString stringWithFormat:@"%@/a%%b&c@d/space: /non-ascii_character:ø", self.databaseURL];
  1235. NSString *expected1 = [NSString
  1236. stringWithFormat:@"%@/a%%25b%%26c%%40d/space%%3A%%20/non-ascii_character%%3A%%C3%%B8",
  1237. self.databaseURL];
  1238. FIRDatabaseReference *ref = [[FTestHelpers defaultDatabase] referenceFromURL:test1];
  1239. NSString *result = [ref description];
  1240. XCTAssertTrue([result isEqualToString:expected1], @"Encodes properly");
  1241. int rnd = arc4random_uniform(100000000);
  1242. NSString *path = [NSString stringWithFormat:@"%i", rnd];
  1243. [[ref child:path] setValue:@"testdata"
  1244. withCompletionBlock:^(NSError *error, FIRDatabaseReference *childRef) {
  1245. FIRDatabaseReference *other =
  1246. [[FTestHelpers defaultDatabase] referenceFromURL:[ref description]];
  1247. [[other child:path] observeEventType:FIRDataEventTypeValue
  1248. withBlock:^(FIRDataSnapshot *snapshot) {
  1249. NSString *val = snapshot.value;
  1250. XCTAssertTrue([val isEqualToString:@"testdata"],
  1251. @"Expected to get testdata back");
  1252. ready = YES;
  1253. }];
  1254. }];
  1255. [self waitUntil:^BOOL {
  1256. return ready;
  1257. }];
  1258. }
  1259. - (void)testNameAtRootAndNonRootLocations {
  1260. FIRDatabaseReference *ref = [[FTestHelpers defaultDatabase] referenceFromURL:self.databaseURL];
  1261. XCTAssertTrue(ref.key == nil, @"Root key should be nil");
  1262. FIRDatabaseReference *child = [ref child:@"a"];
  1263. XCTAssertTrue([child.key isEqualToString:@"a"], @"Should be 'a'");
  1264. FIRDatabaseReference *deeperChild = [child child:@"b/c"];
  1265. XCTAssertTrue([deeperChild.key isEqualToString:@"c"], @"Should be 'c'");
  1266. }
  1267. - (void)testNameAndRefOnSnapshotsForRootAndNonRootLocations {
  1268. FIRDatabaseReference *ref = [[FTestHelpers defaultDatabase] reference];
  1269. __block BOOL ready = NO;
  1270. [ref removeValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1271. ready = YES;
  1272. }];
  1273. [self waitUntil:^BOOL {
  1274. return ready;
  1275. }];
  1276. ready = NO;
  1277. [ref
  1278. observeEventType:FIRDataEventTypeValue
  1279. withBlock:^(FIRDataSnapshot *snapshot) {
  1280. XCTAssertTrue(snapshot.key == nil, @"Root snap should not have a key");
  1281. NSString *snapString = [snapshot.ref description];
  1282. XCTAssertTrue([snapString isEqualToString:snapString], @"Refs should be equivalent");
  1283. FIRDataSnapshot *childSnap = [snapshot childSnapshotForPath:@"a"];
  1284. XCTAssertTrue([childSnap.key isEqualToString:@"a"], @"Properly keys children");
  1285. FIRDatabaseReference *childRef = [ref child:@"a"];
  1286. NSString *refString = [childRef description];
  1287. snapString = [childSnap.ref description];
  1288. XCTAssertTrue([refString isEqualToString:snapString], @"Refs should be equivalent");
  1289. childSnap = [childSnap childSnapshotForPath:@"b/c"];
  1290. childRef = [childRef child:@"b/c"];
  1291. XCTAssertTrue([childSnap.key isEqualToString:@"c"], @"properly keys children");
  1292. refString = [childRef description];
  1293. snapString = [childSnap.ref description];
  1294. XCTAssertTrue([refString isEqualToString:snapString], @"Refs should be equivalent");
  1295. ready = YES;
  1296. }];
  1297. [self waitUntil:^BOOL {
  1298. return ready;
  1299. }];
  1300. ready = NO;
  1301. // generate value event at root
  1302. [ref setValue:@"foo"];
  1303. [self waitUntil:^BOOL {
  1304. return ready;
  1305. }];
  1306. }
  1307. - (void)testParentForRootAndNonRootLocations {
  1308. FIRDatabaseReference *ref = [[FIRDatabase database] reference];
  1309. XCTAssertTrue(ref.parent == nil, @"Parent of root should be nil");
  1310. FIRDatabaseReference *child = [ref child:@"a"];
  1311. XCTAssertTrue([[child.parent description] isEqualToString:[ref description]],
  1312. @"Should be equivalent locations");
  1313. child = [ref child:@"a/b/c"];
  1314. XCTAssertTrue([[child.parent.parent.parent description] isEqualToString:[ref description]],
  1315. @"Should be equivalent locations");
  1316. }
  1317. - (void)testSettingNumericKeysConvertsToStrings {
  1318. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1319. NSDictionary *toSet = @{@4 : @"hi", @5 : @"test"};
  1320. XCTAssertThrows([ref setValue:toSet], @"Keys must be strings");
  1321. }
  1322. - (void)testSetChildAndListenAtRootRegressionTest {
  1323. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1324. FIRDatabaseReference *writer = refs.one;
  1325. FIRDatabaseReference *reader = refs.two;
  1326. __block BOOL ready = NO;
  1327. [writer removeValue];
  1328. [[writer child:@"foo"] setValue:@"hi"
  1329. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1330. [reader observeEventType:FIRDataEventTypeValue
  1331. withBlock:^(FIRDataSnapshot *snapshot) {
  1332. NSDictionary *val = [snapshot value];
  1333. NSDictionary *expected = @{@"foo" : @"hi"};
  1334. XCTAssertTrue([val isEqualToDictionary:expected], @"Got child");
  1335. ready = YES;
  1336. }];
  1337. }];
  1338. [self waitUntil:^BOOL {
  1339. return ready;
  1340. }];
  1341. }
  1342. - (void)testAccessingInvalidPathsThrows {
  1343. NSArray *badPaths = @[ @".test", @"test.", @"fo$o", @"[what", @"ever]", @"ha#sh" ];
  1344. for (NSString *key in badPaths) {
  1345. NSString *url = [NSString stringWithFormat:@"%@/%@", self.databaseURL, key];
  1346. XCTAssertThrows(
  1347. ^{
  1348. FIRDatabaseReference *ref = [[FIRDatabase database] referenceFromURL:url];
  1349. XCTFail(@"Should not get here with ref: %@", ref);
  1350. }(),
  1351. @"should throw");
  1352. url = [NSString stringWithFormat:@"%@/TESTS/%@", self.databaseURL, key];
  1353. XCTAssertThrows(
  1354. ^{
  1355. FIRDatabaseReference *ref = [[FIRDatabase database] referenceFromURL:url];
  1356. XCTFail(@"Should not get here with ref: %@", ref);
  1357. }(),
  1358. @"should throw");
  1359. }
  1360. __block BOOL ready = NO;
  1361. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1362. [ref observeEventType:FIRDataEventTypeValue
  1363. withBlock:^(FIRDataSnapshot *snapshot) {
  1364. for (NSString *key in badPaths) {
  1365. XCTAssertThrows([snapshot childSnapshotForPath:key], @"should throw");
  1366. XCTAssertThrows([snapshot hasChild:key], @"should throw");
  1367. }
  1368. ready = YES;
  1369. }];
  1370. [ref setValue:nil];
  1371. [self waitUntil:^BOOL {
  1372. return ready;
  1373. }];
  1374. }
  1375. - (void)testSettingObjectsAtInvalidKeysThrow {
  1376. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1377. NSArray *badPaths = @[
  1378. @".test", @"test.", @"fo$o", @"[what", @"ever]", @"ha#sh", @"/thing", @"th/ing", @"thing/"
  1379. ];
  1380. NSMutableArray *badObjs = [[NSMutableArray alloc] init];
  1381. for (NSString *key in badPaths) {
  1382. [badObjs addObject:@{key : @"test"}];
  1383. [badObjs addObject:@{@"deeper" : @{key : @"test"}}];
  1384. }
  1385. for (NSDictionary *badObj in badObjs) {
  1386. XCTAssertThrows([ref setValue:badObj], @"Should throw");
  1387. XCTAssertThrows([ref setValue:badObj andPriority:@5], @"Should throw");
  1388. XCTAssertThrows([ref onDisconnectSetValue:badObj], @"Should throw");
  1389. XCTAssertThrows([ref onDisconnectSetValue:badObj andPriority:@5], @"Should throw");
  1390. // XXX transaction
  1391. }
  1392. }
  1393. - (void)testSettingInvalidObjectsThrow {
  1394. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1395. XCTAssertThrows([ref setValue:[NSDate date]], @"Should throw");
  1396. NSDictionary *data = @{@"invalid" : @"data", @".sv" : @"timestamp"};
  1397. XCTAssertThrows([ref setValue:data], @"Should throw");
  1398. data = @{@".value" : @{}};
  1399. XCTAssertThrows([ref setValue:data], @"Should throw");
  1400. }
  1401. - (void)testInvalidUpdateThrow {
  1402. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1403. NSArray *badUpdates = @[
  1404. @{@"/" : @"t", @"a" : @"t"}, @{@"a" : @"t", @"a/b" : @"t"}, @{@"/a" : @"t", @"a/b" : @"t"},
  1405. @{@"/a/b" : @"t", @"a" : @"t"}, @{@"/a/b/.priority" : @"t", @"/a/b" : @"t"},
  1406. @{@"/a/b/.sv" : @"timestamp"}, @{@"/a/b/.value" : @"t"}, @{@"/a/b/.priority" : @{@"x" : @"y"}}
  1407. ];
  1408. for (NSDictionary *update in badUpdates) {
  1409. XCTAssertThrows([ref updateChildValues:update], @"Should throw");
  1410. XCTAssertThrows([ref onDisconnectUpdateChildValues:update], @"Should throw");
  1411. }
  1412. }
  1413. - (void)testSettingNull {
  1414. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1415. XCTAssertNoThrow([ref setValue:nil], @"Should not throw");
  1416. XCTAssertNoThrow([ref setValue:[NSNull null]], @"Should not throw");
  1417. }
  1418. - (void)testSettingNaN {
  1419. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1420. XCTAssertThrows([ref setValue:[NSDecimalNumber notANumber]], @"Should throw");
  1421. }
  1422. - (void)testSettingInvalidPriority {
  1423. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1424. XCTAssertThrows([ref setValue:@"3" andPriority:[NSDecimalNumber notANumber]], @"Should throw");
  1425. XCTAssertThrows([ref setValue:@"4" andPriority:@{}], @"Should throw");
  1426. XCTAssertThrows([ref setValue:@"5" andPriority:@[]], @"Should throw");
  1427. }
  1428. - (void)testRemoveFromOnMobileGraffitiBugAtAngelHack {
  1429. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1430. __block BOOL done = NO;
  1431. [node observeEventType:FIRDataEventTypeChildAdded
  1432. withBlock:^(FIRDataSnapshot *snapshot) {
  1433. [[node child:[snapshot key]]
  1434. removeValueWithCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  1435. done = YES;
  1436. }];
  1437. }];
  1438. [[node childByAutoId] setValue:@"moo"];
  1439. [self waitUntil:^BOOL {
  1440. return done;
  1441. }];
  1442. XCTAssertTrue(done, @"Properly finished");
  1443. }
  1444. - (void)testSetANodeWithAQuotedKey {
  1445. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1446. __block BOOL done = NO;
  1447. __block FIRDataSnapshot *snap;
  1448. [node observeEventType:FIRDataEventTypeValue
  1449. withBlock:^(FIRDataSnapshot *snapshot) {
  1450. snap = snapshot;
  1451. }];
  1452. [node setValue:@{@"\"herp\"" : @1234}
  1453. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  1454. done = YES;
  1455. XCTAssertEqualObjects(@1234, [[snap childSnapshotForPath:@"\"herp\""] value],
  1456. @"Got it back");
  1457. }];
  1458. [self waitUntil:^BOOL {
  1459. return done;
  1460. }];
  1461. XCTAssertTrue(done, @"Properly finished");
  1462. }
  1463. - (void)testSetANodeWithASingleQuoteKey {
  1464. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1465. __block BOOL done = NO;
  1466. __block FIRDataSnapshot *snap;
  1467. [node observeEventType:FIRDataEventTypeValue
  1468. withBlock:^(FIRDataSnapshot *snapshot) {
  1469. snap = snapshot;
  1470. }];
  1471. [node setValue:@{@"\"" : @1234}
  1472. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  1473. done = YES;
  1474. XCTAssertEqualObjects(@1234, [[snap childSnapshotForPath:@"\""] value], @"Got it back");
  1475. }];
  1476. [self waitUntil:^BOOL {
  1477. return done;
  1478. }];
  1479. XCTAssertTrue(done, @"Properly finished");
  1480. }
  1481. - (void)testEmptyChildGetValueEventBeforeParent {
  1482. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1483. NSArray *lookingFor = @[
  1484. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa/aaa"]
  1485. withEvent:FIRDataEventTypeValue
  1486. withString:nil],
  1487. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"]
  1488. withEvent:FIRDataEventTypeValue
  1489. withString:nil],
  1490. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  1491. withEvent:FIRDataEventTypeValue
  1492. withString:nil],
  1493. ];
  1494. FEventTester *et = [[FEventTester alloc] initFrom:self];
  1495. [et addLookingFor:lookingFor];
  1496. [node setValue:@{@"b" : @5}];
  1497. [et wait];
  1498. }
  1499. // iOS behavior is different from what the recursive set test looks for. We don't raise events
  1500. // synchronously
  1501. - (void)testOnAfterSetWaitsForLatestData {
  1502. // We test here that we don't cache sets, but they would be persisted so make sure we are running
  1503. // without persistence
  1504. FTupleFirebase *refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1505. FIRDatabaseReference *node1 = refs.one;
  1506. FIRDatabaseReference *node2 = refs.two;
  1507. __block BOOL ready = NO;
  1508. [node1 setValue:@5
  1509. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1510. [node2 setValue:@42
  1511. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1512. ready = YES;
  1513. }];
  1514. }];
  1515. [self waitUntil:^BOOL {
  1516. return ready;
  1517. }];
  1518. ready = NO;
  1519. [node1 observeEventType:FIRDataEventTypeValue
  1520. withBlock:^(FIRDataSnapshot *snapshot) {
  1521. NSNumber *val = [snapshot value];
  1522. XCTAssertTrue([val isEqualToNumber:@42], @"Should not have cached earlier set");
  1523. ready = YES;
  1524. }];
  1525. [self waitUntil:^BOOL {
  1526. return ready;
  1527. }];
  1528. }
  1529. - (void)testOnceWaitsForLatestData {
  1530. // Can't tolerate stale data; so disable persistence.
  1531. FTupleFirebase *refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1532. FIRDatabaseReference *node1 = refs.one;
  1533. FIRDatabaseReference *node2 = refs.two;
  1534. __block BOOL ready = NO;
  1535. [node1 observeSingleEventOfType:FIRDataEventTypeValue
  1536. withBlock:^(FIRDataSnapshot *snapshot) {
  1537. id val = [snapshot value];
  1538. XCTAssertTrue([NSNull null] == val, @"First value should be null");
  1539. [node2 setValue:@5
  1540. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1541. [node1 observeSingleEventOfType:FIRDataEventTypeValue
  1542. withBlock:^(FIRDataSnapshot *snapshot) {
  1543. NSNumber *val = [snapshot value];
  1544. XCTAssertTrue(
  1545. [val isKindOfClass:[NSNumber class]] &&
  1546. [val isEqualToNumber:@5],
  1547. @"Should get first value");
  1548. ready = YES;
  1549. }];
  1550. }];
  1551. }];
  1552. [self waitUntil:^BOOL {
  1553. return ready;
  1554. }];
  1555. ready = NO;
  1556. [node2 setValue:@42
  1557. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1558. [node1 observeSingleEventOfType:FIRDataEventTypeValue
  1559. withBlock:^(FIRDataSnapshot *snapshot) {
  1560. NSNumber *val = [snapshot value];
  1561. XCTAssertTrue([val isEqualToNumber:@42], @"Got second number");
  1562. ready = YES;
  1563. }];
  1564. }];
  1565. [self waitUntil:^BOOL {
  1566. return ready;
  1567. }];
  1568. }
  1569. - (void)testMemoryFreeingOnUnlistenDoesNotCorruptData {
  1570. // Can't tolerate stale data; so disable persistence.
  1571. FTupleFirebase *refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1572. FIRDatabaseReference *node2 = [[refs.one root] childByAutoId];
  1573. __block BOOL hasRun = NO;
  1574. __block BOOL ready = NO;
  1575. FIRDatabaseHandle handle1 =
  1576. [refs.one observeEventType:FIRDataEventTypeValue
  1577. withBlock:^(FIRDataSnapshot *snapshot) {
  1578. if (!hasRun) {
  1579. hasRun = YES;
  1580. id val = [snapshot value];
  1581. XCTAssertTrue([NSNull null] == val, @"First time should be null");
  1582. [refs.one setValue:@"test"
  1583. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1584. ready = YES;
  1585. }];
  1586. }
  1587. }];
  1588. [self waitUntil:^BOOL {
  1589. return ready;
  1590. }];
  1591. [refs.one removeObserverWithHandle:handle1];
  1592. ready = NO;
  1593. [node2 setValue:@"hello"
  1594. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1595. [refs.one
  1596. observeSingleEventOfType:FIRDataEventTypeValue
  1597. withBlock:^(FIRDataSnapshot *snapshot) {
  1598. NSString *val = [snapshot value];
  1599. XCTAssertTrue([val isEqualToString:@"test"],
  1600. @"Get back the value we set above");
  1601. [refs.two
  1602. observeSingleEventOfType:FIRDataEventTypeValue
  1603. withBlock:^(FIRDataSnapshot *snapshot) {
  1604. NSString *val = [snapshot value];
  1605. XCTAssertTrue([val isEqualToString:@"test"],
  1606. @"Get back the value we set above");
  1607. ready = YES;
  1608. }];
  1609. }];
  1610. }];
  1611. [self waitUntil:^BOOL {
  1612. return ready;
  1613. }];
  1614. // write {x: 1, y : {t: 2, u: 3}}
  1615. // Listen at /. Then listen at /x/t
  1616. // unlisten at /y/t. Off at /. Once at /. Ensure data is still all there.
  1617. // Once at /y. Ensure data is still all there.
  1618. refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1619. ready = NO;
  1620. __block FIRDatabaseHandle deeplisten = NSNotFound;
  1621. __block FIRDatabaseHandle slashlisten = NSNotFound;
  1622. __weak FIRDatabaseReference *refOne = refs.one;
  1623. [refs.one setValue:@{@"x" : @1, @"y" : @{@"t" : @2, @"u" : @3}}
  1624. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1625. slashlisten = [refOne
  1626. observeEventType:FIRDataEventTypeValue
  1627. withBlock:^(FIRDataSnapshot *snapshot) {
  1628. deeplisten = [[refOne child:@"y/t"]
  1629. observeEventType:FIRDataEventTypeValue
  1630. withBlock:^(FIRDataSnapshot *snapshot) {
  1631. [[refOne child:@"y/t"] removeObserverWithHandle:deeplisten];
  1632. [refOne removeObserverWithHandle:slashlisten];
  1633. ready = YES;
  1634. }];
  1635. }];
  1636. }];
  1637. [self waitUntil:^BOOL {
  1638. return ready;
  1639. }];
  1640. ready = NO;
  1641. [[refs.one child:@"x"] setValue:@"test"
  1642. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1643. [refs.one observeSingleEventOfType:FIRDataEventTypeValue
  1644. withBlock:^(FIRDataSnapshot *snapshot) {
  1645. NSDictionary *val = [snapshot value];
  1646. NSDictionary *expected =
  1647. @{@"x" : @"test",
  1648. @"y" : @{@"t" : @2, @"u" : @3}};
  1649. XCTAssertTrue([val isEqualToDictionary:expected],
  1650. @"Got the final value");
  1651. ready = YES;
  1652. }];
  1653. }];
  1654. [self waitUntil:^BOOL {
  1655. return ready;
  1656. }];
  1657. }
  1658. - (void)testUpdateRaisesCorrectLocalEvents {
  1659. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1660. __block FIRDataSnapshot *snap = nil;
  1661. [node observeSingleEventOfType:FIRDataEventTypeValue
  1662. withBlock:^(FIRDataSnapshot *snapshot) {
  1663. snap = snapshot;
  1664. }];
  1665. __block BOOL ready = NO;
  1666. [node setValue:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}
  1667. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1668. ready = YES;
  1669. }];
  1670. [self waitUntil:^BOOL {
  1671. return ready;
  1672. }];
  1673. FEventTester *et = [[FEventTester alloc] initFrom:self];
  1674. NSArray *expectations = @[
  1675. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"]
  1676. withEvent:FIRDataEventTypeValue
  1677. withString:nil],
  1678. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"d"]
  1679. withEvent:FIRDataEventTypeValue
  1680. withString:nil],
  1681. [[FTupleEventTypeString alloc] initWithFirebase:node
  1682. withEvent:FIRDataEventTypeChildChanged
  1683. withString:@"a"],
  1684. [[FTupleEventTypeString alloc] initWithFirebase:node
  1685. withEvent:FIRDataEventTypeChildChanged
  1686. withString:@"d"],
  1687. [[FTupleEventTypeString alloc] initWithFirebase:node
  1688. withEvent:FIRDataEventTypeValue
  1689. withString:nil]
  1690. ];
  1691. [et addLookingFor:expectations];
  1692. [et waitForInitialization];
  1693. [node updateChildValues:@{@"a" : @4, @"d" : @1}];
  1694. [et wait];
  1695. }
  1696. - (void)testUpdateRaisesCorrectRemoteEvents {
  1697. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1698. FIRDatabaseReference *reader = refs.one;
  1699. FIRDatabaseReference *writer = refs.two;
  1700. __block BOOL ready = NO;
  1701. [writer setValue:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}
  1702. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1703. ready = YES;
  1704. }];
  1705. [self waitUntil:^BOOL {
  1706. return ready;
  1707. }];
  1708. FEventTester *et = [[FEventTester alloc] initFrom:self];
  1709. NSArray *expectations = @[
  1710. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"]
  1711. withEvent:FIRDataEventTypeValue
  1712. withString:nil],
  1713. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"d"]
  1714. withEvent:FIRDataEventTypeValue
  1715. withString:nil],
  1716. [[FTupleEventTypeString alloc] initWithFirebase:reader
  1717. withEvent:FIRDataEventTypeChildChanged
  1718. withString:@"a"],
  1719. [[FTupleEventTypeString alloc] initWithFirebase:reader
  1720. withEvent:FIRDataEventTypeChildChanged
  1721. withString:@"d"],
  1722. [[FTupleEventTypeString alloc] initWithFirebase:reader
  1723. withEvent:FIRDataEventTypeValue
  1724. withString:nil]
  1725. ];
  1726. [et addLookingFor:expectations];
  1727. [et waitForInitialization];
  1728. [writer updateChildValues:@{@"a" : @4, @"d" : @1}];
  1729. [et wait];
  1730. ready = NO;
  1731. [reader observeEventType:FIRDataEventTypeValue
  1732. withBlock:^(FIRDataSnapshot *snapshot) {
  1733. NSDictionary *result = [snapshot value];
  1734. NSDictionary *expected = @{@"a" : @4, @"b" : @2, @"c" : @3, @"d" : @1};
  1735. XCTAssertTrue([result isEqualToDictionary:expected], @"Got expected results");
  1736. ready = YES;
  1737. }];
  1738. [self waitUntil:^BOOL {
  1739. return ready;
  1740. }];
  1741. }
  1742. - (void)testUpdateChangesAreStoredCorrectlyByTheServer {
  1743. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1744. FIRDatabaseReference *reader = refs.one;
  1745. FIRDatabaseReference *writer = refs.two;
  1746. [self waitForCompletionOf:writer setValue:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  1747. [self waitForCompletionOf:writer updateChildValues:@{@"a" : @42}];
  1748. [self snapWaiter:reader
  1749. withBlock:^(FIRDataSnapshot *snapshot) {
  1750. NSDictionary *result = [snapshot value];
  1751. NSDictionary *expected = @{@"a" : @42, @"b" : @2, @"c" : @3, @"d" : @4};
  1752. XCTAssertTrue([result isEqualToDictionary:expected], @"Expected updated value");
  1753. }];
  1754. }
  1755. - (void)testUpdateDoesntAffectPriorityLocally {
  1756. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1757. __block FIRDataSnapshot *snap = nil;
  1758. [ref observeEventType:FIRDataEventTypeValue
  1759. withBlock:^(FIRDataSnapshot *snapshot) {
  1760. snap = snapshot;
  1761. }];
  1762. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3} andPriority:@"testpri"];
  1763. [self waitUntil:^BOOL {
  1764. return snap != nil;
  1765. }];
  1766. XCTAssertTrue([[snap priority] isEqualToString:@"testpri"], @"Got initial priority");
  1767. snap = nil;
  1768. [ref updateChildValues:@{@"a" : @4}];
  1769. [self waitUntil:^BOOL {
  1770. return snap != nil;
  1771. }];
  1772. XCTAssertTrue([[snap priority] isEqualToString:@"testpri"], @"Got initial priority");
  1773. }
  1774. - (void)testUpdateDoesntAffectPriorityRemotely {
  1775. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1776. FIRDatabaseReference *reader = refs.one;
  1777. FIRDatabaseReference *writer = refs.two;
  1778. __block BOOL ready = NO;
  1779. [writer setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  1780. andPriority:@"testpri"
  1781. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1782. ready = YES;
  1783. }];
  1784. [self waitUntil:^BOOL {
  1785. return ready;
  1786. }];
  1787. ready = NO;
  1788. [reader observeSingleEventOfType:FIRDataEventTypeValue
  1789. withBlock:^(FIRDataSnapshot *snapshot) {
  1790. NSString *result = [snapshot priority];
  1791. XCTAssertTrue([result isEqualToString:@"testpri"],
  1792. @"Expected initial priority");
  1793. ready = YES;
  1794. }];
  1795. [self waitUntil:^BOOL {
  1796. return ready;
  1797. }];
  1798. ready = NO;
  1799. [writer updateChildValues:@{@"a" : @4}
  1800. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1801. ready = YES;
  1802. }];
  1803. [self waitUntil:^BOOL {
  1804. return ready;
  1805. }];
  1806. ready = NO;
  1807. [reader observeSingleEventOfType:FIRDataEventTypeValue
  1808. withBlock:^(FIRDataSnapshot *snapshot) {
  1809. NSString *result = [snapshot priority];
  1810. XCTAssertTrue([result isEqualToString:@"testpri"],
  1811. @"Expected initial priority");
  1812. ready = YES;
  1813. }];
  1814. [self waitUntil:^BOOL {
  1815. return ready;
  1816. }];
  1817. }
  1818. // TODO: On arm hardware Macs, the following test hangs with the emulator, but passes with a real
  1819. // project.
  1820. - (void)SKIPtestUpdateReplacesChildrenAndIsNotRecursive {
  1821. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1822. FIRDatabaseReference *reader = refs.one;
  1823. FIRDatabaseReference *writer = refs.two;
  1824. __block FIRDataSnapshot *localSnap = nil;
  1825. __block BOOL ready = NO;
  1826. [writer observeEventType:FIRDataEventTypeValue
  1827. withBlock:^(FIRDataSnapshot *snapshot) {
  1828. localSnap = snapshot;
  1829. }];
  1830. [writer setValue:@{@"a" : @{@"aa" : @1, @"ab" : @2}}];
  1831. [writer updateChildValues:@{@"a" : @{@"aa" : @1}}
  1832. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1833. ready = YES;
  1834. }];
  1835. [self waitUntil:^BOOL {
  1836. return ready;
  1837. }];
  1838. ready = NO;
  1839. [reader observeSingleEventOfType:FIRDataEventTypeValue
  1840. withBlock:^(FIRDataSnapshot *snapshot) {
  1841. NSDictionary *result = [snapshot value];
  1842. NSDictionary *expected = @{@"a" : @{@"aa" : @1}};
  1843. XCTAssertTrue([result isEqualToDictionary:expected],
  1844. @"Should get new value");
  1845. ready = YES;
  1846. }];
  1847. [self waitUntil:^BOOL {
  1848. NSDictionary *result = [localSnap value];
  1849. NSDictionary *expected = @{@"a" : @{@"aa" : @1}};
  1850. return ready && [result isEqualToDictionary:expected];
  1851. }];
  1852. }
  1853. - (void)testDeepUpdatesWork {
  1854. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1855. FIRDatabaseReference *reader = refs.one;
  1856. FIRDatabaseReference *writer = refs.two;
  1857. __block FIRDataSnapshot *localSnap = nil;
  1858. __block BOOL ready = NO;
  1859. [writer observeEventType:FIRDataEventTypeValue
  1860. withBlock:^(FIRDataSnapshot *snapshot) {
  1861. localSnap = snapshot;
  1862. }];
  1863. [writer setValue:@{@"a" : @{@"aa" : @1, @"ab" : @2}}];
  1864. [writer updateChildValues:@{
  1865. @"a/aa" : @10,
  1866. @".priority" : @3.0,
  1867. @"a/ab" : @{@".priority" : @2.0, @".value" : @20}
  1868. }
  1869. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1870. ready = YES;
  1871. }];
  1872. [self waitUntil:^BOOL {
  1873. return ready;
  1874. }];
  1875. ready = NO;
  1876. [reader observeSingleEventOfType:FIRDataEventTypeValue
  1877. withBlock:^(FIRDataSnapshot *snapshot) {
  1878. NSDictionary *result = [snapshot value];
  1879. NSDictionary *expected = @{@"a" : @{@"aa" : @10, @"ab" : @20}};
  1880. XCTAssertTrue([result isEqualToDictionary:expected],
  1881. @"Should get new value");
  1882. ready = YES;
  1883. }];
  1884. [self waitUntil:^BOOL {
  1885. NSDictionary *result = [localSnap value];
  1886. NSDictionary *expected = @{@"a" : @{@"aa" : @10, @"ab" : @20}};
  1887. return ready && [result isEqualToDictionary:expected];
  1888. }];
  1889. }
  1890. // Type signature means we don't need a test for updating scalars. They wouldn't compile
  1891. - (void)testEmptyUpdateWorks {
  1892. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1893. __block BOOL ready = NO;
  1894. [ref updateChildValues:@{}
  1895. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1896. XCTAssertTrue(error == nil, @"Should not be an error");
  1897. ready = YES;
  1898. }];
  1899. [self waitUntil:^BOOL {
  1900. return ready;
  1901. }];
  1902. }
  1903. // XXX update stress test
  1904. - (void)testUpdateFiresCorrectEventWhenAChildIsDeleted {
  1905. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1906. FIRDatabaseReference *reader = refs.one;
  1907. FIRDatabaseReference *writer = refs.two;
  1908. __block FIRDataSnapshot *localSnap = nil;
  1909. __block FIRDataSnapshot *remoteSnap = nil;
  1910. [self waitForCompletionOf:writer setValue:@{@"a" : @12, @"b" : @6}];
  1911. [writer observeEventType:FIRDataEventTypeValue
  1912. withBlock:^(FIRDataSnapshot *snapshot) {
  1913. localSnap = snapshot;
  1914. }];
  1915. [reader observeEventType:FIRDataEventTypeValue
  1916. withBlock:^(FIRDataSnapshot *snapshot) {
  1917. remoteSnap = snapshot;
  1918. }];
  1919. [self waitUntil:^BOOL {
  1920. return localSnap != nil && remoteSnap != nil;
  1921. }];
  1922. localSnap = nil;
  1923. remoteSnap = nil;
  1924. [writer updateChildValues:@{@"a" : [NSNull null]}];
  1925. [self waitUntil:^BOOL {
  1926. return localSnap != nil && remoteSnap != nil;
  1927. }];
  1928. NSDictionary *expected = @{@"b" : @6};
  1929. XCTAssertTrue([[remoteSnap value] isEqualToDictionary:expected], @"Removed child");
  1930. XCTAssertTrue([[localSnap value] isEqualToDictionary:expected], @"Removed child");
  1931. }
  1932. - (void)testUpdateFiresCorrectEventOnNewChildren {
  1933. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1934. FIRDatabaseReference *reader = refs.one;
  1935. FIRDatabaseReference *writer = refs.two;
  1936. __block FIRDataSnapshot *localSnap = nil;
  1937. __block FIRDataSnapshot *remoteSnap = nil;
  1938. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue
  1939. withBlock:^(FIRDataSnapshot *snapshot) {
  1940. localSnap = snapshot;
  1941. }];
  1942. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue
  1943. withBlock:^(FIRDataSnapshot *snapshot) {
  1944. remoteSnap = snapshot;
  1945. }];
  1946. [self waitUntil:^BOOL {
  1947. return localSnap != nil && remoteSnap != nil;
  1948. }];
  1949. localSnap = nil;
  1950. remoteSnap = nil;
  1951. [writer updateChildValues:@{@"a" : @42}];
  1952. [self waitUntil:^BOOL {
  1953. return localSnap != nil && remoteSnap != nil;
  1954. }];
  1955. XCTAssertTrue([[remoteSnap value] isEqualToNumber:@42], @"Added child");
  1956. XCTAssertTrue([[localSnap value] isEqualToNumber:@42], @"Added child");
  1957. }
  1958. - (void)testUpdateFiresCorrectEventOnDeletedChildren {
  1959. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1960. FIRDatabaseReference *reader = refs.one;
  1961. FIRDatabaseReference *writer = refs.two;
  1962. __block FIRDataSnapshot *localSnap = nil;
  1963. __block FIRDataSnapshot *remoteSnap = nil;
  1964. [self waitForCompletionOf:writer setValue:@{@"a" : @12}];
  1965. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue
  1966. withBlock:^(FIRDataSnapshot *snapshot) {
  1967. localSnap = snapshot;
  1968. }];
  1969. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue
  1970. withBlock:^(FIRDataSnapshot *snapshot) {
  1971. remoteSnap = snapshot;
  1972. }];
  1973. [self waitUntil:^BOOL {
  1974. return localSnap != nil && remoteSnap != nil;
  1975. }];
  1976. localSnap = nil;
  1977. remoteSnap = nil;
  1978. [writer updateChildValues:@{@"a" : [NSNull null]}];
  1979. [self waitUntil:^BOOL {
  1980. return localSnap != nil && remoteSnap != nil;
  1981. }];
  1982. XCTAssertTrue([remoteSnap value] == [NSNull null], @"Removed child");
  1983. XCTAssertTrue([localSnap value] == [NSNull null], @"Removed child");
  1984. }
  1985. - (void)testUpdateFiresCorrectEventOnChangedChildren {
  1986. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  1987. FIRDatabaseReference *reader = refs.one;
  1988. FIRDatabaseReference *writer = refs.two;
  1989. [self waitForCompletionOf:writer setValue:@{@"a" : @12}];
  1990. __block FIRDataSnapshot *localSnap = nil;
  1991. __block FIRDataSnapshot *remoteSnap = nil;
  1992. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue
  1993. withBlock:^(FIRDataSnapshot *snapshot) {
  1994. localSnap = snapshot;
  1995. }];
  1996. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue
  1997. withBlock:^(FIRDataSnapshot *snapshot) {
  1998. remoteSnap = snapshot;
  1999. }];
  2000. [self waitUntil:^BOOL {
  2001. return localSnap != nil && remoteSnap != nil;
  2002. }];
  2003. localSnap = nil;
  2004. remoteSnap = nil;
  2005. [self waitForCompletionOf:writer updateChildValues:@{@"a" : @11}];
  2006. [self waitUntil:^BOOL {
  2007. return localSnap != nil && remoteSnap != nil;
  2008. }];
  2009. XCTAssertTrue([[remoteSnap value] isEqualToNumber:@11], @"Changed child");
  2010. XCTAssertTrue([[localSnap value] isEqualToNumber:@11], @"Changed child");
  2011. }
  2012. - (void)testUpdateOfPriorityWorks {
  2013. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2014. FIRDatabaseReference *reader = refs.one;
  2015. FIRDatabaseReference *writer = refs.two;
  2016. __block BOOL ready = NO;
  2017. [writer setValue:@{@"a" : @5, @".priority" : @"pri1"}];
  2018. [writer updateChildValues:@{
  2019. @"a" : @6,
  2020. @".priority" : @"pri2",
  2021. @"b" : @{@".priority" : @"pri3", @"c" : @10}
  2022. }
  2023. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2024. NSLog(@"error? %@", error);
  2025. ready = YES;
  2026. }];
  2027. [self waitUntil:^BOOL {
  2028. return ready;
  2029. }];
  2030. ready = NO;
  2031. [reader observeEventType:FIRDataEventTypeValue
  2032. withBlock:^(FIRDataSnapshot *snapshot) {
  2033. XCTAssertEqualObjects([[snapshot childSnapshotForPath:@"a"] value], @6,
  2034. @"Should match write values");
  2035. XCTAssertTrue([[snapshot priority] isEqualToString:@"pri2"],
  2036. @"Should get updated priority");
  2037. XCTAssertTrue(
  2038. [[[snapshot childSnapshotForPath:@"b"] priority] isEqualToString:@"pri3"],
  2039. @"Should get updated priority");
  2040. XCTAssertEqualObjects([[snapshot childSnapshotForPath:@"b/c"] value], @10,
  2041. @"Should match write values");
  2042. ready = YES;
  2043. }];
  2044. [self waitUntil:^BOOL {
  2045. return ready;
  2046. }];
  2047. }
  2048. - (void)testSetWithCircularReferenceFails {
  2049. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2050. NSMutableDictionary *toSet = [[NSMutableDictionary alloc] init];
  2051. NSDictionary *lol = @{@"foo" : @"bar", @"circular" : toSet};
  2052. [toSet setObject:lol forKey:@"lol"];
  2053. XCTAssertThrows([ref setValue:toSet], @"Should not be able to set circular dictionary");
  2054. }
  2055. - (void)testLargeNumbers {
  2056. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2057. long long jsMaxInt = 9007199254740992;
  2058. long jsMaxIntPlusOne = (long)jsMaxInt + 1;
  2059. NSNumber *toSet = [NSNumber numberWithLong:jsMaxIntPlusOne];
  2060. [ref setValue:toSet];
  2061. __block FIRDataSnapshot *snap = nil;
  2062. [ref observeEventType:FIRDataEventTypeValue
  2063. withBlock:^(FIRDataSnapshot *snapshot) {
  2064. snap = snapshot;
  2065. }];
  2066. [self waitUntil:^BOOL {
  2067. return snap != nil;
  2068. }];
  2069. NSNumber *result = [snap value];
  2070. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  2071. toSet = [NSNumber numberWithLong:LONG_MAX];
  2072. snap = nil;
  2073. [ref setValue:toSet];
  2074. [self waitUntil:^BOOL {
  2075. return snap != nil;
  2076. }];
  2077. result = [snap value];
  2078. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  2079. snap = nil;
  2080. toSet = [NSNumber numberWithDouble:DBL_MAX];
  2081. [ref setValue:toSet];
  2082. [self waitUntil:^BOOL {
  2083. return snap != nil;
  2084. }];
  2085. result = [snap value];
  2086. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  2087. }
  2088. #ifdef FLAKY_TEST
  2089. - (void)testParentDeleteShadowsChildListeners {
  2090. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2091. FIRDatabaseReference *writer = refs.one;
  2092. FIRDatabaseReference *deleter = refs.two;
  2093. NSString *childName = [writer childByAutoId].key;
  2094. __block BOOL called = NO;
  2095. [[deleter child:childName]
  2096. observeEventType:FIRDataEventTypeValue
  2097. withBlock:^(FIRDataSnapshot *snapshot) {
  2098. XCTAssertFalse(called, @"Should only be hit once");
  2099. called = YES;
  2100. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  2101. }];
  2102. WAIT_FOR(called);
  2103. __block BOOL done = NO;
  2104. [[writer child:childName] setValue:@"foo"];
  2105. [deleter removeValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2106. done = YES;
  2107. }];
  2108. WAIT_FOR(done);
  2109. [deleter removeAllObservers];
  2110. }
  2111. #endif
  2112. - (void)testParentDeleteShadowsChildListenersWithNonDefaultQuery {
  2113. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2114. FIRDatabaseReference *writer = refs.one;
  2115. FIRDatabaseReference *deleter = refs.two;
  2116. NSString *childName = [writer childByAutoId].key;
  2117. __block BOOL queryCalled = NO;
  2118. __block BOOL deepChildCalled = NO;
  2119. [[[[deleter child:childName] queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  2120. observeEventType:FIRDataEventTypeValue
  2121. withBlock:^(FIRDataSnapshot *snapshot) {
  2122. XCTAssertFalse(queryCalled, @"Should only be hit once");
  2123. queryCalled = YES;
  2124. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  2125. }];
  2126. [[[deleter child:childName] child:@"a"]
  2127. observeEventType:FIRDataEventTypeValue
  2128. withBlock:^(FIRDataSnapshot *snapshot) {
  2129. XCTAssertFalse(deepChildCalled, @"Should only be hit once");
  2130. deepChildCalled = YES;
  2131. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  2132. }];
  2133. WAIT_FOR(deepChildCalled && queryCalled);
  2134. __block BOOL done = NO;
  2135. [[writer child:childName] setValue:@"foo"];
  2136. [deleter removeValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2137. done = YES;
  2138. }];
  2139. WAIT_FOR(done);
  2140. }
  2141. - (void)testLocalServerTimestampEventuallyButNotImmediatelyMatchServer {
  2142. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2143. FIRDatabaseReference *writer = refs.one;
  2144. FIRDatabaseReference *reader = refs.two;
  2145. __block int done = 0;
  2146. NSMutableArray *readSnaps = [[NSMutableArray alloc] init];
  2147. NSMutableArray *writeSnaps = [[NSMutableArray alloc] init];
  2148. [reader observeEventType:FIRDataEventTypeValue
  2149. withBlock:^(FIRDataSnapshot *snapshot) {
  2150. if ([snapshot value] != [NSNull null]) {
  2151. [readSnaps addObject:snapshot];
  2152. if (readSnaps.count == 1) {
  2153. done += 1;
  2154. }
  2155. }
  2156. }];
  2157. [writer observeEventType:FIRDataEventTypeValue
  2158. withBlock:^(FIRDataSnapshot *snapshot) {
  2159. if ([snapshot value] != [NSNull null]) {
  2160. [writeSnaps addObject:snapshot];
  2161. if (writeSnaps.count == 2) {
  2162. done += 1;
  2163. }
  2164. }
  2165. }];
  2166. [writer setValue:[FIRServerValue timestamp] andPriority:[FIRServerValue timestamp]];
  2167. [self waitUntil:^BOOL {
  2168. return done == 2;
  2169. }];
  2170. XCTAssertEqual((unsigned long)[readSnaps count], (unsigned long)1,
  2171. @"Should have received one snapshot on reader");
  2172. XCTAssertEqual((unsigned long)[writeSnaps count], (unsigned long)2,
  2173. @"Should have received two snapshots on writer");
  2174. FIRDataSnapshot *firstReadSnap = [readSnaps objectAtIndex:0];
  2175. FIRDataSnapshot *firstWriteSnap = [writeSnaps objectAtIndex:0];
  2176. FIRDataSnapshot *secondWriteSnap = [writeSnaps objectAtIndex:1];
  2177. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2178. XCTAssertTrue([now doubleValue] - [firstWriteSnap.value doubleValue] < 3000,
  2179. @"Should have received a local event with a value close to timestamp");
  2180. XCTAssertTrue([now doubleValue] - [firstWriteSnap.priority doubleValue] < 3000,
  2181. @"Should have received a local event with a priority close to timestamp");
  2182. XCTAssertTrue([now doubleValue] - [secondWriteSnap.value doubleValue] < 3000,
  2183. @"Should have received a server event with a value close to timestamp");
  2184. XCTAssertTrue([now doubleValue] - [secondWriteSnap.priority doubleValue] < 3000,
  2185. @"Should have received a server event with a priority close to timestamp");
  2186. XCTAssertFalse([firstWriteSnap value] == [secondWriteSnap value],
  2187. @"Initial and future writer values should be different");
  2188. XCTAssertFalse([firstWriteSnap priority] == [secondWriteSnap priority],
  2189. @"Initial and future writer priorities should be different");
  2190. XCTAssertEqualObjects(firstReadSnap.value, secondWriteSnap.value,
  2191. @"Eventual reader and writer values should be equal");
  2192. XCTAssertEqualObjects(firstReadSnap.priority, secondWriteSnap.priority,
  2193. @"Eventual reader and writer priorities should be equal");
  2194. }
  2195. - (void)testServerTimestampSetWithPriorityRemoteEvents {
  2196. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2197. FIRDatabaseReference *writer = refs.one;
  2198. FIRDatabaseReference *reader = refs.two;
  2199. NSDictionary *data = @{
  2200. @"a" : [FIRServerValue timestamp],
  2201. @"b" : @{@".value" : [FIRServerValue timestamp], @".priority" : [FIRServerValue timestamp]}
  2202. };
  2203. __block BOOL done = NO;
  2204. [writer setValue:data
  2205. andPriority:[FIRServerValue timestamp]
  2206. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  2207. done = YES;
  2208. }];
  2209. [self waitUntil:^BOOL {
  2210. return done;
  2211. }];
  2212. [self
  2213. snapWaiter:reader
  2214. withBlock:^(FIRDataSnapshot *snapshot) {
  2215. NSDictionary *value = [snapshot value];
  2216. NSNumber *now =
  2217. [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2218. NSNumber *timestamp = [snapshot priority];
  2219. XCTAssertTrue([[snapshot priority] isKindOfClass:[NSNumber class]],
  2220. @"Should get back number");
  2221. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2222. @"Number should be no more than 2 seconds ago");
  2223. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"a"],
  2224. @"Should get back matching ServerValue.TIMESTAMP");
  2225. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"b"],
  2226. @"Should get back matching ServerValue.TIMESTAMP");
  2227. XCTAssertEqualObjects([snapshot priority], [[snapshot childSnapshotForPath:@"b"] priority],
  2228. @"Should get back matching ServerValue.TIMESTAMP");
  2229. }];
  2230. }
  2231. - (void)testServerTimestampSetPriorityRemoteEvents {
  2232. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2233. FIRDatabaseReference *writer = refs.one;
  2234. FIRDatabaseReference *reader = refs.two;
  2235. __block FIRDataSnapshot *snap = nil;
  2236. [reader observeEventType:FIRDataEventTypeChildMoved
  2237. withBlock:^(FIRDataSnapshot *snapshot) {
  2238. snap = snapshot;
  2239. }];
  2240. [self waitForCompletionOf:[writer child:@"a"] setValue:@1 andPriority:nil];
  2241. [self waitForCompletionOf:[writer child:@"b"] setValue:@1 andPriority:@1];
  2242. [self waitForValueOf:[reader child:@"a"] toBe:@1];
  2243. __block BOOL done = NO;
  2244. [[writer child:@"a"] setPriority:[FIRServerValue timestamp]
  2245. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2246. done = YES;
  2247. }];
  2248. [self waitUntil:^BOOL {
  2249. return done && snap != nil;
  2250. }];
  2251. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2252. NSNumber *timestamp = [snap priority];
  2253. XCTAssertTrue([[snap priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  2254. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2255. @"Number should be no more than 2 seconds ago");
  2256. }
  2257. - (void)testServerTimestampUpdateRemoteEvents {
  2258. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2259. FIRDatabaseReference *writer = refs.one;
  2260. FIRDatabaseReference *reader = refs.two;
  2261. __block FIRDataSnapshot *snap = nil;
  2262. __block BOOL done = NO;
  2263. [reader observeEventType:FIRDataEventTypeValue
  2264. withBlock:^(FIRDataSnapshot *snapshot) {
  2265. snap = snapshot;
  2266. if (snap && [[snap childSnapshotForPath:@"a/b/d"] value] != [NSNull null]) {
  2267. done = YES;
  2268. }
  2269. }];
  2270. [[writer child:@"a/b/c"] setValue:@1];
  2271. [[writer child:@"a"] updateChildValues:@{@"b" : @{@"c" : [FIRServerValue timestamp], @"d" : @1}}];
  2272. [self waitUntil:^BOOL {
  2273. return done;
  2274. }];
  2275. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2276. NSNumber *timestamp = [[snap childSnapshotForPath:@"a/b/c"] value];
  2277. XCTAssertTrue([[[snap childSnapshotForPath:@"a/b/c"] value] isKindOfClass:[NSNumber class]],
  2278. @"Should get back number");
  2279. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2280. @"Number should be no more than 2 seconds ago");
  2281. }
  2282. - (void)testServerTimestampSetWithPriorityLocalEvents {
  2283. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  2284. NSDictionary *data = @{
  2285. @"a" : [FIRServerValue timestamp],
  2286. @"b" : @{@".value" : [FIRServerValue timestamp], @".priority" : [FIRServerValue timestamp]}
  2287. };
  2288. __block FIRDataSnapshot *snap = nil;
  2289. [node observeEventType:FIRDataEventTypeValue
  2290. withBlock:^(FIRDataSnapshot *snapshot) {
  2291. snap = snapshot;
  2292. }];
  2293. __block BOOL done = NO;
  2294. [node setValue:data
  2295. andPriority:[FIRServerValue timestamp]
  2296. withCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  2297. done = YES;
  2298. }];
  2299. [self waitUntil:^BOOL {
  2300. return done;
  2301. }];
  2302. [self
  2303. snapWaiter:node
  2304. withBlock:^(FIRDataSnapshot *snapshot) {
  2305. NSDictionary *value = [snapshot value];
  2306. NSNumber *now =
  2307. [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2308. NSNumber *timestamp = [snapshot priority];
  2309. XCTAssertTrue([[snapshot priority] isKindOfClass:[NSNumber class]],
  2310. @"Should get back number");
  2311. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2312. @"Number should be no more than 2 seconds ago");
  2313. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"a"],
  2314. @"Should get back matching ServerValue.TIMESTAMP");
  2315. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"b"],
  2316. @"Should get back matching ServerValue.TIMESTAMP");
  2317. XCTAssertEqualObjects([snapshot priority], [[snapshot childSnapshotForPath:@"b"] priority],
  2318. @"Should get back matching ServerValue.TIMESTAMP");
  2319. }];
  2320. }
  2321. - (void)testServerTimestampSetPriorityLocalEvents {
  2322. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  2323. __block FIRDataSnapshot *snap = nil;
  2324. [node observeEventType:FIRDataEventTypeChildMoved
  2325. withBlock:^(FIRDataSnapshot *snapshot) {
  2326. snap = snapshot;
  2327. }];
  2328. __block BOOL done = NO;
  2329. [[node child:@"a"] setValue:@1 andPriority:nil];
  2330. [[node child:@"b"] setValue:@1 andPriority:@1];
  2331. [[node child:@"a"] setPriority:[FIRServerValue timestamp]
  2332. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2333. done = YES;
  2334. }];
  2335. [self waitUntil:^BOOL {
  2336. return done;
  2337. }];
  2338. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2339. NSNumber *timestamp = [snap priority];
  2340. XCTAssertTrue([[snap priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  2341. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2342. @"Number should be no more than 2 seconds ago");
  2343. }
  2344. - (void)testServerTimestampUpdateLocalEvents {
  2345. FIRDatabaseReference *node1 = [FTestHelpers getRandomNode];
  2346. __block FIRDataSnapshot *snap1 = nil;
  2347. [node1 observeEventType:FIRDataEventTypeValue
  2348. withBlock:^(FIRDataSnapshot *snapshot) {
  2349. snap1 = snapshot;
  2350. }];
  2351. __block FIRDataSnapshot *snap2 = nil;
  2352. [node1 observeEventType:FIRDataEventTypeValue
  2353. withBlock:^(FIRDataSnapshot *snapshot) {
  2354. snap2 = snapshot;
  2355. }];
  2356. [node1 runTransactionBlock:^FIRTransactionResult *(FIRMutableData *currentData) {
  2357. [currentData setValue:[FIRServerValue timestamp]];
  2358. return [FIRTransactionResult successWithValue:currentData];
  2359. }];
  2360. [self waitUntil:^BOOL {
  2361. return snap1 != nil && snap2 != nil && [snap1 value] != nil && [snap2 value] != nil;
  2362. }];
  2363. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2364. NSNumber *timestamp1 = [snap1 value];
  2365. XCTAssertTrue([[snap1 value] isKindOfClass:[NSNumber class]], @"Should get back number");
  2366. XCTAssertTrue([now doubleValue] - [timestamp1 doubleValue] < 2000,
  2367. @"Number should be no more than 2 seconds ago");
  2368. NSNumber *timestamp2 = [snap2 value];
  2369. XCTAssertTrue([[snap2 value] isKindOfClass:[NSNumber class]], @"Should get back number");
  2370. XCTAssertTrue([now doubleValue] - [timestamp2 doubleValue] < 2000,
  2371. @"Number should be no more than 2 seconds ago");
  2372. }
  2373. - (void)testServerTimestampTransactionLocalEvents {
  2374. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  2375. __block FIRDataSnapshot *snap = nil;
  2376. [node observeEventType:FIRDataEventTypeValue
  2377. withBlock:^(FIRDataSnapshot *snapshot) {
  2378. snap = snapshot;
  2379. }];
  2380. [[node child:@"a/b/c"] setValue:@1];
  2381. [[node child:@"a"] updateChildValues:@{@"b" : @{@"c" : [FIRServerValue timestamp], @"d" : @1}}];
  2382. [self waitUntil:^BOOL {
  2383. return snap != nil && [[snap childSnapshotForPath:@"a/b/d"] value] != nil;
  2384. }];
  2385. NSNumber *now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970] * 1000)];
  2386. NSNumber *timestamp = [[snap childSnapshotForPath:@"a/b/c"] value];
  2387. XCTAssertTrue([[[snap childSnapshotForPath:@"a/b/c"] value] isKindOfClass:[NSNumber class]],
  2388. @"Should get back number");
  2389. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000,
  2390. @"Number should be no more than 2 seconds ago");
  2391. }
  2392. - (void)testServerIncrementOverwritesExistingDataOnline {
  2393. [self checkServerIncrementOverwritesExistingDataWhileOnline:true];
  2394. }
  2395. - (void)testServerIncrementOverwritesExistingDataOffline {
  2396. [self checkServerIncrementOverwritesExistingDataWhileOnline:false];
  2397. }
  2398. - (void)checkServerIncrementOverwritesExistingDataWhileOnline:(BOOL)online {
  2399. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2400. __block NSMutableArray *found = [NSMutableArray new];
  2401. NSMutableArray *expected = [NSMutableArray new];
  2402. [ref observeEventType:FIRDataEventTypeValue
  2403. withBlock:^(FIRDataSnapshot *snap) {
  2404. [found addObject:snap.value];
  2405. }];
  2406. // Going offline ensures that local events get queued up before server events
  2407. if (!online) {
  2408. [ref.repo interrupt];
  2409. }
  2410. // null + incr
  2411. [ref setValue:[FIRServerValue increment:@1]];
  2412. [expected addObject:@1];
  2413. // number + incr
  2414. [ref setValue:@5];
  2415. [ref setValue:[FIRServerValue increment:@1]];
  2416. [expected addObject:@5];
  2417. [expected addObject:@6];
  2418. // string + incr
  2419. [ref setValue:@"hello"];
  2420. [ref setValue:[FIRServerValue increment:@1]];
  2421. [expected addObject:@"hello"];
  2422. [expected addObject:@1];
  2423. // object + incr
  2424. [ref setValue:@{@"hello" : @"world"}];
  2425. [ref setValue:[FIRServerValue increment:@1]];
  2426. [expected addObject:@{@"hello" : @"world"}];
  2427. [expected addObject:@1];
  2428. [self waitUntil:^BOOL {
  2429. return found.count == expected.count;
  2430. }];
  2431. XCTAssertEqualObjects(expected, found);
  2432. if (!online) {
  2433. [ref.repo resume];
  2434. }
  2435. }
  2436. - (void)testServerIncrementPriorityOnline {
  2437. [self checkServerIncrementPriorityWhileOnline:true];
  2438. }
  2439. - (void)testServerIncrementPriorityOffline {
  2440. [self checkServerIncrementPriorityWhileOnline:false];
  2441. }
  2442. - (void)checkServerIncrementPriorityWhileOnline:(BOOL)online {
  2443. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2444. if (!online) {
  2445. [ref.repo interrupt];
  2446. }
  2447. __block NSMutableArray *found = [NSMutableArray new];
  2448. NSMutableArray *expected = [NSMutableArray new];
  2449. [ref observeEventType:FIRDataEventTypeValue
  2450. withBlock:^(FIRDataSnapshot *snap) {
  2451. [found addObject:snap.priority];
  2452. }];
  2453. // Going offline ensures that local events get queued up before server events
  2454. // Also necessary because increment may not be live yet in the server.
  2455. if (!online) {
  2456. [ref.repo interrupt];
  2457. }
  2458. // null + incr
  2459. [ref setValue:@0 andPriority:[FIRServerValue increment:@1]];
  2460. [expected addObject:@1];
  2461. [ref setValue:@0 andPriority:[FIRServerValue increment:@1.5]];
  2462. [expected addObject:@2.5];
  2463. [self waitUntil:^BOOL {
  2464. return found.count == expected.count;
  2465. }];
  2466. XCTAssertEqualObjects(expected, found);
  2467. if (!online) {
  2468. [ref.repo resume];
  2469. }
  2470. }
  2471. - (void)testServerIncrementOverflowAndTypeCoercion {
  2472. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2473. __block NSMutableArray *found = [NSMutableArray new];
  2474. __block NSMutableArray *foundTypes = [NSMutableArray new];
  2475. NSMutableArray *expected = [NSMutableArray new];
  2476. NSMutableArray *expectedTypes = [NSMutableArray new];
  2477. [ref observeEventType:FIRDataEventTypeValue
  2478. withBlock:^(FIRDataSnapshot *snap) {
  2479. [found addObject:snap.value];
  2480. [foundTypes addObject:@([(NSNumber *)snap.value objCType])];
  2481. }];
  2482. // Going offline ensures that local events get queued up before server events
  2483. // Also necessary because increment may not be live yet in the server.
  2484. [ref.repo interrupt];
  2485. // long + double = double
  2486. [ref setValue:@1];
  2487. [ref setValue:[FIRServerValue increment:@1.0]];
  2488. [expected addObject:@1];
  2489. [expected addObject:@2.0];
  2490. [expectedTypes addObject:@(@encode(int))];
  2491. [expectedTypes addObject:@(@encode(double))];
  2492. // double + long = double
  2493. [ref setValue:@1.5];
  2494. [ref setValue:[FIRServerValue increment:@1]];
  2495. [expected addObject:@1.5];
  2496. [expected addObject:@2.5];
  2497. [expectedTypes addObject:@(@encode(double))];
  2498. [expectedTypes addObject:@(@encode(double))];
  2499. // long overflow = double
  2500. [ref setValue:@(1)];
  2501. [ref setValue:[FIRServerValue increment:@(LONG_MAX)]];
  2502. [expected addObject:@(1)];
  2503. [expected addObject:@(LONG_MAX + 1.0)];
  2504. [expectedTypes addObject:@(@encode(int))];
  2505. [expectedTypes addObject:@(@encode(double))];
  2506. // unsigned long long overflow = double
  2507. [ref setValue:@1];
  2508. [ref setValue:[FIRServerValue increment:@((unsigned long long)ULLONG_MAX)]];
  2509. [expected addObject:@1];
  2510. [expected addObject:@((double)ULLONG_MAX + 1)];
  2511. [expectedTypes addObject:@(@encode(int))];
  2512. [expectedTypes addObject:@(@encode(double))];
  2513. // long underflow = double
  2514. [ref setValue:@(-1)];
  2515. [ref setValue:[FIRServerValue increment:@(LONG_MIN)]];
  2516. [expected addObject:@(-1)];
  2517. [expected addObject:@(LONG_MIN - 1.0)];
  2518. [expectedTypes addObject:@(@encode(int))];
  2519. [expectedTypes addObject:@(@encode(double))];
  2520. [self waitUntil:^BOOL {
  2521. return found.count == expected.count && foundTypes.count == expectedTypes.count;
  2522. }];
  2523. XCTAssertEqualObjects(expectedTypes, foundTypes);
  2524. XCTAssertEqualObjects(expected, found);
  2525. [ref.repo resume];
  2526. }
  2527. - (void)testUpdateAfterChildSet {
  2528. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  2529. __block BOOL done = NO;
  2530. __weak FIRDatabaseReference *weakRef = node;
  2531. [node setValue:@{@"a" : @"a"}
  2532. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2533. [weakRef observeEventType:FIRDataEventTypeValue
  2534. withBlock:^(FIRDataSnapshot *snapshot) {
  2535. if (snapshot.childrenCount == 3 && [snapshot hasChild:@"a"] &&
  2536. [snapshot hasChild:@"b"] && [snapshot hasChild:@"c"]) {
  2537. done = YES;
  2538. }
  2539. }];
  2540. [[weakRef child:@"b"] setValue:@"b"];
  2541. [weakRef updateChildValues:@{@"c" : @"c"}];
  2542. }];
  2543. [self waitUntil:^BOOL {
  2544. return done;
  2545. }];
  2546. }
  2547. - (void)testDeltaSyncNoDataUpdatesAfterReconnect {
  2548. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2549. FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"test-config"];
  2550. FIRDatabaseReference *ref2 = [[FTestHelpers databaseForConfig:cfg] referenceWithPath:ref.key];
  2551. __block id data = @{@"a" : @1, @"b" : @2, @"c" : @{@".priority" : @3, @".value" : @3}, @"d" : @4};
  2552. [self waitForCompletionOf:ref setValue:data];
  2553. __block BOOL gotData = NO;
  2554. [ref2 observeEventType:FIRDataEventTypeValue
  2555. withBlock:^(FIRDataSnapshot *snapshot) {
  2556. XCTAssertFalse(gotData, @"event triggered twice.");
  2557. gotData = YES;
  2558. XCTAssertEqualObjects(snapshot.valueInExportFormat, data, @"Got wrong data.");
  2559. }];
  2560. [self waitUntil:^BOOL {
  2561. return gotData;
  2562. }];
  2563. __block BOOL done = NO;
  2564. XCTAssertEqual(ref2.repo.dataUpdateCount, 1L, @"Should have gotten one update.");
  2565. // Bounce connection
  2566. [FRepoManager interrupt:cfg];
  2567. [FRepoManager resume:cfg];
  2568. [[[ref2 root] child:@".info/connected"]
  2569. observeEventType:FIRDataEventTypeValue
  2570. withBlock:^(FIRDataSnapshot *snapshot) {
  2571. if ([snapshot.value boolValue]) {
  2572. // We're connected. Do one more round-trip to make sure all state restoration is
  2573. // done
  2574. [[[ref2 root] child:@"foobar/empty/blah"]
  2575. setValue:nil
  2576. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2577. XCTAssertEqual(ref2.repo.dataUpdateCount, 1L,
  2578. @"Should have gotten one update.");
  2579. done = YES;
  2580. }];
  2581. }
  2582. }];
  2583. [self waitUntil:^BOOL {
  2584. return done;
  2585. }];
  2586. // cleanup
  2587. [FRepoManager interrupt:cfg];
  2588. [FRepoManager disposeRepos:cfg];
  2589. }
  2590. - (void)testServerTimestampEventualConsistencyBetweenLocalAndRemote {
  2591. FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
  2592. FIRDatabaseReference *writer = refs.one;
  2593. FIRDatabaseReference *reader = refs.two;
  2594. __block FIRDataSnapshot *writerSnap = nil;
  2595. __block FIRDataSnapshot *readerSnap = nil;
  2596. [reader observeEventType:FIRDataEventTypeValue
  2597. withBlock:^(FIRDataSnapshot *snapshot) {
  2598. readerSnap = snapshot;
  2599. }];
  2600. [writer observeEventType:FIRDataEventTypeValue
  2601. withBlock:^(FIRDataSnapshot *snapshot) {
  2602. writerSnap = snapshot;
  2603. }];
  2604. [writer setValue:[FIRServerValue timestamp] andPriority:[FIRServerValue timestamp]];
  2605. [self waitUntil:^BOOL {
  2606. if (readerSnap && writerSnap && [[readerSnap value] isKindOfClass:[NSNumber class]] &&
  2607. [[writerSnap value] isKindOfClass:[NSNumber class]]) {
  2608. if ([[readerSnap value] doubleValue] == [[writerSnap value] doubleValue]) {
  2609. return YES;
  2610. }
  2611. }
  2612. return NO;
  2613. }];
  2614. }
  2615. // Listens at a location and then creates a bunch of children, waiting for them all to complete.
  2616. - (void)testChildAddedPerf1 {
  2617. if (!runPerfTests) return;
  2618. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2619. [ref observeEventType:FIRDataEventTypeChildAdded
  2620. withBlock:^(FIRDataSnapshot *snapshot){
  2621. }];
  2622. NSDate *start = [NSDate date];
  2623. int COUNT = 1000;
  2624. __block BOOL done = NO;
  2625. __block NSDate *finished = nil;
  2626. for (int i = 0; i < COUNT; i++) {
  2627. [[ref childByAutoId] setValue:@"01234567890123456789012345678901234567890123456789"
  2628. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2629. if (i == (COUNT - 1)) {
  2630. finished = [NSDate date];
  2631. done = YES;
  2632. }
  2633. }];
  2634. }
  2635. [self
  2636. waitUntil:^BOOL {
  2637. return done;
  2638. }
  2639. timeout:300];
  2640. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2641. NSLog(@"Elapsed: %f", elapsed);
  2642. }
  2643. // Listens at a location, then adds a bunch of grandchildren under a single child.
  2644. - (void)testDeepChildAddedPerf1 {
  2645. if (!runPerfTests) return;
  2646. FIRDatabaseReference *ref = [FTestHelpers getRandomNode], *childRef = [ref child:@"child"];
  2647. [ref observeEventType:FIRDataEventTypeChildAdded
  2648. withBlock:^(FIRDataSnapshot *snapshot){
  2649. }];
  2650. NSDate *start = [NSDate date];
  2651. int COUNT = 1000;
  2652. __block BOOL done = NO;
  2653. __block NSDate *finished = nil;
  2654. for (int i = 0; i < COUNT; i++) {
  2655. [[childRef childByAutoId] setValue:@"01234567890123456789012345678901234567890123456789"
  2656. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2657. if (i == (COUNT - 1)) {
  2658. finished = [NSDate date];
  2659. done = YES;
  2660. }
  2661. }];
  2662. }
  2663. [self
  2664. waitUntil:^BOOL {
  2665. return done;
  2666. }
  2667. timeout:300];
  2668. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2669. NSLog(@"Elapsed: %f", elapsed);
  2670. }
  2671. // Listens at a location, then adds a bunch of grandchildren under a single child, but does it with
  2672. // merges. NOTE[2015-07-14]: This test is still pretty slow, because [FWriteTree removeWriteId] ends
  2673. // up rebuilding the tree after every ack.
  2674. - (void)testDeepChildAddedPerfViaMerge1 {
  2675. if (!runPerfTests) return;
  2676. FIRDatabaseReference *ref = [FTestHelpers getRandomNode], *childRef = [ref child:@"child"];
  2677. [ref observeEventType:FIRDataEventTypeChildAdded
  2678. withBlock:^(FIRDataSnapshot *snapshot){
  2679. }];
  2680. NSDate *start = [NSDate date];
  2681. int COUNT = 250;
  2682. __block BOOL done = NO;
  2683. __block NSDate *finished = nil;
  2684. for (int i = 0; i < COUNT; i++) {
  2685. NSString *childName = [childRef childByAutoId].key;
  2686. [childRef updateChildValues:@{childName : @"01234567890123456789012345678901234567890123456789"}
  2687. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2688. if (i == (COUNT - 1)) {
  2689. finished = [NSDate date];
  2690. done = YES;
  2691. }
  2692. }];
  2693. }
  2694. [self
  2695. waitUntil:^BOOL {
  2696. return done;
  2697. }
  2698. timeout:300];
  2699. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2700. NSLog(@"Elapsed: %f", elapsed);
  2701. }
  2702. @end