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