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