diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift index e4a2cc4c335..e7f4ece2781 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift @@ -126,34 +126,30 @@ public final class HeartbeatController { } } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - public func flushAsync() async -> HeartbeatsPayload { - return await withCheckedContinuation { continuation in - let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in - guard let oldHeartbeatsBundle = heartbeatsBundle else { - return nil // Storage was empty. - } - // The new value that's stored will use the old's cache to prevent the - // logging of duplicates after flushing. - return HeartbeatsBundle( - capacity: self.heartbeatsStorageCapacity, - cache: oldHeartbeatsBundle.lastAddedHeartbeatDates - ) + public func flushAsync(completionHandler: @escaping (HeartbeatsPayload) -> Void) { + let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } - // Asynchronously gets and returns the stored heartbeats, resetting storage - // using the given transform. - storage.getAndSetAsync(using: resetTransform) { result in - switch result { - case let .success(heartbeatsBundle): - // If no heartbeats bundle was stored, return an empty payload. - continuation - .resume(returning: heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload - .emptyPayload) - case .failure: - // If the operation throws, assume no heartbeat(s) were retrieved or set. - continuation.resume(returning: HeartbeatsPayload.emptyPayload) - } + // Asynchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + storage.getAndSetAsync(using: resetTransform) { result in + switch result { + case let .success(heartbeatsBundle): + // If no heartbeats bundle was stored, return an empty payload. + completionHandler(heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload + .emptyPayload) + case .failure: + // If the operation throws, assume no heartbeat(s) were retrieved or set. + completionHandler(HeartbeatsPayload.emptyPayload) } } } diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift index cef5c7d9a8e..c60a1e11cc5 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift @@ -52,15 +52,8 @@ public class _ObjC_HeartbeatController: NSObject { public func flushAsync(completionHandler: @escaping (_ObjC_HeartbeatsPayload) -> Void) { // TODO: When minimum version moves to iOS 13.0, restore the async version // removed in #13952. - if #available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) { - Task { - let heartbeatsPayload = await heartbeatController.flushAsync() - completionHandler(_ObjC_HeartbeatsPayload(heartbeatsPayload)) - } - } else { - // It is not expected to reach this state as this API should only be - // called on iOS 13.0+. - completionHandler(_ObjC_HeartbeatsPayload(HeartbeatsPayload.emptyPayload)) + heartbeatController.flushAsync { heartbeatsPayload in + completionHandler(_ObjC_HeartbeatsPayload(heartbeatsPayload)) } } diff --git a/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift b/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift index b306405f4bd..3a9823aa94a 100644 --- a/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift +++ b/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift @@ -52,29 +52,36 @@ class HeartbeatLoggingIntegrationTests: XCTestCase { ) } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - func testLogAndFlushAsync() async throws { + func testLogAndFlushAsync() throws { // Given let heartbeatController = HeartbeatController(id: #function) let expectedDate = HeartbeatsPayload.dateFormatter.string(from: Date()) + let expectation = self.expectation(description: #function) // When heartbeatController.log("dummy_agent") - let payload = await heartbeatController.flushAsync() - // Then - try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( - payload.headerValue(), - """ - { - "version": 2, - "heartbeats": [ + heartbeatController.flushAsync { payload in + // Then + do { + try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( + payload.headerValue(), + """ { - "agent": "dummy_agent", - "dates": ["\(expectedDate)"] + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent", + "dates": ["\(expectedDate)"] + } + ] } - ] + """ + ) + expectation.fulfill() + } catch { + XCTFail("Unexpected error: \(error)") } - """ - ) + } + waitForExpectations(timeout: 1.0) } /// This test may flake if it is executed during the transition from one day to the next. diff --git a/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift b/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift index ddf3d1c5d9d..82691ed3f24 100644 --- a/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift +++ b/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift @@ -58,35 +58,41 @@ class HeartbeatControllerTests: XCTestCase { assertHeartbeatControllerFlushesEmptyPayload(controller) } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - func testLogAndFlushAsync() async throws { + func testLogAndFlushAsync() throws { // Given let controller = HeartbeatController( storage: HeartbeatStorageFake(), dateProvider: { self.date } ) + let expectation = expectation(description: #function) assertHeartbeatControllerFlushesEmptyPayload(controller) // When controller.log("dummy_agent") - let heartbeatPayload = await controller.flushAsync() - - // Then - try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( - heartbeatPayload.headerValue(), - """ - { - "version": 2, - "heartbeats": [ + controller.flushAsync { heartbeatPayload in + // Then + do { + try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( + heartbeatPayload.headerValue(), + """ { - "agent": "dummy_agent", - "dates": ["2021-11-01"] + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent", + "dates": ["2021-11-01"] + } + ] } - ] + """ + ) + expectation.fulfill() + } catch { + XCTFail("Unexpected error: \(error)") } - """ - ) + } + waitForExpectations(timeout: 1.0) assertHeartbeatControllerFlushesEmptyPayload(controller) }