PageRenderTime 87ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/PathLockFactoryTest.java

https://gitlab.com/unofficial-mirrors/eclipse-che
Java | 239 lines | 207 code | 13 blank | 19 comment | 3 complexity | 38c6b7c593ac02885ff616302debc573 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2012-2016 Codenvy, S.A.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * Codenvy, S.A. - initial API and implementation
  10. *******************************************************************************/
  11. package org.eclipse.che.api.vfs;
  12. import junit.framework.TestCase;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import java.util.concurrent.CountDownLatch;
  16. import java.util.concurrent.atomic.AtomicBoolean;
  17. import java.util.concurrent.atomic.AtomicInteger;
  18. /**
  19. * @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a>
  20. */
  21. public class PathLockFactoryTest extends TestCase {
  22. private final int maxThreads = 3;
  23. private final Path path = Path.of("/a/b/c"); // Path not need to be real path on file system
  24. private PathLockFactory pathLockFactory;
  25. @Override
  26. protected void setUp() throws Exception {
  27. super.setUp();
  28. pathLockFactory = new PathLockFactory(maxThreads);
  29. }
  30. public void testLock() throws Exception {
  31. final AtomicBoolean acquired = new AtomicBoolean(false);
  32. final CountDownLatch waiter = new CountDownLatch(1);
  33. Thread t = new Thread() {
  34. @Override
  35. public void run() {
  36. try {
  37. pathLockFactory.getLock(path, true).acquire();
  38. acquired.set(true);
  39. } finally {
  40. waiter.countDown();
  41. }
  42. }
  43. };
  44. t.start();
  45. waiter.await();
  46. assertTrue(acquired.get());
  47. }
  48. public void testConcurrentExclusiveLocks() throws Throwable {
  49. final AtomicInteger acquired = new AtomicInteger(0);
  50. final CountDownLatch waiter = new CountDownLatch(3);
  51. final List<Throwable> errors = new ArrayList<>(3);
  52. Runnable task = new Runnable() {
  53. @Override
  54. public void run() {
  55. PathLockFactory.PathLock exclusiveLock = pathLockFactory.getLock(path, true);
  56. try {
  57. exclusiveLock.acquire();
  58. // Only one thread has exclusive access
  59. assertEquals(0, acquired.getAndIncrement());
  60. Thread.sleep(100);
  61. } catch (Throwable e) {
  62. errors.add(e);
  63. } finally {
  64. acquired.getAndDecrement();
  65. exclusiveLock.release();
  66. waiter.countDown();
  67. }
  68. }
  69. };
  70. new Thread(task).start();
  71. new Thread(task).start();
  72. new Thread(task).start();
  73. waiter.await();
  74. assertEquals(0, acquired.get()); // all locks must be released
  75. if (!errors.isEmpty()) {
  76. throw errors.get(0);
  77. }
  78. }
  79. public void testLockTimeout() throws Exception {
  80. final CountDownLatch starter = new CountDownLatch(1);
  81. Runnable task = new Runnable() {
  82. @Override
  83. public void run() {
  84. PathLockFactory.PathLock exclusiveLock = pathLockFactory.getLock(path, true);
  85. try {
  86. exclusiveLock.acquire();
  87. starter.countDown();
  88. Thread.sleep(2000); // get lock and sleep
  89. } catch (InterruptedException ignored) {
  90. } finally {
  91. exclusiveLock.release();
  92. }
  93. }
  94. };
  95. new Thread(task).start();
  96. starter.await(); // wait while child thread acquire exclusive lock
  97. PathLockFactory.PathLock timeoutExclusiveLock = pathLockFactory.getLock(path, true);
  98. try {
  99. // Wait lock timeout is much less then sleep time of child thread.
  100. // Here we must be failed to get exclusive permit.
  101. timeoutExclusiveLock.acquire(100);
  102. fail();
  103. } catch (RuntimeException e) {
  104. // OK
  105. }
  106. }
  107. public void testConcurrentLocks() throws Throwable {
  108. final AtomicInteger acquired = new AtomicInteger(0);
  109. final CountDownLatch starter = new CountDownLatch(1);
  110. final CountDownLatch waiter = new CountDownLatch(2);
  111. Runnable task1 = new Runnable() {
  112. @Override
  113. public void run() {
  114. PathLockFactory.PathLock lock = pathLockFactory.getLock(path, false);
  115. lock.acquire();
  116. acquired.incrementAndGet();
  117. starter.countDown();
  118. try {
  119. Thread.sleep(1000);
  120. } catch (InterruptedException ignored) {
  121. } finally {
  122. acquired.getAndDecrement();
  123. lock.release();
  124. waiter.countDown();
  125. }
  126. }
  127. };
  128. final List<Throwable> errors = new ArrayList<>(1);
  129. Runnable task2 = new Runnable() {
  130. @Override
  131. public void run() {
  132. PathLockFactory.PathLock exclusiveLock = pathLockFactory.getLock(path, true);
  133. try {
  134. exclusiveLock.acquire();
  135. // This thread must be blocked while another thread keeps lock.
  136. assertEquals(0, acquired.getAndIncrement());
  137. } catch (Throwable e) {
  138. errors.add(e);
  139. } finally {
  140. acquired.getAndDecrement();
  141. exclusiveLock.release();
  142. waiter.countDown();
  143. }
  144. }
  145. };
  146. new Thread(task1).start();
  147. starter.await();
  148. new Thread(task2).start();
  149. waiter.await();
  150. assertEquals(0, acquired.get()); // all locks must be released
  151. if (!errors.isEmpty()) {
  152. throw errors.get(0);
  153. }
  154. }
  155. public void testHierarchyLock() throws Throwable {
  156. final AtomicInteger acquired = new AtomicInteger(0);
  157. final Path parent = path.getParent();
  158. final CountDownLatch starter = new CountDownLatch(1);
  159. final CountDownLatch waiter = new CountDownLatch(2);
  160. Runnable parentTask = new Runnable() {
  161. @Override
  162. public void run() {
  163. PathLockFactory.PathLock lock = pathLockFactory.getLock(parent, true);
  164. lock.acquire();
  165. acquired.incrementAndGet();
  166. starter.countDown();
  167. try {
  168. Thread.sleep(100);
  169. } catch (InterruptedException ignored) {
  170. } finally {
  171. acquired.getAndDecrement();
  172. lock.release();
  173. waiter.countDown();
  174. }
  175. }
  176. };
  177. final List<Throwable> errors = new ArrayList<>(1);
  178. Runnable childTask = new Runnable() {
  179. @Override
  180. public void run() {
  181. PathLockFactory.PathLock lock = pathLockFactory.getLock(path, false);
  182. try {
  183. lock.acquire();
  184. // This thread must be blocked while another thread keeps lock.
  185. assertEquals(0, acquired.getAndIncrement());
  186. } catch (Throwable e) {
  187. errors.add(e);
  188. } finally {
  189. lock.release();
  190. acquired.getAndDecrement();
  191. waiter.countDown();
  192. }
  193. }
  194. };
  195. new Thread(parentTask).start();
  196. starter.await();
  197. new Thread(childTask).start();
  198. waiter.await();
  199. assertEquals(0, acquired.get()); // all locks must be released
  200. if (!errors.isEmpty()) {
  201. throw errors.get(0);
  202. }
  203. }
  204. public void testLockSameThread() throws Exception {
  205. final AtomicInteger acquired = new AtomicInteger(0);
  206. final CountDownLatch waiter = new CountDownLatch(1);
  207. Runnable task = new Runnable() {
  208. @Override
  209. public void run() {
  210. try {
  211. PathLockFactory.PathLock lock1 = pathLockFactory.getLock(path, true);
  212. PathLockFactory.PathLock lock2 = pathLockFactory.getLock(path, true);
  213. lock1.acquire();
  214. acquired.incrementAndGet();
  215. lock2.acquire(1000); // try with timeout.
  216. acquired.incrementAndGet();
  217. } finally {
  218. waiter.countDown();
  219. }
  220. }
  221. };
  222. new Thread(task).start();
  223. waiter.await();
  224. assertEquals(2, acquired.get());
  225. }
  226. }