mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-01 21:13:10 +01:00
#3425: Fixed suspend/resumeEvents pair in DirectoryWatcher
This commit is contained in:
@@ -61,7 +61,7 @@ public:
|
||||
{
|
||||
return _owner;
|
||||
}
|
||||
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool supportsMoveEvents() const = 0;
|
||||
@@ -73,21 +73,21 @@ protected:
|
||||
size(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ItemInfo(const ItemInfo& other):
|
||||
path(other.path),
|
||||
size(other.size),
|
||||
lastModified(other.lastModified)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
explicit ItemInfo(const File& f):
|
||||
path(f.path()),
|
||||
size(f.isFile() ? f.getSize() : 0),
|
||||
lastModified(f.getLastModified())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string path;
|
||||
File::FileSize size;
|
||||
Timestamp lastModified;
|
||||
@@ -104,7 +104,7 @@ protected:
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void compare(ItemInfoMap& oldEntries, ItemInfoMap& newEntries)
|
||||
{
|
||||
for (auto& np: newEntries)
|
||||
@@ -145,7 +145,7 @@ private:
|
||||
DirectoryWatcherStrategy();
|
||||
DirectoryWatcherStrategy(const DirectoryWatcherStrategy&);
|
||||
DirectoryWatcherStrategy& operator = (const DirectoryWatcherStrategy&);
|
||||
|
||||
|
||||
DirectoryWatcher& _owner;
|
||||
};
|
||||
|
||||
@@ -163,21 +163,21 @@ public:
|
||||
if (!_hStopped)
|
||||
throw SystemException("cannot create event");
|
||||
}
|
||||
|
||||
|
||||
~WindowsDirectoryWatcherStrategy()
|
||||
{
|
||||
CloseHandle(_hStopped);
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
ItemInfoMap entries;
|
||||
scan(entries);
|
||||
|
||||
|
||||
DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED)
|
||||
filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
|
||||
|
||||
|
||||
std::string path(owner().directory().path());
|
||||
std::wstring upath;
|
||||
FileImpl::convertPath(path.c_str(), upath);
|
||||
@@ -195,7 +195,7 @@ public:
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool stopped = false;
|
||||
while (!stopped)
|
||||
{
|
||||
@@ -228,21 +228,21 @@ public:
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
FindCloseChangeNotification(hChange);
|
||||
}
|
||||
|
||||
|
||||
void stop()
|
||||
{
|
||||
SetEvent(_hStopped);
|
||||
}
|
||||
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
HANDLE _hStopped;
|
||||
};
|
||||
@@ -262,12 +262,12 @@ public:
|
||||
_fd = inotify_init();
|
||||
if (_fd == -1) throw Poco::IOException("cannot initialize inotify", errno);
|
||||
}
|
||||
|
||||
|
||||
~LinuxDirectoryWatcherStrategy()
|
||||
{
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
int mask = 0;
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::Buffer<char> buffer(4096);
|
||||
while (!_stopped)
|
||||
{
|
||||
@@ -314,16 +314,16 @@ public:
|
||||
while (n > 0)
|
||||
{
|
||||
struct inotify_event* pEvent = reinterpret_cast<struct inotify_event*>(buffer.begin() + i);
|
||||
|
||||
|
||||
if (pEvent->len > 0)
|
||||
{
|
||||
{
|
||||
if (!owner().eventsSuspended())
|
||||
{
|
||||
Poco::Path p(owner().directory().path());
|
||||
p.makeDirectory();
|
||||
p.setFileName(pEvent->name);
|
||||
Poco::File f(p.toString());
|
||||
|
||||
|
||||
if ((pEvent->mask & IN_CREATE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED);
|
||||
@@ -351,7 +351,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
i += sizeof(inotify_event) + pEvent->len;
|
||||
n -= sizeof(inotify_event) + pEvent->len;
|
||||
}
|
||||
@@ -359,12 +359,12 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stopped = true;
|
||||
}
|
||||
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return true;
|
||||
@@ -469,11 +469,11 @@ public:
|
||||
DirectoryWatcherStrategy(owner)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~PollingDirectoryWatcherStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
ItemInfoMap entries;
|
||||
@@ -493,7 +493,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stopped.set();
|
||||
@@ -520,7 +520,7 @@ DirectoryWatcher::DirectoryWatcher(const std::string& path, int eventMask, int s
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
DirectoryWatcher::DirectoryWatcher(const Poco::File& directory, int eventMask, int scanInterval):
|
||||
_directory(directory),
|
||||
_eventMask(eventMask),
|
||||
@@ -543,16 +543,16 @@ DirectoryWatcher::~DirectoryWatcher()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::suspendEvents()
|
||||
|
||||
void DirectoryWatcher::resumeEvents()
|
||||
{
|
||||
poco_assert (_eventsSuspended > 0);
|
||||
|
||||
|
||||
_eventsSuspended--;
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::resumeEvents()
|
||||
void DirectoryWatcher::suspendEvents()
|
||||
{
|
||||
_eventsSuspended++;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ void DirectoryWatcher::init()
|
||||
{
|
||||
if (!_directory.exists())
|
||||
throw Poco::FileNotFoundException(_directory.path());
|
||||
|
||||
|
||||
if (!_directory.isDirectory())
|
||||
throw Poco::InvalidArgumentException("not a directory", _directory.path());
|
||||
|
||||
@@ -578,7 +578,7 @@ void DirectoryWatcher::init()
|
||||
_thread.start(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DirectoryWatcher::run()
|
||||
{
|
||||
_pStrategy->run();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
using Poco::DirectoryWatcher;
|
||||
|
||||
|
||||
DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name):
|
||||
DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name):
|
||||
CppUnit::TestCase(name),
|
||||
_error(false)
|
||||
{
|
||||
@@ -39,23 +39,23 @@ DirectoryWatcherTest::~DirectoryWatcherTest()
|
||||
void DirectoryWatcherTest::testAdded()
|
||||
{
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
|
||||
Poco::Path p(path());
|
||||
p.setFileName("test.txt");
|
||||
Poco::FileOutputStream fos(p.toString());
|
||||
fos << "Hello, world!";
|
||||
fos.close();
|
||||
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
|
||||
assertTrue (_events.size() >= 1);
|
||||
assertTrue (_events[0].callback == "onItemAdded");
|
||||
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
|
||||
@@ -73,20 +73,20 @@ void DirectoryWatcherTest::testRemoved()
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
|
||||
Poco::File f(p.toString());
|
||||
f.remove();
|
||||
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
|
||||
assertTrue (_events.size() >= 1);
|
||||
assertTrue (_events[0].callback == "onItemRemoved");
|
||||
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
|
||||
@@ -104,21 +104,21 @@ void DirectoryWatcherTest::testModified()
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
|
||||
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
|
||||
fos2 << "Again!";
|
||||
fos2.close();
|
||||
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
|
||||
assertTrue (_events.size() >= 1);
|
||||
assertTrue (_events[0].callback == "onItemModified");
|
||||
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
|
||||
@@ -136,22 +136,22 @@ void DirectoryWatcherTest::testMoved()
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
|
||||
Poco::Path p2(path());
|
||||
p2.setFileName("test2.txt");
|
||||
Poco::File f(p.toString());
|
||||
f.renameTo(p2.toString());
|
||||
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
|
||||
if (dw.supportsMoveEvents())
|
||||
{
|
||||
assertTrue (_events.size() >= 2);
|
||||
@@ -188,11 +188,144 @@ void DirectoryWatcherTest::testMoved()
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcherTest::testSuspend()
|
||||
{
|
||||
Poco::Path p(path());
|
||||
p.setFileName("test.txt");
|
||||
Poco::FileOutputStream fos(p.toString());
|
||||
fos << "Hello, world!";
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
dw.suspendEvents();
|
||||
|
||||
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
|
||||
fos2 << "Again!";
|
||||
fos2.close();
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
assertTrue (_events.size() == 0);
|
||||
assertTrue (!_error);
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcherTest::testResume()
|
||||
{
|
||||
Poco::Path p(path());
|
||||
p.setFileName("test.txt");
|
||||
Poco::FileOutputStream fos(p.toString());
|
||||
fos << "Hello, world!";
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
dw.suspendEvents();
|
||||
|
||||
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
|
||||
fos2 << "Again!";
|
||||
fos2.close();
|
||||
|
||||
assertTrue (_events.size() == 0);
|
||||
assertTrue (!_error);
|
||||
|
||||
dw.resumeEvents();
|
||||
|
||||
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
|
||||
fos3 << "Now it works!";
|
||||
fos3.close();
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
assertTrue (_events.size() >= 1);
|
||||
assertTrue (_events[0].callback == "onItemModified");
|
||||
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
|
||||
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
|
||||
assertTrue (!_error);
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcherTest::testSuspendMultipleTimes()
|
||||
{
|
||||
Poco::Path p(path());
|
||||
p.setFileName("test.txt");
|
||||
Poco::FileOutputStream fos(p.toString());
|
||||
fos << "Hello, world!";
|
||||
fos.close();
|
||||
|
||||
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
|
||||
|
||||
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
|
||||
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
|
||||
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
|
||||
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
|
||||
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
|
||||
|
||||
Poco::Thread::sleep(1000);
|
||||
|
||||
dw.suspendEvents();
|
||||
dw.suspendEvents();
|
||||
dw.suspendEvents();
|
||||
|
||||
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
|
||||
fos2 << "Not notified!";
|
||||
fos2.close();
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
assertTrue (_events.size() == 0);
|
||||
assertTrue (!_error);
|
||||
|
||||
dw.resumeEvents();
|
||||
|
||||
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
|
||||
fos3 << "Still not notified!";
|
||||
fos3.close();
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
assertTrue (_events.size() == 0);
|
||||
assertTrue (!_error);
|
||||
|
||||
dw.resumeEvents();
|
||||
dw.resumeEvents();
|
||||
|
||||
Poco::FileOutputStream fos4(p.toString(), std::ios::app);
|
||||
fos4 << "Now it works!";
|
||||
fos4.close();
|
||||
|
||||
Poco::Thread::sleep(2000*dw.scanInterval());
|
||||
|
||||
assertTrue (_events.size() >= 1);
|
||||
assertTrue (_events[0].callback == "onItemModified");
|
||||
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
|
||||
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
|
||||
assertTrue (!_error);
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcherTest::setUp()
|
||||
{
|
||||
_error = false;
|
||||
_events.clear();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Poco::File d(path().toString());
|
||||
@@ -292,6 +425,9 @@ CppUnit::Test* DirectoryWatcherTest::suite()
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testRemoved);
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testModified);
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testMoved);
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspend);
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testResume);
|
||||
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspendMultipleTimes);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
@@ -35,12 +35,15 @@ public:
|
||||
void testRemoved();
|
||||
void testModified();
|
||||
void testMoved();
|
||||
|
||||
void testSuspend();
|
||||
void testResume();
|
||||
void testSuspendMultipleTimes();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
|
||||
protected:
|
||||
void onItemAdded(const Poco::DirectoryWatcher::DirectoryEvent& ev);
|
||||
void onItemRemoved(const Poco::DirectoryWatcher::DirectoryEvent& ev);
|
||||
@@ -48,7 +51,7 @@ protected:
|
||||
void onItemMovedFrom(const Poco::DirectoryWatcher::DirectoryEvent& ev);
|
||||
void onItemMovedTo(const Poco::DirectoryWatcher::DirectoryEvent& ev);
|
||||
void onError(const Poco::Exception& exc);
|
||||
|
||||
|
||||
Poco::Path path() const;
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user