FData.m 118 KB

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