diff --git a/FirebaseStorage/CHANGELOG.md b/FirebaseStorage/CHANGELOG.md index 7da1289bc6ba..2738305acf33 100644 --- a/FirebaseStorage/CHANGELOG.md +++ b/FirebaseStorage/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fix a potential data race in Storage initialization. (#13369) + # 11.0.0 - [fixed] Updated error handling to support both Swift error enum handling and NSError error handling. Some of the Swift enums have additional parameters which may be a **breaking** change. diff --git a/FirebaseStorage/Tests/Unit/StorageDeleteTests.swift b/FirebaseStorage/Tests/Unit/StorageDeleteTests.swift index 6be3d6f62043..1f6a2ed4efd3 100644 --- a/FirebaseStorage/Tests/Unit/StorageDeleteTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageDeleteTests.swift @@ -110,51 +110,39 @@ class StorageDeleteTests: StorageTestHelpers { waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthenticated() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthenticatedBlock() + func testUnsuccessfulFetchUnauthenticated() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthenticatedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageDeleteTask.deleteTask( - reference: ref, - queue: dispatchQueue!.self - ) { _, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthenticated.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + try await ref.delete() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthenticated.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthorized() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthorizedBlock() + func testUnsuccessfulFetchUnauthorized() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthorizedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageDeleteTask.deleteTask( - reference: ref, - queue: dispatchQueue!.self - ) { _, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthorized.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + try await ref.delete() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthorized.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchObjectDoesntExist() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = notFoundBlock() + func testUnsuccessfulFetchObjectDoesntExist() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(notFoundBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageDeleteTask.deleteTask( - reference: ref, - queue: dispatchQueue!.self - ) { _, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.objectNotFound.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + try await ref.delete() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.objectNotFound.rawValue) } - waitForExpectation(test: self) } } diff --git a/FirebaseStorage/Tests/Unit/StorageGetMetadataTests.swift b/FirebaseStorage/Tests/Unit/StorageGetMetadataTests.swift index 2442a26f6da0..a2428d792fc8 100644 --- a/FirebaseStorage/Tests/Unit/StorageGetMetadataTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageGetMetadataTests.swift @@ -110,52 +110,40 @@ class StorageGetMetadataTests: StorageTestHelpers { waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthenticated() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthenticatedBlock() + func testUnsuccessfulFetchUnauthenticated() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthenticatedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageGetMetadataTask.getMetadataTask( - reference: ref, - queue: dispatchQueue!.self - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthenticated.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.getMetadata() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthenticated.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthorized() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthorizedBlock() + func testUnsuccessfulFetchUnauthorized() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthorizedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageGetMetadataTask.getMetadataTask( - reference: ref, - queue: dispatchQueue!.self - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthorized.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.getMetadata() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthorized.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchObjectDoesntExist() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = notFoundBlock() + func testUnsuccessfulFetchObjectDoesntExist() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(notFoundBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageGetMetadataTask.getMetadataTask( - reference: ref, - queue: dispatchQueue!.self - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.objectNotFound.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.getMetadata() + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.objectNotFound.rawValue) } - waitForExpectation(test: self) } func testUnsuccessfulFetchBadJSON() { diff --git a/FirebaseStorage/Tests/Unit/StorageListTests.swift b/FirebaseStorage/Tests/Unit/StorageListTests.swift index c2b2afb698bb..1b03ee62a180 100644 --- a/FirebaseStorage/Tests/Unit/StorageListTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageListTests.swift @@ -117,25 +117,24 @@ class StorageListTests: StorageTestHelpers { waitForExpectation(test: self) } - func testDefaultListWithEmulator() { - let expectation = self.expectation(description: #function) + func testDefaultListWithEmulator() async throws { let storage = self.storage() storage.useEmulator(withHost: "localhost", port: 8080) - fetcherService?.allowLocalhostRequest = true - fetcherService?.testBlock = { (fetcher: GTMSessionFetcher, - response: GTMSessionFetcherTestResponse) in + let testBlock = { (fetcher: GTMSessionFetcher, + response: GTMSessionFetcherTestResponse) in let url = fetcher.request!.url! XCTAssertEqual(url.scheme, "http") XCTAssertEqual(url.host, "localhost") XCTAssertEqual(url.port, 8080) XCTAssertEqual(url.path, "/v0/b/bucket/o") let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)!.queryItems! - XCTAssertEqual(queryItems.count, 2) + XCTAssertEqual(queryItems.count, 3) for item in queryItems { switch item.name { case "prefix": XCTAssertEqual(item.value, "object/") case "delimiter": XCTAssertEqual(item.value, "/") + case "maxResults": XCTAssertEqual(item.value, "123") default: XCTFail("Unexpected URLComponent Query Item") } } @@ -146,19 +145,9 @@ class StorageListTests: StorageTestHelpers { headerFields: nil) response(httpResponse, "{}".data(using: .utf8), nil) } - - let path = objectPath() - let ref = StorageReference(storage: storage, path: path) - StorageListTask.listTask( - reference: ref, - queue: dispatchQueue!.self, - pageSize: nil, - previousPageToken: nil - ) { result, error in - XCTAssertNil(error) - expectation.fulfill() - } - waitForExpectation(test: self) + await storage.fetcherService.updateTestBlock(testBlock) + let ref = storage.reference(withPath: "object") + let _ = try await ref.list(maxResults: 123) } func testListWithPageSizeAndPageToken() { @@ -243,9 +232,7 @@ class StorageListTests: StorageTestHelpers { waitForExpectation(test: self) } - func testListWithResponse() throws { - let expectation = self.expectation(description: #function) - + func testListWithResponse() async throws { let jsonString = "{\n" + " \"prefixes\": [\n" + " \"object/prefixWithoutSlash\",\n" + @@ -263,11 +250,10 @@ class StorageListTests: StorageTestHelpers { " ],\n" + " \"nextPageToken\": \"foo\"" + "}" - let responseData = try XCTUnwrap(jsonString.data(using: .utf8)) - fetcherService?.testBlock = { (fetcher: GTMSessionFetcher, - response: GTMSessionFetcherTestResponse) in + let testBlock = { (fetcher: GTMSessionFetcher, + response: GTMSessionFetcherTestResponse) in let httpResponse = HTTPURLResponse(url: (fetcher.request?.url)!, statusCode: 200, httpVersion: "HTTP/1.1", @@ -276,35 +262,22 @@ class StorageListTests: StorageTestHelpers { } let storage = storage() + await storage.fetcherService.updateTestBlock(testBlock) let ref = storage.reference(withPath: "object") - StorageListTask.listTask( - reference: ref, - queue: dispatchQueue!.self, - pageSize: nil, - previousPageToken: nil - ) { result, error in - XCTAssertNotNil(result) - XCTAssertNil(error) - - XCTAssertEqual(result?.items, [ref.child("data1.dat"), ref.child("data2.dat")]) - XCTAssertEqual( - result?.prefixes, - [ref.child("prefixWithoutSlash"), ref.child("prefixWithSlash")] - ) - XCTAssertEqual(result?.pageToken, "foo") - - expectation.fulfill() - } - waitForExpectation(test: self) + let result = try await ref.list(maxResults: 1000) + XCTAssertEqual(result.items, [ref.child("data1.dat"), ref.child("data2.dat")]) + XCTAssertEqual( + result.prefixes, + [ref.child("prefixWithoutSlash"), ref.child("prefixWithSlash")] + ) + XCTAssertEqual(result.pageToken, "foo") } - func testListWithErrorResponse() throws { - let expectation = self.expectation(description: #function) - + func testListWithErrorResponse() async { let error = NSError(domain: "com.google.firebase.storage", code: 404) - fetcherService?.testBlock = { (fetcher: GTMSessionFetcher, - response: GTMSessionFetcherTestResponse) in + let testBlock = { (fetcher: GTMSessionFetcher, + response: GTMSessionFetcherTestResponse) in let httpResponse = HTTPURLResponse(url: (fetcher.request?.url)!, statusCode: 403, httpVersion: "HTTP/1.1", @@ -313,19 +286,13 @@ class StorageListTests: StorageTestHelpers { } let storage = storage() + await storage.fetcherService.updateTestBlock(testBlock) let ref = storage.reference(withPath: "object") - StorageListTask.listTask( - reference: ref, - queue: dispatchQueue!.self, - pageSize: nil, - previousPageToken: nil - ) { result, error in - XCTAssertNotNil(error) - XCTAssertNil(result) - XCTAssertEqual((error as? NSError)!.domain, "FIRStorageErrorDomain") - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.objectNotFound.rawValue) - expectation.fulfill() + do { + let _ = try await ref.list(maxResults: 1000) + } catch { + XCTAssertEqual((error as NSError).domain, "FIRStorageErrorDomain") + XCTAssertEqual((error as NSError).code, StorageErrorCode.objectNotFound.rawValue) } - waitForExpectation(test: self) } } diff --git a/FirebaseStorage/Tests/Unit/StorageUpdateMetadataTests.swift b/FirebaseStorage/Tests/Unit/StorageUpdateMetadataTests.swift index 2baa7e3daa73..7650032d1799 100644 --- a/FirebaseStorage/Tests/Unit/StorageUpdateMetadataTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageUpdateMetadataTests.swift @@ -21,7 +21,7 @@ import XCTest class StorageUpdateMetadataTests: StorageTestHelpers { var fetcherService: GTMSessionFetcherService? var dispatchQueue: DispatchQueue? - var metadata: StorageMetadata? + var metadata: StorageMetadata! override func setUp() { super.setUp() @@ -61,22 +61,14 @@ class StorageUpdateMetadataTests: StorageTestHelpers { waitForExpectation(test: self) } - func testSuccessfulFetch() { - let expectation = self.expectation(description: #function) - fetcherService!.testBlock = successBlock(withMetadata: metadata) + func testSuccessfulFetch() async throws { + let storage = storage() + await storage.fetcherService.updateTestBlock(successBlock(withMetadata: metadata)) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageUpdateMetadataTask.updateMetadataTask( - reference: ref, - queue: dispatchQueue!.self, - metadata: metadata! - ) { metadata, error in - XCTAssertNil(error) - XCTAssertEqual(self.metadata?.bucket, metadata?.bucket) - XCTAssertEqual(self.metadata?.name, metadata?.name) - expectation.fulfill() - } - waitForExpectation(test: self) + let ref = StorageReference(storage: storage, path: path) + let metadata = try await ref.updateMetadata(metadata) + XCTAssertEqual(self.metadata?.bucket, metadata.bucket) + XCTAssertEqual(self.metadata?.name, metadata.name) } func testSuccessfulFetchWithEmulator() { @@ -102,55 +94,40 @@ class StorageUpdateMetadataTests: StorageTestHelpers { waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthenticated() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthenticatedBlock() + func testUnsuccessfulFetchUnauthenticated() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthenticatedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageUpdateMetadataTask.updateMetadataTask( - reference: ref, - queue: dispatchQueue!.self, - metadata: metadata! - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthenticated.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.updateMetadata(metadata) + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthenticated.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchUnauthorized() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = unauthorizedBlock() + func testUnsuccessfulFetchUnauthorized() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(unauthorizedBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageUpdateMetadataTask.updateMetadataTask( - reference: ref, - queue: dispatchQueue!.self, - metadata: metadata! - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.unauthorized.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.updateMetadata(metadata) + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.unauthorized.rawValue) } - waitForExpectation(test: self) } - func testUnsuccessfulFetchObjectDoesntExist() { - let expectation = self.expectation(description: #function) - - fetcherService!.testBlock = notFoundBlock() + func testUnsuccessfulFetchObjectDoesntExist() async { + let storage = storage() + await storage.fetcherService.updateTestBlock(notFoundBlock()) let path = objectPath() - let ref = StorageReference(storage: storage(), path: path) - StorageUpdateMetadataTask.updateMetadataTask( - reference: ref, - queue: dispatchQueue!.self, - metadata: metadata! - ) { metadata, error in - XCTAssertEqual((error as? NSError)!.code, StorageErrorCode.objectNotFound.rawValue) - expectation.fulfill() + let ref = StorageReference(storage: storage, path: path) + do { + let _ = try await ref.updateMetadata(metadata) + } catch { + XCTAssertEqual((error as NSError).code, StorageErrorCode.objectNotFound.rawValue) } - waitForExpectation(test: self) } func testUnsuccessfulFetchBadJSON() {