diff --git a/Sources/Pulse/NetworkLogger/NetworkLogger.swift b/Sources/Pulse/NetworkLogger/NetworkLogger.swift index d84e058a5..4f61ac289 100644 --- a/Sources/Pulse/NetworkLogger/NetworkLogger.swift +++ b/Sources/Pulse/NetworkLogger/NetworkLogger.swift @@ -186,7 +186,30 @@ public final class NetworkLogger: @unchecked Sendable { public func logTask(_ task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { lock.lock() context(for: task).metrics = NetworkLogger.Metrics(metrics: metrics) + + guard let originalRequest = task.originalRequest else { + lock.unlock() + return // This should never happen + } + + let context = context(for: task) + let metrics = context.metrics + let data = context.data lock.unlock() + + send(.networkTaskCompleted(.init( + taskId: context.taskId, + taskType: NetworkLogger.TaskType(task: task), + createdAt: Date(), + originalRequest: Request(originalRequest), + currentRequest: task.currentRequest.map(Request.init), + response: task.response.map(Response.init), + error: task.error.map(ResponseError.init), + requestBody: originalRequest.httpBody ?? originalRequest.httpBodyStreamData(), + responseBody: data, + metrics: metrics, + label: configuration.label + ))) } /// Logs the task metrics (optional). diff --git a/Tests/PulseTests/URLSessionProxyDelegateTests.swift b/Tests/PulseTests/URLSessionProxyDelegateTests.swift index fa461bc08..26990a703 100644 --- a/Tests/PulseTests/URLSessionProxyDelegateTests.swift +++ b/Tests/PulseTests/URLSessionProxyDelegateTests.swift @@ -71,6 +71,87 @@ final class URLSessionProxyDelegateTests: XCTestCase { let message = try XCTUnwrap(task.message) XCTAssertEqual(message.label, "network") } + + func testProxyDelegateWithCompletionHandler() throws { + // GIVEN + var myDelegate: MockSessionDelegate? = MockSessionDelegate() + let delegate = URLSessionProxyDelegate(logger: logger, delegate: myDelegate) + let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil) + + // WHEN + let dataURL = directory.url.appending(filename: "logs-archive-v2.pulse") + try Resources.pulseArchive.write(to: dataURL) + let didComplete = expectation(description: "TaskCompleted") + + let dataTask = session.dataTask(with: dataURL) { _, _, error in + XCTAssertNil(error) + didComplete.fulfill() + } + + autoreleasepool { + myDelegate = nil // Make sure that proxy delegate retain the real one (like URLSession does) + } + + dataTask.resume() + + wait(for: [didComplete], timeout: 5) + + // RECORD + let tasks = try store.allTasks() + let task = try XCTUnwrap(tasks.first) + + // THEN + XCTAssertEqual(tasks.count, 1) + + XCTAssertEqual(task.url, dataURL.absoluteString) + XCTAssertEqual(task.host, nil) + XCTAssertEqual(task.httpMethod, "GET") + XCTAssertNil(task.errorDomain) + XCTAssertEqual(task.errorCode, 0) + XCTAssertEqual(task.requestState, NetworkTaskEntity.State.success.rawValue) + + let message = try XCTUnwrap(task.message) + XCTAssertEqual(message.label, "network") + } + + func testProxyDelegateWithCompletionHandlerAsync() async throws { + // GIVEN + var myDelegate: MockSessionDelegate? = MockSessionDelegate() + let delegate = URLSessionProxyDelegate(logger: logger, delegate: myDelegate) + let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil) + + // WHEN + let dataURL = directory.url.appending(filename: "logs-archive-v2.pulse") + try Resources.pulseArchive.write(to: dataURL) + let didComplete = expectation(description: "TaskCompleted") + + let (_, _) = try await session.data(from: dataURL) + + didComplete.fulfill() + + autoreleasepool { + myDelegate = nil // Make sure that proxy delegate retain the real one (like URLSession does) + } + + await fulfillment(of: [didComplete], timeout: 5) + + // RECORD + let tasks = try store.allTasks() + let task = try XCTUnwrap(tasks.first) + + // THEN + XCTAssertEqual(tasks.count, 1) + + XCTAssertEqual(task.url, dataURL.absoluteString) + XCTAssertEqual(task.host, nil) + XCTAssertEqual(task.httpMethod, "GET") + XCTAssertNil(task.errorDomain) + XCTAssertEqual(task.errorCode, 0) + XCTAssertEqual(task.requestState, NetworkTaskEntity.State.success.rawValue) + + let message = try XCTUnwrap(task.message) + XCTAssertEqual(message.label, "network") + } func testForwardingOfUnimplementedMethod() throws { // GIVEN