Skip to content

Commit 591ed5f

Browse files
martin308bryce-b
andauthored
chore: remove NIO from tests (#903)
* Remove swift-nio dependencies from tests and add pure Swift HttpTestServer Replaces NIO-based test servers with a new HttpTestServer implemented using Foundation and POSIX sockets, eliminating the need for swift-nio and related packages in test targets. Updates all affected test files to use the new server and refactors test logic for compatibility. This simplifies test dependencies and improves portability. * refactor: consolidate HTTP test server implementations Consolidates two duplicate HTTP test server implementations into a single shared utility that can be used by both OTLP exporter tests and URLSession instrumentation tests. Changes: - Create unified HttpTestServer in Tests/Shared/TestUtils that combines functionality from both previous implementations - Uses POSIX sockets directly, maintaining independence from external dependencies (no NIO, Swifter, etc.) - Supports OTLP test requirements: request recording, protobuf binary payloads, header verification - Supports URLSession test requirements: path-based responses, success/error callbacks, configuration options - Add SharedTestUtils target to Package.swift for shared test utilities - Update both test targets to depend on SharedTestUtils - Remove duplicate implementations from ExportersTests and InstrumentationTests - Update test files to import SharedTestUtils and use consistent API Benefits: - Eliminates code duplication between test suites - Provides consistent HTTP mocking functionality - Makes it easier to maintain and extend test infrastructure - All OTLP HTTP exporter tests (16) passing successfully Note: URLSession tests have 4 pre-existing failures in error handling that are unrelated to this refactoring. * Handle /error path in HttpTestServer without config Added logic to HttpTestServer to properly handle requests to paths starting with /error when no config is provided, simulating a network error by closing the connection without a response. * Remove unused Darwin import from HttpTestServer.swift The Darwin import was not used in HttpTestServer.swift * fix: add Linux compatibility to HTTP test server - Add conditional imports for Glibc/Musl to support Linux builds - Replace macOS-specific CFSwapInt16BigToHost with portable ntohs for byte order conversion - Fix shutdown() calls to use platform-specific namespaces (Darwin/Glibc/Musl) - Fix minor code warnings (unused variable, boolean test) The HTTP test server now compiles and runs correctly on both macOS and Linux platforms, maintaining full backward compatibility while enabling cross-platform support. This change is required for the test suite to pass in Linux CI environments. * fix: resolve additional Linux type compatibility issues - Fix SOCK_STREAM type conversion on Linux (cast __socket_type to Int32) - Fix SHUT_RDWR type conversion on Linux (cast Int to Int32) These changes ensure proper type compatibility between macOS and Linux socket APIs. * fix: Add platform-specific handling for socket creation and warnings - Add conditional compilation for Darwin vs Linux socket() call - macOS uses SOCK_STREAM directly, Linux needs Int32(SOCK_STREAM.rawValue) - Silence unused result warnings for fcntl and withCString calls - Maintain full compatibility with both OTLP and URLSession tests * fix: Clear received requests when stopping HttpTestServer - Ensures clean state when restarting server - Prevents potential memory leaks from accumulated requests - Maintains consistency with initialization state --------- Co-authored-by: Bryce Buchanan <[email protected]>
1 parent a533cdd commit 591ed5f

File tree

8 files changed

+652
-197
lines changed

8 files changed

+652
-197
lines changed

Package.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ let package = Package(
3737
.package(url: "https://github.com/apple/swift-metrics.git", from: "2.7.0")
3838
],
3939
targets: [
40+
.target(
41+
name: "SharedTestUtils",
42+
dependencies: [],
43+
path: "Tests/Shared/TestUtils"
44+
),
4045
.target(
4146
name: "OTelSwiftLog",
4247
dependencies: [
@@ -147,9 +152,7 @@ let package = Package(
147152
dependencies: [
148153
"OpenTelemetryProtocolExporterGrpc",
149154
"OpenTelemetryProtocolExporterHttp",
150-
.product(name: "NIO", package: "swift-nio"),
151-
.product(name: "NIOHTTP1", package: "swift-nio"),
152-
.product(name: "NIOTestUtils", package: "swift-nio")
155+
"SharedTestUtils",
153156
],
154157
path: "Tests/ExportersTests/OpenTelemetryProtocol"
155158
),
@@ -308,8 +311,7 @@ extension Package {
308311
name: "URLSessionInstrumentationTests",
309312
dependencies: [
310313
"URLSessionInstrumentation",
311-
.product(name: "NIO", package: "swift-nio"),
312-
.product(name: "NIOHTTP1", package: "swift-nio")
314+
"SharedTestUtils",
313315
],
314316
path: "Tests/InstrumentationTests/URLSessionTests"
315317
),

Tests/ExportersTests/OpenTelemetryProtocol/OtlpHTTPExporterBaseTests.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
import FoundationNetworking
1010
#endif
1111
import Logging
12-
import NIO
13-
import NIOHTTP1
14-
import NIOTestUtils
1512
import OpenTelemetryApi
1613
import OpenTelemetryProtocolExporterCommon
1714
@testable import OpenTelemetryProtocolExporterHttp

Tests/ExportersTests/OpenTelemetryProtocol/OtlpHTTPMetricsExporterTest.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,23 @@
55

66
import Foundation
77
import Logging
8-
import NIO
9-
import NIOHTTP1
10-
import NIOTestUtils
118
import OpenTelemetryApi
129
import OpenTelemetryProtocolExporterCommon
1310
@testable import OpenTelemetryProtocolExporterHttp
1411
@testable import OpenTelemetrySdk
1512
import XCTest
13+
import SharedTestUtils
1614

1715
class OtlpHttpMetricsExporterTest: XCTestCase {
18-
var testServer: NIOHTTP1TestServer!
19-
var group: MultiThreadedEventLoopGroup!
16+
var testServer: HttpTestServer!
2017

2118
override func setUp() {
22-
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
23-
testServer = NIOHTTP1TestServer(group: group)
19+
testServer = HttpTestServer()
20+
XCTAssertNoThrow(try testServer.start())
2421
}
2522

2623
override func tearDown() {
2724
XCTAssertNoThrow(try testServer.stop())
28-
XCTAssertNoThrow(try group.syncShutdownGracefully())
2925
}
3026

3127
// The shutdown() function is a no-op, This test is just here to make codecov happy
@@ -51,7 +47,9 @@ class OtlpHttpMetricsExporterTest: XCTestCase {
5147
XCTAssertEqual("headerValue", head.headers.first(name: "headerName"))
5248
})
5349

54-
XCTAssertNotNil(try testServer.receiveBodyAndVerify())
50+
XCTAssertNoThrow(try testServer.receiveBodyAndVerify { _ in
51+
// Body verified
52+
})
5553
XCTAssertNoThrow(try testServer.receiveEnd())
5654
}
5755

@@ -80,10 +78,9 @@ class OtlpHttpMetricsExporterTest: XCTestCase {
8078
})
8179

8280
XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
83-
var contentsBuffer = ByteBuffer(buffer: body)
84-
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
81+
let bodyString = String(decoding: body, as: UTF8.self)
8582
for metricDescription in metricDescriptions {
86-
XCTAssertTrue(contents.contains(metricDescription))
83+
XCTAssertTrue(bodyString.contains(metricDescription))
8784
}
8885
})
8986

@@ -115,10 +112,9 @@ class OtlpHttpMetricsExporterTest: XCTestCase {
115112
})
116113

117114
XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
118-
var contentsBuffer = ByteBuffer(buffer: body)
119-
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
115+
let bodyString = String(decoding: body, as: UTF8.self)
120116
for metricDescription in metricDescriptions {
121-
XCTAssertTrue(contents.contains(metricDescription))
117+
XCTAssertTrue(bodyString.contains(metricDescription))
122118
}
123119
})
124120

Tests/ExportersTests/OpenTelemetryProtocol/OtlpHttpLogRecordExporterTests.swift

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,20 @@
55

66
import Foundation
77
import Logging
8-
import NIO
9-
import NIOHTTP1
10-
import NIOTestUtils
118
import OpenTelemetryApi
129
import OpenTelemetryProtocolExporterCommon
1310
@testable import OpenTelemetryProtocolExporterHttp
1411
@testable import OpenTelemetrySdk
1512
import XCTest
13+
import SharedTestUtils
1614

1715
class OtlpHttpLogRecordExporterTests: XCTestCase {
18-
var testServer: NIOHTTP1TestServer!
19-
var group: MultiThreadedEventLoopGroup!
16+
var testServer: HttpTestServer!
2017
var spanContext: SpanContext!
2118

2219
override func setUp() {
23-
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
24-
testServer = NIOHTTP1TestServer(group: group)
20+
testServer = HttpTestServer()
21+
XCTAssertNoThrow(try testServer.start())
2522

2623
let spanId = SpanId.random()
2724
let traceId = TraceId.random()
@@ -30,7 +27,6 @@ class OtlpHttpLogRecordExporterTests: XCTestCase {
3027

3128
override func tearDown() {
3229
XCTAssertNoThrow(try testServer.stop())
33-
XCTAssertNoThrow(try group.syncShutdownGracefully())
3430
}
3531

3632
func testExport() {
@@ -60,9 +56,8 @@ class OtlpHttpLogRecordExporterTests: XCTestCase {
6056
XCTAssertEqual(otelVersion, head.headers.first(name: Constants.HTTP.userAgent))
6157
})
6258
XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
63-
var contentsBuffer = ByteBuffer(buffer: body)
64-
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
65-
XCTAssertTrue(contents.description.contains(testBody.description))
59+
let bodyString = String(decoding: body, as: UTF8.self)
60+
XCTAssertTrue(bodyString.contains(testBody.description))
6661
})
6762

6863
XCTAssertNoThrow(try testServer.receiveEnd())

Tests/ExportersTests/OpenTelemetryProtocol/OtlpHttpTraceExporterTests.swift

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,23 @@ import Foundation
88
import FoundationNetworking
99
#endif
1010
import Logging
11-
import NIO
12-
import NIOHTTP1
13-
import NIOTestUtils
1411
import OpenTelemetryApi
1512
import OpenTelemetryProtocolExporterCommon
1613
@testable import OpenTelemetryProtocolExporterHttp
1714
@testable import OpenTelemetrySdk
1815
import XCTest
16+
import SharedTestUtils
1917

2018
class OtlpHttpTraceExporterTests: XCTestCase {
21-
var testServer: NIOHTTP1TestServer!
22-
var group: MultiThreadedEventLoopGroup!
19+
var testServer: HttpTestServer!
2320

2421
override func setUp() {
25-
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
26-
testServer = NIOHTTP1TestServer(group: group)
22+
testServer = HttpTestServer()
23+
XCTAssertNoThrow(try testServer.start())
2724
}
2825

2926
override func tearDown() {
3027
XCTAssertNoThrow(try testServer.stop())
31-
XCTAssertNoThrow(try group.syncShutdownGracefully())
3228
}
3329

3430
// This is a somewhat hacky solution to verifying that the spans got across correctly. It simply looks for the metric
@@ -56,10 +52,11 @@ class OtlpHttpTraceExporterTests: XCTestCase {
5652
XCTAssertEqual(otelVersion, head.headers.first(name: Constants.HTTP.userAgent))
5753
})
5854
XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
59-
var contentsBuffer = ByteBuffer(buffer: body)
60-
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
61-
XCTAssertTrue(contents.contains(endpointName1))
62-
XCTAssertTrue(contents.contains(endpointName2))
55+
XCTAssertTrue(body.count > 0, "Body should not be empty")
56+
// Check that endpoint names are present in the protobuf data
57+
let bodyString = String(decoding: body, as: UTF8.self)
58+
XCTAssertTrue(bodyString.contains(endpointName1))
59+
XCTAssertTrue(bodyString.contains(endpointName2))
6360
})
6461

6562
XCTAssertNoThrow(try testServer.receiveEnd())
@@ -68,6 +65,9 @@ class OtlpHttpTraceExporterTests: XCTestCase {
6865
// This is not a thorough test of HTTPClient, but just enough to keep code coverage happy.
6966
// There is a more complete test as part of the DataDog exporter test
7067
func testHttpClient() {
68+
// Clear any previous requests
69+
testServer.clearReceivedRequests()
70+
7171
let endpoint = URL(string: "http://localhost:\(testServer.serverPort)/some-route")!
7272
let httpClient = BaseHTTPClient()
7373
var request = URLRequest(url: endpoint)
@@ -76,7 +76,7 @@ class OtlpHttpTraceExporterTests: XCTestCase {
7676
httpClient.send(request: request) { result in
7777
switch result {
7878
case let .success(response):
79-
XCTAssertEqual(HTTPResponseStatus.imATeapot.code, UInt(response.statusCode))
79+
XCTAssertEqual(HTTPResponseStatus.ok.code, UInt(response.statusCode))
8080
case let .failure(error):
8181
XCTFail("Send failed: \(error)")
8282
}
@@ -85,16 +85,10 @@ class OtlpHttpTraceExporterTests: XCTestCase {
8585
// Assert the server received the expected request.
8686
XCTAssertNoThrow(try testServer.receiveHeadAndVerify { head in
8787
XCTAssertEqual(head.version, .http1_1)
88-
XCTAssertEqual(head.method, .GET)
88+
XCTAssertEqual(head.method.rawValue, "GET")
8989
XCTAssertEqual(head.uri, "/some-route")
9090
})
91-
XCTAssertNoThrow(try testServer.receiveEndAndVerify { trailers in
92-
XCTAssertNil(trailers)
93-
})
94-
95-
// Make the server send a response to the client.
96-
XCTAssertNoThrow(try testServer.writeOutbound(.head(.init(version: .http1_1, status: .imATeapot))))
97-
XCTAssertNoThrow(try testServer.writeOutbound(.end(nil)))
91+
XCTAssertNoThrow(try testServer.receiveEnd())
9892
}
9993

10094
func testFlush() {

Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@testable import OpenTelemetrySdk
88
@testable import URLSessionInstrumentation
99
import XCTest
10+
import SharedTestUtils
1011

1112
class URLSessionInstrumentationTests: XCTestCase {
1213
class Check {

Tests/InstrumentationTests/URLSessionTests/Utils/HttpTestServer.swift

Lines changed: 0 additions & 142 deletions
This file was deleted.

0 commit comments

Comments
 (0)