/* * Copyright 2017 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "FirebaseCore/FIRApp.h" #import "FirebaseCore/FIROptions.h" #import "FTestBase.h" #import "FTestAuthTokenGenerator.h" #import "FIRDatabaseQuery_Private.h" #import "FIRTestAuthTokenProvider.h" @implementation FTestBase + (void)setUp { static dispatch_once_t once; dispatch_once(&once, ^ { [FIRApp configure]; }); } - (void)setUp { [super setUp]; [FIRDatabase setLoggingEnabled:YES]; _databaseURL = [[FIRApp defaultApp] options].databaseURL; // Disabled normally since they slow down the tests and don't actually assert anything (they just NSLog timings). runPerfTests = NO; } - (void)snapWaiter:(FIRDatabaseReference *)path withBlock:(fbt_void_datasnapshot)fn { __block BOOL done = NO; [path observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snap) { fn(snap); done = YES; }]; NSTimeInterval timeTaken = [self waitUntil:^BOOL{ return done; } timeout:kFirebaseTestWaitUntilTimeout]; NSLog(@"snapWaiter:withBlock: timeTaken:%f", timeTaken); XCTAssertTrue(done, @"Properly finished."); } - (void) waitUntilConnected:(FIRDatabaseReference *)ref { __block BOOL connected = NO; FIRDatabaseHandle handle = [[ref.root child:@".info/connected"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { connected = [snapshot.value boolValue]; }]; WAIT_FOR(connected); [ref.root removeObserverWithHandle:handle]; } - (void) waitForRoundTrip:(FIRDatabaseReference *)ref { // HACK: Do a deep setPriority (which we expect to fail because there's no data there) to do a no-op roundtrip. __block BOOL done = NO; [[ref.root child:@"ENTOHTNUHOE/ONTEHNUHTOE"] setPriority:@"blah" withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { done = YES; }]; WAIT_FOR(done); } - (void) waitForQueue:(FIRDatabaseReference *)ref { dispatch_sync([FIRDatabaseQuery sharedQueue], ^{}); } - (void) waitForEvents:(FIRDatabaseReference *)ref { [self waitForQueue:ref]; __block BOOL done = NO; dispatch_async(dispatch_get_main_queue(), ^{ done = YES; }); WAIT_FOR(done); } - (void)waitForValueOf:(FIRDatabaseQuery *)ref toBe:(id)expected { __block id value; FIRDatabaseHandle handle = [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { value = snapshot.value; }]; @try { [self waitUntil:^BOOL { return [value isEqual:expected]; }]; } @catch (NSException *exception) { @throw [NSException exceptionWithName:@"DidNotGetValue" reason:@"Did not get expected value" userInfo:@{ @"expected": (!expected ? @"nil" : expected), @"actual": (!value ? @"nil" : value) }]; } @finally { [ref removeObserverWithHandle:handle]; } } - (void)waitForExportValueOf:(FIRDatabaseQuery *)ref toBe:(id)expected { __block id value; FIRDatabaseHandle handle = [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { value = snapshot.valueInExportFormat; }]; @try { [self waitUntil:^BOOL { return [value isEqual:expected]; }]; } @catch (NSException *exception) { if ([exception.name isEqualToString:@"Timed out"]) { @throw [NSException exceptionWithName:@"DidNotGetValue" reason:@"Did not get expected value" userInfo:@{ @"expected": (!expected ? @"nil" : expected), @"actual": (!value ? @"nil" : value) }]; } else { @throw exception; } } @finally { [ref removeObserverWithHandle:handle]; } } - (void)waitForCompletionOf:(FIRDatabaseReference *)ref setValue:(id)value { [self waitForCompletionOf:ref setValue:value andPriority:nil]; } - (void)waitForCompletionOf:(FIRDatabaseReference *)ref setValue:(id)value andPriority:(id)priority { __block BOOL done = NO; [ref setValue:value andPriority:priority withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { done = YES; }]; @try { WAIT_FOR(done); } @catch (NSException *exception) { @throw [NSException exceptionWithName:@"DidNotSetValue" reason:@"Did not complete setting value" userInfo:@{ @"ref": [ref description], @"done": done ? @"true" : @"false", @"value": (!value ? @"nil" : value), @"priority": (!priority ? @"nil" : priority) }]; } } - (void)waitForCompletionOf:(FIRDatabaseReference *)ref updateChildValues:(NSDictionary *)values { __block BOOL done = NO; [ref updateChildValues:values withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { done = YES; }]; @try { WAIT_FOR(done); } @catch (NSException *exception) { @throw [NSException exceptionWithName:@"DidNotUpdateChildValues" reason:@"Could not finish updating child values" userInfo:@{ @"ref": [ref description], @"values": (!values ? @"nil" : values)}]; } } @end