/*
* Copyright © 2013. Palomino Labs (http://palominolabs.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palominolabs.crm.sf.soap;
import com.palominolabs.testutil.ThreadInterruptTask;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Timer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@SuppressWarnings({"UnusedCatchParameter"})
public class CallSemaphoreTest {
private static final int MAX_PERMITS = 4;
private CallSemaphore sem;
private Timer timer;
@Before
public void setUp() {
this.sem = new CallSemaphore();
this.sem.setMaxPermits(MAX_PERMITS);
this.timer = new Timer();
}
@After
public void tearDown() {
this.timer.cancel();
}
@Test
public void testGetMax() throws InterruptedException {
// should simply work
for (int i = 0; i < MAX_PERMITS; i++) {
this.sem.acquire();
}
}
@Test
public void testZeroSize() {
try {
new CallSemaphore().setMaxPermits(0);
fail();
} catch (IllegalArgumentException e) {
assertEquals("Semaphore size must be at least 1, was 0", e.getMessage());
}
}
@Test
public void testGetMoreThanMaxWillBlock() {
// get all available tokens
for (int i = 0; i < MAX_PERMITS; i++) {
try {
this.sem.acquire();
} catch (InterruptedException e) {
fail();
}
}
// prepare a task to fire in 100ms
this.timer.schedule(new ThreadInterruptTask(Thread.currentThread()), 100);
try {
this.sem.acquire();
fail();
} catch (InterruptedException e) {
}
}
@Test
public void testGetLessThanMaxThenDecreaseMaxWillBlockForNext() {
// get all but one permit
for (int i = 0; i < MAX_PERMITS - 1; i++) {
try {
this.sem.acquire();
} catch (InterruptedException e) {
fail();
}
}
this.sem.setMaxPermits(MAX_PERMITS - 1);
// prepare a task to fire in 100ms
this.timer.schedule(new ThreadInterruptTask(Thread.currentThread()), 100);
try {
this.sem.acquire();
fail();
} catch (InterruptedException e) {
}
}
@Test
public void testBlockedGetPermitsWhenMaxIncreased() throws InterruptedException {
// get all available tokens
for (int i = 0; i < MAX_PERMITS; i++) {
try {
this.sem.acquire();
} catch (InterruptedException e) {
fail();
}
}
ExecutorService exec = Executors.newFixedThreadPool(1);
final CallSemaphore fpool = this.sem;
Future<Void> future1 = exec.submit(new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
fpool.acquire();
return null;
}
});
Future<Void> future2 = exec.submit(new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
fpool.acquire();
return null;
}
});
assertFalse(future1.isDone());
assertFalse(future2.isDone());
this.sem.setMaxPermits(MAX_PERMITS + 2);
Thread.sleep(100);
assertTrue(future1.isDone());
assertTrue(future2.isDone());
try {
assertNull(future1.get());
assertNull(future2.get());
} catch (ExecutionException e) {
fail(e.getCause().getMessage());
}
}
@Test
public void testRelease() {
// get all available tokens
for (int i = 0; i < MAX_PERMITS; i++) {
try {
this.sem.acquire();
} catch (InterruptedException e) {
fail();
}
}
// get all available tokens
for (int i = 0; i < MAX_PERMITS; i++) {
this.sem.release();
}
}
@Test
public void testReleaseMoreThanCapacity() {
// get all available tokens
for (int i = 0; i < MAX_PERMITS; i++) {
try {
this.sem.acquire();
} catch (InterruptedException e) {
fail();
}
}
for (int i = 0; i < MAX_PERMITS; i++) {
this.sem.release();
}
// doesn't do anything... can't detect this error condition, unfortunately
this.sem.release();
}
}