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.meta.types.Qualifiers; 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 }