1 /******************************************************************************* 2 3 Test for the SignalExt behaviour. 4 5 copyright: Copyright (c) 2015 dunnhumby Germany GmbH. All rights reserved 6 7 *******************************************************************************/ 8 9 module integrationtest.signalext.main; 10 11 import ocean.transition; 12 13 import core.sys.posix.signal; 14 import ocean.core.Test; 15 import ocean.sys.ErrnoException; 16 import ocean.util.app.DaemonApp; 17 import ocean.io.select.client.TimerEvent; 18 19 /// Counters incremented from original and application's 20 /// signal handler 21 private int main_counter; 22 private int app_counter; 23 24 class MyApp : DaemonApp 25 { 26 import ocean.io.select.EpollSelectDispatcher; 27 28 private EpollSelectDispatcher epoll; 29 30 this ( ) 31 { 32 this.epoll = new EpollSelectDispatcher; 33 34 istring name = "Application"; 35 istring desc = "Testing signal handling."; 36 37 DaemonApp.OptionalSettings settings; 38 settings.signals = [SIGRTMIN]; 39 40 super(name, desc, VersionInfo.init, settings); 41 } 42 43 // Called after arguments and config file parsing. 44 override protected int run ( Arguments args, ConfigParser config ) 45 { 46 this.startEventHandling(this.epoll); 47 48 auto timer = new TimerEvent( 49 { 50 // This should now trigger the new handler 51 raise(SIGRTMIN); 52 return false; 53 }); 54 55 timer.set(0, 100, 0, 0); 56 this.epoll.register(timer); 57 58 this.epoll.eventLoop(); 59 return 0; // return code to OS 60 } 61 62 // Handle those signals we were interested in 63 override public void onSignal ( int signal ) 64 { 65 test!("==")(signal, SIGRTMIN); 66 .app_counter++; 67 this.epoll.shutdown(); 68 } 69 } 70 71 import ocean.io.device.File; 72 import Path = ocean.io.Path; 73 import ocean.text.util.StringC; 74 import core.sys.posix.unistd; 75 import ocean.stdc.posix.stdlib : mkdtemp; 76 77 version(UnitTest) {} else 78 void main(istring[] args) 79 { 80 static extern(C) void sighandler (int sig) 81 { 82 main_counter++; 83 } 84 85 // Exception to throw on failure. Instantiated for ergonomics 86 auto e = new ErrnoException; 87 88 // Set the initial signal handler 89 sigaction_t handler, old_handler; 90 handler.sa_handler = &sighandler; 91 92 auto sigaction_res = 93 e.enforceRetCode!(sigaction).call(SIGRTMIN, &handler, &old_handler); 94 95 scope (exit) 96 { 97 // Restore the old one on exit 98 sigaction(SIGRTMIN, &old_handler, null); 99 } 100 101 // The main-function signal handler should be triggered here 102 raise(SIGRTMIN); 103 104 // Prepare environment 105 char[4096] old_cwd; 106 e.enforceRetPtr!(getcwd).call(old_cwd.ptr, old_cwd.length); 107 108 auto tmp_path = e.enforceRetPtr!(mkdtemp) 109 .call("/tmp/Dunittest-XXXXXX\0".dup.ptr); 110 111 scope (exit) 112 { 113 auto d_tmp_path = StringC.toDString(tmp_path); 114 // Remove all subdirectories and files in the tmp dir 115 Path.remove(Path.collate(d_tmp_path, "*", true)); 116 // Remove the tmp dir itself 117 Path.remove(d_tmp_path); 118 } 119 120 e.enforceRetCode!(chdir).call(tmp_path); 121 122 scope (exit) 123 { 124 e.enforceRetCode!(chdir).call(old_cwd.ptr); 125 } 126 127 // Now start the application: 128 129 // setup directory structure needed to run 130 if (!Path.exists("etc")) 131 { 132 Path.createFolder("etc"); 133 } 134 135 if (!Path.exists("log")) 136 { 137 Path.createFolder("log"); 138 } 139 140 auto file = new File("etc/config.ini", File.ReadWriteCreate); 141 142 file.write("[LOG.Root]\n" ~ 143 "console = false\n"); 144 145 file.close(); 146 147 auto app = new MyApp; 148 auto ret = app.main(args); 149 150 // The old handler should be triggered here 151 raise(SIGRTMIN); 152 153 test!("==")(main_counter, 2); 154 test!("==")(app_counter, 1); 155 }