1 /** @file
2 
3   Catch based unit tests for IOBuffer
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #define CATCH_CONFIG_MAIN
25 #include "catch.hpp"
26 
27 #include "tscore/I_Layout.h"
28 
29 #include "I_EventSystem.h"
30 #include "RecordsConfig.h"
31 
32 #include "diags.i"
33 
34 #define TEST_THREADS 1
35 
36 TEST_CASE("MIOBuffer", "[iocore]")
37 {
38   // These value could be tweaked by `ink_event_system_init()` using `proxy.config.io.max_buffer_size`
39   REQUIRE(default_small_iobuffer_size == DEFAULT_SMALL_BUFFER_SIZE);
40   REQUIRE(default_large_iobuffer_size == DEFAULT_LARGE_BUFFER_SIZE);
41 
42   REQUIRE(BUFFER_SIZE_FOR_INDEX(default_small_iobuffer_size) == 512);
43   REQUIRE(BUFFER_SIZE_FOR_INDEX(default_large_iobuffer_size) == 4096);
44 
45   SECTION("new_MIOBuffer 100 times")
46   {
47     int64_t read_avail_len1 = 0;
48     int64_t read_avail_len2 = 0;
49 
50     for (unsigned i = 0; i < 100; ++i) {
51       MIOBuffer *b1            = new_MIOBuffer(default_small_iobuffer_size);
52       int64_t len1             = b1->write_avail();
53       IOBufferReader *b1reader = b1->alloc_reader();
54       b1->fill(len1);
55       read_avail_len1 += b1reader->read_avail();
56 
57       MIOBuffer *b2            = new_MIOBuffer(default_large_iobuffer_size);
58       int64_t len2             = b2->write_avail();
59       IOBufferReader *b2reader = b2->alloc_reader();
60       b2->fill(len2);
61       read_avail_len2 += b2reader->read_avail();
62 
63       free_MIOBuffer(b2);
64       free_MIOBuffer(b1);
65     }
66 
67     CHECK(read_avail_len1 == 100 * BUFFER_SIZE_FOR_INDEX(default_small_iobuffer_size));
68     CHECK(read_avail_len2 == 100 * BUFFER_SIZE_FOR_INDEX(default_large_iobuffer_size));
69   }
70 
71   SECTION("write")
72   {
73     MIOBuffer *miob            = new_MIOBuffer();
74     IOBufferReader *miob_r     = miob->alloc_reader();
75     const IOBufferBlock *block = miob->first_write_block();
76 
77     SECTION("initial state")
78     {
79       CHECK(miob->size_index == default_large_iobuffer_size);
80       CHECK(miob->water_mark == 0);
81       CHECK(miob->first_write_block() != nullptr);
82       CHECK(miob->block_size() == 4096);
83       CHECK(miob->block_write_avail() == 4096);
84       CHECK(miob->current_write_avail() == 4096);
85       CHECK(miob->write_avail() == 4096);
86 
87       CHECK(miob->max_read_avail() == 0);
88       CHECK(miob_r->read_avail() == 0);
89     }
90 
91     SECTION("write(const void *rbuf, int64_t nbytes)")
92     {
93       SECTION("1K")
94       {
95         uint8_t buf[1024];
96         memset(buf, 0xAA, sizeof(buf));
97 
98         int64_t written = miob->write(buf, sizeof(buf));
99 
100         REQUIRE(written == sizeof(buf));
101 
102         CHECK(miob->block_size() == 4096);
103         CHECK(miob->block_write_avail() == 3072);
104         CHECK(miob->current_write_avail() == 3072);
105         CHECK(miob->write_avail() == 3072);
106 
107         CHECK(miob->first_write_block() == block);
108 
109         CHECK(miob->max_read_avail() == sizeof(buf));
110         CHECK(miob_r->read_avail() == sizeof(buf));
111       }
112 
113       SECTION("4K")
114       {
115         uint8_t buf[4096];
116         memset(buf, 0xAA, sizeof(buf));
117 
118         int64_t written = miob->write(buf, sizeof(buf));
119 
120         REQUIRE(written == sizeof(buf));
121 
122         CHECK(miob->block_size() == 4096);
123         CHECK(miob->block_write_avail() == 0);
124         CHECK(miob->current_write_avail() == 0);
125         CHECK(miob->write_avail() == 0);
126 
127         CHECK(miob->first_write_block() == block);
128 
129         CHECK(miob->max_read_avail() == sizeof(buf));
130         CHECK(miob_r->read_avail() == sizeof(buf));
131       }
132 
133       SECTION("5K")
134       {
135         uint8_t buf[5120];
136         memset(buf, 0xAA, sizeof(buf));
137 
138         int64_t written = miob->write(buf, sizeof(buf));
139 
140         REQUIRE(written == sizeof(buf));
141 
142         CHECK(miob->block_size() == 4096);
143         CHECK(miob->block_write_avail() == 3072);
144         CHECK(miob->current_write_avail() == 3072);
145         CHECK(miob->write_avail() == 3072);
146 
147         CHECK(miob->first_write_block() != block);
148 
149         CHECK(miob->max_read_avail() == sizeof(buf));
150         CHECK(miob_r->read_avail() == sizeof(buf));
151       }
152 
153       SECTION("8K")
154       {
155         uint8_t buf[8192];
156         memset(buf, 0xAA, sizeof(buf));
157 
158         int64_t written = miob->write(buf, sizeof(buf));
159 
160         REQUIRE(written == sizeof(buf));
161 
162         CHECK(miob->block_size() == 4096);
163         CHECK(miob->block_write_avail() == 0);
164         CHECK(miob->current_write_avail() == 0);
165         CHECK(miob->write_avail() == 0);
166 
167         CHECK(miob->first_write_block() != block);
168 
169         CHECK(miob->max_read_avail() == sizeof(buf));
170         CHECK(miob_r->read_avail() == sizeof(buf));
171       }
172     }
173 
174     free_MIOBuffer(miob);
175   }
176 }
177 
178 struct EventProcessorListener : Catch::TestEventListenerBase {
179   using TestEventListenerBase::TestEventListenerBase;
180 
181   void
182   testRunStarting(Catch::TestRunInfo const &testRunInfo) override
183   {
184     Layout::create();
185     init_diags("", nullptr);
186     RecProcessInit(RECM_STAND_ALONE);
187 
188     // Initialize LibRecordsConfig for `proxy.config.io.max_buffer_size` (32K)
189     LibRecordsConfigInit();
190 
191     ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION);
192     eventProcessor.start(TEST_THREADS);
193 
194     EThread *main_thread = new EThread;
195     main_thread->set_specific();
196   }
197 };
198 
199 CATCH_REGISTER_LISTENER(EventProcessorListener);
200