1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest
import NIO
final class AdaptiveRecvByteBufferAllocatorTest: XCTestCase {
private let allocator = ByteBufferAllocator()
private var adaptive: AdaptiveRecvByteBufferAllocator!
private var fixed: FixedSizeRecvByteBufferAllocator!
override func setUp() {
self.adaptive = AdaptiveRecvByteBufferAllocator(minimum: 64, initial: 1024, maximum: 16 * 1024)
self.fixed = FixedSizeRecvByteBufferAllocator(capacity: 1024)
}
override func tearDown() {
self.adaptive = nil
self.fixed = nil
}
func testAdaptive() throws {
let buffer = adaptive.buffer(allocator: allocator)
XCTAssertEqual(1024, buffer.capacity)
// We double every time.
testActualReadBytes(mayGrow: true, actualReadBytes: 1024, expectedCapacity: 2048)
testActualReadBytes(mayGrow: true, actualReadBytes: 16384, expectedCapacity: 4096)
testActualReadBytes(mayGrow: true, actualReadBytes: 16384, expectedCapacity: 8192)
testActualReadBytes(mayGrow: true, actualReadBytes: 16384, expectedCapacity: 16384)
// Will never go over maximum
testActualReadBytes(mayGrow: false, actualReadBytes: 32768, expectedCapacity: 16384)
// Shrinks if two successive reads below half happen
testActualReadBytes(mayGrow: false, actualReadBytes: 4096, expectedCapacity: 16384)
testActualReadBytes(mayGrow: false, actualReadBytes: 8192, expectedCapacity: 8192)
testActualReadBytes(mayGrow: false, actualReadBytes: 4096, expectedCapacity: 8192)
testActualReadBytes(mayGrow: false, actualReadBytes: 4096, expectedCapacity: 4096)
// But not if an intermediate read is above half.
testActualReadBytes(mayGrow: false, actualReadBytes: 2048, expectedCapacity: 4096)
testActualReadBytes(mayGrow: false, actualReadBytes: 2049, expectedCapacity: 4096)
testActualReadBytes(mayGrow: false, actualReadBytes: 2048, expectedCapacity: 4096)
// Or if we grow in-between.
testActualReadBytes(mayGrow: true, actualReadBytes: 4096, expectedCapacity: 8192)
testActualReadBytes(mayGrow: false, actualReadBytes: 4096, expectedCapacity: 8192)
testActualReadBytes(mayGrow: false, actualReadBytes: 4096, expectedCapacity: 4096)
// Reads above half never shrink the capacity
for _ in 0..<10 {
testActualReadBytes(mayGrow: false, actualReadBytes: 2049, expectedCapacity: 4096)
}
// Consistently reading below half does shrink all the way down.
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 4096)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 2048)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 2048)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 1024)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 1024)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 512)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 512)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 256)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 256)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 128)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 128)
testActualReadBytes(mayGrow: false, actualReadBytes: 64, expectedCapacity: 64)
// Until the bottom, where it stays forever.
for _ in 0..<10 {
testActualReadBytes(mayGrow: false, actualReadBytes: 1, expectedCapacity: 64)
}
}
private func testActualReadBytes(mayGrow: Bool, actualReadBytes: Int, expectedCapacity: Int, file: StaticString = #file, line: UInt = #line) {
XCTAssertEqual(mayGrow, adaptive.record(actualReadBytes: actualReadBytes), "unexpected value for mayGrow", file: file, line: line)
let buffer = adaptive.buffer(allocator: allocator)
XCTAssertEqual(expectedCapacity, buffer.capacity, "unexpected capacity", file: file, line: line)
}
func testFixed() throws {
var buffer = fixed.buffer(allocator: allocator)
XCTAssertEqual(fixed.capacity, buffer.capacity)
XCTAssert(!fixed.record(actualReadBytes: 32768))
buffer = fixed.buffer(allocator: allocator)
XCTAssertEqual(fixed.capacity, buffer.capacity)
XCTAssert(!fixed.record(actualReadBytes: 64))
buffer = fixed.buffer(allocator: allocator)
XCTAssertEqual(fixed.capacity, buffer.capacity)
}
func testMaxAllocSizeIsIntMax() {
// To find the max alloc size, we're going to search for a fixed point in resizing. To do that we're just going to
// keep saying we read max until we can't resize any longer.
self.adaptive = AdaptiveRecvByteBufferAllocator(minimum: 0, initial: .max / 2, maximum: .max)
var mayGrow = true
while mayGrow {
mayGrow = self.adaptive.record(actualReadBytes: .max)
}
let buffer = self.adaptive.buffer(allocator: self.allocator)
XCTAssertEqual(buffer.capacity, 1 << 30)
XCTAssertEqual(self.adaptive.maximum, 1 << 30)
XCTAssertEqual(self.adaptive.minimum, 0)
}
func testAdaptiveRoundsValues() {
let adaptive = AdaptiveRecvByteBufferAllocator(minimum: 9, initial: 677, maximum: 111111)
XCTAssertEqual(adaptive.minimum, 8)
XCTAssertEqual(adaptive.maximum, 131072)
XCTAssertEqual(adaptive.initial, 512)
}
func testSettingMinimumAboveMaxAllowed() {
guard let targetValue = Int(exactly: Int64.max / 2) else {
// On a 32-bit word platform, this test cannot do anything sensible.
return
}
let adaptive = AdaptiveRecvByteBufferAllocator(minimum: targetValue, initial: targetValue + 1, maximum: targetValue + 2)
XCTAssertEqual(adaptive.minimum, 1 << 30)
XCTAssertEqual(adaptive.maximum, 1 << 30)
XCTAssertEqual(adaptive.initial, 1 << 30)
}
}
|