### Question:
SignalizationBasedEventSynchronizer implements EventSynchronizer { @Override public void awaitUntil(SynchronizationEvent synchronizationEvent) throws InterruptedException, TimeoutException { logger.debug("Before await " + synchronizationEvent.isSatisfied()); if (synchronizationEvent.isSatisfied()) { return; } try { lock.lock(); Condition condition = lock.newCondition(); eventConditionMap.put(synchronizationEvent, condition); logger.debug("When calling await " + synchronizationEvent.isSatisfied()); boolean timedOut = !condition.await(timeoutInSeconds, TimeUnit.SECONDS); if (timedOut) { logger.debug("After timeout " + synchronizationEvent.isSatisfied()); logger.error("Condition {} timed out! ", synchronizationEvent.getName()); throw new TimeoutException("The synchronization event " + synchronizationEvent.getName() + " was not satisfied in the specified time"); } } finally { lock.unlock(); } } SignalizationBasedEventSynchronizer(int timeoutInSeconds);  SignalizationBasedEventSynchronizer(int timeoutInSeconds, Lock lock); @Override void awaitUntil(SynchronizationEvent synchronizationEvent); @Override void signalizeEvent(SynchronizationEvent synchronizationEvent);  }### Answer:
@Test public void awaitForEventDoesNotLockTheThreadIfEventIsAlreadySatisfied() throws TimeoutException, InterruptedException { SynchronizationEvent synchronizationEvent = mock(SynchronizationEvent.class); when(synchronizationEvent.isSatisfied()).thenReturn(true); Lock lock = mock(Lock.class); SignalizationBasedEventSynchronizer signalizationBasedEventSynchronizer = new SignalizationBasedEventSynchronizer(timeout, lock); signalizationBasedEventSynchronizer.awaitUntil(synchronizationEvent); verify(lock, never()).lock(); }
@Test public void exceptionIsThrownAndEventIsCleanedUpIfAwaitTimesOut() throws TimeoutException, InterruptedException { SynchronizationEvent synchronizationEvent = mock(SynchronizationEvent.class); when(synchronizationEvent.isSatisfied()).thenReturn(false); Condition condition = mock(Condition.class); when(condition.await(timeout, TimeUnit.SECONDS)).thenReturn(false); Lock lock = mock(Lock.class); when(lock.newCondition()).thenReturn(condition); SignalizationBasedEventSynchronizer signalizationBasedEventSynchronizer = new SignalizationBasedEventSynchronizer(timeout, lock); expectedException.expect(TimeoutException.class); signalizationBasedEventSynchronizer.awaitUntil(synchronizationEvent); }
@Test public void ifEventIsSignalizedThenLockIsUnlocked() throws TimeoutException, InterruptedException { SynchronizationEvent synchronizationEvent = mock(SynchronizationEvent.class); when(synchronizationEvent.isSatisfied()).thenReturn(false); SignalizationBasedEventSynchronizer signalizationBasedEventSynchronizer = new SignalizationBasedEventSynchronizer(timeout); Thread signalizingThread = new Thread(new SignalizingRunnable(signalizationBasedEventSynchronizer, synchronizationEvent)); signalizingThread.start(); signalizationBasedEventSynchronizer.awaitUntil(synchronizationEvent); signalizingThread.join(); }
@Test public void ifIllegalStateExceptionIsThrownIsIsLocked() throws TimeoutException, InterruptedException { SynchronizationEvent synchronizationEvent = mock(SynchronizationEvent.class); when(synchronizationEvent.isSatisfied()).thenReturn(false); Condition condition = mock(Condition.class); doAnswer(invocationOnMock -> { Thread.sleep(2000); return false; }).when(condition).await(timeout, TimeUnit.SECONDS); Lock lock = mock(Lock.class); when(lock.newCondition()).thenReturn(condition); doNothing().doThrow(new IllegalMonitorStateException()).when(lock).lock(); SignalizationBasedEventSynchronizer signalizationBasedEventSynchronizer = new SignalizationBasedEventSynchronizer(timeout, lock); Thread signalizingThread = new Thread(new SignalizingRunnable(signalizationBasedEventSynchronizer, synchronizationEvent)); expectedException.expect(TimeoutException.class); signalizingThread.start(); signalizationBasedEventSynchronizer.awaitUntil(synchronizationEvent); signalizingThread.join(); }