1 /*=============================================================================
2
3 Library: CTK
4
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics
7
8 Licensed under the Apache License, Version 2.0 (the "License");
9 you may not use this file except in compliance with the License.
10 You may obtain a copy of the License at
11
12 http://www.apache.org/licenses/LICENSE-2.0
13
14 Unless required by applicable law or agreed to in writing, software
15 distributed under the License is distributed on an "AS IS" BASIS,
16 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 See the License for the specific language governing permissions and
18 limitations under the License.
19
20 =============================================================================*/
21
22
23 #include "ctkServiceListenerTestSuite_p.h"
24
25 #include <ctkPlugin.h>
26 #include <ctkPluginContext.h>
27 #include <ctkPluginException.h>
28 #include <ctkPluginConstants.h>
29 #include <ctkServiceEvent.h>
30 #include <ctkServiceException.h>
31
32 #include <ctkPluginFrameworkTestUtil.h>
33
34 #include <QTest>
35
36 //----------------------------------------------------------------------------
ctkServiceListenerTestSuite(ctkPluginContext * pc)37 ctkServiceListenerTestSuite::ctkServiceListenerTestSuite(ctkPluginContext* pc)
38 : pc(pc), p(pc->getPlugin())
39 {
40 }
41
42 //----------------------------------------------------------------------------
initTestCase()43 void ctkServiceListenerTestSuite::initTestCase()
44 {
45 pA = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginA_test");
46 QVERIFY(pA);
47 pA2 = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginA2_test");
48 QVERIFY(pA2);
49 pSL1 = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginSL1_test");
50 QVERIFY(pSL1);
51 pSL3 = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginSL3_test");
52 QVERIFY(pSL3);
53 pSL4 = ctkPluginFrameworkTestUtil::installPlugin(pc, "pluginSL4_test");
54 QVERIFY(pSL4);
55 }
56
57 //----------------------------------------------------------------------------
cleanupTestCase()58 void ctkServiceListenerTestSuite::cleanupTestCase()
59 {
60 pA->uninstall();
61 pA2->uninstall();
62 pSL1->uninstall();
63 pSL3->uninstall();
64 pSL4->uninstall();
65 }
66
67 //----------------------------------------------------------------------------
frameSL05a()68 void ctkServiceListenerTestSuite::frameSL05a()
69 {
70 bool teststatus = true;
71 int cnt = 1;
72
73 QList<ctkServiceEvent::Type> events;
74 events << ctkServiceEvent::REGISTERED;
75 events << ctkServiceEvent::UNREGISTERING;
76 teststatus = runStartStopTest("FRAMEsl05A", cnt, pA, events);
77
78 QVERIFY(teststatus);
79 }
80
81 //----------------------------------------------------------------------------
frameSL10a()82 void ctkServiceListenerTestSuite::frameSL10a()
83 {
84 int cnt = 1;
85
86 QList<ctkServiceEvent::Type> events;
87 events << ctkServiceEvent::REGISTERED;
88 events << ctkServiceEvent::UNREGISTERING;
89 QVERIFY(runStartStopTest("FRAMEsl10A", cnt, pA2,events));
90 }
91
92 //----------------------------------------------------------------------------
frameSL25a()93 void ctkServiceListenerTestSuite::frameSL25a()
94 {
95 ctkServiceListener sListen(pc, false);
96 try
97 {
98 pc->connectServiceListener(&sListen, "serviceChanged");
99 }
100 catch (const ctkIllegalStateException& ise)
101 {
102 qDebug() << "service listener registration failed " << ise.what();
103 QFAIL("service listener registration failed");
104 }
105
106 QList<ctkServiceEvent::Type> expectedServiceEventTypes;
107
108 // Startup
109 expectedServiceEventTypes << ctkServiceEvent::REGISTERED; // ctkActivator at start of pSL1
110 expectedServiceEventTypes << ctkServiceEvent::REGISTERED; // ctkFooService at start of pSL4
111 expectedServiceEventTypes << ctkServiceEvent::REGISTERED; // ctkActivator at start of pSL3
112
113 // Stop pSL4
114 expectedServiceEventTypes << ctkServiceEvent::UNREGISTERING; // ctkFooService at first stop of pSL4
115
116 // Shutdown
117 expectedServiceEventTypes << ctkServiceEvent::UNREGISTERING; // ctkActivator at stop of pSL1
118 expectedServiceEventTypes << ctkServiceEvent::UNREGISTERING; // Activator at stop of pSL3
119
120
121 // Start pSL1 to ensure that the Service interface is available.
122 try
123 {
124 qDebug() << "Starting pSL1: " << pSL1;
125 pSL1->start();
126 }
127 catch (const ctkPluginException& pex)
128 {
129 qDebug() << "Failed to start plugin, got exception:" << pex;
130 QFAIL("Failed to start bundle, got exception: ctkPluginException");
131 }
132 catch (const std::exception& e)
133 {
134 qDebug() << "Failed to start plugin, got exception" << e.what();
135 QFAIL("Failed to start plugin, got exception: std::exception");
136 }
137
138 // Start pSL4 that will require the serivce interface and publish
139 // ctkFooService
140 try
141 {
142 qDebug() << "Starting pSL4:" << pSL4;
143 pSL4->start();
144 }
145 catch (const ctkPluginException& pex)
146 {
147 qDebug() << "Failed to start plugin, got exception:" << pex;
148 QFAIL("Failed to start bundle, got exception: ctkPluginException");
149 }
150 catch (const std::exception& e)
151 {
152 qDebug() << "Failed to start plugin, got exception" << e.what();
153 QFAIL("Failed to start plubin, got exception.");
154 }
155
156 // Start buSL3 that will require the serivce interface and get the service
157 try
158 {
159 qDebug() << "Starting pSL3:" << pSL3;
160 pSL3->start();
161 }
162 catch (const ctkPluginException& pex)
163 {
164 qDebug() << "Failed to start plugin, got exception:" << pex;
165 QFAIL("Failed to start plugin, got exception: ctkPluginException");
166 }
167 catch (const std::exception& e)
168 {
169 qDebug() << "Failed to start plugin, got exception" << e.what();
170 QFAIL("Failed to start plugin, got exception.");
171 }
172
173 // sleep to stabelize state.
174 QTest::qWait(300);
175
176 // Check that pSL3 has been notified about the ctkFooService.
177 qDebug() << "Check that ctkFooService is added to service tracker in pSL3";
178 try
179 {
180 ctkServiceReference pSL3SR
181 = pc->getServiceReference("ctkActivatorSL3");
182 QObject* pSL3Activator = pc->getService(pSL3SR);
183 QVERIFY2(pSL3Activator, "No activator service.");
184
185 QVariant serviceAddedField3 = pSL3Activator->property("serviceAdded");
186 QVERIFY2(serviceAddedField3.isValid() && serviceAddedField3.toBool(),
187 "pluginSL3 not notified about presence of ctkFooService");
188 qDebug() << "pSL3Activator::serviceAdded is true";
189 pc->ungetService(pSL3SR);
190 }
191 catch (const ctkServiceException& se)
192 {
193 qDebug() << "Failed to get service reference:" << se;
194 QFAIL("No activator service reference.");
195 }
196
197 // Check that pSL1 has been notified about the ctkFooService.
198 qDebug() << "Check that ctkFooService is added to service tracker in pSL1";
199 try
200 {
201 ctkServiceReference pSL1SR
202 = pc->getServiceReference("ctkActivatorSL1");
203 QObject* pSL1Activator = pc->getService(pSL1SR);
204 QVERIFY2(pSL1Activator, "No activator service.");
205
206 QVariant serviceAddedField = pSL1Activator->property("serviceAdded");
207 QVERIFY2(serviceAddedField.isValid() && serviceAddedField.toBool(),
208 "bundleSL1 not notified about presence of ctkFooService");
209 qDebug() << "pSL1Activator::serviceAdded is true";
210 pc->ungetService(pSL1SR);
211 }
212 catch (const ctkServiceException& se)
213 {
214 qDebug() << "Failed to get service reference:" << se;
215 QFAIL("No activator service reference.");
216 }
217
218 // Stop the service provider: pSL4
219 try
220 {
221 qDebug() << "Stop pSL4:" << pSL4;
222 pSL4->stop();
223 }
224 catch (const ctkPluginException& pex)
225 {
226 qDebug() << "Failed to stop plugin, got exception:" << pex;
227 QFAIL("Failed to stop bundle, got exception: ctkPluginException");
228 }
229 catch (const std::exception& e)
230 {
231 qDebug() << "Failed to stop plugin, got exception:" << e.what();
232 QFAIL("Failed to stop plugin, got exception.");
233 }
234
235 // sleep to stabelize state.
236 QTest::qWait(300);
237
238
239 // Check that pSL3 has been notified about the removal of ctkFooService.
240 qDebug() << "Check that ctkFooService is removed from service tracker in pSL3";
241 try
242 {
243 ctkServiceReference pSL3SR
244 = pc->getServiceReference("ctkActivatorSL3");
245 QObject* pSL3Activator = pc->getService(pSL3SR);
246 QVERIFY2(pSL3Activator, "No activator service.");
247 QVariant serviceRemovedField3 = pSL3Activator->property("serviceRemoved");
248 QVERIFY2(serviceRemovedField3.isValid() && serviceRemovedField3.toBool(),
249 "pluginSL3 not notified about removal of ctkFooService");
250 qDebug() << "pSL3Activator::serviceRemoved is true";
251 pc->ungetService(pSL3SR);
252 }
253 catch (const ctkServiceException& se)
254 {
255 qDebug() << "Failed to get service reference:" << se;
256 QFAIL("No activator service reference.");
257 }
258
259 // Stop pSL1
260 try
261 {
262 qDebug() << "Stop pSL1:" << pSL1;
263 pSL1->stop();
264 }
265 catch (const ctkPluginException& pex)
266 {
267 qDebug() << "Failed to stop plugin, got exception:" << pex;
268 QFAIL("Failed to stop bundle, got exception: ctkPluginException");
269 }
270 catch (const std::exception& e)
271 {
272 qDebug() << "Failed to stop plugin, got exception" << e.what();
273 QFAIL("Failed to stop plugin, got exception.");
274 }
275
276 // Stop pSL3
277 try
278 {
279 qDebug() << "Stop pSL3:" << pSL3;
280 pSL3->stop();
281 }
282 catch (const ctkPluginException& pex)
283 {
284 qDebug() << "Failed to stop plugin, got exception:" << pex;
285 QFAIL("Failed to stop plugin, got exception: ctkPluginException");
286 }
287 catch (const std::exception& e)
288 {
289 qDebug() << "Failed to stop plugin, got exception" << e.what();
290 QFAIL("Failed to stop plugin, got exception.");
291 }
292
293
294 // sleep to stabelize state.
295 QTest::qWait(300);
296
297 // Check service events seen by this class
298 qDebug() << "Checking ServiceEvents(ServiceListener):";
299 if (!sListen.checkEvents(expectedServiceEventTypes))
300 {
301 qDebug() << "Service listener event notification error";
302 QFAIL("Service listener event notification error");
303 }
304
305
306 QVERIFY2(sListen.teststatus, "Service listener checks");
307 try
308 {
309 //pc->disconnectServiceListener(&sListen, "serviceChanged");
310 sListen.clearEvents();
311 }
312 catch (const ctkIllegalStateException& ise)
313 {
314 qDebug() << ise.what();
315 QFAIL("service listener removal failed ");
316 }
317 }
318
319 //----------------------------------------------------------------------------
runStartStopTest(const QString & tcName,int cnt,QSharedPointer<ctkPlugin> targetPlugin,const QList<ctkServiceEvent::Type> & events)320 bool ctkServiceListenerTestSuite::runStartStopTest(
321 const QString& tcName, int cnt, QSharedPointer<ctkPlugin> targetPlugin,
322 const QList<ctkServiceEvent::Type>& events)
323 {
324 bool teststatus = true;
325
326 for (int i = 0; i < cnt && teststatus; ++i)
327 {
328 ctkServiceListener sListen(pc);
329 try
330 {
331 pc->connectServiceListener(&sListen, "serviceChanged");
332 }
333 catch (const ctkIllegalStateException& ise)
334 {
335 teststatus = false;
336 qDebug() << "service listener registration failed " << ise.what()
337 << " :" << tcName << ":FAIL";
338 }
339
340 // Start the test target to get a service published.
341 try
342 {
343 qDebug() << "Starting targetPlugin: " << targetPlugin;
344 targetPlugin->start();
345 }
346 catch (const ctkPluginException& pex)
347 {
348 teststatus = false;
349 qDebug() << "Failed to start plugin, got exception: "
350 << pex.what() << " in " << tcName << ":FAIL";
351 }
352 catch (const std::exception& e)
353 {
354 teststatus = false;
355 qDebug() << "Failed to start plugin, got exception: "
356 << e.what() << " + in " << tcName << ":FAIL";
357 }
358
359 // sleep to stabelize state.
360 QTest::qWait(300);
361
362 // Stop the test target to get a service unpublished.
363 try
364 {
365 targetPlugin->stop();
366 }
367 catch (const ctkPluginException& pex)
368 {
369 teststatus = false;
370 qDebug() << "Failed to stop plugin, got exception: "
371 << pex.what() << " in " << tcName << ":FAIL";
372 }
373 catch (const std::exception& e)
374 {
375 teststatus = false;
376 qDebug() << "Failed to stop plugin, got exception: "
377 << e.what() << " + in " << tcName << ":FAIL";
378 }
379
380 if (teststatus && !sListen.checkEvents(events))
381 {
382 teststatus = false;
383 qDebug() << "Service listener event notification error :"
384 << tcName << ":FAIL";
385 }
386
387 try
388 {
389 pc->disconnectServiceListener(&sListen, "serviceChanged");
390 teststatus &= sListen.teststatus;
391 sListen.clearEvents();
392 }
393 catch (const ctkIllegalStateException& ise)
394 {
395 teststatus = false;
396 qDebug() << "service listener removal failed " << ise.what()
397 << " :" << tcName << ":FAIL";
398 }
399 }
400 return teststatus;
401 }
402
403 //----------------------------------------------------------------------------
ctkServiceListener(ctkPluginContext * pc,bool checkUsingPlugins)404 ctkServiceListener::ctkServiceListener(ctkPluginContext* pc, bool checkUsingPlugins)
405 : checkUsingPlugins(checkUsingPlugins), teststatus(true), pc(pc)
406 {
407
408 }
409
410 //----------------------------------------------------------------------------
clearEvents()411 void ctkServiceListener::clearEvents()
412 {
413 events.clear();
414 }
415
416 //----------------------------------------------------------------------------
checkEvents(const QList<ctkServiceEvent::Type> & eventTypes)417 bool ctkServiceListener::checkEvents(const QList<ctkServiceEvent::Type>& eventTypes)
418 {
419 if (events.size() != eventTypes.size())
420 {
421 dumpEvents(eventTypes);
422 return false;
423 }
424
425 for (int i=0; i < eventTypes.size(); ++i)
426 {
427 if (eventTypes[i] != events[i].getType())
428 {
429 dumpEvents(eventTypes);
430 return false;
431 }
432 }
433 return true;
434 }
435
436 //----------------------------------------------------------------------------
serviceChanged(const ctkServiceEvent & evt)437 void ctkServiceListener::serviceChanged(const ctkServiceEvent& evt)
438 {
439 events.push_back(evt);
440 qDebug() << "ServiceEvent:" << evt;
441 if (ctkServiceEvent::UNREGISTERING == evt.getType())
442 {
443 ctkServiceReference sr = evt.getServiceReference();
444
445 // Validate that no bundle is marked as using the service
446 QList<QSharedPointer<ctkPlugin> > usingPlugins = sr.getUsingPlugins();
447 if (checkUsingPlugins && !usingPlugins.isEmpty())
448 {
449 teststatus = false;
450 printUsingPlugins(sr, "*** Using plugins (unreg) should be empty but is: ");
451 }
452
453 // Check if the service can be fetched
454 QObject* service = pc->getService(sr);
455 usingPlugins = sr.getUsingPlugins();
456 // if (UNREGISTERSERVICE_VALID_DURING_UNREGISTERING) {
457 // In this mode the service shall be obtainable during
458 // unregistration.
459 if (service == 0)
460 {
461 teststatus = false;
462 qDebug() << "*** Service should be available to ServiceListener "
463 << "while handling unregistering event.";
464 }
465 qDebug() << "Service (unreg): " << service->metaObject()->className();
466 if (checkUsingPlugins && usingPlugins.size() != 1)
467 {
468 teststatus = false;
469 printUsingPlugins(sr, "*** One using plugin expected "
470 "(unreg, after getService), found: ");
471 }
472 else
473 {
474 printUsingPlugins(sr, "Using plugins (unreg, after getService): ");
475 }
476 // } else {
477 // // In this mode the service shall NOT be obtainable during
478 // // unregistration.
479 // if (null!=service) {
480 // teststatus = false;
481 // out.print("*** Service should not be available to ServiceListener "
482 // +"while handling unregistering event.");
483 // }
484 // if (checkUsingBundles && null!=usingBundles) {
485 // teststatus = false;
486 // printUsingBundles(sr,
487 // "*** Using bundles (unreg, after getService), "
488 // +"should be null but is: ");
489 // } else {
490 // printUsingBundles(sr,
491 // "Using bundles (unreg, after getService): null");
492 // }
493 // }
494 pc->ungetService(sr);
495
496 // Check that the UNREGISTERING service can not be looked up
497 // using the service registry.
498 try
499 {
500 qulonglong sid = sr.getProperty(ctkPluginConstants::SERVICE_ID).toLongLong();
501 QString sidFilter = QString("(") + ctkPluginConstants::SERVICE_ID + "=" + sid + ")";
502 QList<ctkServiceReference> srs = pc->getServiceReferences("", sidFilter);
503 if (srs.isEmpty())
504 {
505 qDebug() << "ctkServiceReference for UNREGISTERING service is not"
506 " found in the service registry; ok.";
507 }
508 else
509 {
510 teststatus = false;
511 qDebug() << "*** ctkServiceReference for UNREGISTERING service,"
512 << sr << ", not found in the service registry; fail.";
513 qDebug() << "Found the following Service references:";
514 foreach(ctkServiceReference sr, srs)
515 {
516 qDebug() << sr;
517 }
518 }
519 }
520 catch (const std::exception& e)
521 {
522 teststatus = false;
523 qDebug() << "*** Unexpected excpetion when trying to lookup a"
524 " service while it is in state UNREGISTERING;"
525 << e.what();
526 }
527 }
528 }
529
530 //----------------------------------------------------------------------------
printUsingPlugins(const ctkServiceReference & sr,const QString & caption)531 void ctkServiceListener::printUsingPlugins(const ctkServiceReference& sr,
532 const QString& caption)
533 {
534 QList<QSharedPointer<ctkPlugin> > usingPlugins = sr.getUsingPlugins();
535
536 qDebug() << (caption.isEmpty() ? "Using plugins: " : caption);
537 foreach(QSharedPointer<ctkPlugin> plugin, usingPlugins)
538 {
539 qDebug() << " -" << plugin.data();
540 }
541 }
542
543 //----------------------------------------------------------------------------
dumpEvents(const QList<ctkServiceEvent::Type> & eventTypes)544 void ctkServiceListener::dumpEvents(const QList<ctkServiceEvent::Type>& eventTypes)
545 {
546 int max = events.size() > eventTypes.size() ? events.size() : eventTypes.size();
547 qDebug() << "Expected event type -- Actual event";
548 for (int i=0; i < max; ++i)
549 {
550 ctkServiceEvent evt = i < events.size() ? events[i] : ctkServiceEvent();
551 if (i < eventTypes.size())
552 {
553 qDebug() << " " << eventTypes[i] << "--" << evt;
554 }
555 else
556 {
557 qDebug() << " " << "- NONE - " << "--" << evt;
558 }
559 }
560 }
561