/**
* Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.applications.frsync.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.openflowplugin.applications.frsync.SemaphoreKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Test for {@link SemaphoreKeeperGuavaImpl}.
*/
public class SemaphoreKeeperGuavaImplTest {
private static final Logger LOG = LoggerFactory.getLogger(SemaphoreKeeperGuavaImplTest.class);
private SemaphoreKeeperGuavaImpl<String> semaphoreKeeper;
private final String key = "11";
@Before
public void setUp() throws Exception {
semaphoreKeeper = new SemaphoreKeeperGuavaImpl<>(1, true);
}
@Test
public void testSummonGuard() throws Exception {
Semaphore semaphore1 = semaphoreKeeper.summonGuard(key);
final int g1FingerPrint = semaphore1.hashCode();
Semaphore semaphore2 = semaphoreKeeper.summonGuard(key);
final int g2FingerPrint = semaphore2.hashCode();
Assert.assertSame(semaphore1, semaphore2);
Assert.assertEquals(1, semaphore1.availablePermits());
semaphore1.acquire();
semaphore1.release();
Assert.assertEquals(1, semaphore1.availablePermits());
semaphore1 = null;
System.gc();
semaphore2.acquire();
semaphore2.release();
Assert.assertEquals(1, semaphore2.availablePermits());
semaphore2 = null;
Assert.assertEquals(g1FingerPrint, g2FingerPrint);
System.gc();
final Semaphore semaphore3 = semaphoreKeeper.summonGuard(key);
Assert.assertNotEquals(g1FingerPrint, semaphore3.hashCode());
}
@Test
public void testReleaseGuard() throws Exception {
for (int total = 1; total <= 10; total++) {
LOG.info("test run: {}", total);
final Worker task = new Worker(semaphoreKeeper, key);
final ExecutorService executorService = new ThreadPoolExecutor(5, 5,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()) {
@Override
protected void afterExecute(final Runnable r, final Throwable t) {
super.afterExecute(r, t);
if (t != null) {
LOG.error("pool thread crashed", t);
}
}
};
final int steps = 10;
for (int i = 0; i < steps; i++) {
executorService.submit(task);
}
Thread.sleep(50L);
LOG.info("STARTING new serie");
System.gc();
for (int i = 0; i < steps; i++) {
executorService.submit(task);
}
Thread.sleep(100L);
System.gc();
executorService.shutdown();
final boolean terminated = executorService.awaitTermination(10, TimeUnit.SECONDS);
if (!terminated) {
LOG.warn("pool stuck, forcing termination");
executorService.shutdownNow();
Assert.fail("pool failed to finish gracefully");
}
final int counterSize = task.getCounterSize();
LOG.info("final counter = {}", counterSize);
Assert.assertEquals(20, counterSize);
}
}
private static class Worker implements Runnable {
private final SemaphoreKeeper<String> keeper;
private final String key;
private final ConcurrentMap<Integer, Integer> counter = new ConcurrentHashMap<>();
private volatile int index = 0;
public Worker(SemaphoreKeeper<String> keeper, final String key) {
this.keeper = keeper;
this.key = key;
}
@Override
public void run() {
try {
final Semaphore guard = keeper.summonGuard(key);
Thread.sleep(2L);
guard.acquire();
counter.putIfAbsent(index, 0);
counter.put(index, counter.get(index) + 1);
LOG.debug("queue: {} [{}] - {}", guard.getQueueLength(), guard.hashCode(), counter.size());
index++;
guard.release();
} catch (Exception e) {
LOG.warn("acquiring failed.. ", e);
}
}
public int getCounterSize() {
return counter.size();
}
}
}