// 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 @import FirebaseStorage; #import #import "FirebaseCore/Extension/FirebaseCoreInternal.h" #import "FirebaseStorage/Tests/ObjCIntegration/Credentials.h" NSTimeInterval kFIRStorageIntegrationTestTimeout = 60; /** * Firebase Storage Integration tests * * To run these tests, you need to define the following access rights: * rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{directChild=*} { allow read: if request.auth != null; } match /ios { match /public/{allPaths=**} { allow write: if request.auth != null; allow read: if true; } match /private/{allPaths=**} { allow read, write: if false; } } } } * * You also need to enable email/password sign in and add a test user in your * Firebase Authentication settings. Your account credentials need to match * the credentials defined in `kTestUser` and `kTestPassword`. * * You can define these access rights in the Firebase Console of your project. */ NSString *const kTestUser = KUSER_NAME; NSString *const kTestPassword = KPASSWORD; @interface FIRStorageIntegrationTests : XCTestCase @property(strong, nonatomic) FIRApp *app; @property(strong, nonatomic) FIRAuth *auth; @property(strong, nonatomic) FIRStorage *storage; @end @implementation FIRStorageIntegrationTests + (void)setUp { [FIRApp configure]; } - (void)setUp { [super setUp]; self.app = [FIRApp defaultApp]; self.auth = [FIRAuth authWithApp:self.app]; self.storage = [FIRStorage storageForApp:self.app]; static dispatch_once_t once; dispatch_once(&once, ^{ XCTestExpectation *signInExpectation = [self expectationWithDescription:@"signIn"]; [self.auth signInWithEmail:kTestUser password:kTestPassword completion:^(FIRAuthDataResult *result, NSError *error) { XCTAssertNil(error); [signInExpectation fulfill]; }]; [self waitForExpectations]; XCTestExpectation *setUpExpectation = [self expectationWithDescription:@"setUp"]; NSArray *largeFiles = @[ @"ios/public/1mb" ]; NSArray *emptyFiles = @[ @"ios/public/empty", @"ios/public/list/a", @"ios/public/list/b", @"ios/public/list/prefix/c" ]; setUpExpectation.expectedFulfillmentCount = largeFiles.count + emptyFiles.count; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"1mb" ofType:@"dat"]; if (filePath == nil) { // Use bundleForClass to allow 1mb.dat to be in the test target's bundle. NSBundle *bundle = [NSBundle bundleForClass:[self class]]; filePath = [bundle pathForResource:@"1mb" ofType:@"dat"]; } NSData *data = [NSData dataWithContentsOfFile:filePath]; XCTAssertNotNil(data, "Could not load bundled file"); for (NSString *largeFile in largeFiles) { FIRStorageReference *file = [[FIRStorage storage].reference child:largeFile]; [file putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNil(error); [setUpExpectation fulfill]; }]; } for (NSString *emptyFile in emptyFiles) { FIRStorageReference *file = [[FIRStorage storage].reference child:emptyFile]; [file putData:[NSData data] metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNil(error); [setUpExpectation fulfill]; }]; } [self waitForExpectations]; }); } - (void)tearDown { self.app = nil; self.storage = nil; [super tearDown]; } - (void)testSameInstanceNoBucket { FIRStorage *storage1 = [FIRStorage storageForApp:self.app]; FIRStorage *storage2 = [FIRStorage storageForApp:self.app]; XCTAssertEqual(storage1, storage2); } - (void)testSameInstanceCustomBucket { FIRStorage *storage1 = [FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; FIRStorage *storage2 = [FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; XCTAssertEqual(storage1, storage2); } - (void)testDifferentInstance { FIRStorage *storage1 = [FIRStorage storageForApp:self.app]; FIRStorage *storage2 = [FIRStorage storageForApp:self.app URL:@"gs://foo-bar.appspot.com"]; XCTAssertNotEqual(storage1, storage2); } - (void)testName { NSString *aGSURI = [NSString stringWithFormat:@"gs://%@.appspot.com/path/to", [[FIRApp defaultApp] options].projectID]; FIRStorageReference *ref = [self.storage referenceForURL:aGSURI]; XCTAssertEqualObjects(ref.description, aGSURI); } - (void)testGetMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetMetadata"]; FIRStorageReference *ref = [self.storage.reference child:@"ios/public/1mb"]; [ref metadataWithCompletion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testCopyMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetMetadata"]; FIRStorageReference *ref = [self.storage.reference child:@"ios/public/1mb"]; [ref metadataWithCompletion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); FIRStorageMetadata *metadata2 = metadata.copy; XCTAssertNotEqual(metadata, metadata2); XCTAssertEqualObjects(metadata, metadata2); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testDelete { XCTestExpectation *expectation = [self expectationWithDescription:@"testDelete"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/fileToDelete"]; NSData *data = [@"Delete me!!!!!!!" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [ref deleteWithCompletion:^(NSError *error) { XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; }]; [self waitForExpectations]; } - (void)testDeleteWithNilCompletion { XCTestExpectation *expectation = [self expectationWithDescription:@"testDeleteWithNilCompletion"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/fileToDelete"]; NSData *data = [@"Delete me!!!!!!!" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [ref deleteWithCompletion:nil]; [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testPutDataSpecialCharacter { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutDataSpecialCharacter"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/-._~!$'()*,=:@&+;"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testPutDataInBackgroundQueue { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutDataInBackgroundQueue"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testBytesUpload"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; }); [self waitForExpectations]; } - (void)testPutDataWithEmptyData { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutDataWithEmptyData"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testUnauthenticatedSimplePutEmptyData"]; NSData *data = [[NSData alloc] init]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testPutData { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutData"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/private/secretfile.txt"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNil(metadata, "Metadata should be nil"); XCTAssertNotNil(error, "Error should not be nil"); XCTAssertEqual(error.code, FIRStorageErrorCodeUnauthorized); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testPutFile { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutFile"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testUnauthenticatedSimplePutFile"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; [data writeToURL:fileURL atomically:YES]; FIRStorageUploadTask *task = [ref putFile:fileURL metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); }]; __block long uploadedBytes = -1; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); [expectation fulfill]; }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { XCTAssertTrue([[snapshot description] containsString:@"State: Progress"] || [[snapshot description] containsString:@"State: Resume"]); NSProgress *progress = snapshot.progress; XCTAssertGreaterThanOrEqual(progress.completedUnitCount, uploadedBytes); uploadedBytes = (long)progress.completedUnitCount; }]; [self waitForExpectations]; } - (void)testPutFileWithMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutFileWithMetaData"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testUnauthenticatedSimplePutFile"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; [data writeToURL:fileURL atomically:YES]; FIRStorageMetadata *putMetadata = [[FIRStorageMetadata alloc] init]; putMetadata.contentType = @"text/plain"; FIRStorageUploadTask *task = [ref putFile:fileURL metadata:putMetadata completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); }]; __block long uploadedBytes = -1; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); [expectation fulfill]; }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { XCTAssertTrue([[snapshot description] containsString:@"State: Progress"] || [[snapshot description] containsString:@"State: Resume"]); NSProgress *progress = snapshot.progress; XCTAssertGreaterThanOrEqual(progress.completedUnitCount, uploadedBytes); uploadedBytes = (long)progress.completedUnitCount; }]; [self waitForExpectations]; } - (void)testPutFileWithSpecialCharacters { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutFileWithSpecialCharacters"]; NSString *fileName = @"hello&+@_ .txt"; FIRStorageReference *ref = [self.storage referenceWithPath:[@"ios/public/" stringByAppendingString:fileName]]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [tmpDirURL URLByAppendingPathComponent:fileName]; [data writeToURL:fileURL atomically:YES]; [ref putFile:fileURL metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); XCTAssertEqualObjects(fileName, metadata.name); FIRStorageReference *download = [self.storage referenceWithPath:[@"ios/public/" stringByAppendingString:fileName]]; [download metadataWithCompletion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); XCTAssertEqualObjects(fileName, metadata.name); [expectation fulfill]; }]; }]; [self waitForExpectations]; } - (void)testPutDataNoMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutDataNoMetadata"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testUnauthenticatedSimplePutDataNoMetadata"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:data metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testPutFileNoMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testPutFileNoMetadata"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/testUnauthenticatedSimplePutFileNoMetadata"]; NSData *data = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; [data writeToURL:fileURL atomically:YES]; [ref putFile:fileURL metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { XCTAssertNotNil(metadata, "Metadata should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testGetData { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetData"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; [ref dataWithMaxSize:1 * 1024 * 1024 completion:^(NSData *data, NSError *error) { XCTAssertNotNil(data, "Data should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testGetDataInBackgroundQueue { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetDataInBackgroundQueue"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [ref dataWithMaxSize:1 * 1024 * 1024 completion:^(NSData *data, NSError *error) { XCTAssertNotNil(data, "Data should not be nil"); XCTAssertNil(error, "Error should be nil"); [expectation fulfill]; }]; }); [self waitForExpectations]; } - (void)testGetDataWithCustomCallbackQueue { XCTestExpectation *expectation = [self expectationWithDescription:@"testUnauthenticatedGetDataInCustomCallbackQueue"]; NSString *callbackQueueLabelString = @"customCallbackQueue"; const char *callbackQueueLabel = [callbackQueueLabelString UTF8String]; const void *callbackQueueKey = callbackQueueLabel; dispatch_queue_t callbackQueue = dispatch_queue_create(callbackQueueLabel, NULL); dispatch_queue_set_specific(callbackQueue, callbackQueueKey, (void *)callbackQueueKey, NULL); _storage.callbackQueue = callbackQueue; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; [ref dataWithMaxSize:1 * 1024 * 1024 completion:^(NSData *data, NSError *error) { XCTAssertNotNil(data, "Data should not be nil"); XCTAssertNil(error, "Error should be nil"); char *currentQueueLabel = dispatch_get_specific(callbackQueueKey); NSString *currentQueueLabelString = [NSString stringWithUTF8String:currentQueueLabel]; XCTAssertEqualObjects(currentQueueLabelString, callbackQueueLabelString); [expectation fulfill]; // Reset the callbackQueue to default (main queue). self.storage.callbackQueue = dispatch_get_main_queue(); dispatch_queue_set_specific(callbackQueue, callbackQueueKey, NULL, NULL); }]; [self waitForExpectations]; } - (void)testGetDataTooSmall { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetDataTooSmall"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; /// Only allow 1kB size, which is smaller than our file [ref dataWithMaxSize:1 * 1024 completion:^(NSData *data, NSError *error) { XCTAssertNil(data); XCTAssertEqual(error.code, FIRStorageErrorCodeDownloadSizeExceeded); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testGetDownloadURL { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetDownloadURL"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; // Download URL format is // "https://firebasestorage.googleapis.com:443/v0/b/{bucket}/o/{path}?alt=media&token={token}" NSString *downloadURLPattern = @"^https:\\/\\/firebasestorage.googleapis.com:443\\/v0\\/b\\/[^\\/]*\\/o\\/" @"ios%2Fpublic%2F1mb\\?alt=media&token=[a-z0-9-]*$"; [ref downloadURLWithCompletion:^(NSURL *downloadURL, NSError *error) { XCTAssertNil(error); NSRegularExpression *testRegex = [NSRegularExpression regularExpressionWithPattern:downloadURLPattern options:0 error:nil]; NSString *urlString = [downloadURL absoluteString]; XCTAssertEqual([testRegex numberOfMatchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])], 1); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testGetFile { XCTestExpectation *expectation = [self expectationWithDescription:@"testGetFile"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/helloworld"]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; NSData *fileData = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; [ref putData:fileData metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) { FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { [ref dataWithMaxSize:fileData.length completion:^(NSData *_Nullable data, NSError *_Nullable error) { XCTAssertEqualObjects(data, fileData); [expectation fulfill]; }]; }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { NSProgress *progress = snapshot.progress; NSLog(@"%lld of %lld", progress.completedUnitCount, progress.totalUnitCount); }]; [task observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertNil(snapshot.error); }]; }]; [self waitForExpectations]; } - (void)testCancelDownload { XCTestExpectation *expectation = [self expectationWithDescription:@"testCancelDownload"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"dat"]; FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; // Don't fulfill twice if a second observe failure happens before the cancel completes. BOOL __block fulfilled = NO; [task observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertTrue([[snapshot description] containsString:@"State: Failed"]); if (!fulfilled) { fulfilled = YES; XCTAssertEqual(snapshot.error.code, FIRStorageErrorCodeCancelled); [expectation fulfill]; } }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { [task cancel]; }]; [self waitForExpectations]; } - (void)assertMetadata:(FIRStorageMetadata *)actualMetadata contentType:(NSString *)expectedContentType customMetadata:(NSDictionary *)expectedCustomMetadata { XCTAssertEqualObjects(actualMetadata.cacheControl, @"cache-control"); XCTAssertEqualObjects(actualMetadata.contentDisposition, @"content-disposition"); XCTAssertEqualObjects(actualMetadata.contentEncoding, @"gzip"); XCTAssertEqualObjects(actualMetadata.contentLanguage, @"de"); XCTAssertEqualObjects(actualMetadata.contentType, expectedContentType); XCTAssertEqualObjects(actualMetadata.name, @"1mb"); XCTAssertTrue([actualMetadata.md5Hash length] == 24); for (NSString *key in expectedCustomMetadata) { XCTAssertEqualObjects([actualMetadata.customMetadata objectForKey:key], [expectedCustomMetadata objectForKey:key]); } } - (void)assertMetadataNil:(FIRStorageMetadata *)actualMetadata { XCTAssertNil(actualMetadata.cacheControl); XCTAssertNil(actualMetadata.contentDisposition); XCTAssertEqualObjects(actualMetadata.contentEncoding, @"identity"); XCTAssertNil(actualMetadata.contentLanguage); XCTAssertNil(actualMetadata.contentType); XCTAssertTrue([actualMetadata.md5Hash length] == 24); XCTAssertNil(actualMetadata.customMetadata); } - (void)testUpdateMetadata { XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateMetadata"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; // Update all available metadata FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init]; metadata.cacheControl = @"cache-control"; metadata.contentDisposition = @"content-disposition"; metadata.contentEncoding = @"gzip"; metadata.contentLanguage = @"de"; metadata.contentType = @"content-type-a"; metadata.customMetadata = @{@"a" : @"b", @"y" : @"z"}; [ref updateMetadata:metadata completion:^(FIRStorageMetadata *updatedMetadata, NSError *error) { XCTAssertNil(error); [self assertMetadata:updatedMetadata contentType:@"content-type-a" customMetadata:@{@"a" : @"b", @"y" : @"z"}]; // Update a subset of the metadata using the existing object. FIRStorageMetadata *metadata = updatedMetadata; metadata.contentType = @"content-type-b"; metadata.customMetadata = @{@"c" : @"d", @"y" : @""}; [ref updateMetadata:metadata completion:^(FIRStorageMetadata *updatedMetadata, NSError *error) { XCTAssertNil(error); [self assertMetadata:updatedMetadata contentType:@"content-type-b" // "a" is now deleted and the empty string for "y" remains. customMetadata:@{@"c" : @"d", @"y" : @""}]; // Clear all metadata with nils. FIRStorageMetadata *metadata = updatedMetadata; metadata.cacheControl = nil; metadata.contentDisposition = nil; metadata.contentEncoding = nil; metadata.contentLanguage = nil; metadata.contentType = nil; metadata.customMetadata = nil; [ref updateMetadata:metadata completion:^(FIRStorageMetadata *updatedMetadata, NSError *error) { XCTAssertNil(error); [self assertMetadataNil:updatedMetadata]; XCTAssertNil(updatedMetadata.customMetadata); [expectation fulfill]; }]; }]; }]; [self waitForExpectations]; } - (void)testMetadataDictInitAndClear { FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] initWithDictionary:@{ @"cacheControl" : @"cache-control", @"contentDisposition" : @"content-disposition", @"contentEncoding" : @"gzip", @"contentLanguage" : @"de", @"contentType" : @"content-type-a", @"md5Hash" : @"123456789012345678901234", // length 24 @"name" : @"1mb", @"metadata" : @{@"a" : @"b", @"y" : @"z"} }]; [self assertMetadata:metadata contentType:@"content-type-a" customMetadata:@{@"a" : @"b", @"y" : @"z"}]; metadata.cacheControl = nil; metadata.contentDisposition = nil; metadata.contentEncoding = @"identity"; metadata.contentLanguage = nil; metadata.contentType = nil; metadata.customMetadata = nil; [self assertMetadataNil:metadata]; metadata.contentEncoding = nil; XCTestExpectation *expectation = [self expectationWithDescription:@"testMetadataDictInitAndClear"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; [ref updateMetadata:metadata completion:^(FIRStorageMetadata *updatedMetadata, NSError *error) { XCTAssertNil(error); [self assertMetadataNil:updatedMetadata]; XCTAssertNil(updatedMetadata.customMetadata); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testResumeGetFile { XCTestExpectation *expectation = [self expectationWithDescription:@"testResumeGetFile"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; __block long resumeAtBytes = 256 * 1024; __block long downloadedBytes = 0; __block double computationResult = 0; FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); [expectation fulfill]; }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { XCTAssertTrue([[snapshot description] containsString:@"State: Progress"] || [[snapshot description] containsString:@"State: Resume"]); NSProgress *progress = snapshot.progress; XCTAssertGreaterThanOrEqual(progress.completedUnitCount, downloadedBytes); downloadedBytes = (long)progress.completedUnitCount; if (progress.completedUnitCount > resumeAtBytes) { // Making sure the main run loop is busy. for (int i = 0; i < 500; ++i) { dispatch_async(dispatch_get_main_queue(), ^{ computationResult = sqrt(INT_MAX - i); }); } NSLog(@"Pausing"); [task pause]; resumeAtBytes = INT_MAX; } }]; [task observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); NSLog(@"Resuming"); [task resume]; }]; [self waitForExpectations]; XCTAssertEqual(INT_MAX, resumeAtBytes); XCTAssertEqualWithAccuracy(sqrt(INT_MAX - 499), computationResult, 0.1); } - (void)testResumeGetFileInBackgroundQueue { XCTestExpectation *expectation = [self expectationWithDescription:@"testResumeGetFileInBackgroundQueue"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"hello"] URLByAppendingPathExtension:@"txt"]; __block long resumeAtBytes = 256 * 1024; __block long downloadedBytes = 0; FIRStorageDownloadTask *task = [ref writeToFile:fileURL]; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); [expectation fulfill]; }]; [task observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *_Nonnull snapshot) { XCTAssertTrue([[snapshot description] containsString:@"State: Progress"] || [[snapshot description] containsString:@"State: Resume"]); NSProgress *progress = snapshot.progress; XCTAssertGreaterThanOrEqual(progress.completedUnitCount, downloadedBytes); downloadedBytes = (long)progress.completedUnitCount; if (progress.completedUnitCount > resumeAtBytes) { NSLog(@"Pausing"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [task pause]; }); resumeAtBytes = INT_MAX; } }]; [task observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) { XCTAssertEqualObjects([snapshot description], @""); NSLog(@"Resuming"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [task resume]; }); }]; [self waitForExpectations]; XCTAssertEqual(INT_MAX, resumeAtBytes); } - (void)testPagedListFiles { XCTestExpectation *expectation = [self expectationWithDescription:@"testPagedListFiles"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/list"]; [ref listWithMaxResults:2 completion:^(FIRStorageListResult *_Nullable listResult, NSError *_Nullable error) { XCTAssertNotNil(listResult); XCTAssertNil(error); XCTAssertEqualObjects(listResult.items, (@[ [ref child:@"a"], [ref child:@"b"] ])); XCTAssertEqualObjects(listResult.prefixes, @[]); XCTAssertNotNil(listResult.pageToken); [ref listWithMaxResults:2 pageToken:listResult.pageToken completion:^(FIRStorageListResult *_Nullable listResult, NSError *_Nullable error) { XCTAssertNotNil(listResult); XCTAssertNil(error); XCTAssertEqualObjects(listResult.items, @[]); XCTAssertEqualObjects(listResult.prefixes, @[ [ref child:@"prefix"] ]); XCTAssertNil(listResult.pageToken); [expectation fulfill]; }]; }]; [self waitForExpectations]; } - (void)testListAllFiles { XCTestExpectation *expectation = [self expectationWithDescription:@"testListAllFiles"]; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/list"]; [ref listAllWithCompletion:^(FIRStorageListResult *_Nullable listResult, NSError *_Nullable error) { XCTAssertNotNil(listResult); XCTAssertNil(error); XCTAssertEqualObjects(listResult.items, (@[ [ref child:@"a"], [ref child:@"b"] ])); XCTAssertEqualObjects(listResult.prefixes, @[ [ref child:@"prefix"] ]); XCTAssertNil(listResult.pageToken); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testListFilesAtRoot { XCTestExpectation *expectation = [self expectationWithDescription:@"testListFilesAtRoot"]; FIRStorageReference *ref = [self.storage referenceWithPath:@""]; [ref listAllWithCompletion:^(FIRStorageListResult *_Nullable listResult, NSError *_Nullable error) { XCTAssertNotNil(listResult); XCTAssertNil(error); XCTAssertNil(listResult.pageToken); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)testCopyListResult { XCTestExpectation *expectation = [self expectationWithDescription:@"testCopyListResult"]; FIRStorageReference *ref = [self.storage referenceWithPath:@""]; [ref listAllWithCompletion:^(FIRStorageListResult *_Nullable listResult, NSError *_Nullable error) { XCTAssertNotNil(listResult); XCTAssertNil(error); XCTAssertNil(listResult.pageToken); FIRStorageListResult *listResult2 = listResult.copy; XCTAssertEqual(listResult.pageToken, listResult2.pageToken); XCTAssertNotEqual(listResult, listResult2); [expectation fulfill]; }]; [self waitForExpectations]; } - (void)waitForExpectations { [self waitForExpectationsWithTimeout:kFIRStorageIntegrationTestTimeout handler:^(NSError *_Nullable error) { if (error) { NSLog(@"%@", error); } }]; } @end