Speed up the tests (#3601)

### Motivation

We want our tests to pass in reasonable time.

### Changes

- Disable test
`ByteBufferCrashTests.setBytesWithoutContigiousStorageMoreThanUInt32maxBytes`
- Do not initialize data in `ByteBufferCrashTests.
takingOwnershipOfPointerThatsToLarge`

### Result

Tests are faster again.
This commit is contained in:
Fabian Fett
2026-05-20 12:12:53 +02:00
committed by GitHub
parent b24872d3aa
commit 57c0a08a33
4 changed files with 42 additions and 34 deletions
+12 -13
View File
@@ -31,7 +31,9 @@ public final class NIOHTTPRequestHeadersValidator: ChannelOutboundHandler, Remov
public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) { public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
switch NIOHTTPRequestHeadersValidator.unwrapOutboundIn(data) { switch NIOHTTPRequestHeadersValidator.unwrapOutboundIn(data) {
case .head(let head): case .head(let head):
guard Self.uriOnlyContainsAllowedCharacters(head.uri), head.method.isValidToSend, head.headers.areValidToSend else { guard Self.uriOnlyContainsAllowedCharacters(head.uri), head.method.isValidToSend,
head.headers.areValidToSend
else {
promise?.fail(HTTPParserError.invalidHeaderToken) promise?.fail(HTTPParserError.invalidHeaderToken)
context.fireErrorCaught(HTTPParserError.invalidHeaderToken) context.fireErrorCaught(HTTPParserError.invalidHeaderToken)
return return
@@ -98,10 +100,9 @@ public final class NIOHTTPRequestHeadersValidator: ChannelOutboundHandler, Remov
uri.utf8.allSatisfy { byte in uri.utf8.allSatisfy { byte in
switch byte { switch byte {
case case // unreserved
// unreserved // - ALPHA
// - ALPHA UInt8(ascii: "A")...UInt8(ascii: "Z"), UInt8(ascii: "a")...UInt8(ascii: "z"),
UInt8(ascii: "A")...UInt8(ascii: "Z"), UInt8(ascii: "a")...UInt8(ascii: "z"),
// - DIGIT // - DIGIT
UInt8(ascii: "0")...UInt8(ascii: "9"), UInt8(ascii: "0")...UInt8(ascii: "9"),
// - extra characters // - extra characters
@@ -225,7 +226,7 @@ extension HTTPMethod {
.SOURCE: .SOURCE:
true true
case .RAW(value: let value): case .RAW(let value):
// The spec in [RFC 9110](https://httpwg.org/specs/rfc9110.html#method.overview) defines the valid // The spec in [RFC 9110](https://httpwg.org/specs/rfc9110.html#method.overview) defines the valid
// characters as the following: // characters as the following:
// //
@@ -241,9 +242,8 @@ extension HTTPMethod {
value.utf8.allSatisfy { byte in value.utf8.allSatisfy { byte in
switch byte { switch byte {
case case // ALPHA
// ALPHA UInt8(ascii: "A")...UInt8(ascii: "Z"), UInt8(ascii: "a")...UInt8(ascii: "z"),
UInt8(ascii: "A")...UInt8(ascii: "Z"), UInt8(ascii: "a")...UInt8(ascii: "z"),
// DIGIT // DIGIT
UInt8(ascii: "0")...UInt8(ascii: "9"), UInt8(ascii: "0")...UInt8(ascii: "9"),
// token // token
@@ -337,11 +337,10 @@ extension HTTPResponseStatus {
reasonPhrase.utf8.allSatisfy { byte in reasonPhrase.utf8.allSatisfy { byte in
switch byte { switch byte {
case case 9, // HTAB
9, // HTAB 32, // SP
32, // SP
33...126, // VCHAR 33...126, // VCHAR
128...255: // obs-text 128...255: // obs-text
return true return true
default: default:
return false return false
+1 -1
View File
@@ -156,6 +156,7 @@ extension ChannelPipeline {
/// - enableOutboundHeaderValidation: Whether the pipeline should confirm that outbound headers are well-formed. /// - enableOutboundHeaderValidation: Whether the pipeline should confirm that outbound headers are well-formed.
/// Defaults to `true`. /// Defaults to `true`.
/// - encoderConfiguration: The configuration for the ``HTTPRequestEncoder``. /// - encoderConfiguration: The configuration for the ``HTTPRequestEncoder``.
/// - decoderLimitConfiguration: The limit configuration for the ``HTTPDecoder``.
/// - upgrade: Add a ``NIOHTTPClientUpgradeHandler`` to the pipeline, configured for /// - upgrade: Add a ``NIOHTTPClientUpgradeHandler`` to the pipeline, configured for
/// HTTP upgrade. Should be a tuple of an array of ``NIOHTTPClientUpgradeHandler`` and /// HTTP upgrade. Should be a tuple of an array of ``NIOHTTPClientUpgradeHandler`` and
/// the upgrade completion handler. See the documentation on ``NIOHTTPClientUpgradeHandler`` /// the upgrade completion handler. See the documentation on ``NIOHTTPClientUpgradeHandler``
@@ -389,7 +390,6 @@ extension ChannelPipeline {
) )
} }
private func _configureHTTPServerPipeline( private func _configureHTTPServerPipeline(
position: ChannelPipeline.Position = .last, position: ChannelPipeline.Position = .last,
withPipeliningAssistance pipelining: Bool = true, withPipeliningAssistance pipelining: Bool = true,
@@ -12,9 +12,9 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
import Foundation
@_spi(CustomByteBufferAllocator) import NIOCore @_spi(CustomByteBufferAllocator) import NIOCore
import Testing import Testing
import Foundation
#if compiler(>=6.2) #if compiler(>=6.2)
@Suite struct ByteBufferCrashTests { @Suite struct ByteBufferCrashTests {
@@ -91,7 +91,11 @@ import Foundation
} }
} }
@Test func setBytesWithoutContigiousStorageMoreThanUInt32maxBytes() async { @Test(
.disabled(
"This test is taking too long, as it needs to allocate 4GB of memory. It doesn't work on 32bit machines."
)
) func setBytesWithoutContigiousStorageMoreThanUInt32maxBytes() async {
await #expect(processExitsWith: .failure) { await #expect(processExitsWith: .failure) {
let circularBuffer = CircularBuffer<UInt8>(repeating: 0, count: Int(UInt32.max) + 1) let circularBuffer = CircularBuffer<UInt8>(repeating: 0, count: Int(UInt32.max) + 1)
var bb = ByteBuffer() var bb = ByteBuffer()
@@ -138,12 +142,6 @@ import Foundation
let capacity = Int(UInt32.max) + 1 let capacity = Int(UInt32.max) + 1
let ptr = malloc(capacity)! let ptr = malloc(capacity)!
// Initialize some data in the external memory
let boundPtr = ptr.bindMemory(to: UInt8.self, capacity: capacity)
for i in 0..<capacity {
boundPtr[i] = 1
}
let allocator = ByteBufferCustomAllocatorTest.makeTrackedAllocator() let allocator = ByteBufferCustomAllocatorTest.makeTrackedAllocator()
// this should crash // this should crash
@@ -613,7 +613,12 @@ import Testing
try channel.pipeline.syncOperations.addHTTPClientHandlers() try channel.pipeline.syncOperations.addHTTPClientHandlers()
let headers = HTTPHeaders([("Host", "example.com")]) let headers = HTTPHeaders([("Host", "example.com")])
let goodRequest = HTTPRequestHead(version: .http1_1, method: .RAW(value: weirdAllowedMethodName), uri: "/", headers: headers) let goodRequest = HTTPRequestHead(
version: .http1_1,
method: .RAW(value: weirdAllowedMethodName),
uri: "/",
headers: headers
)
let goodRequestBytes = ByteBuffer( let goodRequestBytes = ByteBuffer(
string: "\(weirdAllowedMethodName) / HTTP/1.1\r\nHost: example.com\r\n\r\n" string: "\(weirdAllowedMethodName) / HTTP/1.1\r\nHost: example.com\r\n\r\n"
) )
@@ -638,7 +643,12 @@ import Testing
try channel.pipeline.syncOperations.addHTTPClientHandlers() try channel.pipeline.syncOperations.addHTTPClientHandlers()
let headers = HTTPHeaders([("Host", "example.com")]) let headers = HTTPHeaders([("Host", "example.com")])
let badRequest = HTTPRequestHead(version: .http1_1, method: .RAW(value: forbiddenFieldName), uri: "/", headers: headers) let badRequest = HTTPRequestHead(
version: .http1_1,
method: .RAW(value: forbiddenFieldName),
uri: "/",
headers: headers
)
let error = #expect( let error = #expect(
throws: HTTPParserError.self, throws: HTTPParserError.self,
@@ -662,9 +672,9 @@ import Testing
// ``` // ```
let allowedRanges: [ClosedRange<UInt8>] = [ let allowedRanges: [ClosedRange<UInt8>] = [
9...9, // HTAB 9...9, // HTAB
32...32, // SP 32...32, // SP
33...126, // VCHAR 33...126, // VCHAR
128...255, // obs-text 128...255, // obs-text
] ]
@@ -693,7 +703,9 @@ import Testing
switch allowed { switch allowed {
case true: case true:
let goodRequestBytes = ByteBuffer(string: "HTTP/1.1 600 \(testReason)\r\ntransfer-encoding: chunked\r\n\r\n") let goodRequestBytes = ByteBuffer(
string: "HTTP/1.1 600 \(testReason)\r\ntransfer-encoding: chunked\r\n\r\n"
)
let goodEnd = ByteBuffer(string: "0\r\n\r\n") let goodEnd = ByteBuffer(string: "0\r\n\r\n")
#expect(throws: Never.self, "Rejected reason phrase with byte: \(byte)") { #expect(throws: Never.self, "Rejected reason phrase with byte: \(byte)") {
try channel.writeOutbound(HTTPServerResponsePart.head(response)) try channel.writeOutbound(HTTPServerResponsePart.head(response))
@@ -829,7 +841,7 @@ import Testing
return String(Unicode.Scalar(byte)) return String(Unicode.Scalar(byte))
case 0xC0, 0xC1: case 0xC0, 0xC1:
return nil // forbidden in UTF-8 return nil // forbidden in UTF-8
case 0xC2...0xDF: case 0xC2...0xDF:
// Lead of 2-byte seq. Smallest scalar with this lead: // Lead of 2-byte seq. Smallest scalar with this lead:
@@ -844,7 +856,7 @@ import Testing
let base = UInt32(byte & 0x0F) << 12 let base = UInt32(byte & 0x0F) << 12
let scalar = (byte == 0xE0) ? 0x0800 : base let scalar = (byte == 0xE0) ? 0x0800 : base
// Skip surrogates if we land in D800DFFF (byte == 0xED) // Skip surrogates if we land in D800DFFF (byte == 0xED)
if byte == 0xED { return String(Unicode.Scalar(0xD000 - 0x0800 + base)!) } // simple pick if byte == 0xED { return String(Unicode.Scalar(0xD000 - 0x0800 + base)!) } // simple pick
return Unicode.Scalar(scalar).map { String($0) } return Unicode.Scalar(scalar).map { String($0) }
case 0xF0...0xF4: case 0xF0...0xF4:
@@ -856,12 +868,12 @@ import Testing
switch byte { switch byte {
case 0xF0: scalar = 0x10000 case 0xF0: scalar = 0x10000
case 0xF4: scalar = 0x100000 case 0xF4: scalar = 0x100000
default: scalar = UInt32(byte & 0x07) << 18 default: scalar = UInt32(byte & 0x07) << 18
} }
return Unicode.Scalar(scalar).map { String($0) } return Unicode.Scalar(scalar).map { String($0) }
default: // 0xF5...0xFF default: // 0xF5...0xFF
return nil // forbidden in UTF-8 return nil // forbidden in UTF-8
} }
} }
} }
@@ -872,4 +884,3 @@ extension EmbeddedChannel {
try self.writeInbound(request) try self.writeInbound(request)
} }
} }