1 /******************************************************************************* 2 3 Copyright: 4 Copyright (c) 2017 dunnhumby Germany GmbH. 5 All rights reserved. 6 7 License: 8 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 9 Alternatively, this file may be distributed under the terms of the Tango 10 3-Clause BSD License (see LICENSE_BSD.txt for details). 11 12 *******************************************************************************/ 13 14 module ocean.io.select.protocol.task.TaskSelectTransceiver_test; 15 16 import ocean.io.select.protocol.task.TaskSelectTransceiver; 17 18 import ocean.meta.types.Qualifiers; 19 import ocean.stdc.posix.fcntl: O_NONBLOCK; 20 import core.sys.posix.unistd: write, close; 21 import ocean.sys.ErrnoException; 22 import ocean.io.device.IODevice; 23 import ocean.io.select.protocol.generic.ErrnoIOException; 24 import ocean.io.select.client.model.ISelectClient; 25 import ocean.task.Scheduler; 26 import ocean.task.Task; 27 import ocean.core.Test; 28 29 extern (C) private int pipe2(ref int[2] fd, int flags); 30 31 unittest 32 { 33 // This test uses a pipe as an I/O device. 34 int[2] pipefd; 35 36 if (pipe2(pipefd, O_NONBLOCK)) 37 throw (new ErrnoException).useGlobalErrno("pipe2"); 38 39 // This TaskSelectTransceiver subclass uses a tiny 3-bytes buffer to test 40 // the reading loop. 41 static class TestTaskSelectTransceiver: TaskSelectTransceiver 42 { 43 this ( IODevice iodev ) 44 { 45 super(iodev, new IOWarning(iodev), new IOError(iodev), 3); 46 } 47 48 ~this ( ) { .close(this.iodev.fileHandle); } 49 } 50 51 // Create an input-only task select transceiver for the reading end of the 52 // pipe. 53 scope intst = new TestTaskSelectTransceiver(new class IODevice 54 { 55 Handle fileHandle ( ) { return cast(Handle)pipefd[0]; } 56 override ssize_t write ( const(void)[] src ) { assert(false); } 57 }); 58 59 // Create an output-only task select transceiver for the writing end of the 60 // pipe. 61 scope outtst = new TestTaskSelectTransceiver(new class IODevice 62 { 63 Handle fileHandle ( ) { return cast(Handle)pipefd[1]; } 64 override ssize_t read ( void[] dst ) { assert(false); } 65 override ssize_t write ( const(void)[] src ) 66 { 67 return .write(pipefd[1], src.ptr, src.length); 68 } 69 }); 70 71 initScheduler(SchedulerConfiguration.init); 72 73 static immutable outstr = "Hello World!"; 74 char[outstr.length] instr; 75 76 // Start a task that writes the test string to the pipe. 77 theScheduler.schedule(new class Task 78 { 79 override void run ( ) { outtst.write(outstr); } 80 override void recycle ( ) { outtst.select_client.unregister(); } 81 }); 82 83 // Start a task that reads the test string from the pipe. 84 theScheduler.schedule(new class Task 85 { 86 override void run ( ) 87 { 88 // Read only "Hello " to test readv(). 89 static immutable hello = "Hello ".length; 90 intst.read(instr[0 .. hello]); 91 auto world = instr[hello .. $]; 92 93 // Read "World!". The input buffer size makes only 3 characters 94 // arrive at once. 95 intst.readConsume( 96 (void[] data) 97 { 98 world[0 .. data.length] = cast(char[])data; 99 world = world[data.length .. $]; 100 return data.length + !!world.length; 101 } 102 ); 103 } 104 105 override void recycle ( ) { intst.select_client.unregister(); } 106 }); 107 108 theScheduler.eventLoop(); 109 110 test!("==")(instr, outstr); 111 }