1 /*******************************************************************************
2
3 Unittest for FileSystemEvent.
4
5 Copyright:
6 Copyright (c) 2014-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.filesystemevent.main;
17
18 import ocean.transition;
19
20 import ocean.core.Enforce;
21
22 import ocean.io.device.File;
23
24 import ocean.io.device.TempFile;
25
26 import ocean.io.select.client.TimerEvent;
27
28 import ocean.io.select.client.FileSystemEvent;
29
30 import ocean.io.select.EpollSelectDispatcher;
31
32 import ocean.io.model.IConduit: ISelectable;
33
34 import ocean.io.FilePath;
35
36 import ocean.core.Test;
37
38 import ocean.util.test.DirectorySandbox;
39
40 import ocean.task.Task;
41
42 import ocean.task.Scheduler;
43
44 import ocean.task.util.Event;
45
46 import ocean.text.convert.Formatter;
47
48 import ocean.sys.Environment;
49
50
51 class FileCreationTestTask: Task
52 {
53 /***************************************************************************
54
55 File operations to be checked
56
57 ***************************************************************************/
58
59 private bool created;
60 private bool modified = false;
61 private bool deleted = false;
62 private bool closed = false;
63
64 /***************************************************************************
65
66 Name of the created file.
67
68 ***************************************************************************/
69
70 private cstring created_name;
71
72 /***************************************************************************
73
74 Path to the monitored file.
75
76 ***************************************************************************/
77
78 private FilePath temp_path;
79
80 /***************************************************************************
81
82 Variable to control/test the order of the file operations
83
84 ***************************************************************************/
85
86 private int operation_order = 0;
87
88 /***************************************************************************
89
90 Path to the monitored directory.
91
92 ***************************************************************************/
93
94 private cstring watched_path;
95
96 /***************************************************************************
97
98 Tested FileSystemEvent instance.
99
100 ***************************************************************************/
101
102 private FileSystemEvent inotifier;
103
104 /***************************************************************************
105
106 TaskEvent to suspend/resume the task.
107
108 ***************************************************************************/
109
110 private TaskEvent task_event;
111
112 /***************************************************************************
113
114 Test that tests monitoring a directory and watching for the file
115 creation.
116
117 ***************************************************************************/
118
119 private void testFileCreation ( )
120 {
121 inotifier.watch(this.watched_path.dup,
122 FileEventsEnum.IN_CREATE);
123
124 theScheduler.epoll.register(inotifier);
125
126 auto file_name = "test_file";
127 File.set(file_name, "".dup);
128
129 this.task_event.wait();
130
131 theScheduler.epoll.unregister(inotifier);
132 inotifier.unwatch(this.watched_path.dup);
133
134 test(this.created);
135 test!("==")(this.created_name, file_name);
136 }
137
138 /***************************************************************************
139
140 Test that tests modifications/closing/deleting performed on individual
141 file (not a directory)
142
143 ***************************************************************************/
144
145 private void testFileModification ( )
146 {
147 auto temp_file = new File("./testfile_modification", File.WriteCreate);
148 this.temp_path = FilePath(temp_file.toString());
149
150 inotifier.watch(cast(char[]) temp_file.toString(),
151 FileEventsEnum.IN_MODIFY | FileEventsEnum.IN_DELETE_SELF
152 | FileEventsEnum.IN_CLOSE_WRITE );
153
154 theScheduler.epoll.register(inotifier);
155
156 temp_file.write("something");
157 temp_file.close;
158 temp_path.remove();
159
160 this.task_event.wait();
161
162 theScheduler.epoll.unregister(inotifier);
163
164 test(this.modified);
165 test(this.closed);
166 test(this.deleted);
167 }
168
169 /***************************************************************************
170
171 Test entry point. Prepares environment and tests the FileSystemEvent.
172
173 ***************************************************************************/
174
175 override public void run ( )
176 {
177 auto makd_tmpdir = Environment.get("MAKD_TMPDIR");
178 mstring path_template;
179 sformat(path_template, "{}/Dunittests-XXXXXXXX",
180 makd_tmpdir.length? makd_tmpdir : "/tmp");
181
182 auto sandbox = DirectorySandbox.create(null, path_template);
183 scope (exit)
184 sandbox.exitSandbox();
185
186 this.watched_path = sandbox.path;
187
188 this.inotifier = new FileSystemEvent(&this.fileSystemHandler);
189
190 this.testFileCreation();
191 this.testFileModification();
192 }
193
194 /**********************************************************************
195
196 File System handler: called anytime a File System event occurs.
197
198 Params:
199 path = monitored path
200 name = name of the file
201 event = Inotify event (see FileEventsEnum)
202
203 **********************************************************************/
204
205 private void fileSystemHandler ( FileSystemEvent.RaisedEvent raised_event )
206 {
207 with (raised_event.Active) switch (raised_event.active)
208 {
209 case directory_file_event:
210 auto event = raised_event.directory_file_event;
211
212 if ( this.watched_path == event.path )
213 {
214 switch ( event.event )
215 {
216 case FileEventsEnum.IN_CREATE:
217 this.created = true;
218 this.created_name = event.name.dup;
219 this.task_event.trigger();
220 break;
221 default:
222 test(false, "Unexpected file system event notification.");
223 }
224 }
225 break;
226
227 case file_event:
228 auto event = raised_event.file_event;
229
230 if ( this.temp_path == event.path )
231 {
232 this.operation_order++;
233
234 switch ( event.event )
235 {
236 case FileEventsEnum.IN_MODIFY:
237
238 if ( this.operation_order == 1 )
239 {
240 this.modified = true;
241 }
242 break;
243
244 case FileEventsEnum.IN_CLOSE_WRITE:
245
246 if ( this.operation_order == 2 )
247 {
248 this.closed = true;
249 }
250 break;
251
252 case FileEventsEnum.IN_DELETE_SELF:
253
254 if ( this.operation_order == 3 )
255 {
256 this.deleted = true;
257 this.task_event.trigger();
258 }
259 break;
260
261 case FileEventsEnum.IN_IGNORED:
262 enforce(this.deleted);
263 break;
264
265 default:
266 test(false, "Unexpected file system event notification.");
267 }
268 }
269 break;
270
271 default:
272 assert(false);
273 }
274 }
275 }
276
277
278 /*******************************************************************************
279
280 Main test
281
282 *******************************************************************************/
283
284 version(UnitTest) {} else
285 void main ( )
286 {
287 initScheduler(SchedulerConfiguration.init);
288 theScheduler.exception_handler = (Task t, Exception e) {
289 throw e;
290 };
291
292 auto dir_test_task = new FileCreationTestTask;
293 theScheduler.schedule(dir_test_task);
294 theScheduler.eventLoop();
295 }