Source:
public void competingWithLock() throws Exception { LockRegistry firstRegistry = mock(LockRegistry.class); Lock firstLock = mock(Lock.class); given(firstRegistry.obtain(anyString())).willReturn(firstLock); given(firstLock.tryLock(anyLong(), any(TimeUnit.class))).willReturn(true); LockRegistryLeaderInitiator first = new LockRegistryLeaderInitiator(firstRegistry, new DefaultCandidate()); CountDownLatch firstGranted = new CountDownLatch(1); CountDownLatch firstRevoked = new CountDownLatch(1); first.setLeaderEventPublisher(new CountingPublisher(firstGranted, firstRevoked)); LockRegistry secondRegistry = mock(LockRegistry.class); Lock secondLock = mock(Lock.class); given(secondRegistry.obtain(anyString())).willReturn(secondLock); given(secondLock.tryLock(anyLong(), any(TimeUnit.class))).willReturn(false); LockRegistryLeaderInitiator second = new LockRegistryLeaderInitiator(secondRegistry, new DefaultCandidate()); CountDownLatch secondGranted = new CountDownLatch(1); CountDownLatch secondRevoked = new CountDownLatch(1); second.setLeaderEventPublisher(new CountingPublisher(secondGranted, secondRevoked)); first.start(); second.start(); Thread.sleep(1000); assertThat(first.getContext().isLeader(), is(true)); assertThat(second.getContext().isLeader(), is(false)); assertThat(firstGranted.await(10, TimeUnit.SECONDS), is(true)); given(firstLock.tryLock(anyLong(), any(TimeUnit.class))).willReturn(false); given(secondLock.tryLock(anyLong(), any(TimeUnit.class))).willReturn(true); Thread.sleep(1000); assertThat(second.getContext().isLeader(), is(true)); assertThat(first.getContext().isLeader(), is(false)); assertThat(secondGranted.await(10, TimeUnit.SECONDS), is(true)); assertThat(firstRevoked.await(10, TimeUnit.SECONDS), is(true)); }

Target:
public void competingWithLock() throws Exception { AtomicBoolean firstLocked = new AtomicBoolean(true); LockRegistry firstRegistry = mock(LockRegistry.class); Lock firstLock = mock(Lock.class); given(firstRegistry.obtain(anyString())).willReturn(firstLock); given(firstLock.tryLock(anyLong(), any(TimeUnit.class))).willAnswer(i -> firstLocked.get()); LockRegistryLeaderInitiator first = new LockRegistryLeaderInitiator(firstRegistry, new DefaultCandidate()); CountDownLatch firstGranted = new CountDownLatch(1); CountDownLatch firstRevoked = new CountDownLatch(1); first.setHeartBeatMillis(10); first.setBusyWaitMillis(1); first.setLeaderEventPublisher(new CountingPublisher(firstGranted, firstRevoked)); LockRegistry secondRegistry = mock(LockRegistry.class); Lock secondLock = mock(Lock.class); given(secondRegistry.obtain(anyString())).willReturn(secondLock); given(secondLock.tryLock(anyLong(), any(TimeUnit.class))).willAnswer(i -> !firstLocked.get()); LockRegistryLeaderInitiator second = new LockRegistryLeaderInitiator(secondRegistry, new DefaultCandidate()); CountDownLatch secondGranted = new CountDownLatch(1); CountDownLatch secondRevoked = new CountDownLatch(1); second.setHeartBeatMillis(10); second.setBusyWaitMillis(1); second.setLeaderEventPublisher(new CountingPublisher(secondGranted, secondRevoked)); first.start(); second.start(); Thread.sleep(100); assertThat(first.getContext().isLeader(), is(true)); assertThat(second.getContext().isLeader(), is(false)); assertThat(firstGranted.await(10, TimeUnit.SECONDS), is(true)); firstLocked.set(false); Thread.sleep(100); assertThat(second.getContext().isLeader(), is(true)); assertThat(first.getContext().isLeader(), is(false)); assertThat(secondGranted.await(10, TimeUnit.SECONDS), is(true)); assertThat(firstRevoked.await(10, TimeUnit.SECONDS), is(true)); }