1 /******************************************************************************* 2 3 Test for ReopenableFilesExt in combination with UnixSocketExt 4 5 Copyright: 6 Copyright (c) 2017 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *******************************************************************************/ 15 16 module integrationtest.reopenfiles.main; 17 18 import ocean.transition; 19 20 import core.sys.posix.sys.stat; 21 import core.sys.linux.fcntl; 22 23 import ocean.core.Enforce; 24 import ocean.core.Test; 25 import ocean.io.FilePath; 26 import ocean.io.device.File; 27 import ocean.io.select.protocol.task.TaskSelectTransceiver; 28 import ocean.io.select.protocol.generic.ErrnoIOException: IOWarning, IOError; 29 30 import ocean.sys.socket.UnixSocket; 31 import ocean.stdc.posix.sys.un; 32 33 import ocean.task.Scheduler; 34 import ocean.task.Task; 35 36 import ocean.util.app.DaemonApp; 37 import ocean.util.test.DirectorySandbox; 38 39 /// Socket class to bind/connect 40 private istring socket_path = "reopensocket.socket"; 41 42 /// Main application class 43 class ReopenableFilesApp : DaemonApp 44 { 45 /// Count of the remaining tasks. Shut downs 46 /// the scheduler when 0. 47 private int task_remaining; 48 49 /// Task used to send command and confirm the response 50 class SendingTask: Task 51 { 52 /// Command to send 53 cstring command_to_send; 54 /// Response to expect 55 cstring expected_response; 56 57 /// Constructor 58 this (cstring command_to_send, 59 cstring expected_response) 60 { 61 this.command_to_send = command_to_send; 62 this.expected_response = expected_response; 63 } 64 65 /// Main task method 66 override void run() 67 { 68 auto socket_address = sockaddr_un.create(socket_path); 69 70 auto client = new UnixSocket(); 71 72 auto socket_fd = client.socket(); 73 enforce(socket_fd >= 0, "socket() call failed!"); 74 75 auto connect_result = client.connect(&socket_address); 76 enforce(connect_result == 0, 77 "connect() call failed"); 78 79 // set non-blocking mode on the client socket 80 auto existing_flags = fcntl(client.fileHandle(), 81 F_GETFL, 0); 82 enforce(existing_flags != -1); 83 enforce(fcntl(client.fileHandle(), 84 F_SETFL, existing_flags | O_NONBLOCK) != -1); 85 86 // Use the task-blocking tranceiver, so 87 // the scheduler can handle other epoll clients 88 auto transceiver = new TaskSelectTransceiver(client, 89 new IOWarning(client), new IOError(client)); 90 transceiver.write(command_to_send); 91 92 // Confirm the response! 93 auto buff = new char[this.expected_response.length]; 94 transceiver.read(buff); 95 test!("==")(buff, this.expected_response); 96 97 if (--this.outer.task_remaining == 0) 98 { 99 theScheduler.shutdown(); 100 } 101 } 102 } 103 104 /// Constructor. 105 this ( ) 106 { 107 initScheduler(SchedulerConfiguration.init); 108 theScheduler.exception_handler = (Task, Exception e) { 109 throw e; 110 }; 111 112 istring name = "Application"; 113 istring desc = "Testing reopenable files ext"; 114 115 DaemonApp.OptionalSettings settings; 116 117 super(name, desc, VersionInfo.init, settings); 118 } 119 120 /// Called after arguments and config file parsing. 121 override protected int run ( Arguments args, ConfigParser config ) 122 { 123 this.startEventHandling(theScheduler.epoll); 124 125 auto original_file = new File; 126 original_file.open("filelocation.txt", File.ReadWriteOpen); 127 this.reopenable_files_ext.register(original_file); 128 129 // move this file now 130 auto path = new FilePath(original_file.path()); 131 path.rename("newfilelocation.txt"); 132 133 auto new_file = new File; 134 new_file.open("filelocation.txt", File.ReadWriteOpen); 135 new_file.write("Pre-reload"); 136 137 // we haven't done reloading 138 test!("==")(original_file.length, 0); 139 140 auto good_task = new SendingTask("reopen_files filelocation.txt\n", 141 "ACK\n"); 142 theScheduler.schedule(good_task); 143 144 auto bad_task = new SendingTask("reopen_files nonregistered.txt\n", 145 "ERROR: Could not rotate the file 'nonregistered.txt'\n"); 146 theScheduler.schedule(bad_task); 147 148 // Counter used to figure out when to exit the scheduler 149 this.task_remaining = 2; 150 151 // Spin the task and start working 152 theScheduler.eventLoop(); 153 154 // Test if the file has been reloaded 155 test!("!=")(original_file.length, 0); 156 auto buff = new char["Pre-reload".length]; 157 original_file.read(buff); 158 test!("==")(buff, "Pre-reload"); 159 160 return 0; 161 } 162 163 } 164 165 version(UnitTest) {} else 166 void main(istring[] args) 167 { 168 auto sandbox = DirectorySandbox.create(["etc", "log"]); 169 scope (success) 170 sandbox.remove(); 171 172 File.set("etc/config.ini", "[LOG.Root]\n" ~ 173 "console = false\n\n" ~ 174 "[UNIX_SOCKET]\npath=" ~ socket_path ~ "\nmode=0600"); 175 176 auto app = new ReopenableFilesApp; 177 app.main(args); 178 }