Skip to content

Package: RunnableManagerTest$Stage

RunnableManagerTest$Stage

nameinstructionbranchcomplexitylinemethod
RunnableManagerTest.Stage(Runnable)
M: 15 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getNextStage()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
join()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
lambda$0()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
run()
M: 22 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * edgar - initial API and implementation
13: * Christian W. Damus - bug 545686
14: ******************************************************************************/
15: package org.eclipse.emf.ecp.view.table.ui.swt.test;
16:
17: import static org.hamcrest.MatcherAssert.assertThat;
18: import static org.hamcrest.Matchers.greaterThan;
19: import static org.hamcrest.Matchers.greaterThanOrEqualTo;
20: import static org.hamcrest.Matchers.is;
21: import static org.hamcrest.Matchers.lessThanOrEqualTo;
22: import static org.junit.Assert.assertTrue;
23: import static org.junit.Assert.fail;
24: import static org.mockito.Matchers.any;
25: import static org.mockito.Mockito.doAnswer;
26: import static org.mockito.Mockito.mock;
27:
28: import java.util.concurrent.CountDownLatch;
29: import java.util.concurrent.Executors;
30: import java.util.concurrent.ScheduledExecutorService;
31: import java.util.concurrent.TimeUnit;
32: import java.util.concurrent.atomic.AtomicInteger;
33:
34: import org.eclipse.emf.ecp.view.internal.table.swt.RunnableManager;
35: import org.eclipse.emf.ecp.view.internal.table.swt.RunnableManager.BackgroundStage;
36: import org.eclipse.swt.widgets.Display;
37: import org.junit.AfterClass;
38: import org.junit.BeforeClass;
39: import org.junit.Test;
40: import org.mockito.invocation.InvocationOnMock;
41: import org.mockito.stubbing.Answer;
42:
43: public class RunnableManagerTest {
44:
45:         private static final int NR_RUNNABLES = 1000;
46:         private static final ScheduledExecutorService POOL = Executors.newScheduledThreadPool(1);
47:         private static final ScheduledExecutorService ASYNC_POOL = Executors.newScheduledThreadPool(1);
48:         private static final Display DISPLAY = mock(Display.class);
49:
50:         private Runnable createRunnable(final CountDownLatch latch,
51:                 final AtomicInteger counter) {
52:
53:                 return new Runnable() {
54:                         @Override
55:                         public void run() {
56:                                 counter.getAndIncrement();
57:                                 latch.countDown();
58:                         }
59:                 };
60:         }
61:
62:         @BeforeClass
63:         public static void beforeClass() {
64:                 doAnswer(new Answer<Void>() {
65:                         @Override
66:                         public Void answer(InvocationOnMock invocation) throws Throwable {
67:                                 ASYNC_POOL.submit(
68:                                         Runnable.class.cast(invocation.getArguments()[0]));
69:                                 return null;
70:                         }
71:                 }).when(DISPLAY).asyncExec(any(Runnable.class));
72:
73:         }
74:
75:         @AfterClass
76:         public static void afterClass() {
77:                 ASYNC_POOL.shutdown();
78:                 POOL.shutdown();
79:         }
80:
81:         @Test
82:         public void managedRunnable() throws InterruptedException {
83:                 // setup
84:                 final AtomicInteger asyncCounter = new AtomicInteger(0);
85:                 final AtomicInteger counter = new AtomicInteger(0);
86:                 final CountDownLatch latch = new CountDownLatch(NR_RUNNABLES);
87:                 final RunnableManager runnableManager = new RunnableManager(DISPLAY);
88:
89:                 // act
90:                 for (int x = 0; x < NR_RUNNABLES; x++) {
91:                         runnableManager.executeAsync(createRunnable(latch, asyncCounter));
92:                         POOL.submit(createRunnable(latch, counter));
93:                 }
94:                 latch.await();
95:
96:                 // assert
97:                 // we expect more runnables to be executed via the fixed pool since
98:                 // the RunnableManager only lets a single Runnable to be executed
99:                 assertTrue(counter.intValue() > asyncCounter.intValue());
100:         }
101:
102:         @Test
103:         public void backgroundStage() throws InterruptedException {
104:                 final AtomicInteger stageCount = new AtomicInteger();
105:                 final Stage stage = new Stage(stageCount::incrementAndGet);
106:
107:                 final RunnableManager runnableManager = new RunnableManager(DISPLAY);
108:
109:                 runnableManager.executeAsync(stage);
110:                 stage.join();
111:
112:                 assertThat("Multi-step execution not completed", stageCount.get(), greaterThanOrEqualTo(3));
113:         }
114:
115:         @Test
116:         public void waitForIdle() throws InterruptedException {
117:                 final AtomicInteger countdown = new AtomicInteger(Stage.STAGE_COUNT);
118:                 final Runnable callback = () -> {
119:                         try {
120:                                 Thread.sleep(100L);
121:                         } catch (final InterruptedException e) {
122:                                 fail("Call-back interrupted");
123:                         }
124:                         countdown.decrementAndGet();
125:                 };
126:
127:                 final Stage stage = new Stage(callback);
128:
129:                 final RunnableManager runnableManager = new RunnableManager(DISPLAY);
130:
131:                 runnableManager.executeAsync(stage);
132:
133:                 runnableManager.waitForIdle();
134:
135:                 assertThat("Wait returned early", countdown.get(), lessThanOrEqualTo(0));
136:         }
137:
138:         @Test
139:         public void waitForIdle_time() throws InterruptedException {
140:                 final AtomicInteger countdown = new AtomicInteger(Stage.STAGE_COUNT);
141:                 final Runnable callback = () -> {
142:                         try {
143:                                 Thread.sleep(100L);
144:                         } catch (final InterruptedException e) {
145:                                 fail("Call-back interrupted");
146:                         }
147:                         countdown.decrementAndGet();
148:                 };
149:
150:                 final Stage stage = new Stage(callback);
151:
152:                 final RunnableManager runnableManager = new RunnableManager(DISPLAY);
153:
154:                 runnableManager.executeAsync(stage);
155:
156:                 assertThat("Timed out", runnableManager.waitForIdle(5L, TimeUnit.SECONDS), is(true));
157:
158:                 assertThat("Wait returned early", countdown.get(), lessThanOrEqualTo(0));
159:         }
160:
161:         @Test
162:         public void waitForIdle_timeout() throws InterruptedException {
163:                 final AtomicInteger countdown = new AtomicInteger(Stage.STAGE_COUNT);
164:                 final Runnable callback = () -> {
165:                         try {
166:                                 Thread.sleep(1000L);
167:                         } catch (final InterruptedException e) {
168:                                 fail("Call-back interrupted");
169:                         }
170:                         countdown.decrementAndGet();
171:                 };
172:
173:                 final Stage stage = new Stage(callback);
174:
175:                 final RunnableManager runnableManager = new RunnableManager(DISPLAY);
176:
177:                 runnableManager.executeAsync(stage);
178:
179:                 assertThat("Not timed out", runnableManager.waitForIdle(1L, TimeUnit.SECONDS), is(false));
180:
181:                 assertThat("Task completed", countdown.get(), greaterThan(0));
182:         }
183:
184:         //
185:         // Nested types
186:         //
187:
188:         private static class Stage implements Runnable, BackgroundStage {
189:                 static final int STAGE_COUNT = 3;
190:
191:                 private final Runnable callback;
192:
193:                 private int backgroundStages = STAGE_COUNT - 1;
194:                 private Runnable next;
195:
196:                 private final CountDownLatch done = new CountDownLatch(1);
197:
198:                 Stage(Runnable callback) {
199:                         super();
200:
201:                         this.callback = callback;
202:                 }
203:
204:                 @Override
205:                 public void run() {
206:                         // This is a stage
207:                         try {
208:                                 callback.run();
209:                         } finally {
210:                                 // This is a background stage
211:                                 backgroundStages--;
212:
213:•                                if (backgroundStages <= 0) {
214:                                         // Last stage is foreground
215:                                         next = () -> {
216:                                                 try {
217:                                                         callback.run();
218:                                                 } finally {
219:                                                         done.countDown();
220:                                                 }
221:                                         };
222:                                 } else {
223:                                         // Next stage is background
224:                                         next = this;
225:                                 }
226:                         }
227:                 }
228:
229:                 @Override
230:                 public Runnable getNextStage() {
231:                         return next;
232:                 }
233:
234:                 void join() throws InterruptedException {
235:                         done.await();
236:                 }
237:         }
238:
239: }