package com.github.marschall.memoryfilesystem;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class LockSetTest {
private final MemoryFileLock toAdd;
private final Collection<MemoryFileLock> alreadyPresent;
private LockSet lockSet;
private final boolean expectedSuccess;
public LockSetTest(MemoryFileLock toAdd, Collection<MemoryFileLock> alreadyPresent, boolean expectedSuccess) {
this.toAdd = toAdd;
this.alreadyPresent = alreadyPresent;
this.expectedSuccess = expectedSuccess;
}
@Parameters
public static List<Object[]> data() {
return Arrays.asList(new Object[][] {
{ lock(0L, 1000L), singletonList(lock(1000L, 9000L)), true },
{ lock(10001L, 999L), singletonList(lock(1000L, 9001L)), true },
{ lock(1L, 1000L), singletonList(lock(1000L, 9000L)), false },
{ lock(10000L, 999L), singletonList(lock(1000L, 9001L)), false },
{ lock(2000L, 1000L), singletonList(lock(1000L, 9001L)), false },
{ lock(0L, 20000L), singletonList(lock(1000L, 9001L)), false },
{ lock(0L, 1000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), true },
{ lock(5000L, 1000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), true },
{ lock(20000L, 1000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), true },
{ lock(1500L, 1000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), false },
{ lock(1500L, 100L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), false },
{ lock(10500L, 1000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), false },
{ lock(1500L, 9000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), false },
{ lock(0L, 20000L), asList(lock(1000L, 1000L), lock(10000L, 1000L)), false },
});
}
private static MemoryFileLock lock(long position, long size) {
AsynchronousFileChannel channel = new StubChannel();
return new MemoryFileLock(channel, position, size, false);
}
@Before
public void setUp() throws IOException {
this.lockSet = new LockSet();
for (MemoryFileLock lock : this.alreadyPresent) {
this.lockSet.lock(lock);
}
}
@Test
public void tryLock() {
FileLock lock = this.lockSet.tryLock(this.toAdd);
assertEquals("lock acquision successfull", this.expectedSuccess, lock != null);
if (this.expectedSuccess) {
assertSame(this.toAdd, lock);
}
}
@Test
public void lock() throws IOException {
FileLock lock = null;
try {
lock = this.lockSet.lock(this.toAdd);
if (!this.expectedSuccess) {
fail("lock acquision successfull");
}
} catch (OverlappingFileLockException e) {
if (this.expectedSuccess) {
fail("lock acquision failed");
}
}
if (this.expectedSuccess) {
assertSame(this.toAdd, lock);
} else {
assertNull(lock);
}
}
static final class StubChannel extends AsynchronousFileChannel {
@Override
public void close() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean isOpen() {
throw new UnsupportedOperationException();
}
@Override
public long size() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public AsynchronousFileChannel truncate(long size) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void force(boolean metaData) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public <A> void lock(long position, long size, boolean shared, A attachment, CompletionHandler<FileLock, ? super A> handler) {
throw new UnsupportedOperationException();
}
@Override
public Future<FileLock> lock(long position, long size, boolean shared) {
throw new UnsupportedOperationException();
}
@Override
public FileLock tryLock(long position, long size, boolean shared) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public <A> void read(ByteBuffer dst, long position, A attachment, CompletionHandler<Integer, ? super A> handler) {
throw new UnsupportedOperationException();
}
@Override
public Future<Integer> read(ByteBuffer dst, long position) {
throw new UnsupportedOperationException();
}
@Override
public <A> void write(ByteBuffer src, long position, A attachment, CompletionHandler<Integer, ? super A> handler) {
throw new UnsupportedOperationException();
}
@Override
public Future<Integer> write(ByteBuffer src, long position) {
throw new UnsupportedOperationException();
}
}
}