common-utils/src/test/java/org/warp/commonutils/locks/TransitLockTest.java

157 lines
4.0 KiB
Java
Raw Normal View History

2021-01-22 03:15:14 +01:00
package org.warp.commonutils.locks;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class TransitLockTest {
@Test
public void testTransit() {
var lock = new TransitLock();
lock.transit();
lock.transit();
lock.transit();
}
@Test
public void testPartialTransit() {
var lock = new TransitLock();
lock.startTransit();
lock.endTransit();
lock.startTransit();
lock.endTransit();
lock.startTransit();
lock.endTransit();
}
@Test
public void testAllowTransit() {
var lock = new TransitLock();
2021-01-22 04:22:58 +01:00
lock.disallowTransit();
2021-01-22 03:15:14 +01:00
lock.allowTransit();
lock.transit();
}
@Test
public void testMultiAllowTransit() {
2021-01-22 04:22:58 +01:00
Assertions.assertThrows(IllegalStateException.class, () -> {
var lock = new TransitLock();
lock.allowTransit();
lock.allowTransit();
lock.allowTransit();
lock.transit();
});
2021-01-22 03:15:14 +01:00
}
@Test
public void testMultiDisallowAllowTransit() {
var lock = new TransitLock();
lock.disallowTransit();
lock.allowTransit();
lock.disallowTransit();
lock.disallowTransit();
lock.allowTransit();
2021-01-22 04:22:58 +01:00
lock.allowTransit();
2021-01-22 03:15:14 +01:00
lock.transit();
}
@Test
public void testDisallowTransit() {
var lock = new TransitLock();
lock.disallowTransit();
for (int i = 0; i < 10; i++) {
Assertions.assertThrows(TimeoutException.class, () -> {
CompletableFuture.runAsync(lock::transit).get(5, TimeUnit.MILLISECONDS);
}, "Disallowed transit didn't block a transit");
}
}
@Test
public void testMultiDisallowTransit() {
var lock = new TransitLock();
lock.disallowTransit();
lock.disallowTransit();
lock.disallowTransit();
for (int i = 0; i < 10; i++) {
Assertions.assertThrows(TimeoutException.class, () -> {
CompletableFuture.runAsync(lock::transit).get(5, TimeUnit.MILLISECONDS);
}, "Disallowed transit didn't block a transit");
}
}
@Test
public void testDeadlocks() {
var lock = new TransitLock();
AtomicInteger alreadyRunningTransits = new AtomicInteger();
2021-01-22 04:22:58 +01:00
var pool = Executors.newFixedThreadPool(500);
AtomicReference<Exception> failure = new AtomicReference<>();
2021-01-22 03:15:14 +01:00
for (int i = 0; i < 100; i++) {
int iF = i;
pool.submit(() -> {
try {
2021-01-22 04:22:58 +01:00
for (int j = 0; j < 500; j++) {
2021-01-22 03:15:14 +01:00
if (iF % 2 == 0) {
lock.startTransit();
alreadyRunningTransits.getAndIncrement();
alreadyRunningTransits.decrementAndGet();
lock.endTransit();
} else {
lock.disallowTransit();
Assertions.assertEquals(0, alreadyRunningTransits.get());
lock.allowTransit();
}
}
2021-01-22 04:22:58 +01:00
} catch (Exception e) {
2021-01-22 03:15:14 +01:00
e.printStackTrace();
failure.set(e);
}
});
}
pool.shutdown();
2021-01-22 04:22:58 +01:00
if (failure.get() != null) throw new AssertionError(failure.get());
2021-01-22 03:15:14 +01:00
Assertions.assertDoesNotThrow(() -> pool.awaitTermination(10, TimeUnit.SECONDS));
Assertions.assertTrue(pool.isTerminated());
}
@Test
public void testParallelTransit() {
var lock = new TransitLock();
AtomicInteger alreadyRunningTransits = new AtomicInteger();
var pool = Executors.newFixedThreadPool(100);
AtomicReference<AssertionError> failure = new AtomicReference<>();
for (int i = 0; i < 100; i++) {
pool.submit(() -> {
try {
lock.startTransit();
alreadyRunningTransits.getAndIncrement();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
Assertions.fail(e);
}
alreadyRunningTransits.decrementAndGet();
lock.endTransit();
} catch (AssertionError e) {
e.printStackTrace();
failure.set(e);
}
});
}
lock.disallowTransit();
Assertions.assertEquals(0, alreadyRunningTransits.get());
lock.allowTransit();
pool.shutdown();
if (failure.get() != null) throw failure.get();
Assertions.assertDoesNotThrow(() -> pool.awaitTermination(10, TimeUnit.SECONDS));
Assertions.assertTrue(pool.isTerminated());
}
}