package org.araqne.logstorage.file;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import org.araqne.logstorage.LockKey;
import org.araqne.logstorage.LockStatus;
import org.araqne.logstorage.Log;
import org.araqne.logstorage.LogStorage;
import org.araqne.logstorage.LogUtil;
import org.araqne.logstorage.TableLock;
import org.araqne.logstorage.TableLockImpl;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class TableLockTest {
LogStorage ls;
TableLockImpl lock;
@Before
public void setup() throws InterruptedException {
ls = mock(LogStorage.class);
lock = new TableLockImpl(0);
when(ls.lock(any(LockKey.class), any(String.class), any(Long.class), any(TimeUnit.class))).thenAnswer(
new Answer<UUID>() {
@Override
public UUID answer(InvocationOnMock inv) throws Throwable {
LockKey key = (LockKey) inv.getArguments()[0];
String p = (String) inv.getArguments()[1];
TableLock writeLock = lock.writeLock(key.owner, p);
return writeLock.tryLock();
}
});
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock inv) throws Throwable {
LockKey key = (LockKey) inv.getArguments()[0];
String p = (String) inv.getArguments()[1];
TableLock writeLock = lock.writeLock(key.owner, p);
writeLock.unlock();
return null;
}
}).when(ls).unlock(any(LockKey.class), any(String.class));
when(ls.lockStatus(any(LockKey.class))).thenAnswer(new Answer<LockStatus>() {
@Override
public LockStatus answer(InvocationOnMock inv) throws Throwable {
@SuppressWarnings("unused")
LockKey key = (LockKey) inv.getArguments()[0];
if (lock.getOwner() != null)
return new LockStatus(
lock.getOwner(), lock.availableShared(), lock.getReentrantCount(),
lock.getPurposes());
else
return new LockStatus(lock.availableShared());
}
});
when(ls.tryWrite(any(Log.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
TableLock readLock = lock.readLock();
UUID locked = readLock.tryLock();
if (locked != null)
readLock.unlock();
return locked != null;
}
});
}
@Test
public void tableLockTest() throws InterruptedException {
List<Log> logs = new ArrayList<Log>();
logs.add(new Log("test1", LogUtil.getDay(new Date()), LogUtil.newLogData("line", "line0")));
logs.add(new Log("test1", LogUtil.getDay(new Date()), LogUtil.newLogData("line", "line1")));
logs.add(new Log("test1", LogUtil.getDay(new Date()), LogUtil.newLogData("line", "line2")));
assertTrue(ls.tryWrite(logs.get(0)));
assertTrue(ls.tryWrite(logs.get(1)));
ls.lock(new LockKey("test", "T1", null), "test", Long.MAX_VALUE, TimeUnit.SECONDS);
assertFalse(ls.tryWrite(logs.get(2)));
assertEquals("test", ls.lockStatus(new LockKey("test", "T1", null)).getOwner());
ls.unlock(new LockKey("test", "T1", null), "test");
assertTrue(ls.tryWrite(logs.get(2)));
assertEquals(null, ls.lockStatus(new LockKey("test", "T1", null)).getOwner());
}
@Test
public void reentrantLockingTest() throws InterruptedException {
// precondition
LockKey lk = new LockKey("test", "T2", null);
assertEquals(null, ls.lockStatus(lk).getOwner());
// test
assertTrue(ls.lock(lk, "test1", Long.MAX_VALUE, TimeUnit.SECONDS) != null);
assertTrue(ls.lock(lk, "test2", Long.MAX_VALUE, TimeUnit.SECONDS) != null);
assertFalse(ls.lock(
new LockKey("test2", "T2", null), "test1", Long.MAX_VALUE, TimeUnit.SECONDS) != null);
assertEquals("test", ls.lockStatus(new LockKey("test", "T2", null)).getOwner());
assertEquals(
"[test2:1, test1:1]",
sortedPurposes(ls.lockStatus(new LockKey("test", "T2", null)).getPurposes()));
ls.unlock(lk, "test2");
assertEquals("test", ls.lockStatus(new LockKey("test", "T2", null)).getOwner());
assertFalse(ls.lock(
new LockKey("test2", "T2", null), "test1", Long.MAX_VALUE, TimeUnit.SECONDS) != null);
ls.unlock(lk, "test1");
// postcondition
assertEquals(null, ls.lockStatus(new LockKey("test", "T1", null)).getOwner());
}
private String sortedPurposes(Collection<String> purposes) {
Object[] arr = purposes.toArray();
Arrays.sort(arr, Collections.reverseOrder());
return Arrays.toString(arr);
}
@Test
public void ensureUnlockingTest() throws InterruptedException {
LockKey lk = new LockKey("test", "T3", null);
ls.lock(lk, "Live", Long.MAX_VALUE, TimeUnit.SECONDS);
System.out.println(ls.lockStatus(lk));
ls.unlock(lk, "Live");
System.out.println(ls.lockStatus(lk));
ls.unlock(lk, "Live");
System.out.println(ls.lockStatus(lk));
ls.lock(lk, "Sync", 0, TimeUnit.SECONDS);
ls.unlock(lk, "Live");
ls.lock(lk, "Sync", 0, TimeUnit.SECONDS);
ls.lock(lk, "Live", 0, TimeUnit.SECONDS);
ls.lock(lk, "Sync", 0, TimeUnit.SECONDS);
ls.unlock(lk, "Live");
System.out.println(ls.lockStatus(lk));
}
}