View Javadoc
1   /*
2    * Copyright (C) 2010, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.lib;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertNull;
16  import static org.junit.Assert.assertTrue;
17  import static org.junit.Assert.fail;
18  
19  import java.util.concurrent.CountDownLatch;
20  import java.util.concurrent.TimeUnit;
21  
22  import org.junit.Test;
23  
24  public class ThreadSafeProgressMonitorTest {
25  	@Test
26  	public void testFailsMethodsOnBackgroundThread()
27  			throws InterruptedException {
28  		final MockProgressMonitor mock = new MockProgressMonitor();
29  		final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
30  
31  		runOnThread(() -> {
32  			try {
33  				pm.start(1);
34  				fail("start did not fail on background thread");
35  			} catch (IllegalStateException notMainThread) {
36  				// Expected result
37  			}
38  
39  			try {
40  				pm.beginTask("title", 1);
41  				fail("beginTask did not fail on background thread");
42  			} catch (IllegalStateException notMainThread) {
43  				// Expected result
44  			}
45  
46  			try {
47  				pm.endTask();
48  				fail("endTask did not fail on background thread");
49  			} catch (IllegalStateException notMainThread) {
50  				// Expected result
51  			}
52  		});
53  
54  		// Ensure we didn't alter the mock above when checking threads.
55  		assertNull(mock.taskTitle);
56  		assertEquals(0, mock.value);
57  	}
58  
59  	@Test
60  	public void testMethodsOkOnMainThread() {
61  		final MockProgressMonitor mock = new MockProgressMonitor();
62  		final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
63  
64  		pm.start(1);
65  		assertEquals(1, mock.value);
66  
67  		pm.beginTask("title", 42);
68  		assertEquals("title", mock.taskTitle);
69  		assertEquals(42, mock.value);
70  
71  		pm.update(1);
72  		pm.pollForUpdates();
73  		assertEquals(43, mock.value);
74  
75  		pm.update(2);
76  		pm.pollForUpdates();
77  		assertEquals(45, mock.value);
78  
79  		pm.endTask();
80  		assertNull(mock.taskTitle);
81  		assertEquals(0, mock.value);
82  	}
83  
84  	@Test
85  	public void testUpdateOnBackgroundThreads() throws InterruptedException {
86  		final MockProgressMonitor mock = new MockProgressMonitor();
87  		final ThreadSafeProgressMonitor pm = new ThreadSafeProgressMonitor(mock);
88  
89  		pm.startWorker();
90  
91  		final CountDownLatch doUpdate = new CountDownLatch(1);
92  		final CountDownLatch didUpdate = new CountDownLatch(1);
93  		final CountDownLatch doEndWorker = new CountDownLatch(1);
94  
95  		final Thread bg = new Thread() {
96  			@Override
97  			public void run() {
98  				assertFalse(pm.isCancelled());
99  
100 				await(doUpdate);
101 				pm.update(2);
102 				didUpdate.countDown();
103 
104 				await(doEndWorker);
105 				pm.update(1);
106 				pm.endWorker();
107 			}
108 		};
109 		bg.start();
110 
111 		pm.pollForUpdates();
112 		assertEquals(0, mock.value);
113 		doUpdate.countDown();
114 
115 		await(didUpdate);
116 		pm.pollForUpdates();
117 		assertEquals(2, mock.value);
118 
119 		doEndWorker.countDown();
120 		pm.waitForCompletion();
121 		assertEquals(3, mock.value);
122 	}
123 
124 	private static void await(CountDownLatch cdl) {
125 		try {
126 			assertTrue("latch released", cdl.await(1000, TimeUnit.MILLISECONDS));
127 		} catch (InterruptedException ie) {
128 			fail("Did not expect to be interrupted");
129 		}
130 	}
131 
132 	private static void runOnThread(Runnable task) throws InterruptedException {
133 		Thread t = new Thread(task);
134 		t.start();
135 		t.join(1000);
136 		assertFalse("thread has stopped", t.isAlive());
137 	}
138 
139 	private static class MockProgressMonitor implements ProgressMonitor {
140 		String taskTitle;
141 
142 		int value;
143 
144 		@Override
145 		public void update(int completed) {
146 			value += completed;
147 		}
148 
149 		@Override
150 		public void start(int totalTasks) {
151 			value = totalTasks;
152 		}
153 
154 		@Override
155 		public void beginTask(String title, int totalWork) {
156 			taskTitle = title;
157 			value = totalWork;
158 		}
159 
160 		@Override
161 		public void endTask() {
162 			taskTitle = null;
163 			value = 0;
164 		}
165 
166 		@Override
167 		public boolean isCancelled() {
168 			return false;
169 		}
170 	}
171 }