1 /** @file
2
3 A brief file description
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 /****************************************************************************
25
26 NetVCTest.cc
27
28 Description:
29 Unit test for infrastructure for VConnections implementing the
30 NetVConnection interface
31
32
33
34
35 ****************************************************************************/
36
37 #include "P_Net.h"
38
39 // Each test requires two definition entries. One for the passive
40 // side of the connection and one for the active side
41 //
42 // test fields:
43 //
44 // name bytes_to_send nbytes_write bytes_to_read nbytes_read write_per timeout read_term write_term
45 //
46 NVC_test_def netvc_tests_def[] = {
47
48 {"basic", 2000, 2000, 2000, 2000, 50, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
49 {"basic", 2000, 2000, 2000, 2000, 50, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
50
51 {"basic2", 10001, 10001, 5001, 5001, 1024, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
52 {"basic2", 5001, 5001, 10001, 10001, 1024, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
53
54 {"large", 1000000, 1000000, 500000, 500000, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
55 {"large", 500000, 500000, 1000000, 1000000, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
56
57 // Test large block transfers
58 {"larget", 1000000, 1000000, 500000, 500000, 40000, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
59 {"larget", 500000, 500000, 1000000, 1000000, 40000, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
60
61 {"eos", 4000, 4000, 10, 10, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
62 {"eos", 10, 10, 6000, 6000, 8192, 10, VC_EVENT_EOS, VC_EVENT_WRITE_COMPLETE},
63
64 {"werr", 4000, 4000, 10, 10, 129, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_ERROR},
65 {"werr", 10, 10, 10, 10, 129, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
66
67 {"itimeout", 6000, 8000, 10, 10, 512, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_INACTIVITY_TIMEOUT},
68 {"itimeout", 10, 10, 6000, 8000, 512, 20, VC_EVENT_EOS, VC_EVENT_WRITE_COMPLETE},
69
70 // Test the small transfer code one byte at a time
71 {"smallt", 400, 400, 500, 500, 1, 15, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
72 {"smallt", 500, 500, 400, 400, 1, 15, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE},
73
74 // The purpose of this test is show that stack can over flow if we move too
75 // small of blocks between the buffers. EVENT_NONE is wild card error event
76 // since which side gets the timeout is unpredictable
77 {"overflow", 1000000, 1000000, 50, 50, 1, 20, VC_EVENT_READ_COMPLETE, EVENT_NONE},
78 {"overflow", 50, 50, 0, 35000, 1024, 35, EVENT_NONE, VC_EVENT_WRITE_COMPLETE}
79
80 };
81 const unsigned num_netvc_tests = countof(netvc_tests_def);
82
NetVCTest()83 NetVCTest::NetVCTest() : Continuation(nullptr) {}
84
~NetVCTest()85 NetVCTest::~NetVCTest()
86 {
87 mutex = nullptr;
88
89 if (read_buffer) {
90 Debug(debug_tag, "Freeing read MIOBuffer with %d blocks on %s", read_buffer->max_block_count(),
91 (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive");
92 free_MIOBuffer(read_buffer);
93 read_buffer = nullptr;
94 }
95
96 if (write_buffer) {
97 Debug(debug_tag, "Freeing write MIOBuffer with %d blocks on %s", write_buffer->max_block_count(),
98 (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive");
99 free_MIOBuffer(write_buffer);
100 write_buffer = nullptr;
101 }
102 }
103
104 void
init_test(NetVcTestType_t c_type,NetTestDriver * driver_arg,NetVConnection * nvc,RegressionTest * robj,NVC_test_def * my_def,const char * module_name_arg,const char * debug_tag_arg)105 NetVCTest::init_test(NetVcTestType_t c_type, NetTestDriver *driver_arg, NetVConnection *nvc, RegressionTest *robj,
106 NVC_test_def *my_def, const char *module_name_arg, const char *debug_tag_arg)
107 {
108 test_cont_type = c_type;
109 driver = driver_arg;
110 test_vc = nvc;
111 regress = robj;
112 module_name = module_name_arg;
113 debug_tag = debug_tag_arg;
114
115 bytes_to_send = my_def->bytes_to_send;
116 bytes_to_read = my_def->bytes_to_read;
117
118 nbytes_read = my_def->nbytes_read;
119 nbytes_write = my_def->nbytes_write;
120
121 write_bytes_to_add_per = my_def->write_bytes_per;
122 timeout = my_def->timeout;
123 expected_read_term = my_def->expected_read_term;
124 expected_write_term = my_def->expected_write_term;
125 test_name = my_def->test_name;
126
127 mutex = new_ProxyMutex();
128 SET_HANDLER(&NetVCTest::main_handler);
129
130 if (c_type == NET_VC_TEST_ACTIVE) {
131 start_test();
132 }
133 }
134
135 void
start_test()136 NetVCTest::start_test()
137 {
138 test_vc->set_inactivity_timeout(HRTIME_SECONDS(timeout));
139 test_vc->set_active_timeout(HRTIME_SECONDS(timeout + 5));
140
141 read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
142 write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
143
144 reader_for_rbuf = read_buffer->alloc_reader();
145 reader_for_wbuf = write_buffer->alloc_reader();
146
147 if (nbytes_read > 0) {
148 read_vio = test_vc->do_io_read(this, nbytes_read, read_buffer);
149 } else {
150 read_done = true;
151 }
152
153 if (nbytes_write > 0) {
154 write_vio = test_vc->do_io_write(this, nbytes_write, reader_for_wbuf);
155 } else {
156 write_done = true;
157 }
158 }
159
160 int
fill_buffer(MIOBuffer * buf,uint8_t * seed,int bytes)161 NetVCTest::fill_buffer(MIOBuffer *buf, uint8_t *seed, int bytes)
162 {
163 char *space = static_cast<char *>(ats_malloc(bytes));
164 char *tmp = space;
165 int to_add = bytes;
166
167 while (bytes > 0) {
168 *tmp = *seed;
169 (*seed)++;
170 bytes--;
171 tmp++;
172 }
173
174 buf->write(space, to_add);
175 ats_free(space);
176
177 return to_add;
178 }
179
180 int
consume_and_check_bytes(IOBufferReader * r,uint8_t * seed)181 NetVCTest::consume_and_check_bytes(IOBufferReader *r, uint8_t *seed)
182 {
183 uint8_t *tmp, *end;
184 int b_consumed = 0;
185
186 if (actual_bytes_read >= bytes_to_read) {
187 return 1;
188 }
189
190 while (r->read_avail() > 0) {
191 int64_t b_avail = r->block_read_avail();
192
193 tmp = reinterpret_cast<uint8_t *>(r->start());
194 end = tmp + b_avail;
195 b_consumed = 0;
196
197 while (tmp < end && actual_bytes_read < bytes_to_read) {
198 actual_bytes_read++;
199 b_consumed++;
200 if (*tmp != *seed) {
201 r->consume(b_consumed);
202 return 0;
203
204 } else {
205 tmp++;
206 (*seed)++;
207 }
208 }
209
210 Debug(debug_tag, "consume_&_check: read %d, to_read %d", actual_bytes_read, bytes_to_read);
211 r->consume(b_consumed);
212 }
213
214 return 1;
215 }
216
217 void
write_finished()218 NetVCTest::write_finished()
219 {
220 if (nbytes_write != write_vio->ndone && expected_write_term == VC_EVENT_WRITE_COMPLETE) {
221 record_error("write: bad ndone value");
222 return;
223 }
224
225 write_done = true;
226
227 if (read_done) {
228 test_vc->do_io_close();
229 finished();
230 } else {
231 test_vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
232 }
233 }
234
235 void
read_finished()236 NetVCTest::read_finished()
237 {
238 if (nbytes_read != read_vio->ndone && expected_read_term != VC_EVENT_EOS && expected_read_term != VC_EVENT_NONE) {
239 record_error("read: bad ndone value");
240 return;
241 }
242
243 read_done = true;
244
245 if (write_done) {
246 test_vc->do_io_close();
247 finished();
248 } else {
249 test_vc->do_io_shutdown(IO_SHUTDOWN_READ);
250 }
251 }
252
253 void
record_error(const char * msg)254 NetVCTest::record_error(const char *msg)
255 {
256 rprintf(regress, " %s test: %s failed : %s : on %s\n", module_name, test_name, msg,
257 (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive");
258 ink_atomic_increment(&driver->errors, 1);
259
260 test_vc->do_io_close();
261 finished();
262 }
263
264 void
finished()265 NetVCTest::finished()
266 {
267 eventProcessor.schedule_imm(driver);
268 delete this;
269 }
270
271 void
write_handler(int event)272 NetVCTest::write_handler(int event)
273 {
274 Debug(debug_tag, "write_handler received event %d on %s", event, (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive");
275
276 switch (event) {
277 case VC_EVENT_WRITE_READY:
278 if (write_vio->ndone < bytes_to_send) {
279 int left_to_send = bytes_to_send - actual_bytes_sent;
280 ink_assert(left_to_send >= 0);
281 int to_fill = std::min(left_to_send, write_bytes_to_add_per);
282 actual_bytes_sent += fill_buffer(write_buffer, &write_seed, to_fill);
283 write_vio->reenable();
284 }
285 break;
286 case VC_EVENT_WRITE_COMPLETE:
287 write_finished();
288 break;
289 case VC_EVENT_INACTIVITY_TIMEOUT:
290 case VC_EVENT_ACTIVE_TIMEOUT:
291 case VC_EVENT_ERROR:
292 if (expected_write_term != event && expected_write_term != VC_EVENT_NONE) {
293 record_error("write: Unexpected error or timeout");
294 } else {
295 write_finished();
296 }
297 break;
298 default:
299 record_error("write: Unknown event");
300 break;
301 }
302 }
303
304 void
read_handler(int event)305 NetVCTest::read_handler(int event)
306 {
307 Debug(debug_tag, "read_handler received event %d on %s", event, (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive");
308
309 switch (event) {
310 case VC_EVENT_READ_READY:
311 if (consume_and_check_bytes(reader_for_rbuf, &read_seed) == 0) {
312 record_error("Read content corrupt");
313 return;
314 } else {
315 read_vio->reenable();
316 }
317 break;
318 case VC_EVENT_READ_COMPLETE:
319 if (consume_and_check_bytes(reader_for_rbuf, &read_seed) == 0) {
320 record_error("Read content corrupt");
321 return;
322 } else {
323 read_finished();
324 }
325 break;
326 case VC_EVENT_EOS:
327 if (expected_read_term != VC_EVENT_EOS && expected_read_term != VC_EVENT_NONE) {
328 record_error("read: Unexpected EOS Event");
329 } else {
330 read_finished();
331 }
332 break;
333 case VC_EVENT_INACTIVITY_TIMEOUT:
334 case VC_EVENT_ACTIVE_TIMEOUT:
335 case VC_EVENT_ERROR:
336 if (expected_read_term != event && expected_read_term != VC_EVENT_NONE) {
337 record_error("read: Unexpected error or timeout");
338 } else {
339 read_finished();
340 }
341 break;
342 default:
343 record_error("read: Unknown event");
344 break;
345 }
346 }
347
348 int
main_handler(int event,void * data)349 NetVCTest::main_handler(int event, void *data)
350 {
351 if (event == NET_EVENT_ACCEPT) {
352 test_vc = static_cast<NetVConnection *>(data);
353 start_test();
354 return 0;
355 }
356
357 if (data == read_vio) {
358 read_handler(event);
359 } else if (data == write_vio) {
360 write_handler(event);
361 } else {
362 record_error("main: unknown event");
363 }
364
365 return 0;
366 }
367
NetTestDriver()368 NetTestDriver::NetTestDriver() : Continuation(nullptr) {}
369
~NetTestDriver()370 NetTestDriver::~NetTestDriver() {}
371