Bladeren bron

Initial test suite for PluginFramework service events.

Sascha Zelzer 14 jaren geleden
bovenliggende
commit
585cd6c2c4

+ 2 - 0
Libs/PluginFramework/Testing/FrameworkTest/CMakeLists.txt

@@ -5,11 +5,13 @@ SET(PLUGIN_export_directive "org_commontk_pluginfwtest_EXPORT")
 SET(PLUGIN_SRCS
   ctkPluginFrameworkTestActivator.cpp
   ctkPluginFrameworkTestSuite.cpp
+  ctkServiceListenerTestSuite.cpp
 )
 
 SET(PLUGIN_MOC_SRCS
   ctkPluginFrameworkTestActivator_p.h
   ctkPluginFrameworkTestSuite_p.h
+  ctkServiceListenerTestSuite_p.h
 )
 
 SET(PLUGIN_UI_FORMS

+ 6 - 0
Libs/PluginFramework/Testing/FrameworkTest/ctkPluginFrameworkTestActivator.cpp

@@ -22,6 +22,7 @@
 #include "ctkPluginFrameworkTestActivator_p.h"
 
 #include "ctkPluginFrameworkTestSuite_p.h"
+#include "ctkServiceListenerTestSuite_p.h"
 
 #include <ctkPluginContext.h>
 #include <ctkPluginConstants.h>
@@ -37,6 +38,10 @@ void ctkPluginFrameworkTestActivator::start(ctkPluginContext* context)
   props.clear();
   props.insert(ctkPluginConstants::SERVICE_PID, frameworkTestSuite->metaObject()->className());
   context->registerService(QStringList("ctkTestSuiteInterface"), frameworkTestSuite, props);
+
+  serviceListenerTestSuite = new ctkServiceListenerTestSuite(context);
+  props.insert(ctkPluginConstants::SERVICE_PID, frameworkTestSuite->metaObject()->className());
+  context->registerService(QStringList("ctkTestSuiteInterface"), serviceListenerTestSuite, props);
 }
 
 void ctkPluginFrameworkTestActivator::stop(ctkPluginContext* context)
@@ -44,6 +49,7 @@ void ctkPluginFrameworkTestActivator::stop(ctkPluginContext* context)
   Q_UNUSED(context);
 
   delete frameworkTestSuite;
+  delete serviceListenerTestSuite;
 }
 
 Q_EXPORT_PLUGIN2(org_commontk_pluginfwtest, ctkPluginFrameworkTestActivator)

+ 1 - 0
Libs/PluginFramework/Testing/FrameworkTest/ctkPluginFrameworkTestActivator_p.h

@@ -40,6 +40,7 @@ public:
 private:
 
   QObject* frameworkTestSuite;
+  QObject* serviceListenerTestSuite;
 };
 
 #endif // CTKPLUGINFRAMEWORKTESTACTIVATOR_H

+ 298 - 0
Libs/PluginFramework/Testing/FrameworkTest/ctkServiceListenerTestSuite.cpp

@@ -0,0 +1,298 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#include "ctkServiceListenerTestSuite_p.h"
+
+#include <ctkPlugin.h>
+#include <ctkPluginContext.h>
+#include <ctkPluginException.h>
+#include <ctkPluginConstants.h>
+#include <ctkServiceEvent.h>
+
+#include <ctkPluginFrameworkTestUtil.h>
+
+#include <QTest>
+
+ctkServiceListenerTestSuite::ctkServiceListenerTestSuite(ctkPluginContext* pc)
+  : pc(pc), p(pc->getPlugin())
+{
+}
+
+void ctkServiceListenerTestSuite::initTestCase()
+{
+  pA = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginA_test");
+  QVERIFY(pA);
+}
+
+void ctkServiceListenerTestSuite::cleanupTestCase()
+{
+  pA->uninstall();
+}
+
+void ctkServiceListenerTestSuite::frameSL05a()
+{
+  bool teststatus = true;
+  int cnt = 1;
+
+  QList<ctkServiceEvent::Type> events;
+  events << ctkServiceEvent::REGISTERED;
+  events << ctkServiceEvent::UNREGISTERING;
+  teststatus = runStartStopTest("FRAMEsl05A", cnt, pA, events);
+
+  QVERIFY(teststatus);
+}
+
+bool ctkServiceListenerTestSuite::runStartStopTest(
+  const QString& tcName, int cnt, QSharedPointer<ctkPlugin> targetPlugin,
+  const QList<ctkServiceEvent::Type>& events)
+{
+  bool teststatus = true;
+
+  for (int i = 0; i < cnt && teststatus; ++i)
+  {
+    ctkServiceListener sListen(pc);
+    try
+    {
+      pc->connectServiceListener(&sListen, "serviceChanged");
+    }
+    catch (const std::logic_error& ise)
+    {
+      teststatus  = false;
+      qDebug() << "service listener registration failed " << ise.what()
+               << " :" << tcName << ":FAIL";
+    }
+
+    // Start the test target to get a service published.
+    try
+    {
+      qDebug() << "Starting targetPlugin: " << targetPlugin;
+      targetPlugin->start();
+    }
+    catch (const ctkPluginException& pex)
+    {
+      teststatus  = false;
+      qDebug() << "Failed to start plugin, got exception: "
+               << pex.what() << " in " << tcName << ":FAIL";
+    }
+    catch (const std::exception& e)
+    {
+      teststatus  = false;
+      qDebug() << "Failed to start plugin, got exception: "
+               << e.what() << " + in " << tcName << ":FAIL";
+    }
+
+    // sleep to stabelize state.
+    QTest::qWait(300);
+
+    // Stop the test target to get a service unpublished.
+    try
+    {
+      targetPlugin->stop();
+    }
+    catch (const ctkPluginException& pex)
+    {
+      teststatus  = false;
+      qDebug() << "Failed to stop plugin, got exception: "
+               << pex.what() << " in " << tcName << ":FAIL";
+    }
+    catch (const std::exception& e)
+    {
+      teststatus  = false;
+      qDebug() << "Failed to stop plugin, got exception: "
+               << e.what() << " + in " << tcName << ":FAIL";
+    }
+
+    if (teststatus && !sListen.checkEvents(events))
+    {
+      teststatus  = false;
+      qDebug() << "Service listener event notification error :"
+               << tcName << ":FAIL";
+    }
+
+    try
+    {
+      pc->disconnectServiceListener(&sListen, "serviceChanged");
+      teststatus &= sListen.teststatus;
+      sListen.clearEvents();
+    }
+    catch (const std::logic_error& ise)
+    {
+      teststatus  = false;
+      qDebug() << "service listener removal failed " << ise.what()
+               << " :" << tcName << ":FAIL";
+    }
+  }
+  return teststatus;
+}
+
+ctkServiceListener::ctkServiceListener(ctkPluginContext* pc, bool checkUsingBundles)
+  : checkUsingBundles(checkUsingBundles), teststatus(true), pc(pc)
+{
+
+}
+
+void ctkServiceListener::clearEvents()
+{
+  events.clear();
+}
+
+bool ctkServiceListener::checkEvents(const QList<ctkServiceEvent::Type>& eventTypes)
+{
+  if (events.size() != eventTypes.size())
+  {
+    dumpEvents(eventTypes);
+    return false;
+  }
+
+  for (int i=0; i < eventTypes.size(); ++i)
+  {
+    if (eventTypes[i] != events[i].getType())
+    {
+      dumpEvents(eventTypes);
+      return false;
+    }
+  }
+  return true;
+}
+
+void ctkServiceListener::serviceChanged(const ctkServiceEvent& evt)
+{
+  events.push_back(evt);
+  qDebug() << "ServiceEvent:" << evt;
+  if (ctkServiceEvent::UNREGISTERING == evt.getType())
+  {
+    ctkServiceReference sr = evt.getServiceReference();
+
+    // Validate that no bundle is marked as using the service
+    QList<ctkPlugin*> usingPlugins = sr.getUsingPlugins();
+    if (checkUsingBundles && !usingPlugins.isEmpty())
+    {
+      teststatus = false;
+      printUsingPlugins(sr, "*** Using plugins (unreg) should be empty but is: ");
+    }
+
+    // Check if the service can be fetched
+    QObject* service = pc->getService(sr);
+    usingPlugins = sr.getUsingPlugins();
+//    if (UNREGISTERSERVICE_VALID_DURING_UNREGISTERING) {
+      // In this mode the service shall be obtainable during
+      // unregistration.
+      if (service == 0)
+      {
+        teststatus = false;
+        qDebug() << "*** Service should be available to ServiceListener "
+                 << "while handling unregistering event.";
+      }
+      qDebug() << "Service (unreg): " << service->metaObject()->className();
+      if (checkUsingBundles && usingPlugins.size() != 1)
+      {
+        teststatus = false;
+        printUsingPlugins(sr, "*** One using plugin expected "
+                          "(unreg, after getService), found: ");
+      }
+      else
+      {
+        printUsingPlugins(sr, "Using plugins (unreg, after getService): ");
+      }
+//    } else {
+//      // In this mode the service shall NOT be obtainable during
+//      // unregistration.
+//      if (null!=service) {
+//        teststatus = false;
+//        out.print("*** Service should not be available to ServiceListener "
+//                  +"while handling unregistering event.");
+//      }
+//      if (checkUsingBundles && null!=usingBundles) {
+//        teststatus = false;
+//        printUsingBundles(sr,
+//                          "*** Using bundles (unreg, after getService), "
+//                          +"should be null but is: ");
+//      } else {
+//        printUsingBundles(sr,
+//                          "Using bundles (unreg, after getService): null");
+//      }
+//    }
+    pc->ungetService(sr);
+
+    // Check that the UNREGISTERING service can not be looked up
+    // using the service registry.
+    try
+    {
+      qulonglong sid = sr.getProperty(ctkPluginConstants::SERVICE_ID).toLongLong();
+      QString sidFilter = QString("(") + ctkPluginConstants::SERVICE_ID + "=" + sid + ")";
+      QList<ctkServiceReference> srs = pc->getServiceReferences("", sidFilter);
+      if (srs.isEmpty())
+      {
+        qDebug() << "ctkServiceReference for UNREGISTERING service is not"
+                    " found in the service registry; ok.";
+      }
+      else
+      {
+        teststatus = false;
+        qDebug() << "*** ctkServiceReference for UNREGISTERING service,"
+                 << sr << ", not found in the service registry; fail.";
+        qDebug() << "Found the following Service references:";
+        foreach(ctkServiceReference sr, srs)
+        {
+          qDebug() << sr;
+        }
+      }
+    }
+    catch (const std::exception& e)
+    {
+      teststatus = false;
+      qDebug() << "*** Unexpected excpetion when trying to lookup a"
+                  " service while it is in state UNREGISTERING;"
+               << e.what();
+    }
+  }
+}
+
+void ctkServiceListener::printUsingPlugins(const ctkServiceReference& sr,
+                                           const QString& caption)
+{
+  QList<ctkPlugin*> usingPlugins = sr.getUsingPlugins();
+
+  qDebug() << (caption.isEmpty() ? "Using plugins: " : caption);
+  foreach(ctkPlugin* plugin, usingPlugins)
+  {
+    qDebug() << "  -" << plugin;
+  }
+}
+
+void ctkServiceListener::dumpEvents(const QList<ctkServiceEvent::Type>& eventTypes)
+{
+  int max = events.size() > eventTypes.size() ? events.size() : eventTypes.size();
+  qDebug() << "Expected event type --  Actual event";
+  for (int i=0; i < max; ++i)
+  {
+    ctkServiceEvent evt = i < events.size() ? events[i] : ctkServiceEvent();
+    if (i < eventTypes.size())
+    {
+      qDebug() << " " << eventTypes[i] << "--" << evt;
+    }
+    else
+    {
+      qDebug() << " " << "- NONE - " << "--" << evt;
+    }
+  }
+}

+ 105 - 0
Libs/PluginFramework/Testing/FrameworkTest/ctkServiceListenerTestSuite_p.h

@@ -0,0 +1,105 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKSERVICELISTENERTESTSUITE_P_H
+#define CTKSERVICELISTENERTESTSUITE_P_H
+
+#include <QObject>
+
+#include <ctkTestSuiteInterface.h>
+#include <ctkServiceEvent.h>
+
+class ctkPlugin;
+class ctkPluginContext;
+
+class ctkServiceListenerTestSuite : public QObject,
+    public ctkTestSuiteInterface
+{
+  Q_OBJECT
+
+public:
+    ctkServiceListenerTestSuite(ctkPluginContext* pc);
+
+private slots:
+
+    void initTestCase();
+    void cleanupTestCase();
+
+    // test functions
+    void frameSL05a();
+//    void frameSL10a();
+//    void frameSL15a();
+//    void frameSL20a();
+//    void frameSL25a();
+
+private:
+
+    ctkPluginContext* pc;
+    QSharedPointer<ctkPlugin> p;
+
+    QSharedPointer<ctkPlugin> pA;
+    QSharedPointer<ctkPlugin> pA2;
+
+    bool runStartStopTest(
+      const QString& tcName, int cnt, QSharedPointer<ctkPlugin> targetPlugin,
+      const QList<ctkServiceEvent::Type>& events);
+};
+
+class ctkServiceListener : public QObject
+{
+  Q_OBJECT
+
+private:
+
+  friend class ctkServiceListenerTestSuite;
+
+  const bool checkUsingBundles;
+  QList<ctkServiceEvent> events;
+
+  bool teststatus;
+
+  ctkPluginContext* pc;
+
+public:
+
+  ctkServiceListener(ctkPluginContext* pc, bool checkUsingBundles = true);
+
+  void clearEvents();
+
+  bool checkEvents(const QList<ctkServiceEvent::Type>& eventTypes);
+
+protected slots:
+
+  void serviceChanged(const ctkServiceEvent& evt);
+
+private:
+
+  void printUsingPlugins(const ctkServiceReference& sr, const QString& caption);
+
+  // Print expected and actual service events.
+  void dumpEvents(const QList<ctkServiceEvent::Type>& eventTypes);
+
+}; // end of class ctkServiceListener
+
+
+
+#endif // CTKSERVICELISTENERTESTSUITE_P_H