|
@@ -24,7 +24,11 @@
|
|
|
#include "ctkCmdLineModuleBackend.h"
|
|
|
#include "ctkException.h"
|
|
|
#include "ctkCmdLineModuleFuture.h"
|
|
|
+#include "ctkCmdLineModuleReferenceResult.h"
|
|
|
+#include <ctkCmdLineModuleConcurrentHelpers.h>
|
|
|
+#include <ctkCmdLineModuleTimeoutException.h>
|
|
|
|
|
|
+#include "ctkUtils.h"
|
|
|
#include "ctkTest.h"
|
|
|
|
|
|
#include <QCoreApplication>
|
|
@@ -43,18 +47,47 @@ class BackendMockUp : public ctkCmdLineModuleBackend
|
|
|
|
|
|
public:
|
|
|
|
|
|
- void addModule(const QUrl& location, const QByteArray& xml)
|
|
|
+ void addModule(const QUrl& location, const QByteArray& xml, int msDelay = 0)
|
|
|
{
|
|
|
- this->UrlToXml[location] = xml;
|
|
|
+ this->m_UrlToXmlRetrievalCount[location] = 0;
|
|
|
+ this->m_UrlToXml[location] = xml;
|
|
|
+ this->m_UrlToXmlOutputDelay[location] = msDelay;
|
|
|
+ }
|
|
|
+
|
|
|
+ void setTimestamp(const QUrl& location, qint64 timestamp)
|
|
|
+ {
|
|
|
+ this->m_UrlToTimestamp[location] = timestamp;
|
|
|
+ }
|
|
|
+
|
|
|
+ QList<QUrl> moduleLocations() const
|
|
|
+ {
|
|
|
+ return this->m_UrlToXml.keys();
|
|
|
+ }
|
|
|
+
|
|
|
+ int xmlRetrievalCount(const QUrl& location) const
|
|
|
+ {
|
|
|
+ QHash<QUrl,int>::ConstIterator iter = this->m_UrlToXmlRetrievalCount.find(location);
|
|
|
+ return iter == this->m_UrlToXmlRetrievalCount.end() ? 0 : iter.value();
|
|
|
}
|
|
|
|
|
|
virtual QString name() const { return "Mockup"; }
|
|
|
virtual QString description() const { return "Test Mock-up"; }
|
|
|
virtual QList<QString> schemes() const { return QList<QString>() << "test"; }
|
|
|
- virtual qint64 timeStamp(const QUrl& /*location*/) const { return 0; }
|
|
|
- virtual QByteArray rawXmlDescription(const QUrl& location)
|
|
|
+
|
|
|
+ virtual qint64 timeStamp(const QUrl& location) const
|
|
|
+ {
|
|
|
+ QHash<QUrl,qint64>::ConstIterator iter = this->m_UrlToTimestamp.find(location);
|
|
|
+ return iter == this->m_UrlToTimestamp.end() ? 0 : iter.value();
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual QByteArray rawXmlDescription(const QUrl& location, int timeout)
|
|
|
{
|
|
|
- return UrlToXml[location];
|
|
|
+ ++m_UrlToXmlRetrievalCount[location];
|
|
|
+ if (timeout < m_UrlToXmlOutputDelay[location])
|
|
|
+ {
|
|
|
+ throw ctkCmdLineModuleTimeoutException(location, "Timeout in BackendMockUp occurred");
|
|
|
+ }
|
|
|
+ return m_UrlToXml[location];
|
|
|
}
|
|
|
|
|
|
protected:
|
|
@@ -66,7 +99,10 @@ protected:
|
|
|
|
|
|
private:
|
|
|
|
|
|
- QHash<QUrl, QByteArray> UrlToXml;
|
|
|
+ QHash<QUrl, qint64> m_UrlToTimestamp;
|
|
|
+ QHash<QUrl, int> m_UrlToXmlRetrievalCount;
|
|
|
+ QHash<QUrl, int> m_UrlToXmlOutputDelay;
|
|
|
+ QHash<QUrl, QByteArray> m_UrlToXml;
|
|
|
};
|
|
|
|
|
|
}
|
|
@@ -79,15 +115,19 @@ class ctkCmdLineModuleManagerTester : public QObject
|
|
|
private Q_SLOTS:
|
|
|
|
|
|
void initTestCase();
|
|
|
+ void cleanup();
|
|
|
|
|
|
void testStrictValidation();
|
|
|
void testWeakValidation();
|
|
|
void testSkipValidation();
|
|
|
+ void testTimeoutHandling();
|
|
|
+ void testCaching();
|
|
|
|
|
|
private:
|
|
|
|
|
|
QByteArray validXml;
|
|
|
QByteArray invalidXml;
|
|
|
+ QString cachePath;
|
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
@@ -122,6 +162,14 @@ void ctkCmdLineModuleManagerTester::initTestCase()
|
|
|
" </integer>\n"
|
|
|
" </parameters>\n"
|
|
|
"</executable>\n";
|
|
|
+
|
|
|
+ cachePath = QDir::tempPath() + QDir::separator() + "ctkCmdLineModuleManagerTester_cache";
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkCmdLineModuleManagerTester::cleanup()
|
|
|
+{
|
|
|
+ ctk::removeDirRecursively(cachePath);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
@@ -186,6 +234,168 @@ void ctkCmdLineModuleManagerTester::testSkipValidation()
|
|
|
QVERIFY(moduleRef2.xmlValidationErrorString().isEmpty());
|
|
|
}
|
|
|
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkCmdLineModuleManagerTester::testTimeoutHandling()
|
|
|
+{
|
|
|
+ BackendMockUp backend;
|
|
|
+ backend.addModule(QUrl("test://validXml"), validXml, 1000);
|
|
|
+ backend.addModule(QUrl("test://validXml2"), validXml);
|
|
|
+
|
|
|
+ ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::STRICT_VALIDATION, cachePath);
|
|
|
+ manager.setTimeOutForXMLRetrieval(2000);
|
|
|
+
|
|
|
+ manager.registerBackend(&backend);
|
|
|
+
|
|
|
+ // register modules with a sufficient large timeout value
|
|
|
+ QList<ctkCmdLineModuleReferenceResult> results =
|
|
|
+ QtConcurrent::blockingMapped(backend.moduleLocations(),
|
|
|
+ ctkCmdLineModuleConcurrentRegister(&manager, true));
|
|
|
+
|
|
|
+ QVERIFY(results.size() == 2);
|
|
|
+ QVERIFY(results[0].m_Reference && results[0].m_RuntimeError.isEmpty());
|
|
|
+ QVERIFY(results[1].m_Reference && results[1].m_RuntimeError.isEmpty());
|
|
|
+
|
|
|
+ // unregister the modules
|
|
|
+ QList<bool> unregisterResults =
|
|
|
+ QtConcurrent::blockingMapped(backend.moduleLocations(),
|
|
|
+ ctkCmdLineModuleConcurrentUnRegister(&manager));
|
|
|
+ QVERIFY(unregisterResults.size() == 2);
|
|
|
+ QVERIFY(unregisterResults[0] && unregisterResults[1]);
|
|
|
+
|
|
|
+ // register modules where one runs into a timeout
|
|
|
+ manager.setTimeOutForXMLRetrieval(500);
|
|
|
+ results = QtConcurrent::blockingMapped(backend.moduleLocations(),
|
|
|
+ ctkCmdLineModuleConcurrentRegister(&manager, true));
|
|
|
+
|
|
|
+ QVERIFY(results.size() == 2);
|
|
|
+ QVERIFY(!results[0].m_Reference && !results[0].m_RuntimeError.isEmpty());
|
|
|
+ QVERIFY(results[1].m_Reference && results[1].m_RuntimeError.isEmpty());
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkCmdLineModuleManagerTester::testCaching()
|
|
|
+{
|
|
|
+ QUrl location("test://validXml");
|
|
|
+ QUrl location2("test://validXml2");
|
|
|
+
|
|
|
+ // The code below is inside a local scopes so the manager is destroyed
|
|
|
+ // but the cache is still available (unregistering the module would also
|
|
|
+ // remove the cache entry, but we need to test the entry)
|
|
|
+
|
|
|
+ {
|
|
|
+ BackendMockUp backend;
|
|
|
+ backend.addModule(location, validXml, 1000);
|
|
|
+
|
|
|
+ ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::STRICT_VALIDATION, cachePath);
|
|
|
+ manager.setTimeOutForXMLRetrieval(500);
|
|
|
+
|
|
|
+ manager.registerBackend(&backend);
|
|
|
+
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 0);
|
|
|
+
|
|
|
+ // module runs into a timeout
|
|
|
+ try
|
|
|
+ {
|
|
|
+ manager.registerModule(location);
|
|
|
+ QFAIL("ctkCmdLineModuleTimeoutException expected");
|
|
|
+ }
|
|
|
+ catch (const ctkCmdLineModuleTimeoutException&)
|
|
|
+ {}
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 1);
|
|
|
+
|
|
|
+ // Increase the timeout and register the module again. It should
|
|
|
+ // not have been cached and the manager is supposed to try to
|
|
|
+ // retrieve the XML description again
|
|
|
+ manager.setTimeOutForXMLRetrieval(2000);
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 2);
|
|
|
+
|
|
|
+ // Registering the same module again should just return the already
|
|
|
+ // created module reference
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ BackendMockUp backend;
|
|
|
+ backend.addModule(location, validXml);
|
|
|
+ backend.setTimestamp(location, 1);
|
|
|
+ backend.addModule(location2, invalidXml);
|
|
|
+ backend.setTimestamp(location2, 1);
|
|
|
+
|
|
|
+ ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::STRICT_VALIDATION, cachePath);
|
|
|
+ manager.registerBackend(&backend);
|
|
|
+
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 1);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ manager.registerModule(location2);
|
|
|
+ QFAIL("ctkInvalidArgumentException (invalid XML) expected");
|
|
|
+ }
|
|
|
+ catch (const ctkInvalidArgumentException&)
|
|
|
+ {}
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location2) == 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do the same again but now the cache entries should be returned
|
|
|
+ {
|
|
|
+ BackendMockUp backend;
|
|
|
+ backend.addModule(location, validXml);
|
|
|
+ backend.setTimestamp(location, 1);
|
|
|
+ backend.addModule(location2, invalidXml);
|
|
|
+ backend.setTimestamp(location2, 1);
|
|
|
+
|
|
|
+ ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::STRICT_VALIDATION, cachePath);
|
|
|
+ manager.registerBackend(&backend);
|
|
|
+
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 0);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ manager.registerModule(location2);
|
|
|
+ QFAIL("ctkInvalidArgumentException (invalid XML) expected");
|
|
|
+ }
|
|
|
+ catch (const ctkInvalidArgumentException&)
|
|
|
+ {}
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location2) == 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now test updated timestamps
|
|
|
+ {
|
|
|
+ BackendMockUp backend;
|
|
|
+ backend.addModule(location, validXml);
|
|
|
+ backend.setTimestamp(location, 2);
|
|
|
+ // use valid XML now but keep the previous timestamp
|
|
|
+ backend.addModule(location2, validXml);
|
|
|
+ backend.setTimestamp(location2, 1);
|
|
|
+
|
|
|
+ ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::STRICT_VALIDATION, cachePath);
|
|
|
+ manager.registerBackend(&backend);
|
|
|
+
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 1);
|
|
|
+
|
|
|
+ // should still throw an exception due to the cache entry
|
|
|
+ try
|
|
|
+ {
|
|
|
+ manager.registerModule(location2);
|
|
|
+ QFAIL("ctkInvalidArgumentException (invalid XML) expected");
|
|
|
+ }
|
|
|
+ catch (const ctkInvalidArgumentException&)
|
|
|
+ {}
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location2) == 0);
|
|
|
+
|
|
|
+ // now update the timestamp and check that the valid XML is retrieved
|
|
|
+ backend.setTimestamp(location, 2);
|
|
|
+ QVERIFY(manager.registerModule(location));
|
|
|
+ QVERIFY(backend.xmlRetrievalCount(location) == 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// ----------------------------------------------------------------------------
|
|
|
CTK_TEST_MAIN(ctkCmdLineModuleManagerTest)
|
|
|
#include "moc_ctkCmdLineModuleManagerTest.cpp"
|