Repository navigation
Implement MockFileSystemWatcher - #373
rkoeninger wants to merge 3 commits into
Conversation
|
To be honest I'm kind of hesitant to provide this feature at all, mainly for the following reasons
I value your work but I would really tend to not do this. What do the others (@jpreese, @tathamoddie, @ericnewton76) think? |
|
I knew this was borderline madness when I started working on it. Would synchronous triggering of event handlers work or still too complicated? If the library isn't going to provide file watching functionality, it should throw an exception as soon as you create a file watcher and not just let one get created that won't do anything. That would be a very confusing issue to encounter. |
|
For my test scenario I have made the event handler internal and call it directly from the unit test, however in case my code initializes the FSW completely wrong (watching the wrong directory, no subdirectories, forgetting to add event handlers, EnableRaisingEvents=false, wrong filter), this is untested. If I can call a method to trigger an event (Changed, Created, Deleted, Renamed) with a filename (or perhaps 2 filenames in the event of Renamed) and the FSW only raises the event (and calls my code) if the path matches the listener settings, this would give me enough tools to verify that my code is working as intended. I tried implementing this in a custom MockFSW, but MockFileSystem does not allow me to inject my own FSWFactory, so I deemed it to be too much hassle. /my 2 cents |
|
I'm going to retract this PR. I'll update #329 to have the MockFileSystem be able to accept a mocked FSW and have a default FSW factory that just throws. |
Fixes #329
Here's my attempt at a working
MockFileSystemWatcher. The referenced issue was only for theWaitForChangedmethods, but really the whole class didn't do anything.In order to support this,
MockFileSystemneeded an event dispatch system built into it.Current Approach
Listeners can get hold of a
ConcurrentQueueby callingListenand the MFS will keep a list of those queues, pushing events into them as modification operations are performed.For the
WaitForChangedmethods specifically, they are effectively one-time filtered (by event type) event handlers. AWaitableRefclass was added to so the accumulation of waiters on a particular event can be modeled. Each waiter has aManualResetEventto signal when the required event type has happened and an internal field to hold the event object. The waiters get added to a dictionary in theMockFileSystemWatcher. When the watcher receives an event, it checks if there are waiters that need that event type,Sendit to them (which triggers theWaiting thread to wake up) and removes them from the dictionary.There are a few tests, but they don't pass reliably on my machine. Concurrency is surely not implemented too well. I would also want to get rid of those
Thread.Sleeps.More notes:
FileSystemWatcheronly handles events on files.MockFileSystemdispatches events synchronously. Not too big of a deal as the event handling code doesn't immediately run on the same thread, but this does make the calling thread toFile.Create, etc spend the time to add the events to the queues.Renamedevent, not two separateDeletedandCreatedevents.MockFileSystem.MoveFileevent to better identify events.MockFileInfostill needs to be updated, in particular, to prevent it from doing delete/create and using the internalMoveFilefunction instead.Changedevent currently not dispatched. I assume this means file contents changed.Reactive
The current use of concurrency is fairly fragile, and it occurred to me that
System.Reactivewould be a better way to go. The MFS would have aSubjectthat it wouldOnNextevents to, and the FSWs would be able to simplySubscribeto theSubjectand use.Whereto filter for messages under the directory root that they are watching. Waiters would subscribe to their watcher's filtered subscription, but with an additional.FirstAsync(e => e.ChangeType == changeType)so they only get the next event of the required type. Then chain.ToTask().Wait(int)to synchronously wait for the event as theWaitForChangedmethod is designed that way.I don't think adding
System.Reactivewould be too onerous as it would only be added to theTestingHelpers, it wouldn't make the S.IO.A.dll any bigger, or introduce transitive dependency issues in prod. On the other hand, I wasn't sure which version to use to supportnet40,netstandard1.4andnetstandard2.0as this library does.OK, so after all of that, how accurately do we want to reproduce the behavior of
FileSystemWatcher? Should we just cut corner on this one? Unit tests could get a hold of the MockFSW passed into SUT and call itsOnCreate, etc methods directly. That might be enough?