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