Make tests work on 32-bit (#486)

* 32-bit fix for tests: Replace 0xDEADBEEF w/ 0x1337BEEF

Motivation:

Make tests compile on Raspberry Pi.

Modifications:

- Change tests so that they compile on 32-bit machines,
like Raspi. Replaced 0xDEADBEEF which doesn't fit into
an Int32, w/ 0x1337BEEF.
- make ByteBuffer work better on 32-bit
- fix other wrong assertions and limits that are too big on 32bit

Also use TimeAmount.Value in one test.

Result:

Tests will compile on Raspi ...
This commit is contained in:
Helge Heß 2018-08-16 19:05:11 +02:00 committed by Johannes Weiss
parent 0ce3cf5b79
commit e8c04e0eca
9 changed files with 83 additions and 35 deletions

View File

@ -112,7 +112,9 @@ extension FixedWidthInteger {
}
extension UInt32 {
/// Returns the next power of two unless that would overflow in which case UInt32.max is returned.
/// Returns the next power of two unless that would overflow, in which case UInt32.max (on 64-bit systems) or
/// Int32.max (on 32-bit systems) is returned. The returned value is always safe to be cast to Int and passed
/// to malloc on all platforms.
public func nextPowerOf2ClampedToMax() -> UInt32 {
guard self > 0 else {
return 1
@ -120,13 +122,19 @@ extension UInt32 {
var n = self
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let max = UInt32(Int32.max)
#else
let max = UInt32.max
#endif
n -= 1
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
if n != .max {
if n != max {
n += 1
}

View File

@ -20,7 +20,14 @@ public typealias IOVector = iovec
/// The maximum number of bytes to write per `writev` call.
static var writevLimitBytes: Int {
return Int(Int32.max)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// Note(hh): This is not a _proper_ fix, but necessary because
// other places extend on that. Should be fine in
// practice on 32-bit platforms.
return Int(Int32.max / 4)
#else
return Int(Int32.max)
#endif
}
/// The maximum number of `IOVector`s to write per `writev` call.

View File

@ -16,7 +16,14 @@ import NIO
private let maxOneByteSize = 125
private let maxTwoByteSize = Int(UInt16.max)
private let maxNIOFrameSize = Int(UInt32.max)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// Note(hh): This is not a _proper_ fix, but necessary because
// other places extend on that. Should be fine in
// practice on 32-bit platforms.
private let maxNIOFrameSize = Int(Int32.max / 4)
#else
private let maxNIOFrameSize = Int(UInt32.max)
#endif
/// An inbound `ChannelHandler` that serializes structured websocket frames into a byte stream
/// for sending on the network.

View File

@ -1073,22 +1073,37 @@ class ByteBufferTest: XCTestCase {
}
func testAllocationOfReallyBigByteBuffer() throws {
let alloc = ByteBufferAllocator(hookedMalloc: { testAllocationOfReallyBigByteBuffer_mallocHook($0) },
hookedRealloc: { testAllocationOfReallyBigByteBuffer_reallocHook($0, $1) },
hookedFree: { testAllocationOfReallyBigByteBuffer_freeHook($0) },
hookedMemcpy: { testAllocationOfReallyBigByteBuffer_memcpyHook($0, $1, $2) })
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// FIXME: Fails hard on Raspi 32-bit even with Int16.max in `__memcpy_neon`. Figure out how and why.
XCTAssertTrue(false, "testAllocationOfReallyBigByteBuffer fails on 32-bit Raspi")
#else
let alloc = ByteBufferAllocator(hookedMalloc: { testAllocationOfReallyBigByteBuffer_mallocHook($0) },
hookedRealloc: { testAllocationOfReallyBigByteBuffer_reallocHook($0, $1) },
hookedFree: { testAllocationOfReallyBigByteBuffer_freeHook($0) },
hookedMemcpy: { testAllocationOfReallyBigByteBuffer_memcpyHook($0, $1, $2) })
XCTAssertEqual(AllocationExpectationState.begin, testAllocationOfReallyBigByteBuffer_state)
var buf = alloc.buffer(capacity: Int(Int32.max))
XCTAssertEqual(AllocationExpectationState.mallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertGreaterThanOrEqual(buf.capacity, Int(Int32.max))
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let reallyBigSize = Int(Int16.max) // well, but Int32 is too big (1GB RAM, no swap)
#else
let reallyBigSize = Int(Int32.max)
#endif
XCTAssertEqual(AllocationExpectationState.begin, testAllocationOfReallyBigByteBuffer_state)
var buf = alloc.buffer(capacity: reallyBigSize)
XCTAssertEqual(AllocationExpectationState.mallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertGreaterThanOrEqual(buf.capacity, reallyBigSize)
buf.set(bytes: [1], at: 0)
/* now make it expand (will trigger realloc) */
buf.set(bytes: [1], at: buf.capacity)
buf.set(bytes: [1], at: 0)
/* now make it expand (will trigger realloc) */
buf.set(bytes: [1], at: buf.capacity)
XCTAssertEqual(AllocationExpectationState.reallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertEqual(buf.capacity, Int(UInt32.max))
XCTAssertEqual(AllocationExpectationState.reallocDone, testAllocationOfReallyBigByteBuffer_state)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// TODO(hh): no idea, but not UInt32.max :-)
XCTAssertGreaterThanOrEqual(buf.capacity, reallyBigSize)
#else
XCTAssertEqual(buf.capacity, Int(UInt32.max))
#endif
#endif
}
func testWritableBytesAccountsForSlicing() throws {

View File

@ -157,9 +157,15 @@ public class ChannelTests: XCTestCase {
for _ in 0..<bufferSize {
buffer.write(staticString: "a")
}
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let lotsOfData = Int(Int32.max / 8)
#else
let lotsOfData = Int(Int32.max)
#endif
var written = 0
while written <= Int(INT32_MAX) {
while written <= lotsOfData {
clientChannel.write(NIOAny(buffer), promise: nil)
written += bufferSize
}
@ -208,7 +214,7 @@ public class ChannelTests: XCTestCase {
var iovecs: [IOVector] = Array(repeating: iovec(), count: Socket.writevLimitIOVectors + 1)
var managed: [Unmanaged<AnyObject>] = Array(repeating: Unmanaged.passUnretained(o), count: Socket.writevLimitIOVectors + 1)
/* put a canary value at the end */
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)!, iov_len: 0xdeadbeef)
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0x1337beef)!, iov_len: 0x1337beef)
try iovecs.withUnsafeMutableBufferPointer { iovecs in
try managed.withUnsafeMutableBufferPointer { managed in
let pwm = NIO.PendingStreamWritesManager(iovecs: iovecs, storageRefs: managed)
@ -225,8 +231,8 @@ public class ChannelTests: XCTestCase {
}
/* assert that the canary values are still okay, we should definitely have never written those */
XCTAssertEqual(managed.last!.toOpaque(), Unmanaged.passUnretained(o).toOpaque())
XCTAssertEqual(0xdeadbeef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0xdeadbeef, iovecs.last!.iov_len)
XCTAssertEqual(0x1337beef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0x1337beef, iovecs.last!.iov_len)
}
}
@ -664,8 +670,8 @@ public class ChannelTests: XCTestCase {
/// Test that with a few massive buffers, we don't offer more than we should to `writev` if the individual chunks fit.
func testPendingWritesNoMoreThanWritevLimitIsWritten() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
@ -696,8 +702,8 @@ public class ChannelTests: XCTestCase {
/// Test that with a massive buffers (bigger than writev size), we don't offer more than we should to `writev`.
func testPendingWritesNoMoreThanWritevLimitIsWrittenInOneMassiveChunk() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */

View File

@ -244,8 +244,13 @@ final class DatagramChannelTests: XCTestCase {
}
let envelope = AddressedEnvelope(remoteAddress: self.secondChannel.localAddress!, data: buffer)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let lotsOfData = Int(Int32.max / 8)
#else
let lotsOfData = Int(Int32.max)
#endif
var written = 0
while written <= Int(INT32_MAX) {
while written <= lotsOfData {
self.firstChannel.write(NIOAny(envelope), promise: myPromise)
overall = EventLoopFuture<Void>.andAll([overall, myPromise.futureResult], eventLoop: self.firstChannel.eventLoop)
written += bufferSize

View File

@ -110,7 +110,7 @@ public class EmbeddedEventLoopTest: XCTestCase {
var sentinel = 0
let loop = EmbeddedEventLoop()
for index in 1...10 {
_ = loop.scheduleTask(in: .nanoseconds(index)) {
_ = loop.scheduleTask(in: .nanoseconds(TimeAmount.Value(index))) {
sentinel = index
}
}

View File

@ -62,7 +62,7 @@ class PendingDatagramWritesManagerTests: XCTestCase {
var msgs: [MMsgHdr] = Array(repeating: MMsgHdr(), count: Socket.writevLimitIOVectors + 1)
var addresses: [sockaddr_storage] = Array(repeating: sockaddr_storage(), count: Socket.writevLimitIOVectors + 1)
/* put a canary value at the end */
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)!, iov_len: 0xdeadbeef)
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0x1337beef)!, iov_len: 0x1337beef)
try iovecs.withUnsafeMutableBufferPointer { iovecs in
try managed.withUnsafeMutableBufferPointer { managed in
try msgs.withUnsafeMutableBufferPointer { msgs in
@ -83,8 +83,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
}
/* assert that the canary values are still okay, we should definitely have never written those */
XCTAssertEqual(managed.last!.toOpaque(), Unmanaged.passUnretained(o).toOpaque())
XCTAssertEqual(0xdeadbeef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0xdeadbeef, iovecs.last!.iov_len)
XCTAssertEqual(0x1337beef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0x1337beef, iovecs.last!.iov_len)
}
}
@ -433,8 +433,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
/// Test that with a few massive buffers, we don't offer more than we should to `writev` if the individual chunks fit.
func testPendingWritesNoMoreThanWritevLimitIsWritten() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
@ -466,8 +466,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
func testPendingWritesNoMoreThanWritevLimitIsWrittenInOneMassiveChunk() throws {
let el = EmbeddedEventLoop()
let address = try SocketAddress(ipAddress: "127.0.0.1", port: 65535)
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */

View File

@ -72,7 +72,7 @@ func runSystemCallWrapperPerformanceTest(testAssertFunction: (@autoclosure () ->
}
let iterations = isDebugMode ? 100_000 : 1_000_000
let pointer = UnsafePointer<UInt8>(bitPattern: 0xdeadbeef)!
let pointer = UnsafePointer<UInt8>(bitPattern: 0x1337beef)!
let directCallTime = try measureRunTime { () -> Int in
/* imitate what the system call wrappers do to have a fair comparison */