@@ -1887,6 +1887,92 @@ class NetworkInstrumentationFeatureTests: XCTestCase {
18871887 XCTAssertEqual ( interception. trace, traceContexts. first, " It should register first injected Trace Context " )
18881888 }
18891889
1890+ // MARK: - isSupportedForInstrumentation
1891+
1892+ func testIsSupportedForInstrumentation_returnsTrueForDataTask( ) {
1893+ let session = URLSession ( configuration: . ephemeral)
1894+ let task = session. dataTask ( with: URL . mockAny ( ) )
1895+ defer { task. cancel ( ) }
1896+ XCTAssertTrue ( task. isSupportedForInstrumentation)
1897+ }
1898+
1899+ func testIsSupportedForInstrumentation_returnsTrueForUploadTask( ) {
1900+ let session = URLSession ( configuration: . ephemeral)
1901+ let task = session. uploadTask ( with: URLRequest ( url: URL . mockAny ( ) ) , from: Data ( ) )
1902+ defer { task. cancel ( ) }
1903+ XCTAssertTrue ( task. isSupportedForInstrumentation)
1904+ }
1905+
1906+ func testIsSupportedForInstrumentation_returnsTrueForDownloadTask( ) {
1907+ let session = URLSession ( configuration: . ephemeral)
1908+ let task = session. downloadTask ( with: URL . mockAny ( ) )
1909+ defer { task. cancel ( ) }
1910+ XCTAssertTrue ( task. isSupportedForInstrumentation)
1911+ }
1912+
1913+ @available ( iOS 13 . 0 , tvOS 13 . 0 , * )
1914+ func testIsSupportedForInstrumentation_returnsTrueForWebSocketTask( ) {
1915+ let session = URLSession ( configuration: . ephemeral)
1916+ let task = session. webSocketTask ( with: URL ( string: " wss://example.com " ) !)
1917+ defer { task. cancel ( ) }
1918+ XCTAssertTrue ( task. isSupportedForInstrumentation)
1919+ }
1920+
1921+ func testIsSupportedForInstrumentation_returnsTrueForStreamTask( ) {
1922+ let session = URLSession ( configuration: . ephemeral)
1923+ let task = session. streamTask ( withHostName: " example.com " , port: 80 )
1924+ defer { task. cancel ( ) }
1925+ XCTAssertTrue ( task. isSupportedForInstrumentation)
1926+ }
1927+
1928+ func testIsSupportedForInstrumentation_returnsFalseForUnsupportedAVTaskTypes( ) {
1929+ let unsupportedClassNames = [
1930+ " AVAssetDownloadTask " ,
1931+ " NSURLSessionAVAssetDownloadTask " ,
1932+ " AVAggregateAssetDownloadTask " ,
1933+ " NSURLSessionAVAggregateAssetDownloadTask " ,
1934+ " __NSCFBackgroundAVAssetDownloadTask "
1935+ ]
1936+ for className in unsupportedClassNames {
1937+ guard let task = NSClassFromString ( className) ? . alloc ( ) as? URLSessionTask else {
1938+ continue // class unavailable on this platform/OS version
1939+ }
1940+ XCTAssertFalse ( task. isSupportedForInstrumentation, " \( className) should not be instrumented " )
1941+ }
1942+ }
1943+
1944+ // MARK: - Crash regression: resume() on various task types
1945+
1946+ @available ( iOS 13 . 0 , tvOS 13 . 0 , * )
1947+ func testWebSocketTask_resumeDoesNotCrash( ) throws {
1948+ // Regression: verify that resuming a WebSocketTask with the swizzle installed doesn't crash.
1949+ // The crash in interceptResume is synchronous, so no real connection is needed — we cancel immediately.
1950+ try URLSessionInstrumentation . enableOrThrow ( with: nil , in: core)
1951+ let session = URLSession ( configuration: . ephemeral)
1952+ let task = session. webSocketTask ( with: URL ( string: " wss://example.com " ) !)
1953+ task. resume ( )
1954+ task. cancel ( )
1955+
1956+ let feature = try XCTUnwrap ( core. get ( feature: NetworkInstrumentationFeature . self) )
1957+ feature. flush ( )
1958+ // No crash = pass. WebSocketTask is a supported type and should be tracked.
1959+ XCTAssertEqual ( handler. interceptions. count, 1 )
1960+ }
1961+
1962+ func testStreamTask_resumeDoesNotCrash( ) throws {
1963+ // Regression: verify that resuming a StreamTask with the swizzle installed doesn't crash.
1964+ try URLSessionInstrumentation . enableOrThrow ( with: nil , in: core)
1965+ let session = URLSession ( configuration: . ephemeral)
1966+ let task = session. streamTask ( withHostName: " example.com " , port: 80 )
1967+ task. resume ( )
1968+ task. cancel ( )
1969+
1970+ let feature = try XCTUnwrap ( core. get ( feature: NetworkInstrumentationFeature . self) )
1971+ feature. flush ( )
1972+ // No crash = pass. StreamTask is a supported type and should be tracked.
1973+ XCTAssertEqual ( handler. interceptions. count, 1 )
1974+ }
1975+
18901976 // MARK: - First Party Hosts
18911977
18921978 func testAutomaticMode_detectsFirstPartyHosts( ) throws {
0 commit comments