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 #if defined(darwin)
32 #include "P_IOBuffer.h"
33 #endif
34 
35 #include "diags.i"
36 
37 #define TEST_THREADS 1
38 
39 TEST_CASE("MIOBuffer", "[iocore]")
40 {
41   SECTION("new_MIOBuffer 100 times")
42   {
43     int64_t read_avail_len1 = 0;
44     int64_t read_avail_len2 = 0;
45 
46     for (unsigned i = 0; i < 100; ++i) {
47       MIOBuffer *b1            = new_MIOBuffer(BUFFER_SIZE_INDEX_512);
48       int64_t len1             = b1->write_avail();
49       IOBufferReader *b1reader = b1->alloc_reader();
50       b1->fill(len1);
51       read_avail_len1 += b1reader->read_avail();
52 
53       MIOBuffer *b2            = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
54       int64_t len2             = b2->write_avail();
55       IOBufferReader *b2reader = b2->alloc_reader();
56       b2->fill(len2);
57       read_avail_len2 += b2reader->read_avail();
58 
59       free_MIOBuffer(b2);
60       free_MIOBuffer(b1);
61     }
62 
63     CHECK(read_avail_len1 == 100 * BUFFER_SIZE_FOR_INDEX(BUFFER_SIZE_INDEX_512));
64     CHECK(read_avail_len2 == 100 * BUFFER_SIZE_FOR_INDEX(BUFFER_SIZE_INDEX_4K));
65   }
66 
67   SECTION("write")
68   {
69     MIOBuffer *miob            = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
70     IOBufferReader *miob_r     = miob->alloc_reader();
71     const IOBufferBlock *block = miob->first_write_block();
72 
73     SECTION("initial state")
74     {
75       CHECK(miob->size_index == BUFFER_SIZE_INDEX_4K);
76       CHECK(miob->water_mark == 0);
77       CHECK(miob->first_write_block() != nullptr);
78       CHECK(miob->block_size() == 4096);
79       CHECK(miob->block_write_avail() == 4096);
80       CHECK(miob->current_write_avail() == 4096);
81       CHECK(miob->write_avail() == 4096);
82 
83       CHECK(miob->max_read_avail() == 0);
84       CHECK(miob_r->read_avail() == 0);
85     }
86 
87     SECTION("write(const void *rbuf, int64_t nbytes)")
88     {
89       SECTION("1K")
90       {
91         uint8_t buf[1024];
92         memset(buf, 0xAA, sizeof(buf));
93 
94         int64_t written = miob->write(buf, sizeof(buf));
95 
96         REQUIRE(written == sizeof(buf));
97 
98         CHECK(miob->block_size() == 4096);
99         CHECK(miob->block_write_avail() == 3072);
100         CHECK(miob->current_write_avail() == 3072);
101         CHECK(miob->write_avail() == 3072);
102 
103         CHECK(miob->first_write_block() == block);
104 
105         CHECK(miob->max_read_avail() == sizeof(buf));
106         CHECK(miob_r->read_avail() == sizeof(buf));
107       }
108 
109       SECTION("4K")
110       {
111         uint8_t buf[4096];
112         memset(buf, 0xAA, sizeof(buf));
113 
114         int64_t written = miob->write(buf, sizeof(buf));
115 
116         REQUIRE(written == sizeof(buf));
117 
118         CHECK(miob->block_size() == 4096);
119         CHECK(miob->block_write_avail() == 0);
120         CHECK(miob->current_write_avail() == 0);
121         CHECK(miob->write_avail() == 0);
122 
123         CHECK(miob->first_write_block() == block);
124 
125         CHECK(miob->max_read_avail() == sizeof(buf));
126         CHECK(miob_r->read_avail() == sizeof(buf));
127       }
128 
129       SECTION("5K")
130       {
131         uint8_t buf[5120];
132         memset(buf, 0xAA, sizeof(buf));
133 
134         int64_t written = miob->write(buf, sizeof(buf));
135 
136         REQUIRE(written == sizeof(buf));
137 
138         CHECK(miob->block_size() == 4096);
139         CHECK(miob->block_write_avail() == 3072);
140         CHECK(miob->current_write_avail() == 3072);
141         CHECK(miob->write_avail() == 3072);
142 
143         CHECK(miob->first_write_block() != block);
144 
145         CHECK(miob->max_read_avail() == sizeof(buf));
146         CHECK(miob_r->read_avail() == sizeof(buf));
147       }
148 
149       SECTION("8K")
150       {
151         uint8_t buf[8192];
152         memset(buf, 0xAA, sizeof(buf));
153 
154         int64_t written = miob->write(buf, sizeof(buf));
155 
156         REQUIRE(written == sizeof(buf));
157 
158         CHECK(miob->block_size() == 4096);
159         CHECK(miob->block_write_avail() == 0);
160         CHECK(miob->current_write_avail() == 0);
161         CHECK(miob->write_avail() == 0);
162 
163         CHECK(miob->first_write_block() != block);
164 
165         CHECK(miob->max_read_avail() == sizeof(buf));
166         CHECK(miob_r->read_avail() == sizeof(buf));
167       }
168     }
169 
170     free_MIOBuffer(miob);
171   }
172 
173   SECTION("write_avail")
174   {
175     MIOBuffer *miob        = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
176     IOBufferReader *miob_r = miob->alloc_reader();
177     uint8_t buf[8192];
178     memset(buf, 0xAA, sizeof(buf));
179 
180     // initial state
181     CHECK(miob->block_size() == 4096);
182     CHECK(miob->current_write_avail() == 4096);
183     CHECK(miob->write_avail() == 4096);
184 
185     SECTION("water_mark == 0 (default)")
186     {
187       REQUIRE(miob->water_mark == 0);
188 
189       // fill half of the current buffer
190       miob->write(buf, 2048);
191       CHECK(miob->max_read_avail() == 2048);
192       CHECK(miob->current_write_avail() == 2048);
193       CHECK(miob->high_water() == true);
194       CHECK(miob->current_low_water() == false);
195       CHECK(miob->write_avail() == 2048); ///< should have no side effect
196 
197       // fill all of the current buffer
198       miob->write(buf, 2048);
199       CHECK(miob->max_read_avail() == 4096);
200       CHECK(miob->current_write_avail() == 0);
201       CHECK(miob->high_water() == true);
202       CHECK(miob->current_low_water() == true);
203       CHECK(miob->write_avail() == 0); ///< should have no side effect
204 
205       // consume half of the data
206       miob_r->consume(2048);
207       CHECK(miob->max_read_avail() == 2048);
208       CHECK(miob->current_write_avail() == 0);
209       CHECK(miob->high_water() == true);
210       CHECK(miob->current_low_water() == true);
211       CHECK(miob->write_avail() == 0); ///< should have no side effect
212 
213       // consume all of the data
214       miob_r->consume(2048);
215       CHECK(miob->max_read_avail() == 0);
216       CHECK(miob->current_write_avail() == 0);
217       CHECK(miob->high_water() == false);
218       CHECK(miob->current_low_water() == true);
219       CHECK(miob->write_avail() == 4096); ///< should have a side effect: add a new block
220 
221       CHECK(miob->max_read_avail() == 0);
222       CHECK(miob->current_write_avail() == 4096);
223       CHECK(miob->high_water() == false);
224       CHECK(miob->current_low_water() == false);
225       CHECK(miob->write_avail() == 4096); ///< should have no side effect
226     }
227 
228     SECTION("water_mark == half of block size")
229     {
230       miob->water_mark = 2048;
231       REQUIRE(miob->water_mark * 2 == miob->block_size());
232 
233       // fill half of the current buffer
234       miob->write(buf, 2048);
235       CHECK(miob->max_read_avail() == 2048);
236       CHECK(miob->current_write_avail() == 2048);
237       CHECK(miob->high_water() == false);
238       CHECK(miob->current_low_water() == true);
239       CHECK(miob->write_avail() == 6144); ///< should have a side effect: add a new block
240 
241       CHECK(miob->max_read_avail() == 2048);
242       CHECK(miob->current_write_avail() == 6144);
243       CHECK(miob->high_water() == false);
244       CHECK(miob->current_low_water() == false);
245       CHECK(miob->write_avail() == 6144); ///< should have no side effect
246 
247       // fill all of the current buffer
248       miob->write(buf, 6144);
249       CHECK(miob->max_read_avail() == 8192);
250       CHECK(miob->current_write_avail() == 0);
251       CHECK(miob->high_water() == true);
252       CHECK(miob->current_low_water() == true);
253       CHECK(miob->write_avail() == 0); ///< should have no side effect
254 
255       // consume half of the data
256       miob_r->consume(4096);
257       CHECK(miob->max_read_avail() == 4096);
258       CHECK(miob->current_write_avail() == 0);
259       CHECK(miob->high_water() == true);
260       CHECK(miob->current_low_water() == true);
261       CHECK(miob->write_avail() == 0); ///< should have no side effect
262 
263       // consume all of the data
264       miob_r->consume(4096);
265       CHECK(miob->max_read_avail() == 0);
266       CHECK(miob->current_write_avail() == 0);
267       CHECK(miob->high_water() == false);
268       CHECK(miob->current_low_water() == true);
269       CHECK(miob->write_avail() == 4096); ///< should have a side effect: add a new block
270 
271       CHECK(miob->max_read_avail() == 0);
272       CHECK(miob->current_write_avail() == 4096);
273       CHECK(miob->high_water() == false);
274       CHECK(miob->current_low_water() == false);
275       CHECK(miob->write_avail() == 4096); ///< should have no side effect
276     }
277 
278     SECTION("water_mark == block_size()")
279     {
280       miob->water_mark = 4096;
281       REQUIRE(miob->water_mark == miob->block_size());
282 
283       // fill half of the current buffer
284       miob->write(buf, 2048);
285       CHECK(miob->max_read_avail() == 2048);
286       CHECK(miob->current_write_avail() == 2048);
287       CHECK(miob->high_water() == false);
288       CHECK(miob->current_low_water() == true);
289       CHECK(miob->write_avail() == 6144); ///< should have a side effect: add a new block
290 
291       CHECK(miob->max_read_avail() == 2048);
292       CHECK(miob->current_write_avail() == 6144);
293       CHECK(miob->high_water() == false);
294       CHECK(miob->current_low_water() == false);
295       CHECK(miob->write_avail() == 6144); ///< should have no side effect
296 
297       // fill all of the current buffer
298       miob->write(buf, 6144);
299       CHECK(miob->max_read_avail() == 8192);
300       CHECK(miob->current_write_avail() == 0);
301       CHECK(miob->high_water() == true);
302       CHECK(miob->current_low_water() == true);
303       CHECK(miob->write_avail() == 0); ///< should have no side effect
304 
305       // consume half of the data
306       miob_r->consume(4096);
307       CHECK(miob->max_read_avail() == 4096);
308       CHECK(miob->current_write_avail() == 0);
309       CHECK(miob->high_water() == false);
310       CHECK(miob->current_low_water() == true);
311       CHECK(miob->write_avail() == 4096); ///< should have a side effect: add a new block
312       IOBufferBlock *tail = miob->_writer->next.get();
313       CHECK(tail != nullptr);
314 
315       CHECK(miob->max_read_avail() == 4096);
316       CHECK(miob->current_write_avail() == 4096);
317       CHECK(miob->high_water() == false);
318       CHECK(miob->current_low_water() == true);
319       CHECK(miob->write_avail() == 4096);       ///< should have no side effect
320       CHECK(tail == miob->_writer->next.get()); ///< the tail block should not be changed
321 
322       // consume all of the data
323       miob_r->consume(4096);
324       CHECK(miob->max_read_avail() == 0);
325       CHECK(miob->current_write_avail() == 4096);
326       CHECK(miob->high_water() == false);
327       CHECK(miob->current_low_water() == true);
328       CHECK(miob->write_avail() == 4096);       ///< should have no side effect
329       CHECK(tail == miob->_writer->next.get()); ///< the tail block should not be changed
330     }
331 
332     free_MIOBuffer(miob);
333   }
334 }
335 
336 struct EventProcessorListener : Catch::TestEventListenerBase {
337   using TestEventListenerBase::TestEventListenerBase;
338 
339   void
testRunStartingEventProcessorListener340   testRunStarting(Catch::TestRunInfo const &testRunInfo) override
341   {
342     Layout::create();
343     init_diags("", nullptr);
344     RecProcessInit(RECM_STAND_ALONE);
345 
346     LibRecordsConfigInit();
347 
348     ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION);
349     eventProcessor.start(TEST_THREADS);
350 
351     EThread *main_thread = new EThread;
352     main_thread->set_specific();
353   }
354 };
355 
356 CATCH_REGISTER_LISTENER(EventProcessorListener);
357