1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.lib;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNull;
49 import static org.junit.Assert.assertTrue;
50 import static org.junit.Assert.fail;
51
52 import java.util.concurrent.CountDownLatch;
53 import java.util.concurrent.TimeUnit;
54
55 import org.junit.Test;
56
57 public class ThreadSafeProgressMonitorTest {
58 @Test
59 public void testFailsMethodsOnBackgroundThread()
60 throws InterruptedException {
61 final MockProgressMonitor mock = new MockProgressMonitor();
62 final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
63
64 runOnThread(() -> {
65 try {
66 pm.start(1);
67 fail("start did not fail on background thread");
68 } catch (IllegalStateException notMainThread) {
69
70 }
71
72 try {
73 pm.beginTask("title", 1);
74 fail("beginTask did not fail on background thread");
75 } catch (IllegalStateException notMainThread) {
76
77 }
78
79 try {
80 pm.endTask();
81 fail("endTask did not fail on background thread");
82 } catch (IllegalStateException notMainThread) {
83
84 }
85 });
86
87
88 assertNull(mock.taskTitle);
89 assertEquals(0, mock.value);
90 }
91
92 @Test
93 public void testMethodsOkOnMainThread() {
94 final MockProgressMonitor mock = new MockProgressMonitor();
95 final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
96
97 pm.start(1);
98 assertEquals(1, mock.value);
99
100 pm.beginTask("title", 42);
101 assertEquals("title", mock.taskTitle);
102 assertEquals(42, mock.value);
103
104 pm.update(1);
105 pm.pollForUpdates();
106 assertEquals(43, mock.value);
107
108 pm.update(2);
109 pm.pollForUpdates();
110 assertEquals(45, mock.value);
111
112 pm.endTask();
113 assertNull(mock.taskTitle);
114 assertEquals(0, mock.value);
115 }
116
117 @Test
118 public void testUpdateOnBackgroundThreads() throws InterruptedException {
119 final MockProgressMonitor mock = new MockProgressMonitor();
120 final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
121
122 pm.startWorker();
123
124 final CountDownLatch doUpdate = new CountDownLatch(1);
125 final CountDownLatch didUpdate = new CountDownLatch(1);
126 final CountDownLatch doEndWorker = new CountDownLatch(1);
127
128 final Thread bg = new Thread() {
129 @Override
130 public void run() {
131 assertFalse(pm.isCancelled());
132
133 await(doUpdate);
134 pm.update(2);
135 didUpdate.countDown();
136
137 await(doEndWorker);
138 pm.update(1);
139 pm.endWorker();
140 }
141 };
142 bg.start();
143
144 pm.pollForUpdates();
145 assertEquals(0, mock.value);
146 doUpdate.countDown();
147
148 await(didUpdate);
149 pm.pollForUpdates();
150 assertEquals(2, mock.value);
151
152 doEndWorker.countDown();
153 pm.waitForCompletion();
154 assertEquals(3, mock.value);
155 }
156
157 private static void await(CountDownLatch cdl) {
158 try {
159 assertTrue("latch released", cdl.await(1000, TimeUnit.MILLISECONDS));
160 } catch (InterruptedException ie) {
161 fail("Did not expect to be interrupted");
162 }
163 }
164
165 private static void runOnThread(Runnable task) throws InterruptedException {
166 Thread t = new Thread(task);
167 t.start();
168 t.join(1000);
169 assertFalse("thread has stopped", t.isAlive());
170 }
171
172 private static class MockProgressMonitor implements ProgressMonitor {
173 String taskTitle;
174
175 int value;
176
177 @Override
178 public void update(int completed) {
179 value += completed;
180 }
181
182 @Override
183 public void start(int totalTasks) {
184 value = totalTasks;
185 }
186
187 @Override
188 public void beginTask(String title, int totalWork) {
189 taskTitle = title;
190 value = totalWork;
191 }
192
193 @Override
194 public void endTask() {
195 taskTitle = null;
196 value = 0;
197 }
198
199 @Override
200 public boolean isCancelled() {
201 return false;
202 }
203 }
204 }