ac31c46b4f14d794dc751b889633b896b4d00432
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core.tests / src / org / eclipse / tracecompass / tmf / core / tests / signal / TmfSignalManagerTest.java
1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Bernd Hufmann - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.tmf.core.tests.signal;
14
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.fail;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.CountDownLatch;
21
22 import org.eclipse.tracecompass.tmf.core.component.TmfComponent;
23 import org.eclipse.tracecompass.tmf.core.signal.TmfEndSynchSignal;
24 import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
25 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
26 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
27 import org.eclipse.tracecompass.tmf.core.signal.TmfStartSynchSignal;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31
32 /**
33 * Test suite for {@link TmfSignalManager}
34 *
35 * @author Bernd Hufmann
36 */
37 public class TmfSignalManagerTest {
38
39 private TestSignalSender signalSender;
40
41 /**
42 * Pre-test setup
43 */
44 @Before
45 public void setUp() {
46 signalSender = new TestSignalSender();
47 }
48
49 /**
50 * After-test cleanup
51 */
52 @After
53 public void tearDown() {
54 signalSender.dispose();
55 }
56
57 // ------------------------------------------------------------------------
58 // Test cases
59 // ------------------------------------------------------------------------
60
61 /**
62 * Test send and receive including synch signals.
63 */
64 @Test
65 public void testSendReceive() {
66 final int NB_HANDLERS = 10;
67 TestSignalHandler[] signalReceivers = new TestSignalHandler[NB_HANDLERS];
68 for (int i = 0; i < NB_HANDLERS; i++) {
69 signalReceivers[i] = new TestSignalHandler();
70 }
71 final TestSignal1 firstSignal = new TestSignal1(signalSender);
72 final TestSignal2 secondSignal = new TestSignal2(signalSender);
73
74 final Class<?>[] expectedOrder = new Class[] {
75 TmfStartSynchSignal.class, TestSignal1.class, TmfEndSynchSignal.class,
76 TmfStartSynchSignal.class, TestSignal2.class, TmfEndSynchSignal.class };
77
78 try {
79 signalSender.sendSignal(firstSignal);
80 signalSender.sendSignal(secondSignal);
81
82 for (int i = 0; i < NB_HANDLERS; i++) {
83 assertEquals(expectedOrder.length, signalReceivers[i].receivedSignals.size());
84
85 for (int k = 0; k < expectedOrder.length; k++) {
86 assertEquals(signalReceivers[i].receivedSignals.get(k).getClass(), expectedOrder[k]);
87 }
88
89 for (int k = 0; k < expectedOrder.length; k += 3) {
90 // Verify signal IDs
91 int startSyncId = signalReceivers[i].receivedSignals.get(k).getReference();
92 int signalId = signalReceivers[i].receivedSignals.get(k + 1).getReference();
93 int endSyncId = signalReceivers[i].receivedSignals.get(k + 2).getReference();
94
95 assertEquals(startSyncId, signalId);
96 assertEquals(startSyncId, endSyncId);
97 }
98 }
99 } finally {
100 // Make sure that handlers are disposed in any case (success or not success)
101 for (int i = 0; i < NB_HANDLERS; i++) {
102 signalReceivers[i].dispose();
103 }
104 }
105 }
106
107 /**
108 * Test nesting signals. Verify that they are handled in the same thread.
109 */
110 @Test
111 public void testNestedSignals() {
112 TestSignalHandlerNested signalResender = new TestSignalHandlerNested();
113 TestSignalHandler signalReceiver = new TestSignalHandler();
114
115 final TestSignal1 mainSignal = new TestSignal1(signalSender);
116
117 final Class<?>[] expectedOrder = new Class[] {
118 TmfStartSynchSignal.class,
119 TmfStartSynchSignal.class,
120 TestSignal2.class,
121 TmfEndSynchSignal.class,
122 TmfStartSynchSignal.class,
123 TmfStartSynchSignal.class,
124 TestSignal4.class,
125 TmfEndSynchSignal.class,
126 TestSignal3.class,
127 TmfEndSynchSignal.class,
128 TestSignal1.class,
129 TmfEndSynchSignal.class
130 };
131
132 /*
133 * Index of signals in array signalReceiver.receivedSignals which have
134 * to have the same signal ID.
135 */
136
137 final int[] sameSigNoIndex = new int[] {
138 0, 10, 11, 1, 2, 3, 4, 8, 9, 5, 6, 7
139 };
140
141 try {
142 signalSender.sendSignal(mainSignal);
143
144 assertEquals(expectedOrder.length, signalReceiver.receivedSignals.size());
145
146 for (int i = 0; i < expectedOrder.length; i++) {
147 assertEquals(signalReceiver.receivedSignals.get(i).getClass(), expectedOrder[i]);
148 }
149
150 for (int i = 0; i < sameSigNoIndex.length; i+=3) {
151 // Verify signal IDs
152 int startSyncId = signalReceiver.receivedSignals.get(sameSigNoIndex[i]).getReference();
153 int signalId = signalReceiver.receivedSignals.get(sameSigNoIndex[i + 1]).getReference();
154 int endSyncId = signalReceiver.receivedSignals.get(sameSigNoIndex[i + 2]).getReference();
155 assertEquals(startSyncId, signalId);
156 assertEquals(startSyncId, endSyncId);
157 }
158 } finally {
159 // Make sure that handlers are disposed in any case (success or not success)
160 signalResender.dispose();
161 signalReceiver.dispose();
162 }
163 }
164
165 /**
166 * Test concurrent signals. Verify that they are handled one after each
167 * other.
168 */
169 @Test
170 public void testConcurrentSignals() {
171
172 TestSignalHandlerNested signalResender = new TestSignalHandlerNested();
173 TestSignalHandler signalReceiver = new TestSignalHandler(false, null);
174
175 /*
176 * Test of synchronization of signal manager.
177 *
178 * The order of received signals is either set of signals triggered by
179 * thread1 before set of signals triggered by thread2 or the other way
180 * around.
181 *
182 * If both received sets were interleaved then the synchronization of
183 * the signal manager would be not working.
184 */
185
186 final Class<?>[] expectedOrder1 = new Class[] {
187 TestSignal2.class, TestSignal4.class, TestSignal3.class, TestSignal1.class, // signals triggered by thread 1
188 TestSignal4.class // signal triggered by thread2
189 };
190
191 final Class<?>[] expectedOrder2 = new Class[] {
192 TestSignal4.class, // signal triggered by thread2
193 TestSignal2.class, TestSignal4.class, TestSignal3.class, TestSignal1.class // signals triggered by thread 1
194 };
195
196 /*
197 * Run it multiple times so that both expected order are triggered
198 */
199 try {
200 for (int k = 0; k < 10; k++) {
201 // Latch to ensure that both threads are started
202 final CountDownLatch startLatch = new CountDownLatch(2);
203 // Latch to ensure that signals are send roughly at the same time
204 final CountDownLatch sendLatch = new CountDownLatch(1);
205 // Latch to ensure that both treads are finished
206 final CountDownLatch endLatch = new CountDownLatch(2);
207
208 signalReceiver.receivedSignals.clear();
209
210 Thread senderThread1 = new Thread() {
211 @Override
212 public void run() {
213 startLatch.countDown();
214 try {
215 sendLatch.await();
216 } catch (InterruptedException e) {
217 }
218 signalSender.sendSignal(new TestSignal1(signalSender));
219 endLatch.countDown();
220 }
221 };
222
223 Thread senderThread2 = new Thread() {
224 @Override
225 public void run() {
226 startLatch.countDown();
227 try {
228 sendLatch.await();
229 } catch (InterruptedException e) {
230 }
231 signalSender.sendSignal(new TestSignal4(signalSender));
232 endLatch.countDown();
233 }
234 };
235
236 senderThread1.start();
237 senderThread2.start();
238 try {
239 startLatch.await();
240 } catch (InterruptedException e) {
241 }
242 sendLatch.countDown();
243
244 try {
245 endLatch.await();
246 } catch (InterruptedException e) {
247 }
248
249 assertEquals(expectedOrder1.length, signalReceiver.receivedSignals.size());
250 boolean pass = true;
251 for (int i = 0; i < expectedOrder1.length; i++) {
252 if (!signalReceiver.receivedSignals.get(i).getClass().equals(expectedOrder1[i])) {
253 pass = false;
254 break;
255 }
256 }
257
258 if (!pass) {
259 for (int i = 0; i < expectedOrder2.length; i++) {
260 if (!signalReceiver.receivedSignals.get(i).getClass().equals(expectedOrder2[i])) {
261 fail("Concurrent signal test failure!");
262 }
263 }
264 }
265 }
266 } finally {
267 // Make sure that handlers are disposed in any case (success or not success)
268 signalResender.dispose();
269 signalReceiver.dispose();
270 }
271 }
272
273 /**
274 * Test broadcastAsync()
275 */
276 @Test
277 public void testBroadcastAsync() {
278 TestSignalHandlerNested signalResender = new TestSignalHandlerNested(false);
279
280 final int NB_HANDLERS = 10;
281 final CountDownLatch latch = new CountDownLatch(NB_HANDLERS);
282 TestSignalHandler[] signalReceivers = new TestSignalHandler[NB_HANDLERS];
283 for (int i = 0; i < NB_HANDLERS; i++) {
284 signalReceivers[i] = new TestSignalHandler(false, latch);
285 }
286
287 final Class<?>[] expectedOrder = new Class[] {
288 TestSignal1.class, TestSignal2.class, TestSignal3.class, TestSignal4.class
289 };
290
291 try {
292 final TestSignal1 mainSignal = new TestSignal1(signalSender);
293 signalSender.sendSignal(mainSignal);
294
295 try {
296 latch.await();
297 } catch (InterruptedException e) {
298 }
299
300 for (int i = 0; i < NB_HANDLERS; i++) {
301 assertEquals(expectedOrder.length, signalReceivers[i].receivedSignals.size());
302 for (int k = 0; k < expectedOrder.length; k++) {
303 assertEquals(signalReceivers[i].receivedSignals.get(k).getClass(), expectedOrder[k]);
304 }
305 }
306 } finally {
307 // Make sure that handlers are disposed in any case (success or not success)
308 for (int i = 0; i < NB_HANDLERS; i++) {
309 signalReceivers[i].dispose();
310 }
311 signalResender.dispose();
312 }
313 }
314
315 // ------------------------------------------------------------------------
316 // Helper classes
317 // ------------------------------------------------------------------------
318
319 /**
320 * Signal sender
321 */
322 private class TestSignalSender extends TmfComponent {
323
324 TestSignalSender() {
325 super("TestSignalSender");
326 }
327
328 /**
329 * Send a signal
330 *
331 * @param signal
332 * main signal to send
333 */
334 public void sendSignal(TmfSignal signal) {
335 broadcast(signal);
336 }
337 }
338
339 /**
340 * Signal handler implementation for testing nested signals.
341 * Needs to be public so TmfSignalManager can see it.
342 */
343 public class TestSignalHandlerNested extends AbstractBaseSignalHandler {
344
345 private boolean sync;
346
347 /**
348 * Constructor
349 */
350 private TestSignalHandlerNested() {
351 this(true);
352 }
353
354 /**
355 * Constructor
356 *
357 * @param sync
358 * log sync signals
359 *
360 */
361 private TestSignalHandlerNested(boolean sync) {
362 super("TestSignalHandlerNested", false);
363 this.sync = sync;
364 TmfSignalManager.deregister(this);
365 TmfSignalManager.registerVIP(this);
366 }
367
368 /**
369 * Receive a signal of type TestSignal1.
370 *
371 * @param signal
372 * Signal received
373 */
374 @TmfSignalHandler
375 public void receiveSignal1(final TestSignal1 signal) {
376 if (sync) {
377 broadcast(new TestSignal2(signal.getSource()));
378 broadcast(new TestSignal3(signal.getSource()));
379 } else {
380 broadcastAsync(new TestSignal2(signal.getSource()));
381 broadcastAsync(new TestSignal3(signal.getSource()));
382 }
383 }
384
385 /**
386 * Receive a signal of type TestSignal3.
387 *
388 * @param signal
389 * Signal received
390 */
391 @TmfSignalHandler
392 public void receiveSignal3(final TestSignal3 signal) {
393 if (sync) {
394 broadcast(new TestSignal4(signal.getSource()));
395 } else {
396 broadcastAsync(new TestSignal4(signal.getSource()));
397 }
398 }
399 }
400
401 /**
402 * Signal handler implementation for testing of sending and receiving
403 * signals.
404 */
405 public class TestSignalHandler extends AbstractBaseSignalHandler {
406
407 private CountDownLatch latch;
408
409 /**
410 * Constructor
411 *
412 */
413 private TestSignalHandler() {
414 this(true, null);
415 }
416
417 /**
418 * Constructor
419 *
420 * @param logSyncSigs
421 * log sync signals
422 * @param latch
423 * latch to count down when receiving last signal
424 * (TmfSingal4)
425 */
426 private TestSignalHandler(boolean logSyncSigs, CountDownLatch latch) {
427 super("TestSignalHandler", logSyncSigs);
428 this.latch = latch;
429 }
430
431 /**
432 * Receive a signal of type TestSignal1.
433 *
434 * @param signal
435 * Signal received
436 */
437 @TmfSignalHandler
438 public void receiveSignal1(final TestSignal1 signal) {
439 receivedSignals.add(signal);
440 }
441
442 /**
443 * Receive a signal of type TestSignal2.
444 *
445 * @param signal
446 * Signal received
447 */
448 @TmfSignalHandler
449 public void receiveSignal2(final TestSignal2 signal) {
450 receivedSignals.add(signal);
451 }
452
453 /**
454 * Receive a signal of type TestSignal3.
455 *
456 * @param signal
457 * Signal received
458 */
459 @TmfSignalHandler
460 public void receiveSignal3(final TestSignal3 signal) {
461 receivedSignals.add(signal);
462 }
463
464 /**
465 * Receive a signal of type TestSignal4.
466 *
467 * @param signal
468 * Signal received
469 */
470 @TmfSignalHandler
471 public void receiveSignal4(final TestSignal4 signal) {
472 receivedSignals.add(signal);
473 if (latch != null) {
474 latch.countDown();
475 }
476 }
477 }
478
479 /**
480 * Base signal handler for start and end sync signals.
481 */
482 public abstract class AbstractBaseSignalHandler extends TmfComponent {
483 List<TmfSignal> receivedSignals = new ArrayList<>();
484 private boolean logSyncSigs;
485
486 private AbstractBaseSignalHandler(String name, boolean logSyncSignal) {
487 super(name);
488 this.logSyncSigs = logSyncSignal;
489 }
490
491 /**
492 * Receive a signal of type TmfStartSynchSignal.
493 *
494 * @param signal
495 * Signal received
496 */
497 @TmfSignalHandler
498 public void receiveStartSynch(final TmfStartSynchSignal signal) {
499 if (logSyncSigs) {
500 receivedSignals.add(signal);
501 }
502 }
503
504 /**
505 * Receive a signal of type TmfEndSynchSignal.
506 *
507 * @param signal
508 * Signal received
509 */
510 @TmfSignalHandler
511 public void receiveEndSynch(final TmfEndSynchSignal signal) {
512 if (logSyncSigs) {
513 receivedSignals.add(signal);
514 }
515 }
516 }
517
518
519 /**
520 * Test Signal object
521 */
522 private class TestSignal1 extends TmfSignal {
523
524 public TestSignal1(Object source) {
525 super(source);
526 }
527 }
528
529 /**
530 * Test Signal object
531 */
532 private class TestSignal2 extends TmfSignal {
533
534 public TestSignal2(Object source) {
535 super(source);
536 }
537 }
538
539 /**
540 * Test Signal object
541 */
542 private class TestSignal3 extends TmfSignal {
543
544 public TestSignal3(Object source) {
545 super(source);
546 }
547 }
548
549 /**
550 * Test Signal object
551 */
552 private class TestSignal4 extends TmfSignal {
553
554 public TestSignal4(Object source) {
555 super(source);
556 }
557 }
558 }
This page took 0.044575 seconds and 4 git commands to generate.