Skip to content

Commit

Permalink
[Core] Prefer completion handler APIs in Core Internal (#13954)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncooke3 authored Oct 22, 2024
1 parent 4e9c6dd commit 181c7c8
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 22 additions & 16 deletions FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 181c7c8

Please sign in to comment.