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