ctkPluginFrameworkTestRunner.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkPluginFrameworkTestRunner.h"
  16. #include "ctkTestSuiteInterface.h"
  17. #include <ctkPluginFrameworkFactory.h>
  18. #include <ctkPluginFramework.h>
  19. #include <ctkPluginContext.h>
  20. #include <ctkPluginException.h>
  21. #include <QStringList>
  22. #include <QPair>
  23. #include <QCoreApplication>
  24. #include <QDirIterator>
  25. #include <QTest>
  26. #include <QThread>
  27. #include <QDebug>
  28. #ifdef _WIN32
  29. #include <windows.h>
  30. #include <stdlib.h>
  31. #endif // _WIN32
  32. class TestRunner : public QThread
  33. {
  34. public:
  35. typedef QPair<long, ctkPlugin::StartOptions> StartPluginPair;
  36. TestRunner(ctkPluginContext* context, const QSet<StartPluginPair>& startPlugins, int argc, char** argv)
  37. : context(context), startPluginInfos(startPlugins),
  38. argc(argc), argv(argv)
  39. {
  40. }
  41. void run()
  42. {
  43. // start the specified plugins which may register the test suites (QObject classes)
  44. foreach(StartPluginPair pluginInfo, startPluginInfos)
  45. {
  46. QSharedPointer<ctkPlugin> plugin = context->getPlugin(pluginInfo.first);
  47. plugin->start(pluginInfo.second);
  48. }
  49. QList<ctkServiceReference> refs = context->getServiceReferences<ctkTestSuiteInterface>();
  50. int result = 0;
  51. int count = 0;
  52. foreach(ctkServiceReference ref, refs)
  53. {
  54. result = QTest::qExec(context->getService(ref), argc, argv);
  55. if (result > 0) break;
  56. ++count;
  57. }
  58. qDebug() << "#########" << count << "out of" << refs.size() << "test suites passed #########";
  59. if (result > 0)
  60. {
  61. QCoreApplication::exit(result);
  62. qApp->thread()->wait();
  63. }
  64. }
  65. private:
  66. ctkPluginContext* context;
  67. QSet<StartPluginPair> startPluginInfos;
  68. int argc;
  69. char** argv;
  70. };
  71. class ctkPluginFrameworkTestRunnerPrivate
  72. {
  73. public:
  74. typedef QPair<QString, bool> PluginPathPair;
  75. QList<PluginPathPair> pluginPaths;
  76. typedef QPair<QString, QString> InstallCandPair;
  77. QList<InstallCandPair> installCandidates;
  78. typedef QPair<QString, ctkPlugin::StartOptions> ActivatePair;
  79. QList<ActivatePair> activatePlugins;
  80. typedef QPair<long, ctkPlugin::StartOptions> StartPluginPair;
  81. QSet<StartPluginPair> startPlugins;
  82. ctkPluginContext* context;
  83. ctkPluginFrameworkFactory* fwFactory;
  84. ctkPluginFrameworkTestRunnerPrivate()
  85. : context(0), fwFactory(0)
  86. {
  87. pluginLibFilter << "*.dll" << "*.so" << "*.dylib";
  88. }
  89. void installPlugins(const QString& path)
  90. {
  91. QDirIterator dirIter(path, pluginLibFilter, QDir::Files);
  92. while(dirIter.hasNext())
  93. {
  94. dirIter.next();
  95. try
  96. {
  97. QSharedPointer<ctkPlugin> plugin = context->installPlugin(QUrl::fromLocalFile(dirIter.filePath()));
  98. long pluginId = plugin->getPluginId();
  99. QString symbolicName = plugin->getSymbolicName();
  100. foreach(ActivatePair activatePlugin, activatePlugins)
  101. {
  102. if (activatePlugin.first == symbolicName)
  103. {
  104. startPlugins.insert(qMakePair(pluginId, activatePlugin.second));
  105. activatePlugins.removeAll(activatePlugin);
  106. break;
  107. }
  108. }
  109. }
  110. catch (const ctkPluginException& e)
  111. {
  112. qCritical() << e.what();
  113. }
  114. }
  115. }
  116. void installPlugin(const QString& path, const QString& name)
  117. {
  118. QDirIterator dirIter(path, pluginLibFilter, QDir::Files);
  119. while(dirIter.hasNext())
  120. {
  121. dirIter.next();
  122. if (dirIter.fileName().contains(name))
  123. {
  124. try
  125. {
  126. QSharedPointer<ctkPlugin> plugin = context->installPlugin(QUrl::fromLocalFile(dirIter.filePath()));
  127. QString symbolicName = plugin->getSymbolicName();
  128. long pluginId = plugin->getPluginId();
  129. foreach(ActivatePair activatePlugin, activatePlugins)
  130. {
  131. if (activatePlugin.first == symbolicName)
  132. {
  133. startPlugins.insert(qMakePair(pluginId, activatePlugin.second));
  134. activatePlugins.removeAll(activatePlugin);
  135. break;
  136. }
  137. }
  138. break;
  139. }
  140. catch (const ctkPluginException& e)
  141. {
  142. qCritical() << e.what();
  143. }
  144. }
  145. }
  146. }
  147. private:
  148. QStringList pluginLibFilter;
  149. };
  150. ctkPluginFrameworkTestRunner::ctkPluginFrameworkTestRunner()
  151. : d_ptr(new ctkPluginFrameworkTestRunnerPrivate())
  152. {
  153. }
  154. ctkPluginFrameworkTestRunner::~ctkPluginFrameworkTestRunner()
  155. {
  156. Q_D(ctkPluginFrameworkTestRunner);
  157. delete d->fwFactory;
  158. }
  159. void ctkPluginFrameworkTestRunner::addPluginPath(const QString& path, bool install)
  160. {
  161. Q_D(ctkPluginFrameworkTestRunner);
  162. d->pluginPaths.push_back(qMakePair(path, install));
  163. #ifdef _WIN32
  164. #ifdef __MINGW32__
  165. QString pathVar("PATH");
  166. QString oldPath(getenv("PATH"));
  167. pathVar += "=" + oldPath + ";" + path;
  168. if(_putenv(qPrintable(pathVar)))
  169. #else
  170. std::size_t bufferLength;
  171. getenv_s(&bufferLength, NULL, 0, "PATH");
  172. QString newPath = path;
  173. if (bufferLength > 0)
  174. {
  175. char* oldPath = new char[bufferLength];
  176. getenv_s(&bufferLength, oldPath, bufferLength, "PATH");
  177. newPath.append(";").append(oldPath);
  178. delete[] oldPath;
  179. }
  180. qDebug() << "new PATH:" << newPath;
  181. if(_putenv_s("PATH", qPrintable(newPath)))
  182. #endif
  183. {
  184. LPVOID lpMsgBuf;
  185. DWORD dw = GetLastError();
  186. FormatMessage(
  187. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  188. FORMAT_MESSAGE_FROM_SYSTEM |
  189. FORMAT_MESSAGE_IGNORE_INSERTS,
  190. NULL,
  191. dw,
  192. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  193. (LPTSTR) &lpMsgBuf,
  194. 0, NULL );
  195. QString msg = QString("Adding '%1' to the PATH environment variable failed: %2")
  196. .arg(path).arg(QString((LPCTSTR)lpMsgBuf));
  197. qWarning() << msg;
  198. LocalFree(lpMsgBuf);
  199. }
  200. #endif
  201. }
  202. void ctkPluginFrameworkTestRunner::addPlugin(const QString &path, const QString &name)
  203. {
  204. Q_D(ctkPluginFrameworkTestRunner);
  205. d->installCandidates.push_back(qMakePair(path, name));
  206. }
  207. void ctkPluginFrameworkTestRunner::startPluginOnRun(const QString& pluginId, ctkPlugin::StartOptions opts)
  208. {
  209. Q_D(ctkPluginFrameworkTestRunner);
  210. d->activatePlugins.push_back(qMakePair(pluginId, opts));
  211. }
  212. void ctkPluginFrameworkTestRunner::init(const ctkProperties& fwProps)
  213. {
  214. Q_D(ctkPluginFrameworkTestRunner);
  215. d->fwFactory = new ctkPluginFrameworkFactory(fwProps);
  216. QSharedPointer<ctkPluginFramework> framework = d->fwFactory->getFramework();
  217. framework->start();
  218. d->context = framework->getPluginContext();
  219. foreach(ctkPluginFrameworkTestRunnerPrivate::PluginPathPair path,
  220. d->pluginPaths)
  221. {
  222. QCoreApplication::addLibraryPath(path.first);
  223. if (path.second) d->installPlugins(path.first);
  224. }
  225. foreach(ctkPluginFrameworkTestRunnerPrivate::InstallCandPair candidate,
  226. d->installCandidates)
  227. {
  228. d->installPlugin(candidate.first, candidate.second);
  229. }
  230. }
  231. int ctkPluginFrameworkTestRunner::run(int argc, char** argv)
  232. {
  233. Q_D(ctkPluginFrameworkTestRunner);
  234. if (!d->activatePlugins.isEmpty())
  235. {
  236. qCritical() << "The following plugins will not be started, because"
  237. << "they could not be installed:";
  238. foreach(ctkPluginFrameworkTestRunnerPrivate::ActivatePair p,
  239. d->activatePlugins)
  240. {
  241. qCritical() << " -" << p.first;
  242. }
  243. return EXIT_FAILURE;
  244. }
  245. TestRunner runner(d->context, d->startPlugins, argc, argv);
  246. runner.connect(&runner, SIGNAL(finished()), qApp, SLOT(quit()));
  247. runner.start();
  248. return qApp->exec();
  249. }