Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnzhou committed Jan 4, 2024
2 parents d45a698 + 45c64b0 commit 6f5b61a
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 18 deletions.
7 changes: 4 additions & 3 deletions Mock/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get():

@app.route("/server-timing", methods=['GET'])
def get_server_timing():
use_empty_server_timing = request.headers.get("Use-Empty-Server-Timing", False)
use_empty_server_timing = request.headers.get("Use-Empty-Server-Timing", "False")
use_empty_server_timing = use_empty_server_timing.lower() in ['true', 'yes']

num_server_timing_metrics = request.headers.get("Number-Of-Metrics", 1)
Expand All @@ -60,7 +60,7 @@ def get_server_timing():
desired_status_code = request.headers.get("Status-Code", 200)

response = _generate_response(desired_status_code=desired_status_code)
if use_empty_server_timing:
if not use_empty_server_timing:
response.headers.set("Server-Timing", "")
else:
res = ""
Expand All @@ -73,5 +73,6 @@ def get_server_timing():
if i != num_server_timing_metrics - 1:
res += ", "
response.headers.set("Server-Timing", res)
print(f"response header is {response.headers}")
return response


5 changes: 5 additions & 0 deletions Sources/LCLPing/HTTP/HTTPPing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ internal struct HTTPPing: Pingable {
let resolvedAddress = try SocketAddress.makeAddressResolvingHost(host, port: Int(port))
logger.debug("resolved address is \(resolvedAddress)")

if pingStatus == .stopped || pingStatus == .error {
return
}

pingStatus = .running
do {
let pingResponses = try await withThrowingTaskGroup(of: PingResponse.self, returning: [PingResponse].self) { group in
Expand Down Expand Up @@ -133,6 +137,7 @@ internal struct HTTPPing: Pingable {

return try NIOAsyncChannel<PingResponse, HTTPOutboundIn>(wrappingChannelSynchronously: channel)
}.get()

asyncChannel.channel.pipeline.fireChannelActive()

logger.debug("pipeline is: \(asyncChannel.channel.pipeline.debugDescription)")
Expand Down
3 changes: 3 additions & 0 deletions Sources/LCLPing/ICMP/ICMPPing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ internal struct ICMPPing: Pingable {
let rewriteHeaders = rewriteHeaders
#endif

if pingStatus == .stopped || pingStatus == .error {
return
}

do {
asyncChannel = try await DatagramBootstrap(group: group)
Expand Down
2 changes: 1 addition & 1 deletion Sources/LCLPing/Utilities/PingState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Foundation


/// Possible states of an instance of LCLPing
public enum PingState {
public enum PingState: Equatable {

/// LCLPing is ready to initiate ping requests
case ready
Expand Down
151 changes: 149 additions & 2 deletions Tests/IntegrationTests/HTTPIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ final class HTTPIntegrationTests: XCTestCase {
return (PingState.error, nil)
}


func testfullyConnectedNetwork() async throws {
let (pingStatus, pingSummary) = try await runTest()
switch pingStatus {
Expand Down Expand Up @@ -109,6 +108,7 @@ final class HTTPIntegrationTests: XCTestCase {
}

func testMinorInOutPacketDrop() async throws {
throw XCTSkip("Skipped: re-enable test after https://github.com/apple/swift-nio/issues/2612 is fixed")
let networkLink = TrafficControllerChannelHandler.NetworkLinkConfiguration(inPacketLoss: 0.1, outPacketLoss: 0.1)
let (pingStatus, _) = try await runTest(networkLinkConfig: networkLink)
switch pingStatus {
Expand Down Expand Up @@ -164,9 +164,156 @@ final class HTTPIntegrationTests: XCTestCase {
XCTFail("HTTP Test failed with status \(pingStatus)")
}
}

}

func testBasicServerTiming() async throws {
var httpOptions = LCLPing.PingConfiguration.HTTPOptions()
let desiredHeaders = [
"Status-Code": "200",
"Use-Empty-Server-Timing": "False",
"Number-Of-Metrics": "1"
]
httpOptions.useServerTiming = true
httpOptions.httpHeaders = desiredHeaders
let pingConfig: LCLPing.PingConfiguration = .init(type: .http(httpOptions), endpoint: .ipv4("http://127.0.0.1/server-timing", 8080), count: 3)
let expectedSequenceNumbers: Set<UInt16> = [0, 1, 2]
let (pingStatus, pingSummary) = try await runTest(pingConfig: pingConfig)
switch pingStatus {
case .finished:
XCTAssertEqual(pingSummary?.totalCount, 3)
XCTAssertEqual(pingSummary?.details.count, 3)
pingSummary?.details.forEach { element in
XCTAssertEqual(expectedSequenceNumbers.contains(element.seqNum), true)
}
default:
XCTFail("HTTP Test failed with status \(pingStatus)")
}
}

func testEmptyServerTimingField() async throws {
var httpOptions = LCLPing.PingConfiguration.HTTPOptions()
let desiredHeaders = [
"Status-Code": "200",
"Use-Empty-Server-Timing": "True",
"Number-Of-Metrics": "1"
]
httpOptions.useServerTiming = true
httpOptions.httpHeaders = desiredHeaders
let pingConfig: LCLPing.PingConfiguration = .init(type: .http(httpOptions), endpoint: .ipv4("http://127.0.0.1/server-timing", 8080), count: 3)
let expectedSequenceNumbers: Set<UInt16> = [0, 1, 2]
let (pingStatus, pingSummary) = try await runTest(pingConfig: pingConfig)
switch pingStatus {
case .finished:
XCTAssertEqual(pingSummary?.totalCount, 3)
XCTAssertEqual(pingSummary?.details.count, 3)
pingSummary?.details.forEach { element in
XCTAssertEqual(expectedSequenceNumbers.contains(element.seqNum), true)
}
default:
XCTFail("HTTP Test failed with status \(pingStatus)")
}
}

func testMultipleServerTimingFields() async throws {
var httpOptions = LCLPing.PingConfiguration.HTTPOptions()
let desiredHeaders = [
"Status-Code": "200",
"Use-Empty-Server-Timing": "True",
"Number-Of-Metrics": "4"
]
httpOptions.useServerTiming = true
httpOptions.httpHeaders = desiredHeaders
let pingConfig: LCLPing.PingConfiguration = .init(type: .http(httpOptions), endpoint: .ipv4("http://127.0.0.1/server-timing", 8080), count: 3)
let expectedSequenceNumbers: Set<UInt16> = [0, 1, 2]
let (pingStatus, pingSummary) = try await runTest(pingConfig: pingConfig)
switch pingStatus {
case .finished:
XCTAssertEqual(pingSummary?.totalCount, 3)
XCTAssertEqual(pingSummary?.details.count, 3)
pingSummary?.details.forEach { element in
XCTAssertEqual(expectedSequenceNumbers.contains(element.seqNum), true)
}
default:
XCTFail("HTTP Test failed with status \(pingStatus)")
}
}

func testCancelBeforeTestStarts() async throws {
let networkLinkConfig: TrafficControllerChannelHandler.NetworkLinkConfiguration = .fullyConnected
let pingConfig: LCLPing.PingConfiguration = .init(type: .http(LCLPing.PingConfiguration.HTTPOptions()), endpoint: .ipv4("http://127.0.0.1", 8080))
switch pingConfig.type {
case .http(let httpOptions):
var httpPing = HTTPPing(httpOptions: httpOptions, networkLinkConfig: networkLinkConfig)
httpPing.stop()
try await httpPing.start(with: pingConfig)
switch httpPing.pingStatus {
case .stopped:
XCTAssertNil(httpPing.summary)
default:
XCTFail("Invalid HTTP Ping state. Should be .stopped, but is \(httpPing.pingStatus)")
}
default:
XCTFail("Invalid PingConfig. Need HTTP, but received \(pingConfig.type)")
}
}

// @MainActor
// func testCancelDuringTest() async throws {
// throw XCTSkip("Skipped: the following test after https://github.com/apple/swift-nio/issues/2612 is fixed")
// for waitSecond in [2, 4, 5, 6, 7, 9] {
// let networkLinkConfig: TrafficControllerChannelHandler.NetworkLinkConfiguration = .fullyConnected
// let pingConfig: LCLPing.PingConfiguration = .init(type: .http(LCLPing.PingConfiguration.HTTPOptions()), endpoint: .ipv4("http://127.0.0.1", 8080))
// switch pingConfig.type {
// case .http(let httpOptions):
// var httpPing = HTTPPing(httpOptions: httpOptions, networkLinkConfig: networkLinkConfig)
//
// Task {
// try await Task.sleep(nanoseconds: UInt64(waitSecond) * 1_000_000_000)
// httpPing.stop()
// }
//
// try await httpPing.start(with: pingConfig)
//
// switch httpPing.pingStatus {
// case .stopped:
// XCTAssertNotNil(httpPing.summary?.totalCount)
// XCTAssertLessThanOrEqual(httpPing.summary!.totalCount, waitSecond + 1)
// XCTAssertEqual(httpPing.summary?.details.isEmpty, false)
// XCTAssertEqual(httpPing.summary?.duplicates.count, 0)
// XCTAssertEqual(httpPing.summary?.timeout.count, 0)
// default:
// XCTFail("Invalid HTTP Ping state. Should be .finished, but is \(httpPing.pingStatus)")
// }
// default:
// XCTFail("Invalid PingConfig. Need HTTP, but received \(pingConfig.type)")
// }
// }
// }

func testCancelAfterTestFinishes() async throws {
let networkLinkConfig: TrafficControllerChannelHandler.NetworkLinkConfiguration = .fullyConnected
let pingConfig: LCLPing.PingConfiguration = .init(type: .http(LCLPing.PingConfiguration.HTTPOptions()), endpoint: .ipv4("http://127.0.0.1", 8080), count: 3)
switch pingConfig.type {
case .http(let httpOptions):
var httpPing = HTTPPing(httpOptions: httpOptions, networkLinkConfig: networkLinkConfig)
try await httpPing.start(with: pingConfig)
httpPing.stop()
switch httpPing.pingStatus {
case .finished:
XCTAssertEqual(httpPing.summary?.totalCount, 3)
XCTAssertEqual(httpPing.summary?.details.isEmpty, false)
XCTAssertEqual(httpPing.summary?.duplicates.count, 0)
XCTAssertEqual(httpPing.summary?.timeout.count, 0)
default:
XCTFail("Invalid HTTP Ping state. Should be .finished, but is \(httpPing.pingStatus)")
}
default:
XCTFail("Invalid PingConfig. Need HTTP, but received \(pingConfig.type)")
}
}



// FIXME: re-enable the following test after https://github.com/apple/swift-nio/issues/2612 is fixed

// func testMediumInOutPacketDrop() async throws {
Expand Down
Loading

0 comments on commit 6f5b61a

Please sign in to comment.