using System;
using System.IO;
using System.Threading;
using NUnit.Framework;
using Spring.Threading;
namespace Spring.Services.WindowsService.Common.Deploy.FileSystem{
class FileSystemMonitorTester
{
private string _path;
AutoResetEvent _resetEvent = new AutoResetEvent(false);
public FileSystemMonitorTester(string path)
{
this._path = path;
}
public void CreateFile(string fileName)
{
Directory.CreateDirectory(Path.Combine(_path, Path.GetDirectoryName(fileName)));
using (File.CreateText(Path.Combine(_path, fileName)))
{}
}
public void DeleteFile(string file)
{
File.Delete(Path.Combine(_path, file));
}
public void ChangeFile(string aFile)
{
using (StreamWriter writer = File.AppendText(Path.Combine(_path, aFile)))
{
writer.WriteLine("Random data");
}
}
public void RenameFile(string file, string newName)
{
File.Move(Path.Combine(_path, file), Path.Combine(_path, newName));
}
public bool TryToCauseAnError (ISync sync, long msecs)
{
new Thread(new ThreadStart(Go)).Start();
bool got = sync.Attempt(msecs);
_resetEvent.Set();
return got;
}
private void Go ()
{
string subDir = Guid.NewGuid().ToString();
Directory.CreateDirectory(Path.Combine (_path, subDir));
while (true)
{
if (_resetEvent.WaitOne(0, true))
break;
string file = Path.Combine(subDir, Guid.NewGuid().ToString());
CreateFile(file);
ChangeFile(file);
DeleteFile(file);
}
}
}
[TestFixture]
public class FileSystemMonitorTest
{
FileSystemMonitor monitor;
string _path;
ISync sync;
long msecs;
FileSystemMonitorTester tester;
string aFile;
[SetUp]
public void SetUp ()
{
_path = Path.GetFullPath(Guid.NewGuid().ToString());
Directory.CreateDirectory(_path);
monitor = new FileSystemMonitor(_path);
monitor.Start();
tester = new FileSystemMonitorTester(_path);
sync = new Semaphore(0);
msecs = 1000;
aFile = "foo.txt";
}
[TearDown]
public void TearDown ()
{
try
{
monitor.Stop();
Directory.Delete(_path, true);
}
catch (IOException ex)
{
Console.Write(ex);
}
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void DoesNotAcceptANonExistingDirectory ()
{
new FileSystemMonitor("oh-no");
}
[Test]
public void CanBeStoppedEvenIfNotStarted ()
{
monitor.Stop();
monitor = new FileSystemMonitor(_path);
monitor.Stop();
Assert.IsTrue(true);
}
[Test]
public void AllowRegisteringToCreatedEvents ()
{
monitor.Created += new FileSystemEventHandler(OnCreated);
tester.CreateFile(aFile);
Assert.IsTrue(sync.Attempt(msecs), "created event timed out");
}
[Test]
public void AllowRegisteringToDeletedEvents ()
{
tester.CreateFile(aFile);
monitor.Deleted += new FileSystemEventHandler(OnDeleted);
tester.DeleteFile(aFile);
Assert.IsTrue(sync.Attempt(msecs), "deleted event timed out");
}
[Test]
public void AllowRegisteringToChangedEvents ()
{
tester.CreateFile(aFile);
monitor.Changed += new FileSystemEventHandler(OnChanged);
tester.ChangeFile(aFile);
Assert.IsTrue(sync.Attempt(msecs), "changed event timed out");
}
[Test]
public void AllowRegisteringToRenamedEvents ()
{
tester.CreateFile(aFile);
monitor.Renamed += new RenamedEventHandler(OnRenamed);
tester.RenameFile(aFile, "oh-what");
Assert.IsTrue(sync.Attempt(msecs), "renamed event timed out");
}
[Test]
public void ErrorEventsAreNotFiltered ()
{
monitor.InternalBufferSize = 4096;
monitor.PathMatcherExcludes = "**/*.*";
monitor.Error += new ErrorEventHandler(OnError);
monitor.Created += new FileSystemEventHandler(noOp);
monitor.Deleted += new FileSystemEventHandler(noOp);
Assert.IsTrue(tester.TryToCauseAnError(sync, msecs * 10), "error event timed out");
}
[Test]
public void SupportsNantLikePattensToFilterAllowedEvents ()
{
monitor.NotifyFilter = NotifyFilters.FileName;
monitor.IncludeSubdirectories = true;
monitor.PathMatcherIncludes = "**/sub/*.txt";
monitor.Created += new FileSystemEventHandler(OnCreated);
tester.CreateFile("sub/Bar.bar");
Assert.IsFalse(sync.Attempt(msecs), "created event NOT filtered and propagated");
tester.CreateFile("sub/Bar.txt");
Assert.IsTrue(sync.Attempt(msecs), "created event filtered and NOT propagated");
}
[Test]
public void SupportsNantLikePattensToFilterNotAllowedEvents ()
{
monitor.NotifyFilter = NotifyFilters.FileName;
monitor.IncludeSubdirectories = true;
monitor.PathMatcherExcludes = "**/sub/*.txt";
monitor.Created += new FileSystemEventHandler(OnCreated);
tester.CreateFile("sub/Bar.bar");
Assert.IsTrue(sync.Attempt(msecs), "created event filtered and NOT propagated");
tester.CreateFile("sub/Bar.txt");
Assert.IsFalse(sync.Attempt(msecs), "created event NOT filtered and propagated");
}
[Test]
public void CanBeStoppedOnAnEvent ()
{
//TODO: test with a buffer of capacity 1 to have blocked thread
// when shut down
monitor.Created += new FileSystemEventHandler(ShutDownOnCreated);
// TODO: simulate a big number of
// events and randomly shut down
tester.CreateFile(aFile);
tester.CreateFile("buzzWords");
Assert.IsTrue(sync.Attempt(msecs), "created event timed out");
tester.DeleteFile(aFile);
// no more events: the monitor is stopped
sync = new Latch();
tester.CreateFile(aFile);
Assert.IsFalse(sync.Attempt(msecs), "created event NOT timed out");
}
private void OnCreated(object sender, FileSystemEventArgs e)
{
Assert.AreEqual(WatcherChangeTypes.Created, e.ChangeType);
sync.Release();
}
private void OnDeleted(object sender, FileSystemEventArgs e)
{
Assert.AreEqual(WatcherChangeTypes.Deleted, e.ChangeType);
sync.Release();
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
Assert.AreEqual(WatcherChangeTypes.Changed, e.ChangeType);
sync.Release();
}
private void OnRenamed(object sender, RenamedEventArgs e)
{
Assert.AreEqual(WatcherChangeTypes.Renamed, e.ChangeType);
sync.Release();
}
private void OnError (object sender, ErrorEventArgs e)
{
sync.Release();
}
private void ShutDownOnCreated(object sender, FileSystemEventArgs e)
{
monitor.Stop();
sync.Release();
}
private void noOp (object sender, FileSystemEventArgs e)
{
}
}
}
|