// Path: src/main/java/uk/sky/cqlmigrate/exception/CannotAcquireLockException.java
// public class CannotAcquireLockException extends LockException {
// 
//     public CannotAcquireLockException(String message) {
//         super(message);
//     }
// 
//     public CannotAcquireLockException(String message, Throwable cause) {
//         super(message, cause);
//     }
// }
// 
// Path: src/main/java/uk/sky/cqlmigrate/exception/CannotReleaseLockException.java
// public class CannotReleaseLockException extends LockException {
// 
//     public CannotReleaseLockException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public CannotReleaseLockException(String message) {
//         super(message);
//     }
// }


import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import uk.sky.cqlmigrate.exception.CannotAcquireLockException;
import uk.sky.cqlmigrate.exception.CannotReleaseLockException;
import java.time.Duration;

    @Test
    public void retriesToReleaseLockAfterIntervalIfFailedTheFirstTime() throws Throwable {
        //given
        given(lockingMechanism.acquire(LOCK_CONFIG.getClientId())).willReturn(true);
        given(lockingMechanism.release(LOCK_CONFIG.getClientId())).willReturn(false, true);
        lock.lock();

        //when
        long startTime = System.currentTimeMillis();
        lock.unlock(false);
        long duration = System.currentTimeMillis() - startTime;

        //then
        assertThat(duration).isGreaterThanOrEqualTo(POLLING_MILLIS);
        verify(lockingMechanism, times(2)).release(LOCK_CONFIG.getClientId());
    }

    @Test
    public void throwsExceptionIfFailedToReleaseLockBeforeTimeout() throws Throwable {
        //given
        given(lockingMechanism.acquire(LOCK_CONFIG.getClientId())).willReturn(true);
        given(lockingMechanism.release(LOCK_CONFIG.getClientId())).willReturn(false);
        lock.lock();

        //when
        long startTime = System.currentTimeMillis();
        try {
            lock.unlock(false);
            fail("Expected Exception");
// Path: src/main/java/uk/sky/cqlmigrate/exception/CannotAcquireLockException.java
// public class CannotAcquireLockException extends LockException {
// 
//     public CannotAcquireLockException(String message) {
//         super(message);
//     }
// 
//     public CannotAcquireLockException(String message, Throwable cause) {
//         super(message, cause);
//     }
// }
// 
// Path: src/main/java/uk/sky/cqlmigrate/exception/CannotReleaseLockException.java
// public class CannotReleaseLockException extends LockException {
// 
//     public CannotReleaseLockException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public CannotReleaseLockException(String message) {
//         super(message);
//     }
// }


// Path: src/test/java/uk/sky/cqlmigrate/LockTest.java
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import uk.sky.cqlmigrate.exception.CannotAcquireLockException;
import uk.sky.cqlmigrate.exception.CannotReleaseLockException;
import java.time.Duration;


    @Test
    public void retriesToReleaseLockAfterIntervalIfFailedTheFirstTime() throws Throwable {
        //given
        given(lockingMechanism.acquire(LOCK_CONFIG.getClientId())).willReturn(true);
        given(lockingMechanism.release(LOCK_CONFIG.getClientId())).willReturn(false, true);
        lock.lock();

        //when
        long startTime = System.currentTimeMillis();
        lock.unlock(false);
        long duration = System.currentTimeMillis() - startTime;

        //then
        assertThat(duration).isGreaterThanOrEqualTo(POLLING_MILLIS);
        verify(lockingMechanism, times(2)).release(LOCK_CONFIG.getClientId());
    }

    @Test
    public void throwsExceptionIfFailedToReleaseLockBeforeTimeout() throws Throwable {
        //given
        given(lockingMechanism.acquire(LOCK_CONFIG.getClientId())).willReturn(true);
        given(lockingMechanism.release(LOCK_CONFIG.getClientId())).willReturn(false);
        lock.lock();

        //when
        long startTime = System.currentTimeMillis();
        try {
            lock.unlock(false);
            fail("Expected Exception");
        } catch (CannotReleaseLockException e) {