FData.m 118 KB

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