diff --git a/Sources/Instrumentation/NetworkStatus/NetworkStatus.swift b/Sources/Instrumentation/NetworkStatus/NetworkStatus.swift index a471b7787..e4b9c1026 100644 --- a/Sources/Instrumentation/NetworkStatus/NetworkStatus.swift +++ b/Sources/Instrumentation/NetworkStatus/NetworkStatus.swift @@ -27,7 +27,7 @@ case .cellular: if #available(iOS 13.0, *) { if let serviceId = networkInfo.dataServiceIdentifier, let value = networkInfo.serviceCurrentRadioAccessTechnology?[serviceId] { - return ("cell", simpleConnectionName(connectionType: value), networkInfo.serviceSubscriberCellularProviders?[networkInfo.dataServiceIdentifier!]) + return ("cell", simpleConnectionName(connectionType: value), networkInfo.serviceSubscriberCellularProviders?[serviceId]) } } else { if let radioType = networkInfo.currentRadioAccessTechnology { diff --git a/Sources/Instrumentation/URLSession/URLSessionInstrumentation.swift b/Sources/Instrumentation/URLSession/URLSessionInstrumentation.swift index ef72475b2..c6d4cea35 100644 --- a/Sources/Instrumentation/URLSession/URLSessionInstrumentation.swift +++ b/Sources/Instrumentation/URLSession/URLSessionInstrumentation.swift @@ -87,7 +87,9 @@ public class URLSessionInstrumentation { URLSessionDataDelegate.urlSession(_:dataTask:didBecome:) as (URLSessionDataDelegate) -> ( (URLSession, URLSessionDataTask, URLSessionStreamTask) -> Void - )?) + )?), + #selector( + URLSessionTaskDelegate.urlSession(_:task:didFinishCollecting:)) ] let classes = configuration.delegateClassesToInstrument diff --git a/Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift b/Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift index 4814325ac..e54619485 100644 --- a/Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift +++ b/Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift @@ -53,6 +53,17 @@ class URLSessionInstrumentationTests: XCTestCase { } } + /// A minimal delegate that only implements didFinishCollecting. + /// This tests that delegate classes are discovered even when they only implement + /// urlSession(_:task:didFinishCollecting:) and no other delegate methods. + class MinimalMetricsDelegate: NSObject, URLSessionTaskDelegate { + var didFinishCollectingCalled = false + + func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { + didFinishCollectingCalled = true + } + } + static var requestCopy: URLRequest! static var responseCopy: HTTPURLResponse! @@ -933,6 +944,27 @@ class URLSessionInstrumentationTests: XCTestCase { XCTAssertTrue(URLSessionInstrumentationTests.checker.receivedResponseCalled, "receivedResponse should be called") } + /// Tests that delegate classes are discovered and swizzled even when they only implement + /// urlSession(_:task:didFinishCollecting:) and no other delegate methods. + /// This is a regression test for a bug where the selector for didFinishCollecting was missing + /// from the delegate discovery mechanism. + @available(macOS 10.15, iOS 13.0, tvOS 13.0, *) + public func testDelegateWithOnlyDidFinishCollectingIsDiscovered() async throws { + let request = URLRequest(url: URL(string: "http://localhost:33333/success")!) + + let delegate = MinimalMetricsDelegate() + let session = URLSession(configuration: URLSessionConfiguration.default, delegate: delegate, delegateQueue: nil) + + _ = try await session.data(for: request) + + // Verify the user's delegate was called (proves swizzling forwarded the call) + XCTAssertTrue(delegate.didFinishCollectingCalled, "Delegate should receive metrics callback") + + // Verify instrumentation worked (span was created and completed) + XCTAssertTrue(URLSessionInstrumentationTests.checker.createdRequestCalled, "Instrumentation should capture the request") + XCTAssertTrue(URLSessionInstrumentationTests.checker.receivedResponseCalled, "Instrumentation should capture the response") + } + public func testOldSemanticConvention() { URLSessionInstrumentationTests.instrumentation.configuration.semanticConvention = .old