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 }