File: RecvByteBufAllocatorTest.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (143 lines) | stat: -rw-r--r-- 6,719 bytes parent folder | download
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)
    }
}