FData.m 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691
  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 "FData.h"
  17. #import "FTestHelpers.h"
  18. #import "FEventTester.h"
  19. #import "FTupleEventTypeString.h"
  20. #import <FirebaseCore/FIRApp.h>
  21. #import "FIRDatabaseQuery_Private.h"
  22. #import "FIRDatabaseConfig_Private.h"
  23. #import <FirebaseCore/FIROptions.h>
  24. #import "FRepo_Private.h"
  25. #import <limits.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 withBlock:^(FIRDataSnapshot *snapshot) {
  47. XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw correct value");
  48. }];
  49. }
  50. - (void) testProperParamChecking {
  51. // ios doesn't have an equivalent of this test
  52. }
  53. - (void) testNamespaceCaseInsensitivityWithinARepo {
  54. FIRDatabaseReference * ref1 = [[FIRDatabase database] referenceFromURL:[self.databaseURL uppercaseString]];
  55. FIRDatabaseReference * ref2 = [[FIRDatabase database] referenceFromURL:[self.databaseURL lowercaseString]];
  56. XCTAssertTrue([ref1.description isEqualToString:ref2.description], @"Descriptions should match");
  57. }
  58. - (void) testRootProperty {
  59. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  60. FIRDatabaseReference * root = node.root;
  61. XCTAssertTrue(root != nil, @"Should get a root");
  62. XCTAssertTrue([[root description] isEqualToString:self.databaseURL], @"Root is actually the root");
  63. }
  64. - (void) testValReturnsCompoundObjectWithChildren {
  65. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  66. [node setValue:@{@"foo": @{@"bar": @5}}];
  67. [self snapWaiter:node withBlock:^(FIRDataSnapshot *snapshot) {
  68. XCTAssertEqualObjects([[[snapshot value] objectForKey:@"foo"] objectForKey:@"bar"], @5, @"Properly saw compound object");
  69. }];
  70. }
  71. - (void) testWriteDataAndWaitForServerConfirmation {
  72. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  73. [self waitForCompletionOf:node setValue:@42];
  74. }
  75. - (void) testWriteAValueAndRead {
  76. // dupe of FEvent testWriteLeafExpectValueChanged
  77. }
  78. - (void) testWriteABunchOfDataAndRead {
  79. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  80. FIRDatabaseReference * writeNode = tuple.one;
  81. FIRDatabaseReference * readNode = tuple.two;
  82. __block BOOL done = NO;
  83. [[[[writeNode child:@"a"] child:@"b"] child:@"c"] setValue:@1];
  84. [[[[writeNode child:@"a"] child:@"d"] child:@"e"] setValue:@2];
  85. [[[[writeNode child:@"a"] child:@"d"] child:@"f"] setValue:@3];
  86. [[writeNode child:@"g"] setValue:@4 withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) { done = YES; }];
  87. [self waitUntil:^BOOL{ return done; }];
  88. [super snapWaiter:readNode withBlock:^(FIRDataSnapshot *s) {
  89. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"b"] childSnapshotForPath:@"c"] value], @1, @"Proper child value");
  90. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"d"] childSnapshotForPath:@"e"] value], @2, @"Proper child value");
  91. XCTAssertEqualObjects([[[[s childSnapshotForPath:@"a"] childSnapshotForPath:@"d"] childSnapshotForPath:@"f"] value], @3, @"Proper child value");
  92. XCTAssertEqualObjects([[s childSnapshotForPath:@"g"] value], @4, @"Proper child value");
  93. }];
  94. }
  95. - (void) testWriteABunchOfDataWithLeadingZeroesAndRead {
  96. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  97. FIRDatabaseReference * writeNode = tuple.one;
  98. FIRDatabaseReference * readNode = tuple.two;
  99. [self waitForCompletionOf:[writeNode child:@"1"] setValue:@1];
  100. [self waitForCompletionOf:[writeNode child:@"01"] setValue:@2];
  101. [self waitForCompletionOf:[writeNode child:@"001"] setValue:@3];
  102. [self waitForCompletionOf:[writeNode child:@"0001"] setValue:@4];
  103. [super snapWaiter:readNode withBlock:^(FIRDataSnapshot *s) {
  104. XCTAssertEqualObjects([[s childSnapshotForPath:@"1"] value], @1, @"Proper child value");
  105. XCTAssertEqualObjects([[s childSnapshotForPath:@"01"] value], @2, @"Proper child value");
  106. XCTAssertEqualObjects([[s childSnapshotForPath:@"001"] value], @3, @"Proper child value");
  107. XCTAssertEqualObjects([[s childSnapshotForPath:@"0001"] value], @4, @"Proper child value");
  108. }];
  109. }
  110. - (void) testLeadingZeroesTurnIntoDictionary {
  111. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  112. [self waitForCompletionOf:[ref child:@"1"] setValue:@1];
  113. [self waitForCompletionOf:[ref child:@"01"] setValue:@2];
  114. __block BOOL done = NO;
  115. __block FIRDataSnapshot * snap = nil;
  116. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  117. snap = snapshot;
  118. done = YES;
  119. }];
  120. WAIT_FOR(done);
  121. XCTAssertTrue([snap.value isKindOfClass:[NSDictionary class]], @"Should be dictionary");
  122. XCTAssertEqualObjects([snap.value objectForKey:@"1"], @1, @"Proper child value");
  123. XCTAssertEqualObjects([snap.value objectForKey:@"01"], @2, @"Proper child value");
  124. }
  125. - (void) testLeadingZerosDontCollapseLocally {
  126. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  127. __block BOOL done = NO;
  128. __block FIRDataSnapshot * snap = nil;
  129. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  130. snap = snapshot;
  131. done = (snapshot.childrenCount == 2);
  132. }];
  133. [[ref child:@"3"] setValue:@YES];
  134. [[ref child:@"03"] setValue:@NO];
  135. WAIT_FOR(done);
  136. XCTAssertEqualObjects([[snap childSnapshotForPath:@"3"] value], @YES, @"Proper child value");
  137. XCTAssertEqualObjects([[snap childSnapshotForPath:@"03"] value], @NO, @"Proper child value");
  138. }
  139. - (void) testSnapshotRef {
  140. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  141. __block BOOL done = NO;
  142. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  143. [snapshot.ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  144. done = YES;
  145. }];
  146. }];
  147. WAIT_FOR(done);
  148. }
  149. - (void) testWriteLeafNodeOverwriteAtParentVerifyExpectedEvents {
  150. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  151. FIRDatabaseReference * connected = [[[FIRDatabase database] reference] child:@".info/connected"];
  152. __block BOOL ready = NO;
  153. [connected observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  154. NSNumber *val = [snapshot value];
  155. ready = [val boolValue];
  156. }];
  157. WAIT_FOR(ready);
  158. NSArray* lookingFor = @[
  159. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil], // 4
  160. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"], // 0
  161. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil], // 4
  162. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildChanged withString:@"aa"], // 2
  163. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil], // 4
  164. ];
  165. [[node repo] interrupt]; // Going offline ensures that local events get queued up before server events
  166. FEventTester* et = [[FEventTester alloc] initFrom:self];
  167. [et addLookingFor:lookingFor];
  168. [[node child:@"a/aa"] setValue:@1];
  169. [[node child:@"a"] setValue:@{@"aa": @2}];
  170. [[node repo] resume];
  171. [et wait];
  172. }
  173. - (void) testWriteLeafNodeOverwriteAtParentMultipleTimesVerifyExpectedEvents {
  174. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  175. NSArray* lookingFor = @[
  176. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  177. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  178. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  179. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/bb"] withEvent:FIRDataEventTypeValue withString:nil],
  180. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildChanged withString:@"aa"],
  181. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  182. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  183. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildChanged withString:@"aa"],
  184. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  185. ];
  186. [[node repo] interrupt]; // Going offline ensures that local events get queued up before server events
  187. FEventTester* et = [[FEventTester alloc] initFrom:self];
  188. [et addLookingFor:lookingFor];
  189. [[node child:@"a/aa"] setValue:@1];
  190. [[node child:@"a"] setValue:@{@"aa": @2}];
  191. [[node child:@"a"] setValue:@{@"aa": @3}];
  192. [[node child:@"a"] setValue:@{@"aa": @3}];
  193. [[node repo] resume];
  194. [et wait];
  195. }
  196. - (void) testWriteParentNodeOverwriteAtLeafVerifyExpectedEvents {
  197. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  198. NSArray* lookingFor = @[
  199. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  200. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  201. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  202. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  203. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeChildChanged withString:@"aa"],
  204. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  205. ];
  206. [[node repo] interrupt]; // Going offline ensures that local events get queued up before server events
  207. FEventTester* et = [[FEventTester alloc] initFrom:self];
  208. [et addLookingFor:lookingFor];
  209. [[node child:@"a"] setValue:@{@"aa": @2}];
  210. [[node child:@"a/aa"] setValue:@1];
  211. [[node repo] resume];
  212. [et wait];
  213. }
  214. - (void) testWriteLeafNodeRemoveParentNodeVerifyExpectedEvents {
  215. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  216. FIRDatabaseReference * writer = refs.one;
  217. FIRDatabaseReference * reader = refs.two;
  218. NSArray* lookingFor = @[
  219. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  220. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  221. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  222. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeChildAdded withString:@"a"],
  223. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeValue withString:nil],
  224. ];
  225. FEventTester* et = [[FEventTester alloc] initFrom:self];
  226. [et addLookingFor:lookingFor];
  227. [[writer child:@"a/aa"] setValue:@42];
  228. // the local events
  229. [et wait];
  230. // the reader should get all of the events intermingled
  231. FEventTester* readerEvents = [[FEventTester alloc] initFrom:self];
  232. lookingFor = @[
  233. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  234. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  235. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  236. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildAdded withString:@"a"],
  237. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeValue withString:nil]
  238. ];
  239. [readerEvents addLookingFor:lookingFor];
  240. [readerEvents wait];
  241. lookingFor = @[
  242. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  243. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeChildRemoved withString:@"aa"],
  244. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  245. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildRemoved withString:@"a"],
  246. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeValue withString:nil]
  247. ];
  248. [readerEvents addLookingFor:lookingFor];
  249. lookingFor = @[
  250. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  251. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeChildRemoved withString:@"aa"],
  252. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  253. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeChildRemoved withString:@"a"],
  254. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeValue withString:nil]
  255. ];
  256. [et addLookingFor:lookingFor];
  257. [[writer child:@"a"] removeValue];
  258. [et wait];
  259. [readerEvents wait];
  260. [et unregister];
  261. [readerEvents unregister];
  262. // Ensure we can write a new value
  263. __block NSNumber* readVal = @0.0;
  264. __block NSNumber* writeVal = @0.0;
  265. [[reader child:@"a/aa"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  266. id val = [snapshot value];
  267. if (val != [NSNull null]) {
  268. readVal = val;
  269. }
  270. }];
  271. [[writer child:@"a/aa"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  272. id val = [snapshot value];
  273. if (val != [NSNull null]) {
  274. writeVal = val;
  275. }
  276. }];
  277. [[writer child:@"a/aa"] setValue:@3.1415];
  278. [self waitUntil:^BOOL{
  279. return fabs([readVal doubleValue] - 3.1415) < 0.001 && fabs([writeVal doubleValue] - 3.1415) < 0.001;
  280. //return [readVal isEqualToNumber:@3.1415] && [writeVal isEqualToNumber:@3.1415];
  281. }];
  282. }
  283. - (void) testWriteLeafNodeRemoveLeafVerifyExpectedEvents {
  284. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  285. FIRDatabaseReference * writer = refs.one;
  286. FIRDatabaseReference * reader = refs.two;
  287. NSArray* lookingFor = @[
  288. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  289. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  290. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  291. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeChildAdded withString:@"a"],
  292. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeValue withString:nil],
  293. ];
  294. FEventTester* et = [[FEventTester alloc] initFrom:self];
  295. [et addLookingFor:lookingFor];
  296. [[writer child:@"a/aa"] setValue:@42];
  297. // the local events
  298. [et wait];
  299. // the reader should get all of the events intermingled
  300. FEventTester* readerEvents = [[FEventTester alloc] initFrom:self];
  301. lookingFor = @[
  302. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  303. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeChildAdded withString:@"aa"],
  304. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  305. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildAdded withString:@"a"],
  306. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeValue withString:nil]
  307. ];
  308. [readerEvents addLookingFor:lookingFor];
  309. [readerEvents wait];
  310. lookingFor = @[
  311. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  312. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeChildRemoved withString:@"aa"],
  313. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  314. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildRemoved withString:@"a"],
  315. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeValue withString:nil]
  316. ];
  317. [readerEvents addLookingFor:lookingFor];
  318. lookingFor = @[
  319. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  320. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeChildRemoved withString:@"aa"],
  321. [[FTupleEventTypeString alloc] initWithFirebase:[writer child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  322. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeChildRemoved withString:@"a"],
  323. [[FTupleEventTypeString alloc] initWithFirebase:writer withEvent:FIRDataEventTypeValue withString:nil]
  324. ];
  325. [et addLookingFor:lookingFor];
  326. // remove just the leaf
  327. [[writer child:@"a/aa"] removeValue];
  328. [et wait];
  329. [readerEvents wait];
  330. [et unregister];
  331. [readerEvents unregister];
  332. // Ensure we can write a new value
  333. __block NSNumber* readVal = @0.0;
  334. __block NSNumber* writeVal = @0.0;
  335. [[reader child:@"a/aa"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  336. id val = [snapshot value];
  337. if (val != [NSNull null]) {
  338. readVal = val;
  339. }
  340. }];
  341. [[writer child:@"a/aa"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  342. id val = [snapshot value];
  343. if (val != [NSNull null]) {
  344. writeVal = val;
  345. }
  346. }];
  347. [[writer child:@"a/aa"] setValue:@3.1415];
  348. [self waitUntil:^BOOL{
  349. //NSLog(@"readVal: %@, writeVal: %@, vs %@", readVal, writeVal, @3.1415);
  350. //return [readVal isEqualToNumber:@3.1415] && [writeVal isEqualToNumber:@3.1415];
  351. return fabs([readVal doubleValue] - 3.1415) < 0.001 && fabs([writeVal doubleValue] - 3.1415) < 0.001;
  352. }];
  353. }
  354. - (void) testWriteMultipleLeafNodesRemoveOnlyOneVerifyExpectedEvents {
  355. // XXX impl
  356. }
  357. - (void) testVerifyNodeNamesCantStartWithADot {
  358. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  359. XCTAssertThrows([ref child:@".foo"], @"not a valid .prefix");
  360. XCTAssertThrows([ref child:@"foo/.foo"], @"not a valid path");
  361. // Should not throw
  362. [[ref parent] child:@".info"];
  363. }
  364. - (void) testVerifyWritingToDotLengthAndDotKeysThrows {
  365. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  366. XCTAssertThrows([[ref child:@".keys"] setValue:@42], @"not a valid .prefix");
  367. XCTAssertThrows([[ref child:@".length"] setValue:@42], @"not a valid path");
  368. }
  369. - (void) testNumericKeysGetTurnedIntoArrays {
  370. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  371. [[ref child:@"0"] setValue:@"alpha"];
  372. [[ref child:@"1"] setValue:@"bravo"];
  373. [[ref child:@"2"] setValue:@"charlie"];
  374. [[ref child:@"3"] setValue:@"delta"];
  375. [[ref child:@"4"] setValue:@"echo"];
  376. __block BOOL ready = NO;
  377. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  378. id val = [snapshot value];
  379. XCTAssertTrue([val isKindOfClass:[NSArray class]], @"Expected an array");
  380. NSArray *expected = @[@"alpha", @"bravo", @"charlie", @"delta", @"echo"];
  381. XCTAssertTrue([expected isEqualToArray:val], @"Did not get the correct array");
  382. ready = YES;
  383. }];
  384. [self waitUntil:^{ return ready; }];
  385. }
  386. // This was an issue on 64-bit.
  387. - (void) testLargeNumericKeysDontGetTurnedIntoArrays {
  388. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  389. [[ref child:@"100003354884401"] setValue:@"alpha"];
  390. __block BOOL ready = NO;
  391. [ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  392. id val = [snapshot value];
  393. XCTAssertTrue([val isKindOfClass:[NSDictionary class]], @"Expected a dictionary.");
  394. ready = YES;
  395. }];
  396. [self waitUntil:^{ return ready; }];
  397. }
  398. - (void) testWriteCompoundObjectAndGetItBack {
  399. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  400. NSDictionary* data = @{
  401. @"a": @{@"aa": @5,
  402. @"ab": @3},
  403. @"b": @{@"ba": @"hey there!",
  404. @"bb": @{@"bba": @NO}},
  405. @"c": @[@0,
  406. @{@"c_1": @4},
  407. @"hey",
  408. @YES,
  409. @NO,
  410. @"dude"]
  411. };
  412. __block FIRDataSnapshot *snap = nil;
  413. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  414. snap = snapshot;
  415. }];
  416. __block BOOL done = NO;
  417. [node setValue:data withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) { done = YES; }];
  418. [self waitUntil:^BOOL{
  419. return done;
  420. }];
  421. [self snapWaiter:node withBlock:^(FIRDataSnapshot *snapshot) {
  422. XCTAssertTrue([[[[snapshot value] objectForKey:@"c"] objectAtIndex:3] boolValue], @"Got proper boolean");
  423. }];
  424. }
  425. - (void) testCanPassValueToPush {
  426. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  427. FIRDatabaseReference * pushA = [node childByAutoId];
  428. [pushA setValue:@5];
  429. [self snapWaiter:pushA withBlock:^(FIRDataSnapshot *snapshot) {
  430. XCTAssertEqualObjects(@5, [snapshot value], @"Got proper value");
  431. }];
  432. FIRDatabaseReference * pushB = [node childByAutoId];
  433. [pushB setValue:@{@"a": @5, @"b": @6}];
  434. [self snapWaiter:pushB withBlock:^(FIRDataSnapshot *snapshot) {
  435. XCTAssertEqualObjects(@5, [[snapshot value] objectForKey:@"a"], @"Got proper value");
  436. XCTAssertEqualObjects(@6, [[snapshot value] objectForKey:@"b"], @"Got proper value");
  437. }];
  438. }
  439. // Dropped test that tested callbacks to push. Support was removed.
  440. - (void) testRemoveCallbackHit {
  441. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  442. __block BOOL setDone = NO;
  443. __block BOOL removeDone = NO;
  444. __block BOOL readDone = NO;
  445. [node setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  446. setDone = YES;
  447. }];
  448. [self waitUntil:^BOOL{
  449. return setDone;
  450. }];
  451. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  452. id val = [snapshot value];
  453. if (val == [NSNull null]) {
  454. readDone = YES;
  455. }
  456. }];
  457. [node removeValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  458. XCTAssertTrue(error == nil, @"Should not be an error removing");
  459. removeDone = YES;
  460. }];
  461. [self waitUntil:^BOOL{
  462. return readDone && removeDone;
  463. }];
  464. }
  465. - (void) testRemoveCallbackIsHitForNodesThatAreAlreadyRemoved {
  466. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  467. __block int removes = 0;
  468. [node removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  469. removes = removes + 1;
  470. }];
  471. [node removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  472. removes = removes + 1;
  473. }];
  474. [self waitUntil:^BOOL{
  475. return removes == 2;
  476. }];
  477. }
  478. - (void) testUsingNumbersAsKeysDoesntCreateHugeSparseArrays {
  479. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  480. [[ref child:@"3024"] setValue:@5];
  481. __block BOOL ready = NO;
  482. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  483. id val = [snapshot value];
  484. XCTAssertTrue(![val isKindOfClass:[NSArray class]], @"Should not be an array");
  485. ready = YES;
  486. }];
  487. [self waitUntil:^BOOL{
  488. return ready;
  489. }];
  490. }
  491. - (void) testOnceWithACallbackHitsServer {
  492. FTupleFirebase* tuple = [FTestHelpers getRandomNodeTriple];
  493. FIRDatabaseReference * writeNode = tuple.one;
  494. FIRDatabaseReference * readNode = tuple.two;
  495. FIRDatabaseReference * readNodeB = tuple.three;
  496. __block BOOL initialReadDone = NO;
  497. [readNode observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  498. XCTAssertTrue([[snapshot value] isEqual:[NSNull null]], @"First callback is null");
  499. initialReadDone = YES;
  500. }];
  501. [self waitUntil:^BOOL{
  502. return initialReadDone;
  503. }];
  504. __block BOOL writeDone = NO;
  505. [writeNode setValue:@42 withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  506. writeDone = YES;
  507. }];
  508. [self waitUntil:^BOOL{
  509. return writeDone;
  510. }];
  511. __block BOOL readDone = NO;
  512. [readNodeB observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  513. XCTAssertEqualObjects(@42, [snapshot value], @"Proper second read");
  514. readDone = YES;
  515. }];
  516. [self waitUntil:^BOOL{
  517. return readDone;
  518. }];
  519. }
  520. // Removed test of forEach aborting iteration. Support dropped, use for .. in syntax
  521. - (void) testSetAndThenListenForValueEventsAreCorrect {
  522. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  523. __block BOOL setDone = NO;
  524. [node setValue:@"moo" withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  525. setDone = YES;
  526. }];
  527. __block int calls = 0;
  528. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  529. calls = calls + 1;
  530. XCTAssertTrue(calls == 1, @"Only called once");
  531. XCTAssertEqualObjects([snapshot value], @"moo", @"Proper snapshot value");
  532. }];
  533. [self waitUntil:^BOOL{
  534. return setDone && calls == 1;
  535. }];
  536. [node removeAllObservers];
  537. }
  538. - (void) testHasChildrenWorksCorrectly {
  539. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  540. [node setValue:@{@"one" : @42, @"two": @{@"a": @5}, @"three": @{@"a": @5, @"b": @6}}];
  541. __block BOOL removedTwo = NO;
  542. __block BOOL done = NO;
  543. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  544. if (!removedTwo) {
  545. XCTAssertFalse([[snapshot childSnapshotForPath:@"one"] hasChildren], @"nope");
  546. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] hasChildren], @"nope");
  547. XCTAssertTrue([[snapshot childSnapshotForPath:@"three"] hasChildren], @"nope");
  548. XCTAssertFalse([[snapshot childSnapshotForPath:@"four"] hasChildren], @"nope");
  549. removedTwo = YES;
  550. [[node child:@"two"] removeValue];
  551. }
  552. else {
  553. XCTAssertFalse([[snapshot childSnapshotForPath:@"two"] hasChildren], @"Second time around");
  554. done = YES;
  555. }
  556. }];
  557. [self waitUntil:^BOOL{
  558. return done;
  559. }];
  560. }
  561. - (void) testNumChildrenWorksCorrectly {
  562. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  563. [node setValue:@{@"one" : @42, @"two": @{@"a": @5}, @"three": @{@"a": @5, @"b": @6}}];
  564. __block BOOL removedTwo = NO;
  565. __block BOOL done = NO;
  566. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  567. if (!removedTwo) {
  568. XCTAssertTrue([snapshot childrenCount] == 3, @"Total children");
  569. XCTAssertTrue([[snapshot childSnapshotForPath:@"one"] childrenCount] == 0, @"Two's children");
  570. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] childrenCount] == 1, @"Two's children");
  571. XCTAssertTrue([[snapshot childSnapshotForPath:@"three"] childrenCount] == 2, @"Two's children");
  572. XCTAssertTrue([[snapshot childSnapshotForPath:@"four"] childrenCount] == 0, @"Two's children");
  573. removedTwo = YES;
  574. [[node child:@"two"] removeValue];
  575. }
  576. else {
  577. XCTAssertTrue([snapshot childrenCount] == 2, @"Total children");
  578. XCTAssertTrue([[snapshot childSnapshotForPath:@"two"] childrenCount] == 0, @"Two's children");
  579. done = YES;
  580. }
  581. }];
  582. [self waitUntil:^BOOL{
  583. return done;
  584. }];
  585. }
  586. - (void) testSettingANodeWithChildrenToAPrimitiveAndBack {
  587. // Can't tolerate stale data; so disable persistence.
  588. FTupleFirebase* tuple = [FTestHelpers getRandomNodePairWithoutPersistence];
  589. FIRDatabaseReference * writeNode = tuple.one;
  590. FIRDatabaseReference * readNode = tuple.two;
  591. __block BOOL done = NO;
  592. NSDictionary* compound = @{@"a": @5, @"b": @6};
  593. NSNumber* number = @76;
  594. [writeNode setValue:compound];
  595. [self snapWaiter:writeNode withBlock:^(FIRDataSnapshot *snapshot) {
  596. XCTAssertTrue([snapshot hasChildren], @"Has children");
  597. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  598. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  599. done = YES;
  600. }];
  601. [self waitUntil:^BOOL{
  602. return done;
  603. }];
  604. done = NO;
  605. [self snapWaiter:readNode withBlock:^(FIRDataSnapshot *snapshot) {
  606. XCTAssertTrue([snapshot hasChildren], @"has children");
  607. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  608. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  609. done = YES;
  610. }];
  611. [self waitUntil:^BOOL{
  612. return done;
  613. }];
  614. done = NO;
  615. [writeNode setValue:number withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  616. done = YES;
  617. }];
  618. [self waitUntil:^BOOL{
  619. return done;
  620. }];
  621. done = NO;
  622. [self snapWaiter:readNode withBlock:^(FIRDataSnapshot *snapshot) {
  623. XCTAssertFalse([snapshot hasChildren], @"No more children");
  624. XCTAssertEqualObjects(number, [snapshot value], @"Proper non compound value");
  625. done = YES;
  626. }];
  627. [self waitUntil:^BOOL{
  628. return done;
  629. }];
  630. done = NO;
  631. [writeNode setValue:compound withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  632. done = YES;
  633. }];
  634. [self waitUntil:^BOOL{
  635. return done;
  636. }];
  637. done = NO;
  638. [self snapWaiter:readNode withBlock:^(FIRDataSnapshot *snapshot) {
  639. XCTAssertTrue([snapshot hasChildren], @"Has children");
  640. XCTAssertEqualObjects(@5, [[snapshot childSnapshotForPath:@"a"] value], @"First child");
  641. XCTAssertEqualObjects(@6, [[snapshot childSnapshotForPath:@"b"] value], @"First child");
  642. done = YES;
  643. }];
  644. [self waitUntil:^BOOL{
  645. return done;
  646. }];
  647. XCTAssertTrue(done, @"Properly finished");
  648. }
  649. - (void) testWriteLeafRemoveLeafAddChildToRemovedNode {
  650. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  651. FIRDatabaseReference * writer = refs.one;
  652. FIRDatabaseReference * reader = refs.two;
  653. __block BOOL ready = NO;
  654. [writer setValue:@5];
  655. [writer removeValue];
  656. [[writer child:@"abc"] setValue:@5 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  657. ready = YES;
  658. }];
  659. [self waitUntil:^BOOL{
  660. return ready;
  661. }];
  662. __block NSDictionary* readVal = nil;
  663. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  664. readVal = [snapshot value];
  665. }];
  666. [self waitUntil:^BOOL{
  667. return readVal != nil;
  668. }];
  669. NSNumber* five = [readVal objectForKey:@"abc"];
  670. XCTAssertTrue([five isEqualToNumber:@5], @"Should get 5");
  671. }
  672. - (void) testListenForValueAndThenWriteOnANodeWithExistingData {
  673. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  674. FIRDatabaseReference * writer = refs.one;
  675. FIRDatabaseReference * reader = refs.two;
  676. [self waitForCompletionOf:writer setValue:@{@"a": @5, @"b": @2}];
  677. __block int calls = 0;
  678. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  679. calls++;
  680. if (calls == 1) {
  681. NSDictionary *val = [snapshot value];
  682. NSDictionary *expected = @{@"a" : @10, @"b" : @2};
  683. XCTAssertTrue([val isEqualToDictionary:expected], @"Got the correct value");
  684. } else {
  685. XCTFail(@"Should only be called once");
  686. }
  687. }];
  688. [[reader child:@"a"] setValue:@10];
  689. [self waitUntil:^BOOL{
  690. return calls == 1;
  691. }];
  692. [reader removeAllObservers];
  693. }
  694. - (void) testSetPriorityOnNonexistentNodeFails {
  695. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  696. __block BOOL ready = NO;
  697. [ref setPriority:@5 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  698. XCTAssertTrue(error != nil, @"This should not succeed");
  699. ready = YES;
  700. }];
  701. [self waitUntil:^BOOL{
  702. return ready;
  703. }];
  704. }
  705. - (void) testSetPriorityOnExistentNodeSucceeds {
  706. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  707. __block BOOL ready = NO;
  708. [ref setValue:@"hello!"];
  709. [ref setPriority:@5 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  710. XCTAssertTrue(error == nil, @"This should succeed");
  711. ready = YES;
  712. }];
  713. [self waitUntil:^BOOL{
  714. return ready;
  715. }];
  716. }
  717. - (void) testSetWithPrioritySetsValueAndPriority {
  718. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  719. FIRDatabaseReference * writer = refs.one;
  720. FIRDatabaseReference * reader = refs.two;
  721. [self waitForCompletionOf:writer setValue:@"hello" andPriority:@5];
  722. __block FIRDataSnapshot * writeSnap = nil;
  723. __block FIRDataSnapshot * readSnap = nil;
  724. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  725. writeSnap = snapshot;
  726. }];
  727. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  728. readSnap = snapshot;
  729. }];
  730. [self waitUntil:^BOOL{
  731. return readSnap != nil && writeSnap != nil;
  732. }];
  733. XCTAssertTrue([@"hello" isEqualToString:[readSnap value]], @"Got the value on the reader");
  734. XCTAssertTrue([@"hello" isEqualToString:[writeSnap value]], @"Got the value on the writer");
  735. XCTAssertTrue([@5 isEqualToNumber:[readSnap priority]], @"Got the priority on the reader");
  736. XCTAssertTrue([@5 isEqualToNumber:[writeSnap priority]], @"Got the priority on the writer");
  737. }
  738. - (void) testEffectsOfSetPriorityIsImmediatelyEvident {
  739. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  740. NSMutableArray* values = [[NSMutableArray alloc] init];
  741. NSMutableArray* priorities = [[NSMutableArray alloc] init];
  742. [ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  743. [values addObject:[snapshot value]];
  744. [priorities addObject:[snapshot priority]];
  745. }];
  746. [ref setValue:@5];
  747. [ref setPriority:@10];
  748. __block BOOL ready = NO;
  749. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  750. [values addObject:[snapshot value]];
  751. [priorities addObject:[snapshot priority]];
  752. ready = YES;
  753. }];
  754. [self waitUntil:^BOOL{
  755. return ready;
  756. }];
  757. NSArray* expectedValues = @[@5, @5];
  758. NSArray* expectedPriorites = @[[NSNull null], @10];
  759. XCTAssertTrue([values isEqualToArray:expectedValues], @"Expected both listeners to get 5, got %@ instead", values);
  760. XCTAssertTrue([priorities isEqualToArray:expectedPriorites], @"The first listener should have missed the priority, got %@ instead", priorities);
  761. }
  762. - (void) testSetOverwritesPriorityOfTopLevelNodeAndSubnodes {
  763. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  764. FIRDatabaseReference * writer = refs.one;
  765. FIRDatabaseReference * reader = refs.two;
  766. __block BOOL ready = NO;
  767. [writer setValue:@{@"a": @5}];
  768. [writer setPriority:@10];
  769. [[writer child:@"a"] setPriority:@18];
  770. [writer setValue:@{@"a": @7} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  771. ready = YES;
  772. }];
  773. [self waitUntil:^BOOL{
  774. return ready;
  775. }];
  776. ready = NO;
  777. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  778. id pri = [snapshot priority];
  779. XCTAssertTrue([NSNull null] == pri, @"Expected null priority");
  780. FIRDataSnapshot *child = [snapshot childSnapshotForPath:@"a"];
  781. XCTAssertTrue([NSNull null] == [child priority], @"Child priority should be null too");
  782. ready = YES;
  783. }];
  784. [self waitUntil:^BOOL{
  785. return ready;
  786. }];
  787. }
  788. - (void) testSetPriorityOfLeafSavesCorrectly {
  789. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  790. FIRDatabaseReference * writer = refs.one;
  791. FIRDatabaseReference * reader = refs.two;
  792. __block BOOL ready = NO;
  793. [writer setValue:@"testleaf" andPriority:@992 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  794. ready = YES;
  795. }];
  796. [self waitUntil:^BOOL{
  797. return ready;
  798. }];
  799. ready = NO;
  800. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  801. id pri = [snapshot priority];
  802. XCTAssertTrue([@992 isEqualToNumber:pri], @"Expected non-null priority");
  803. ready = YES;
  804. }];
  805. [self waitUntil:^BOOL{
  806. return ready;
  807. }];
  808. }
  809. - (void) testSetPriorityOfObjectSavesCorrectly {
  810. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  811. FIRDatabaseReference * writer = refs.one;
  812. FIRDatabaseReference * reader = refs.two;
  813. __block BOOL ready = NO;
  814. [writer setValue:@{@"a": @5} andPriority:@991 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  815. ready = YES;
  816. }];
  817. [self waitUntil:^BOOL{
  818. return ready;
  819. }];
  820. ready = NO;
  821. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  822. id pri = [snapshot priority];
  823. XCTAssertTrue([@991 isEqualToNumber:pri], @"Expected non-null priority");
  824. ready = YES;
  825. }];
  826. [self waitUntil:^BOOL{
  827. return ready;
  828. }];
  829. }
  830. - (void) testSetWithPriorityFollowedBySetClearsPriority {
  831. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  832. FIRDatabaseReference * writer = refs.one;
  833. FIRDatabaseReference * reader = refs.two;
  834. __block BOOL ready = NO;
  835. [writer setValue:@{@"a": @5} andPriority:@991 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  836. ready = YES;
  837. }];
  838. [self waitUntil:^BOOL{
  839. return ready;
  840. }];
  841. ready = NO;
  842. [reader setValue:@{@"a": @19} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  843. ready = YES;
  844. }];
  845. [self waitUntil:^BOOL{
  846. return ready;
  847. }];
  848. ready = NO;
  849. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  850. id pri = [snapshot priority];
  851. XCTAssertTrue([NSNull null] == pri, @"Expected null priority");
  852. ready = YES;
  853. }];
  854. [self waitUntil:^BOOL{
  855. return ready;
  856. }];
  857. }
  858. - (void) testGetPriorityReturnsCorrectType {
  859. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  860. __block FIRDataSnapshot * snap = nil;
  861. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  862. snap = snapshot;
  863. }];
  864. [ref setValue:@"a"];
  865. [self waitUntil:^BOOL{
  866. return snap != nil;
  867. }];
  868. XCTAssertTrue([snap priority] == [NSNull null], @"Expect null priority");
  869. snap = nil;
  870. [ref setValue:@"b" andPriority:@5];
  871. [self waitUntil:^BOOL{
  872. return snap != nil;
  873. }];
  874. XCTAssertTrue([[snap priority] isEqualToNumber:@5], @"Expect priority");
  875. snap = nil;
  876. [ref setValue:@"c" andPriority:@"6"];
  877. [self waitUntil:^BOOL{
  878. return snap != nil;
  879. }];
  880. XCTAssertTrue([[snap priority] isEqualToString:@"6"], @"Expect priority");
  881. snap = nil;
  882. [ref setValue:@"d" andPriority:@7];
  883. [self waitUntil:^BOOL{
  884. return snap != nil;
  885. }];
  886. XCTAssertTrue([[snap priority] isEqualToNumber:@7], @"Expect priority");
  887. snap = nil;
  888. [ref setValue:@{@".value": @"e", @".priority": @8}];
  889. [self waitUntil:^BOOL{
  890. return snap != nil;
  891. }];
  892. XCTAssertTrue([[snap priority] isEqualToNumber:@8], @"Expect priority");
  893. snap = nil;
  894. [ref setValue:@{@".value": @"f", @".priority": @"8"}];
  895. [self waitUntil:^BOOL{
  896. return snap != nil;
  897. }];
  898. XCTAssertTrue([[snap priority] isEqualToString:@"8"], @"Expect priority");
  899. snap = nil;
  900. [ref setValue:@{@".value": @"e", @".priority": [NSNull null]}];
  901. [self waitUntil:^BOOL{
  902. return snap != nil;
  903. }];
  904. XCTAssertTrue([snap priority] == [NSNull null], @"Expect priority");
  905. snap = nil;
  906. }
  907. - (void) testExportValIncludesPriorities {
  908. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  909. NSDictionary* contents = @{@"foo": @{@"bar": @{@".value": @5, @".priority": @7}, @".priority": @"hi"}};
  910. __block FIRDataSnapshot * snap = nil;
  911. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  912. snap = snapshot;
  913. }];
  914. [ref setValue:contents];
  915. [self waitUntil:^BOOL{
  916. return snap != nil;
  917. }];
  918. XCTAssertTrue([contents isEqualToDictionary:[snap valueInExportFormat]], @"Expected priorities in snapshot");
  919. }
  920. - (void) testPriorityIsOverwrittenByServer {
  921. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  922. FIRDatabaseReference * reader = refs.one;
  923. FIRDatabaseReference * writer = refs.two;
  924. __block int event = 0;
  925. __block BOOL done = NO;
  926. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  927. NSLog(@"%@ Snapshot", snapshot);
  928. id pri = [snapshot priority];
  929. if (event == 0) {
  930. XCTAssertTrue([@100 isEqualToNumber:pri], @"Expect local priority. Got %@ instead.", pri);
  931. } else if (event == 1) {
  932. XCTAssertTrue(pri == [NSNull null], @"Expect remote priority. Got %@ instead.", pri);
  933. } else {
  934. XCTFail(@"Extra event");
  935. }
  936. event++;
  937. if (event == 2) {
  938. done = YES;
  939. }
  940. }];
  941. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  942. id pri = [snapshot priority];
  943. if ([[pri class] isSubclassOfClass:[NSNumber class]] && [@100 isEqualToNumber:pri]) {
  944. [writer setValue:@"whatever"];
  945. }
  946. }];
  947. [reader setValue:@"hi" andPriority:@100];
  948. [self waitUntil:^BOOL{
  949. return done;
  950. }];
  951. }
  952. - (void) testLargeNumericPrioritiesWork {
  953. NSNumber* bigPriority = @1356721306842;
  954. __block BOOL ready = NO;
  955. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  956. FIRDatabaseReference * reader = refs.one;
  957. FIRDatabaseReference * writer = refs.two;
  958. [self waitForCompletionOf:writer setValue:@5 andPriority:bigPriority];
  959. __block NSNumber* serverPriority = @0;
  960. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  961. serverPriority = [snapshot priority];
  962. ready = YES;
  963. }];
  964. [self waitUntil:^BOOL{
  965. return ready;
  966. }];
  967. XCTAssertTrue([bigPriority isEqualToNumber:serverPriority], @"Expect big priority back");
  968. }
  969. - (void) testToString {
  970. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  971. FIRDatabaseReference * parent = [ref parent];
  972. XCTAssertTrue([[parent description] isEqualToString:self.databaseURL], @"Expect domain");
  973. FIRDatabaseReference * child = [parent child:@"a/b/c"];
  974. NSString* expected = [NSString stringWithFormat:@"%@/a/b/c", self.databaseURL];
  975. XCTAssertTrue([[child description] isEqualToString:expected], @"Expected path");
  976. }
  977. - (void) testURLEncodingOfDescriptionAndURLDecodingOfNewFirebase {
  978. __block BOOL ready = NO;
  979. NSString* test1 = [NSString stringWithFormat:@"%@/a%%b&c@d/space: /non-ascii_character:ø", self.databaseURL];
  980. NSString* expected1 = [NSString stringWithFormat:@"%@/a%%25b%%26c%%40d/space%%3A%%20/non-ascii_character%%3A%%C3%%B8", self.databaseURL];
  981. FIRDatabaseReference * ref = [[FIRDatabase database] referenceFromURL:test1];
  982. NSString* result = [ref description];
  983. XCTAssertTrue([result isEqualToString:expected1], @"Encodes properly");
  984. int rnd = arc4random_uniform(100000000);
  985. NSString* path = [NSString stringWithFormat:@"%i", rnd];
  986. [[ref child:path] setValue:@"testdata" withCompletionBlock:^(NSError* error, FIRDatabaseReference * childRef) {
  987. FIRDatabaseReference * other = [[FIRDatabase database] referenceFromURL:[ref description]];
  988. [[other child:path] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  989. NSString *val = snapshot.value;
  990. XCTAssertTrue([val isEqualToString:@"testdata"], @"Expected to get testdata back");
  991. ready = YES;
  992. }];
  993. }];
  994. [self waitUntil:^BOOL{
  995. return ready;
  996. }];
  997. }
  998. - (void) testNameAtRootAndNonRootLocations {
  999. FIRDatabaseReference * ref = [[FIRDatabase database] referenceFromURL:self.databaseURL];
  1000. XCTAssertTrue(ref.key == nil, @"Root key should be nil");
  1001. FIRDatabaseReference * child = [ref child:@"a"];
  1002. XCTAssertTrue([child.key isEqualToString:@"a"], @"Should be 'a'");
  1003. FIRDatabaseReference * deeperChild = [child child:@"b/c"];
  1004. XCTAssertTrue([deeperChild.key isEqualToString:@"c"], @"Should be 'c'");
  1005. }
  1006. - (void) testNameAndRefOnSnapshotsForRootAndNonRootLocations {
  1007. FIRDatabaseReference * ref = [[FIRDatabase database] reference];
  1008. __block BOOL ready = NO;
  1009. [ref removeValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1010. ready = YES;
  1011. }];
  1012. [self waitUntil:^BOOL{
  1013. return ready;
  1014. }];
  1015. ready = NO;
  1016. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1017. XCTAssertTrue(snapshot.key == nil, @"Root snap should not have a key");
  1018. NSString *snapString = [snapshot.ref description];
  1019. XCTAssertTrue([snapString isEqualToString:snapString], @"Refs should be equivalent");
  1020. FIRDataSnapshot *childSnap = [snapshot childSnapshotForPath:@"a"];
  1021. XCTAssertTrue([childSnap.key isEqualToString:@"a"], @"Properly keys children");
  1022. FIRDatabaseReference *childRef = [ref child:@"a"];
  1023. NSString *refString = [childRef description];
  1024. snapString = [childSnap.ref description];
  1025. XCTAssertTrue([refString isEqualToString:snapString], @"Refs should be equivalent");
  1026. childSnap = [childSnap childSnapshotForPath:@"b/c"];
  1027. childRef = [childRef child:@"b/c"];
  1028. XCTAssertTrue([childSnap.key isEqualToString:@"c"], @"properly keys children");
  1029. refString = [childRef description];
  1030. snapString = [childSnap.ref description];
  1031. XCTAssertTrue([refString isEqualToString:snapString], @"Refs should be equivalent");
  1032. ready = YES;
  1033. }];
  1034. [self waitUntil:^BOOL{
  1035. return ready;
  1036. }];
  1037. ready = NO;
  1038. // generate value event at root
  1039. [ref setValue:@"foo"];
  1040. [self waitUntil:^BOOL{
  1041. return ready;
  1042. }];
  1043. }
  1044. - (void) testParentForRootAndNonRootLocations {
  1045. FIRDatabaseReference * ref = [[FIRDatabase database] reference];
  1046. XCTAssertTrue(ref.parent == nil, @"Parent of root should be nil");
  1047. FIRDatabaseReference * child = [ref child:@"a"];
  1048. XCTAssertTrue([[child.parent description] isEqualToString:[ref description]], @"Should be equivalent locations");
  1049. child = [ref child:@"a/b/c"];
  1050. XCTAssertTrue([[child.parent.parent.parent description] isEqualToString:[ref description]], @"Should be equivalent locations");
  1051. }
  1052. - (void) testSettingNumericKeysConvertsToStrings {
  1053. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1054. NSDictionary* toSet = @{@4: @"hi", @5: @"test"};
  1055. XCTAssertThrows([ref setValue:toSet], @"Keys must be strings");
  1056. }
  1057. - (void) testSetChildAndListenAtRootRegressionTest {
  1058. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1059. FIRDatabaseReference * writer = refs.one;
  1060. FIRDatabaseReference * reader = refs.two;
  1061. __block BOOL ready = NO;
  1062. [writer removeValue];
  1063. [[writer child:@"foo"] setValue:@"hi" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1064. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1065. NSDictionary *val = [snapshot value];
  1066. NSDictionary *expected = @{@"foo" : @"hi"};
  1067. XCTAssertTrue([val isEqualToDictionary:expected], @"Got child");
  1068. ready = YES;
  1069. }];
  1070. }];
  1071. [self waitUntil:^BOOL{
  1072. return ready;
  1073. }];
  1074. }
  1075. - (void) testAccessingInvalidPathsThrows {
  1076. NSArray* badPaths = @[
  1077. @".test",
  1078. @"test.",
  1079. @"fo$o",
  1080. @"[what",
  1081. @"ever]",
  1082. @"ha#sh"
  1083. ];
  1084. for (NSString* key in badPaths) {
  1085. NSString* url = [NSString stringWithFormat:@"%@/%@", self.databaseURL, key];
  1086. XCTAssertThrows(^{
  1087. FIRDatabaseReference * ref = [[FIRDatabase database] referenceFromURL:url];
  1088. XCTFail(@"Should not get here with ref: %@", ref);
  1089. }(), @"should throw");
  1090. url = [NSString stringWithFormat:@"%@/TESTS/%@", self.databaseURL, key];
  1091. XCTAssertThrows(^{
  1092. FIRDatabaseReference * ref = [[FIRDatabase database] referenceFromURL:url];
  1093. XCTFail(@"Should not get here with ref: %@", ref);
  1094. }(), @"should throw");
  1095. }
  1096. __block BOOL ready = NO;
  1097. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1098. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1099. for (NSString *key in badPaths) {
  1100. XCTAssertThrows([snapshot childSnapshotForPath:key], @"should throw");
  1101. XCTAssertThrows([snapshot hasChild:key], @"should throw");
  1102. }
  1103. ready = YES;
  1104. }];
  1105. [ref setValue:nil];
  1106. [self waitUntil:^BOOL{
  1107. return ready;
  1108. }];
  1109. }
  1110. - (void) testSettingObjectsAtInvalidKeysThrow {
  1111. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1112. NSArray* badPaths = @[
  1113. @".test",
  1114. @"test.",
  1115. @"fo$o",
  1116. @"[what",
  1117. @"ever]",
  1118. @"ha#sh",
  1119. @"/thing",
  1120. @"th/ing",
  1121. @"thing/"
  1122. ];
  1123. NSMutableArray* badObjs = [[NSMutableArray alloc] init];
  1124. for (NSString* key in badPaths) {
  1125. [badObjs addObject:@{key: @"test"}];
  1126. [badObjs addObject:@{@"deeper": @{key: @"test"}}];
  1127. }
  1128. for (NSDictionary* badObj in badObjs) {
  1129. XCTAssertThrows([ref setValue:badObj], @"Should throw");
  1130. XCTAssertThrows([ref setValue:badObj andPriority:@5], @"Should throw");
  1131. XCTAssertThrows([ref onDisconnectSetValue:badObj], @"Should throw");
  1132. XCTAssertThrows([ref onDisconnectSetValue:badObj andPriority:@5], @"Should throw");
  1133. // XXX transaction
  1134. }
  1135. }
  1136. - (void) testSettingInvalidObjectsThrow {
  1137. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1138. XCTAssertThrows([ref setValue:[NSDate date]], @"Should throw");
  1139. NSDictionary *data = @{@"invalid":@"data", @".sv":@"timestamp"};
  1140. XCTAssertThrows([ref setValue:data], @"Should throw");
  1141. data = @{@".value": @{}};
  1142. XCTAssertThrows([ref setValue:data], @"Should throw");
  1143. }
  1144. - (void) testInvalidUpdateThrow {
  1145. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1146. NSArray *badUpdates = @[
  1147. @{@"/":@"t", @"a":@"t"},
  1148. @{@"a":@"t", @"a/b":@"t"},
  1149. @{@"/a":@"t", @"a/b":@"t"},
  1150. @{@"/a/b":@"t", @"a":@"t"},
  1151. @{@"/a/b/.priority":@"t", @"/a/b":@"t"},
  1152. @{@"/a/b/.sv":@"timestamp"},
  1153. @{@"/a/b/.value":@"t"},
  1154. @{@"/a/b/.priority":@{@"x": @"y"}}];
  1155. for (NSDictionary* update in badUpdates) {
  1156. XCTAssertThrows([ref updateChildValues:update], @"Should throw");
  1157. XCTAssertThrows([ref onDisconnectUpdateChildValues:update], @"Should throw");
  1158. }
  1159. }
  1160. - (void) testSettingNull {
  1161. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1162. XCTAssertNoThrow([ref setValue:nil], @"Should not throw");
  1163. XCTAssertNoThrow([ref setValue:[NSNull null]], @"Should not throw");
  1164. }
  1165. - (void) testSettingNaN {
  1166. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1167. XCTAssertThrows([ref setValue:[NSDecimalNumber notANumber]], @"Should throw");
  1168. }
  1169. - (void) testSettingInvalidPriority {
  1170. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1171. XCTAssertThrows([ref setValue:@"3" andPriority:[NSDecimalNumber notANumber]], @"Should throw");
  1172. XCTAssertThrows([ref setValue:@"4" andPriority:@{}], @"Should throw");
  1173. XCTAssertThrows([ref setValue:@"5" andPriority:@[]], @"Should throw");
  1174. }
  1175. - (void) testRemoveFromOnMobileGraffitiBugAtAngelHack {
  1176. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1177. __block BOOL done = NO;
  1178. [node observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  1179. [[node child:[snapshot key]] removeValueWithCompletionBlock:^(NSError *err, FIRDatabaseReference *ref) {
  1180. done = YES;
  1181. }];
  1182. }];
  1183. [[node childByAutoId] setValue:@"moo"];
  1184. [self waitUntil:^BOOL{
  1185. return done;
  1186. }];
  1187. XCTAssertTrue(done, @"Properly finished");
  1188. }
  1189. - (void) testSetANodeWithAQuotedKey {
  1190. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1191. __block BOOL done = NO;
  1192. __block FIRDataSnapshot * snap;
  1193. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1194. snap = snapshot;
  1195. }];
  1196. [node setValue:@{@"\"herp\"": @1234} withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  1197. done = YES;
  1198. XCTAssertEqualObjects(@1234, [[snap childSnapshotForPath:@"\"herp\""] value], @"Got it back");
  1199. }];
  1200. [self waitUntil:^BOOL{
  1201. return done;
  1202. }];
  1203. XCTAssertTrue(done, @"Properly finished");
  1204. }
  1205. - (void) testSetANodeWithASingleQuoteKey {
  1206. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1207. __block BOOL done = NO;
  1208. __block FIRDataSnapshot * snap;
  1209. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1210. snap = snapshot;
  1211. }];
  1212. [node setValue:@{@"\"": @1234} withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) {
  1213. done = YES;
  1214. XCTAssertEqualObjects(@1234, [[snap childSnapshotForPath:@"\""] value], @"Got it back");
  1215. }];
  1216. [self waitUntil:^BOOL{
  1217. return done;
  1218. }];
  1219. XCTAssertTrue(done, @"Properly finished");
  1220. }
  1221. - (void) testEmptyChildGetValueEventBeforeParent {
  1222. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1223. NSArray* lookingFor = @[
  1224. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa/aaa"] withEvent:FIRDataEventTypeValue withString:nil],
  1225. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a/aa"] withEvent:FIRDataEventTypeValue withString:nil],
  1226. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  1227. ];
  1228. FEventTester* et = [[FEventTester alloc] initFrom:self];
  1229. [et addLookingFor:lookingFor];
  1230. [node setValue:@{@"b": @5}];
  1231. [et wait];
  1232. }
  1233. // iOS behavior is different from what the recursive set test looks for. We don't raise events synchronously
  1234. - (void) testOnAfterSetWaitsForLatestData {
  1235. // We test here that we don't cache sets, but they would be persisted so make sure we are running without
  1236. // persistence
  1237. FTupleFirebase* refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1238. FIRDatabaseReference * node1 = refs.one;
  1239. FIRDatabaseReference * node2 = refs.two;
  1240. __block BOOL ready = NO;
  1241. [node1 setValue:@5 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1242. [node2 setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1243. ready = YES;
  1244. }];
  1245. }];
  1246. [self waitUntil:^BOOL{
  1247. return ready;
  1248. }];
  1249. ready = NO;
  1250. [node1 observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1251. NSNumber *val = [snapshot value];
  1252. XCTAssertTrue([val isEqualToNumber:@42], @"Should not have cached earlier set");
  1253. ready = YES;
  1254. }];
  1255. [self waitUntil:^BOOL{
  1256. return ready;
  1257. }];
  1258. }
  1259. - (void) testOnceWaitsForLatestData {
  1260. // Can't tolerate stale data; so disable persistence.
  1261. FTupleFirebase* refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1262. FIRDatabaseReference * node1 = refs.one;
  1263. FIRDatabaseReference * node2 = refs.two;
  1264. __block BOOL ready = NO;
  1265. [node1 observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1266. id val = [snapshot value];
  1267. XCTAssertTrue([NSNull null] == val, @"First value should be null");
  1268. [node2 setValue:@5 withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1269. [node1 observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1270. NSNumber *val = [snapshot value];
  1271. XCTAssertTrue([val isKindOfClass:[NSNumber class]] && [val isEqualToNumber:@5], @"Should get first value");
  1272. ready = YES;
  1273. }];
  1274. }];
  1275. }];
  1276. [self waitUntil:^BOOL{
  1277. return ready;
  1278. }];
  1279. ready = NO;
  1280. [node2 setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1281. [node1 observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1282. NSNumber *val = [snapshot value];
  1283. XCTAssertTrue([val isEqualToNumber:@42], @"Got second number");
  1284. ready = YES;
  1285. }];
  1286. }];
  1287. [self waitUntil:^BOOL{
  1288. return ready;
  1289. }];
  1290. }
  1291. - (void) testMemoryFreeingOnUnlistenDoesNotCorruptData {
  1292. // Can't tolerate stale data; so disable persistence.
  1293. FTupleFirebase* refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1294. FIRDatabaseReference * node2 = [[refs.one root] childByAutoId];
  1295. __block BOOL hasRun = NO;
  1296. __block BOOL ready = NO;
  1297. FIRDatabaseHandle handle1 = [refs.one observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1298. if (!hasRun) {
  1299. hasRun = YES;
  1300. id val = [snapshot value];
  1301. XCTAssertTrue([NSNull null] == val, @"First time should be null");
  1302. [refs.one setValue:@"test" withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1303. ready = YES;
  1304. }];
  1305. }
  1306. }];
  1307. [self waitUntil:^BOOL{
  1308. return ready;
  1309. }];
  1310. [refs.one removeObserverWithHandle:handle1];
  1311. ready = NO;
  1312. [node2 setValue:@"hello" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1313. [refs.one observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1314. NSString *val = [snapshot value];
  1315. XCTAssertTrue([val isEqualToString:@"test"], @"Get back the value we set above");
  1316. [refs.two observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1317. NSString *val = [snapshot value];
  1318. XCTAssertTrue([val isEqualToString:@"test"], @"Get back the value we set above");
  1319. ready = YES;
  1320. }];
  1321. }];
  1322. }];
  1323. [self waitUntil:^BOOL{
  1324. return ready;
  1325. }];
  1326. //write {x: 1, y : {t: 2, u: 3}}
  1327. //Listen at /. Then listen at /x/t
  1328. //unlisten at /y/t. Off at /. Once at /. Ensure data is still all there.
  1329. //Once at /y. Ensure data is still all there.
  1330. refs = [FTestHelpers getRandomNodePairWithoutPersistence];
  1331. ready = NO;
  1332. __block FIRDatabaseHandle deeplisten = NSNotFound;
  1333. __block FIRDatabaseHandle slashlisten = NSNotFound;
  1334. __weak FIRDatabaseReference * refOne = refs.one;
  1335. [refs.one setValue:@{@"x": @1, @"y": @{@"t": @2, @"u": @3}} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1336. slashlisten = [refOne observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1337. deeplisten = [[refOne child:@"y/t"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1338. [[refOne child:@"y/t"] removeObserverWithHandle:deeplisten];
  1339. [refOne removeObserverWithHandle:slashlisten];
  1340. ready = YES;
  1341. }];
  1342. }];
  1343. }];
  1344. [self waitUntil:^BOOL{
  1345. return ready;
  1346. }];
  1347. ready = NO;
  1348. [[refs.one child:@"x"] setValue:@"test" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1349. [refs.one observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1350. NSDictionary *val = [snapshot value];
  1351. NSDictionary *expected = @{@"x" : @"test", @"y" : @{@"t" : @2, @"u" : @3}};
  1352. XCTAssertTrue([val isEqualToDictionary:expected], @"Got the final value");
  1353. ready = YES;
  1354. }];
  1355. }];
  1356. [self waitUntil:^BOOL{
  1357. return ready;
  1358. }];
  1359. }
  1360. - (void) testUpdateRaisesCorrectLocalEvents {
  1361. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1362. __block FIRDataSnapshot * snap = nil;
  1363. [node observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1364. snap = snapshot;
  1365. }];
  1366. __block BOOL ready = NO;
  1367. [node setValue:@{@"a": @1, @"b": @2, @"c": @3, @"d": @4} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1368. ready = YES;
  1369. }];
  1370. [self waitUntil:^BOOL{
  1371. return ready;
  1372. }];
  1373. FEventTester* et = [[FEventTester alloc] initFrom:self];
  1374. NSArray* expectations = @[
  1375. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  1376. [[FTupleEventTypeString alloc] initWithFirebase:[node child:@"d"] withEvent:FIRDataEventTypeValue withString:nil],
  1377. [[FTupleEventTypeString alloc] initWithFirebase:node withEvent:FIRDataEventTypeChildChanged withString:@"a"],
  1378. [[FTupleEventTypeString alloc] initWithFirebase:node withEvent:FIRDataEventTypeChildChanged withString:@"d"],
  1379. [[FTupleEventTypeString alloc] initWithFirebase:node withEvent:FIRDataEventTypeValue withString:nil]
  1380. ];
  1381. [et addLookingFor:expectations];
  1382. [et waitForInitialization];
  1383. [node updateChildValues:@{@"a": @4, @"d": @1}];
  1384. [et wait];
  1385. }
  1386. - (void) testUpdateRaisesCorrectRemoteEvents {
  1387. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1388. FIRDatabaseReference * reader = refs.one;
  1389. FIRDatabaseReference * writer = refs.two;
  1390. __block BOOL ready = NO;
  1391. [writer setValue:@{@"a": @1, @"b": @2, @"c": @3, @"d": @4} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1392. ready = YES;
  1393. }];
  1394. [self waitUntil:^BOOL{
  1395. return ready;
  1396. }];
  1397. FEventTester* et = [[FEventTester alloc] initFrom:self];
  1398. NSArray* expectations = @[
  1399. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  1400. [[FTupleEventTypeString alloc] initWithFirebase:[reader child:@"d"] withEvent:FIRDataEventTypeValue withString:nil],
  1401. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildChanged withString:@"a"],
  1402. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeChildChanged withString:@"d"],
  1403. [[FTupleEventTypeString alloc] initWithFirebase:reader withEvent:FIRDataEventTypeValue withString:nil]
  1404. ];
  1405. [et addLookingFor:expectations];
  1406. [et waitForInitialization];
  1407. [writer updateChildValues:@{@"a": @4, @"d": @1}];
  1408. [et wait];
  1409. ready = NO;
  1410. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1411. NSDictionary *result = [snapshot value];
  1412. NSDictionary *expected = @{@"a" : @4, @"b" : @2, @"c" : @3, @"d" : @1};
  1413. XCTAssertTrue([result isEqualToDictionary:expected], @"Got expected results");
  1414. ready = YES;
  1415. }];
  1416. [self waitUntil:^BOOL{
  1417. return ready;
  1418. }];
  1419. }
  1420. - (void) testUpdateChangesAreStoredCorrectlyByTheServer {
  1421. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1422. FIRDatabaseReference * reader = refs.one;
  1423. FIRDatabaseReference * writer = refs.two;
  1424. [self waitForCompletionOf:writer setValue:@{@"a": @1, @"b": @2, @"c": @3, @"d": @4}];
  1425. [self waitForCompletionOf:writer updateChildValues:@{@"a": @42}];
  1426. [self snapWaiter:reader withBlock:^(FIRDataSnapshot *snapshot) {
  1427. NSDictionary* result = [snapshot value];
  1428. NSDictionary* expected = @{@"a": @42, @"b": @2, @"c": @3, @"d": @4};
  1429. XCTAssertTrue([result isEqualToDictionary:expected], @"Expected updated value");
  1430. }];
  1431. }
  1432. - (void) testUpdateDoesntAffectPriorityLocally {
  1433. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1434. __block FIRDataSnapshot * snap = nil;
  1435. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1436. snap = snapshot;
  1437. }];
  1438. [ref setValue:@{@"a": @1, @"b": @2, @"c": @3} andPriority:@"testpri"];
  1439. [self waitUntil:^BOOL{
  1440. return snap != nil;
  1441. }];
  1442. XCTAssertTrue([[snap priority] isEqualToString:@"testpri"], @"Got initial priority");
  1443. snap = nil;
  1444. [ref updateChildValues:@{@"a": @4}];
  1445. [self waitUntil:^BOOL{
  1446. return snap != nil;
  1447. }];
  1448. XCTAssertTrue([[snap priority] isEqualToString:@"testpri"], @"Got initial priority");
  1449. }
  1450. - (void) testUpdateDoesntAffectPriorityRemotely {
  1451. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1452. FIRDatabaseReference * reader = refs.one;
  1453. FIRDatabaseReference * writer = refs.two;
  1454. __block BOOL ready = NO;
  1455. [writer setValue:@{@"a": @1, @"b": @2, @"c": @3} andPriority:@"testpri" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1456. ready = YES;
  1457. }];
  1458. [self waitUntil:^BOOL{
  1459. return ready;
  1460. }];
  1461. ready = NO;
  1462. [reader observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1463. NSString *result = [snapshot priority];
  1464. XCTAssertTrue([result isEqualToString:@"testpri"], @"Expected initial priority");
  1465. ready = YES;
  1466. }];
  1467. [self waitUntil:^BOOL{
  1468. return ready;
  1469. }];
  1470. ready = NO;
  1471. [writer updateChildValues:@{@"a": @4} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1472. ready = YES;
  1473. }];
  1474. [self waitUntil:^BOOL{
  1475. return ready;
  1476. }];
  1477. ready = NO;
  1478. [reader observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1479. NSString *result = [snapshot priority];
  1480. XCTAssertTrue([result isEqualToString:@"testpri"], @"Expected initial priority");
  1481. ready = YES;
  1482. }];
  1483. [self waitUntil:^BOOL{
  1484. return ready;
  1485. }];
  1486. }
  1487. - (void) testUpdateReplacesChildrenAndIsNotRecursive {
  1488. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1489. FIRDatabaseReference * reader = refs.one;
  1490. FIRDatabaseReference * writer = refs.two;
  1491. __block FIRDataSnapshot * localSnap = nil;
  1492. __block BOOL ready = NO;
  1493. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1494. localSnap = snapshot;
  1495. }];
  1496. [writer setValue:@{@"a": @{@"aa": @1, @"ab": @2}}];
  1497. [writer updateChildValues:@{@"a": @{@"aa": @1}} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1498. ready = YES;
  1499. }];
  1500. [self waitUntil:^BOOL{
  1501. return ready;
  1502. }];
  1503. ready = NO;
  1504. [reader observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1505. NSDictionary *result = [snapshot value];
  1506. NSDictionary *expected = @{@"a" : @{@"aa" : @1}};
  1507. XCTAssertTrue([result isEqualToDictionary:expected], @"Should get new value");
  1508. ready = YES;
  1509. }];
  1510. [self waitUntil:^BOOL{
  1511. NSDictionary* result = [localSnap value];
  1512. NSDictionary* expected = @{@"a": @{@"aa": @1}};
  1513. return ready && [result isEqualToDictionary:expected];
  1514. }];
  1515. }
  1516. - (void) testDeepUpdatesWork {
  1517. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1518. FIRDatabaseReference * reader = refs.one;
  1519. FIRDatabaseReference * writer = refs.two;
  1520. __block FIRDataSnapshot * localSnap = nil;
  1521. __block BOOL ready = NO;
  1522. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1523. localSnap = snapshot;
  1524. }];
  1525. [writer setValue:@{@"a": @{@"aa": @1, @"ab": @2}}];
  1526. [writer updateChildValues:@{@"a/aa": @10,
  1527. @".priority": @3.0,
  1528. @"a/ab": @{@".priority": @2.0,
  1529. @".value": @20}}
  1530. withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1531. ready = YES;
  1532. }];
  1533. [self waitUntil:^BOOL{
  1534. return ready;
  1535. }];
  1536. ready = NO;
  1537. [reader observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1538. NSDictionary *result = [snapshot value];
  1539. NSDictionary *expected = @{@"a" : @{@"aa" : @10, @"ab" : @20}};
  1540. XCTAssertTrue([result isEqualToDictionary:expected], @"Should get new value");
  1541. ready = YES;
  1542. }];
  1543. [self waitUntil:^BOOL{
  1544. NSDictionary* result = [localSnap value];
  1545. NSDictionary* expected = @{@"a": @{@"aa": @10, @"ab": @20}};
  1546. return ready && [result isEqualToDictionary:expected];
  1547. }];
  1548. }
  1549. // Type signature means we don't need a test for updating scalars. They wouldn't compile
  1550. - (void) testEmptyUpdateWorks {
  1551. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1552. __block BOOL ready = NO;
  1553. [ref updateChildValues:@{} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1554. XCTAssertTrue(error == nil, @"Should not be an error");
  1555. ready = YES;
  1556. }];
  1557. [self waitUntil:^BOOL{
  1558. return ready;
  1559. }];
  1560. }
  1561. // XXX update stress test
  1562. - (void) testUpdateFiresCorrectEventWhenAChildIsDeleted {
  1563. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1564. FIRDatabaseReference * reader = refs.one;
  1565. FIRDatabaseReference * writer = refs.two;
  1566. __block FIRDataSnapshot * localSnap = nil;
  1567. __block FIRDataSnapshot * remoteSnap = nil;
  1568. [self waitForCompletionOf:writer setValue:@{@"a": @12, @"b": @6}];
  1569. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1570. localSnap = snapshot;
  1571. }];
  1572. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1573. remoteSnap = snapshot;
  1574. }];
  1575. [self waitUntil:^BOOL{
  1576. return localSnap != nil && remoteSnap != nil;
  1577. }];
  1578. localSnap = nil;
  1579. remoteSnap = nil;
  1580. [writer updateChildValues:@{@"a": [NSNull null]}];
  1581. [self waitUntil:^BOOL{
  1582. return localSnap != nil && remoteSnap != nil;
  1583. }];
  1584. NSDictionary* expected = @{@"b": @6};
  1585. XCTAssertTrue([[remoteSnap value] isEqualToDictionary:expected], @"Removed child");
  1586. XCTAssertTrue([[localSnap value] isEqualToDictionary:expected], @"Removed child");
  1587. }
  1588. - (void) testUpdateFiresCorrectEventOnNewChildren {
  1589. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1590. FIRDatabaseReference * reader = refs.one;
  1591. FIRDatabaseReference * writer = refs.two;
  1592. __block FIRDataSnapshot * localSnap = nil;
  1593. __block FIRDataSnapshot * remoteSnap = nil;
  1594. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1595. localSnap = snapshot;
  1596. }];
  1597. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1598. remoteSnap = snapshot;
  1599. }];
  1600. [self waitUntil:^BOOL{
  1601. return localSnap != nil && remoteSnap != nil;
  1602. }];
  1603. localSnap = nil;
  1604. remoteSnap = nil;
  1605. [writer updateChildValues:@{@"a": @42}];
  1606. [self waitUntil:^BOOL{
  1607. return localSnap != nil && remoteSnap != nil;
  1608. }];
  1609. XCTAssertTrue([[remoteSnap value] isEqualToNumber:@42], @"Added child");
  1610. XCTAssertTrue([[localSnap value] isEqualToNumber:@42], @"Added child");
  1611. }
  1612. - (void) testUpdateFiresCorrectEventOnDeletedChildren {
  1613. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1614. FIRDatabaseReference * reader = refs.one;
  1615. FIRDatabaseReference * writer = refs.two;
  1616. __block FIRDataSnapshot * localSnap = nil;
  1617. __block FIRDataSnapshot * remoteSnap = nil;
  1618. [self waitForCompletionOf:writer setValue:@{@"a": @12}];
  1619. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1620. localSnap = snapshot;
  1621. }];
  1622. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1623. remoteSnap = snapshot;
  1624. }];
  1625. [self waitUntil:^BOOL{
  1626. return localSnap != nil && remoteSnap != nil;
  1627. }];
  1628. localSnap = nil;
  1629. remoteSnap = nil;
  1630. [writer updateChildValues:@{@"a": [NSNull null]}];
  1631. [self waitUntil:^BOOL{
  1632. return localSnap != nil && remoteSnap != nil;
  1633. }];
  1634. XCTAssertTrue([remoteSnap value] == [NSNull null], @"Removed child");
  1635. XCTAssertTrue([localSnap value] == [NSNull null], @"Removed child");
  1636. }
  1637. - (void) testUpdateFiresCorrectEventOnChangedChildren {
  1638. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1639. FIRDatabaseReference * reader = refs.one;
  1640. FIRDatabaseReference * writer = refs.two;
  1641. [self waitForCompletionOf:writer setValue:@{@"a": @12}];
  1642. __block FIRDataSnapshot * localSnap = nil;
  1643. __block FIRDataSnapshot * remoteSnap = nil;
  1644. [[writer child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1645. localSnap = snapshot;
  1646. }];
  1647. [[reader child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1648. remoteSnap = snapshot;
  1649. }];
  1650. [self waitUntil:^BOOL{
  1651. return localSnap != nil && remoteSnap != nil;
  1652. }];
  1653. localSnap = nil;
  1654. remoteSnap = nil;
  1655. [self waitForCompletionOf:writer updateChildValues:@{@"a": @11}];
  1656. [self waitUntil:^BOOL{
  1657. return localSnap != nil && remoteSnap != nil;
  1658. }];
  1659. XCTAssertTrue([[remoteSnap value] isEqualToNumber:@11], @"Changed child");
  1660. XCTAssertTrue([[localSnap value] isEqualToNumber:@11], @"Changed child");
  1661. }
  1662. - (void) testUpdateOfPriorityWorks {
  1663. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1664. FIRDatabaseReference * reader = refs.one;
  1665. FIRDatabaseReference * writer = refs.two;
  1666. __block BOOL ready = NO;
  1667. [writer setValue:@{@"a": @5, @".priority": @"pri1"}];
  1668. [writer updateChildValues:@{@"a": @6, @".priority": @"pri2", @"b": @{ @".priority": @"pri3", @"c": @10 } } withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1669. NSLog(@"error? %@", error);
  1670. ready = YES;
  1671. }];
  1672. [self waitUntil:^BOOL{
  1673. return ready;
  1674. }];
  1675. ready = NO;
  1676. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1677. XCTAssertEqualObjects([[snapshot childSnapshotForPath:@"a"] value], @6, @"Should match write values");
  1678. XCTAssertTrue([[snapshot priority] isEqualToString:@"pri2"], @"Should get updated priority");
  1679. XCTAssertTrue([[[snapshot childSnapshotForPath:@"b"] priority] isEqualToString:@"pri3"], @"Should get updated priority");
  1680. XCTAssertEqualObjects([[snapshot childSnapshotForPath:@"b/c"] value], @10, @"Should match write values");
  1681. ready = YES;
  1682. }];
  1683. [self waitUntil:^BOOL{
  1684. return ready;
  1685. }];
  1686. }
  1687. - (void) testSetWithCircularReferenceFails {
  1688. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1689. NSMutableDictionary* toSet = [[NSMutableDictionary alloc] init];
  1690. NSDictionary* lol = @{@"foo": @"bar", @"circular": toSet};
  1691. [toSet setObject:lol forKey:@"lol"];
  1692. XCTAssertThrows([ref setValue:toSet], @"Should not be able to set circular dictionary");
  1693. }
  1694. - (void) testLargeNumbers {
  1695. FIRDatabaseReference * ref = [FTestHelpers getRandomNode];
  1696. long long jsMaxInt = 9007199254740992;
  1697. long jsMaxIntPlusOne = jsMaxInt + 1;
  1698. NSNumber* toSet = [NSNumber numberWithLong:jsMaxIntPlusOne];
  1699. [ref setValue:toSet];
  1700. __block FIRDataSnapshot * snap = nil;
  1701. [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1702. snap = snapshot;
  1703. }];
  1704. [self waitUntil:^BOOL{
  1705. return snap != nil;
  1706. }];
  1707. NSNumber* result = [snap value];
  1708. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  1709. toSet = [NSNumber numberWithLong:LONG_MAX];
  1710. snap = nil;
  1711. [ref setValue:toSet];
  1712. [self waitUntil:^BOOL{
  1713. return snap != nil;
  1714. }];
  1715. result = [snap value];
  1716. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  1717. snap = nil;
  1718. toSet = [NSNumber numberWithDouble:DBL_MAX];
  1719. [ref setValue:toSet];
  1720. [self waitUntil:^BOOL{
  1721. return snap != nil;
  1722. }];
  1723. result = [snap value];
  1724. XCTAssertTrue([result isEqualToNumber:toSet], @"Should get back same number");
  1725. }
  1726. - (void) testParentDeleteShadowsChildListeners {
  1727. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1728. FIRDatabaseReference * writer = refs.one;
  1729. FIRDatabaseReference * deleter = refs.two;
  1730. NSString* childName = [writer childByAutoId].key;
  1731. __block BOOL called = NO;
  1732. [[deleter child:childName] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1733. XCTAssertFalse(called, @"Should only be hit once");
  1734. called = YES;
  1735. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  1736. }];
  1737. WAIT_FOR(called);
  1738. __block BOOL done = NO;
  1739. [[writer child:childName] setValue:@"foo"];
  1740. [deleter removeValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1741. done = YES;
  1742. }];
  1743. WAIT_FOR(done);
  1744. [deleter removeAllObservers];
  1745. }
  1746. - (void) testParentDeleteShadowsChildListenersWithNonDefaultQuery {
  1747. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1748. FIRDatabaseReference * writer = refs.one;
  1749. FIRDatabaseReference * deleter = refs.two;
  1750. NSString* childName = [writer childByAutoId].key;
  1751. __block BOOL queryCalled = NO;
  1752. __block BOOL deepChildCalled = NO;
  1753. [[[[deleter child:childName] queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1754. XCTAssertFalse(queryCalled, @"Should only be hit once");
  1755. queryCalled = YES;
  1756. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  1757. }];
  1758. [[[deleter child:childName] child:@"a"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1759. XCTAssertFalse(deepChildCalled, @"Should only be hit once");
  1760. deepChildCalled = YES;
  1761. XCTAssertTrue(snapshot.value == [NSNull null], @"Value should be null");
  1762. }];
  1763. WAIT_FOR(deepChildCalled && queryCalled);
  1764. __block BOOL done = NO;
  1765. [[writer child:childName] setValue:@"foo"];
  1766. [deleter removeValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1767. done = YES;
  1768. }];
  1769. WAIT_FOR(done);
  1770. }
  1771. - (void) testLocalServerValuesEventuallyButNotImmediatelyMatchServer {
  1772. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1773. FIRDatabaseReference* writer = refs.one;
  1774. FIRDatabaseReference* reader = refs.two;
  1775. __block int done = 0;
  1776. NSMutableArray* readSnaps = [[NSMutableArray alloc] init];
  1777. NSMutableArray* writeSnaps = [[NSMutableArray alloc] init];
  1778. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1779. if ([snapshot value] != [NSNull null]) {
  1780. [readSnaps addObject:snapshot];
  1781. if (readSnaps.count == 1) {
  1782. done += 1;
  1783. }
  1784. }
  1785. }];
  1786. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1787. if ([snapshot value] != [NSNull null]) {
  1788. [writeSnaps addObject:snapshot];
  1789. if (writeSnaps.count == 2) {
  1790. done += 1;
  1791. }
  1792. }
  1793. }];
  1794. [writer setValue:[FIRServerValue timestamp] andPriority:[FIRServerValue timestamp]];
  1795. [self waitUntil:^BOOL{
  1796. return done == 2;
  1797. }];
  1798. XCTAssertEqual((unsigned long)[readSnaps count], (unsigned long)1, @"Should have received one snapshot on reader");
  1799. XCTAssertEqual((unsigned long)[writeSnaps count], (unsigned long)2, @"Should have received two snapshots on writer");
  1800. FIRDataSnapshot * firstReadSnap = [readSnaps objectAtIndex:0];
  1801. FIRDataSnapshot * firstWriteSnap = [writeSnaps objectAtIndex:0];
  1802. FIRDataSnapshot * secondWriteSnap = [writeSnaps objectAtIndex:1];
  1803. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1804. XCTAssertTrue([now doubleValue] - [firstWriteSnap.value doubleValue] < 3000, @"Should have received a local event with a value close to timestamp");
  1805. XCTAssertTrue([now doubleValue] - [firstWriteSnap.priority doubleValue] < 3000, @"Should have received a local event with a priority close to timestamp");
  1806. XCTAssertTrue([now doubleValue] - [secondWriteSnap.value doubleValue] < 3000, @"Should have received a server event with a value close to timestamp");
  1807. XCTAssertTrue([now doubleValue] - [secondWriteSnap.priority doubleValue] < 3000, @"Should have received a server event with a priority close to timestamp");
  1808. XCTAssertFalse([firstWriteSnap value] == [secondWriteSnap value], @"Initial and future writer values should be different");
  1809. XCTAssertFalse([firstWriteSnap priority] == [secondWriteSnap priority], @"Initial and future writer priorities should be different");
  1810. XCTAssertEqualObjects(firstReadSnap.value, secondWriteSnap.value, @"Eventual reader and writer values should be equal");
  1811. XCTAssertEqualObjects(firstReadSnap.priority, secondWriteSnap.priority, @"Eventual reader and writer priorities should be equal");
  1812. }
  1813. - (void) testServerValuesSetWithPriorityRemoteEvents {
  1814. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1815. FIRDatabaseReference * writer = refs.one;
  1816. FIRDatabaseReference * reader = refs.two;
  1817. NSDictionary* data = @{
  1818. @"a": [FIRServerValue timestamp],
  1819. @"b": @{
  1820. @".value": [FIRServerValue timestamp],
  1821. @".priority": [FIRServerValue timestamp]
  1822. }
  1823. };
  1824. __block BOOL done = NO;
  1825. [writer setValue:data andPriority:[FIRServerValue timestamp] withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) { done = YES; }];
  1826. [self waitUntil:^BOOL{
  1827. return done;
  1828. }];
  1829. [self snapWaiter:reader withBlock:^(FIRDataSnapshot *snapshot) {
  1830. NSDictionary* value = [snapshot value];
  1831. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1832. NSNumber* timestamp = [snapshot priority];
  1833. XCTAssertTrue([[snapshot priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  1834. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1835. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"a"], @"Should get back matching ServerValue.TIMESTAMP");
  1836. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"b"], @"Should get back matching ServerValue.TIMESTAMP");
  1837. XCTAssertEqualObjects([snapshot priority], [[snapshot childSnapshotForPath:@"b"] priority], @"Should get back matching ServerValue.TIMESTAMP");
  1838. }];
  1839. }
  1840. - (void) testServerValuesSetPriorityRemoteEvents {
  1841. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1842. FIRDatabaseReference * writer = refs.one;
  1843. FIRDatabaseReference * reader = refs.two;
  1844. __block FIRDataSnapshot *snap = nil;
  1845. [reader observeEventType:FIRDataEventTypeChildMoved withBlock:^(FIRDataSnapshot *snapshot) {
  1846. snap = snapshot;
  1847. }];
  1848. [self waitForCompletionOf:[writer child:@"a"] setValue:@1 andPriority:nil];
  1849. [self waitForCompletionOf:[writer child:@"b"] setValue:@1 andPriority:@1];
  1850. [self waitForValueOf:[reader child:@"a"] toBe:@1];
  1851. __block BOOL done = NO;
  1852. [[writer child:@"a"] setPriority:[FIRServerValue timestamp] withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1853. done = YES;
  1854. }];
  1855. [self waitUntil:^BOOL{
  1856. return done && snap != nil;
  1857. }];
  1858. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1859. NSNumber* timestamp = [snap priority];
  1860. XCTAssertTrue([[snap priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  1861. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1862. }
  1863. - (void) testServerValuesUpdateRemoteEvents {
  1864. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  1865. FIRDatabaseReference * writer = refs.one;
  1866. FIRDatabaseReference * reader = refs.two;
  1867. __block FIRDataSnapshot *snap = nil;
  1868. __block BOOL done = NO;
  1869. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1870. snap = snapshot;
  1871. if (snap && [[snap childSnapshotForPath:@"a/b/d"] value] != [NSNull null]) {
  1872. done = YES;
  1873. }
  1874. }];
  1875. [[writer child:@"a/b/c"] setValue:@1];
  1876. [[writer child:@"a"] updateChildValues:@{ @"b": @{ @"c": [FIRServerValue timestamp], @"d":@1 } }];
  1877. [self waitUntil:^BOOL{
  1878. return done;
  1879. }];
  1880. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1881. NSNumber* timestamp = [[snap childSnapshotForPath:@"a/b/c"] value];
  1882. XCTAssertTrue([[[snap childSnapshotForPath:@"a/b/c"] value] isKindOfClass:[NSNumber class]], @"Should get back number");
  1883. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1884. }
  1885. - (void) testServerValuesSetWithPriorityLocalEvents {
  1886. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1887. NSDictionary* data = @{
  1888. @"a": [FIRServerValue timestamp],
  1889. @"b": @{
  1890. @".value": [FIRServerValue timestamp],
  1891. @".priority": [FIRServerValue timestamp]
  1892. }
  1893. };
  1894. __block FIRDataSnapshot *snap = nil;
  1895. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1896. snap = snapshot;
  1897. }];
  1898. __block BOOL done = NO;
  1899. [node setValue:data andPriority:[FIRServerValue timestamp] withCompletionBlock:^(NSError* err, FIRDatabaseReference * ref) { done = YES; }];
  1900. [self waitUntil:^BOOL{
  1901. return done;
  1902. }];
  1903. [self snapWaiter:node withBlock:^(FIRDataSnapshot *snapshot) {
  1904. NSDictionary* value = [snapshot value];
  1905. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1906. NSNumber* timestamp = [snapshot priority];
  1907. XCTAssertTrue([[snapshot priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  1908. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1909. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"a"], @"Should get back matching ServerValue.TIMESTAMP");
  1910. XCTAssertEqualObjects([snapshot priority], [value objectForKey:@"b"], @"Should get back matching ServerValue.TIMESTAMP");
  1911. XCTAssertEqualObjects([snapshot priority], [[snapshot childSnapshotForPath:@"b"] priority], @"Should get back matching ServerValue.TIMESTAMP");
  1912. }];
  1913. }
  1914. - (void) testServerValuesSetPriorityLocalEvents {
  1915. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1916. __block FIRDataSnapshot *snap = nil;
  1917. [node observeEventType:FIRDataEventTypeChildMoved withBlock:^(FIRDataSnapshot *snapshot) {
  1918. snap = snapshot;
  1919. }];
  1920. __block BOOL done = NO;
  1921. [[node child:@"a"] setValue:@1 andPriority:nil];
  1922. [[node child:@"b"] setValue:@1 andPriority:@1];
  1923. [[node child:@"a"] setPriority:[FIRServerValue timestamp] withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  1924. done = YES;
  1925. }];
  1926. [self waitUntil:^BOOL{
  1927. return done;
  1928. }];
  1929. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1930. NSNumber* timestamp = [snap priority];
  1931. XCTAssertTrue([[snap priority] isKindOfClass:[NSNumber class]], @"Should get back number");
  1932. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1933. }
  1934. - (void) testServerValuesUpdateLocalEvents {
  1935. FIRDatabaseReference * node1 = [FTestHelpers getRandomNode];
  1936. __block FIRDataSnapshot *snap1 = nil;
  1937. [node1 observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1938. snap1 = snapshot;
  1939. }];
  1940. __block FIRDataSnapshot *snap2 = nil;
  1941. [node1 observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1942. snap2 = snapshot;
  1943. }];
  1944. [node1 runTransactionBlock:^FIRTransactionResult *(FIRMutableData *currentData) {
  1945. [currentData setValue:[FIRServerValue timestamp]];
  1946. return [FIRTransactionResult successWithValue:currentData];
  1947. }];
  1948. [self waitUntil:^BOOL{
  1949. return snap1 != nil && snap2 != nil && [snap1 value] != nil && [snap2 value] != nil;
  1950. }];
  1951. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1952. NSNumber* timestamp1 = [snap1 value];
  1953. XCTAssertTrue([[snap1 value] isKindOfClass:[NSNumber class]], @"Should get back number");
  1954. XCTAssertTrue([now doubleValue] - [timestamp1 doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1955. NSNumber* timestamp2 = [snap2 value];
  1956. XCTAssertTrue([[snap2 value] isKindOfClass:[NSNumber class]], @"Should get back number");
  1957. XCTAssertTrue([now doubleValue] - [timestamp2 doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1958. }
  1959. - (void) testServerValuesTransactionLocalEvents {
  1960. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  1961. __block FIRDataSnapshot *snap = nil;
  1962. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1963. snap = snapshot;
  1964. }];
  1965. [[node child:@"a/b/c"] setValue:@1];
  1966. [[node child:@"a"] updateChildValues:@{ @"b": @{ @"c": [FIRServerValue timestamp], @"d":@1 } }];
  1967. [self waitUntil:^BOOL{
  1968. return snap != nil && [[snap childSnapshotForPath:@"a/b/d"] value] != nil;
  1969. }];
  1970. NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
  1971. NSNumber* timestamp = [[snap childSnapshotForPath:@"a/b/c"] value];
  1972. XCTAssertTrue([[[snap childSnapshotForPath:@"a/b/c"] value] isKindOfClass:[NSNumber class]], @"Should get back number");
  1973. XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
  1974. }
  1975. - (void) testUpdateAfterChildSet {
  1976. FIRDatabaseReference *node = [FTestHelpers getRandomNode];
  1977. __block BOOL done = NO;
  1978. __weak FIRDatabaseReference *weakRef = node;
  1979. [node setValue:@{@"a": @"a"} withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  1980. [weakRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  1981. if (snapshot.childrenCount == 3 && [snapshot hasChild:@"a"] && [snapshot hasChild:@"b"] && [snapshot hasChild:@"c"]) {
  1982. done = YES;
  1983. }
  1984. }];
  1985. [[weakRef child:@"b"] setValue:@"b"];
  1986. [weakRef updateChildValues:@{@"c" : @"c"}];
  1987. }];
  1988. [self waitUntil:^BOOL{
  1989. return done;
  1990. }];
  1991. }
  1992. - (void) testDeltaSyncNoDataUpdatesAfterReconnect {
  1993. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  1994. FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"test-config"];
  1995. FIRDatabaseReference * ref2 = [[[FIRDatabaseReference alloc] initWithConfig:cfg] child:ref.key];
  1996. __block id data = @{ @"a": @1, @"b": @2, @"c": @{ @".priority": @3, @".value": @3}, @"d": @4 };
  1997. [self waitForCompletionOf:ref setValue:data];
  1998. __block BOOL gotData = NO;
  1999. [ref2 observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  2000. XCTAssertFalse(gotData, @"event triggered twice.");
  2001. gotData = YES;
  2002. XCTAssertEqualObjects(snapshot.valueInExportFormat, data, @"Got wrong data.");
  2003. }];
  2004. [self waitUntil:^BOOL{ return gotData; }];
  2005. __block BOOL done = NO;
  2006. XCTAssertEqual(ref2.repo.dataUpdateCount, 1L, @"Should have gotten one update.");
  2007. // Bounce connection
  2008. [FRepoManager interrupt:cfg];
  2009. [FRepoManager resume:cfg];
  2010. [[[ref2 root] child:@".info/connected"] observeEventType:FIRDataEventTypeValue
  2011. withBlock:^(FIRDataSnapshot *snapshot) {
  2012. if ([snapshot.value boolValue]) {
  2013. // We're connected. Do one more round-trip to make sure all state restoration is done
  2014. [[[ref2 root] child:@"foobar/empty/blah"] setValue:nil withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2015. XCTAssertEqual(ref2.repo.dataUpdateCount, 1L, @"Should have gotten one update.");
  2016. done = YES;
  2017. }];
  2018. }
  2019. }
  2020. ];
  2021. [self waitUntil:^BOOL{ return done; }];
  2022. // cleanup
  2023. [FRepoManager interrupt:cfg];
  2024. [FRepoManager disposeRepos:cfg];
  2025. }
  2026. - (void) testServerValuesEventualConsistencyBetweenLocalAndRemote {
  2027. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2028. FIRDatabaseReference * writer = refs.one;
  2029. FIRDatabaseReference * reader = refs.two;
  2030. __block FIRDataSnapshot *writerSnap = nil;
  2031. __block FIRDataSnapshot *readerSnap = nil;
  2032. [reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  2033. readerSnap = snapshot;
  2034. }];
  2035. [writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  2036. writerSnap = snapshot;
  2037. }];
  2038. [writer setValue:[FIRServerValue timestamp] andPriority:[FIRServerValue timestamp]];
  2039. [self waitUntil:^BOOL{
  2040. if (readerSnap && writerSnap && [[readerSnap value] isKindOfClass:[NSNumber class]] && [[writerSnap value] isKindOfClass:[NSNumber class]]) {
  2041. if ([[readerSnap value] doubleValue] == [[writerSnap value] doubleValue]) {
  2042. return YES;
  2043. }
  2044. }
  2045. return NO;
  2046. }];
  2047. }
  2048. // Listens at a location and then creates a bunch of children, waiting for them all to complete.
  2049. - (void) testChildAddedPerf1 {
  2050. if (!runPerfTests) return;
  2051. FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
  2052. [ref observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  2053. }];
  2054. NSDate *start = [NSDate date];
  2055. int COUNT = 1000;
  2056. __block BOOL done = NO;
  2057. __block NSDate *finished = nil;
  2058. for(int i = 0; i < COUNT; i++) {
  2059. [[ref childByAutoId] setValue:@"01234567890123456789012345678901234567890123456789" withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2060. if (i == (COUNT - 1)) {
  2061. finished = [NSDate date];
  2062. done = YES;
  2063. }
  2064. }];
  2065. }
  2066. [self waitUntil:^BOOL {
  2067. return done;
  2068. } timeout:300];
  2069. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2070. NSLog(@"Elapsed: %f", elapsed);
  2071. }
  2072. // Listens at a location, then adds a bunch of grandchildren under a single child.
  2073. - (void) testDeepChildAddedPerf1 {
  2074. if (!runPerfTests) return;
  2075. FIRDatabaseReference *ref = [FTestHelpers getRandomNode],
  2076. *childRef = [ref child:@"child"];
  2077. [ref observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  2078. }];
  2079. NSDate *start = [NSDate date];
  2080. int COUNT = 1000;
  2081. __block BOOL done = NO;
  2082. __block NSDate *finished = nil;
  2083. for(int i = 0; i < COUNT; i++) {
  2084. [[childRef childByAutoId] setValue:@"01234567890123456789012345678901234567890123456789" withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2085. if (i == (COUNT - 1)) {
  2086. finished = [NSDate date];
  2087. done = YES;
  2088. }
  2089. }];
  2090. }
  2091. [self waitUntil:^BOOL {
  2092. return done;
  2093. } timeout:300];
  2094. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2095. NSLog(@"Elapsed: %f", elapsed);
  2096. }
  2097. // Listens at a location, then adds a bunch of grandchildren under a single child, but does it with merges.
  2098. // NOTE[2015-07-14]: This test is still pretty slow, because [FWriteTree removeWriteId] ends up rebuilding the tree after
  2099. // every ack.
  2100. - (void) testDeepChildAddedPerfViaMerge1 {
  2101. if (!runPerfTests) return;
  2102. FIRDatabaseReference *ref = [FTestHelpers getRandomNode],
  2103. *childRef = [ref child:@"child"];
  2104. [ref observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  2105. }];
  2106. NSDate *start = [NSDate date];
  2107. int COUNT = 250;
  2108. __block BOOL done = NO;
  2109. __block NSDate *finished = nil;
  2110. for(int i = 0; i < COUNT; i++) {
  2111. NSString *childName = [childRef childByAutoId].key;
  2112. [childRef updateChildValues:@{
  2113. childName: @"01234567890123456789012345678901234567890123456789"
  2114. } withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  2115. if (i == (COUNT - 1)) {
  2116. finished = [NSDate date];
  2117. done = YES;
  2118. }
  2119. }];
  2120. }
  2121. [self waitUntil:^BOOL {
  2122. return done;
  2123. } timeout:300];
  2124. NSTimeInterval elapsed = [finished timeIntervalSinceDate:start];
  2125. NSLog(@"Elapsed: %f", elapsed);
  2126. }
  2127. @end