package com.lithium.dbi.rdbi.recipes.locking;

import com.google.common.base.Optional;
import com.lithium.dbi.rdbi.Handle;
import com.lithium.dbi.rdbi.RDBI;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import redis.clients.jedis.JedisPool;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

@Test(groups = "integration")
public class SemaphoreTest {
    private static final RDBI rdbi = new RDBI(new JedisPool("localhost"));
    private static final String ownerId = "ownerSemaphoreTest";
    private static final String semaphoreKey = "semaphoreKeySemaphoreTest";
    private static final Integer semaphoreLengthInSeconds = 10;
    private Semaphore semaphore;

    @BeforeMethod
    public void beforeTest(){
        semaphore = new Semaphore(rdbi, ownerId, semaphoreKey);
    }

    @AfterMethod
    public void afterTest(){
        semaphore.releaseSemaphore();
    }

    @Test
    public void testAcquireRelease() {
        assertTrue(semaphore.acquireSemaphore(semaphoreLengthInSeconds));
        try (Handle handle = rdbi.open()) {
            assertNotEquals(handle.jedis().setnx(semaphoreKey, ownerId + "New"), 1L);
        }

        // Verify that we have deleted the semaphore
        Optional<String> realOwner = semaphore.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
        try (Handle handle = rdbi.open()) {
            String checkOwnerId = handle.jedis().get(semaphoreKey);
            assertNull(checkOwnerId);
        }
    }

    @Test
    public void testAcquireReleaseMultipleLocks() {
        assertTrue(semaphore.acquireSemaphore(semaphoreLengthInSeconds));

        // Acquire a second semaphore
        Semaphore semaphoreDiffKey = new Semaphore(rdbi, ownerId, semaphoreKey + "diffKey");
        assertTrue(semaphoreDiffKey.acquireSemaphore(semaphoreLengthInSeconds));

        // Verify that we have deleted the semaphore
        Optional<String> realOwner = semaphore.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
        try (Handle handle = rdbi.open()) {
            String checkOwnerId = handle.jedis().get(semaphoreKey);
            assertNull(checkOwnerId);

            checkOwnerId = handle.jedis().get(semaphoreKey + "diffKey");
            assertNotNull(checkOwnerId);
        }

        // Verify that we have deleted the semaphore
        realOwner = semaphoreDiffKey.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
    }

    @Test
    public void testAcquireReleaseMultipleTimes() {
        assertTrue(semaphore.acquireSemaphore(semaphoreLengthInSeconds));

        // Verify cannot acquire a second time
        assertFalse(semaphore.acquireSemaphore(semaphoreLengthInSeconds));

        // Verify that we have deleted the semaphore
        Optional<String> realOwner = semaphore.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
        try (Handle handle = rdbi.open()) {
            String checkOwnerId = handle.jedis().get(semaphoreKey);
            assertNull(checkOwnerId);
        }

        // Verify that we cannot delete twice
        realOwner = semaphore.releaseSemaphore();
        assertFalse(realOwner.isPresent());
    }

    @Test
    public void testAcquireReleaseDifferentOwner() {
        assertTrue(semaphore.acquireSemaphore(semaphoreLengthInSeconds));

        // Should not be able to acquire another owner's semaphore
        Semaphore semaphoreNew = new Semaphore(rdbi, ownerId + "Wrong", semaphoreKey);
        assertFalse(semaphoreNew.acquireSemaphore(semaphoreLengthInSeconds));

        // Verify that cannot release another owner's semaphore
        Optional<String> realOwner = semaphoreNew.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
        try (Handle handle = rdbi.open()) {
            String checkOwnerId = handle.jedis().get(semaphoreKey);
            assertNotNull(checkOwnerId);
            assertEquals(ownerId, checkOwnerId);
        }

        // Verify that we have deleted the semaphore
        realOwner = semaphore.releaseSemaphore();
        assertTrue(realOwner.isPresent());
        assertEquals(ownerId, realOwner.get());
    }
}

@@ -896,38 +896,39 @@
 nteger semaphore
-Length
+Timeout
 InSeconds = 10;%0A
@@ -928,9 +928,8 @@
  = 1
-0
 ;%0A  
@@ -1266,38 +1266,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A   
@@ -1805,32 +1805,418 @@
        %7D%0A    %7D%0A%0A
+    @Test%0A    public void testAcquireTimeout() throws InterruptedException %7B%0A        assertTrue(semaphore.acquireSemaphore(semaphoreTimeoutInSeconds));%0A        Thread.sleep(semaphoreTimeoutInSeconds * 1000 + 100);%0A%0A        // Verify that we have deleted the semaphore%0A        Optional%3CString%3E realOwner = semaphore.releaseSemaphore();%0A        assertFalse(realOwner.isPresent());%0A    %7D%0A%0A
     @Test%0A    pu
@@ -2308,38 +2308,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A%0A  
@@ -2522,38 +2522,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A%0A  
@@ -3355,38 +3355,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A%0A  
@@ -3479,38 +3479,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A%0A  
@@ -4137,38 +4137,39 @@
 aphore(semaphore
-Length
+Timeout
 InSeconds));%0A%0A  
@@ -4383,14 +4383,15 @@
 hore
-Length
+Timeout
 InSe

Add timeout test.