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 }