package org.stem.client; import org.easymock.IMocksControl; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.stem.client.Message.Request; import org.stem.client.Requests.DeleteBlob; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import static org.easymock.EasyMock.*; public class ConsistentResponseHandlerTest { @Rule public ExpectedException expectedException = ExpectedException.none(); IMocksControl ctrl; Session session; Consistency.Level consistency = Consistency.Level.QUORUM; long sessionTimeoutMs = 10; @Before public void before() { this.ctrl = createControl(); final Metadata metadata = this.ctrl.createMock(Metadata.class); Host host = new Host(InetSocketAddress.createUnresolved("blablabla.com", 993)); expect(metadata.getHost(isA(InetSocketAddress.class))).andReturn(host).anyTimes(); RequestRouter router = this.ctrl.createMock(RequestRouter.class); expect(router.getHost(isA(Request.class))).andReturn(host).anyTimes(); this.session = new Session(null, router) { @Override public Metadata getClusterMetadata() { return metadata; } }; } @Test(timeout = 500) public void shouldTimeoutIfFuturesWeAreWaitingForAreBlockingForTooMuchTime() throws Exception { long sleepMs = this.sessionTimeoutMs + 2000; List<DefaultResultFuture> futures = Arrays.asList(createFutureSleeping(this.ctrl, sleepMs)); this.ctrl.replay(); ConsistentResponseHandler handler = new ConsistentResponseHandler(this.session, futures, this.consistency, this.sessionTimeoutMs); this.expectedException.expectMessage("Response is inconsistent"); handler.waitFor(); } @Test(timeout = 500) public void shouldThrowOnWaitForIfConsistencyCanNotBeAchieved() throws Exception { List<DefaultResultFuture> futures = new ArrayList<>(); for (int i=0; i<5; i++) { futures.add(createResultFuture(this.ctrl)); } for (int i=0; i<5; i++) { futures.add(createErrorFuture(this.ctrl)); } this.ctrl.replay(); ConsistentResponseHandler handler = new ConsistentResponseHandler(this.session, futures, this.consistency, this.sessionTimeoutMs); this.expectedException.expectMessage("Response is inconsistent"); handler.waitFor(); } @Test(timeout = 500) public void shouldOkIfConsistencyAchieved() throws Exception { List<DefaultResultFuture> futures = new ArrayList<>(); for (int i=0; i<5; i++) { futures.add(createResultFuture(this.ctrl)); } this.ctrl.replay(); ConsistentResponseHandler handler = new ConsistentResponseHandler(this.session, futures, this.consistency, this.sessionTimeoutMs); this.expectedException.expectMessage("Response is inconsistent"); handler.waitFor(); } private DefaultResultFuture createFutureSleeping(IMocksControl ctrl, final long sleepMs) throws InterruptedException, ExecutionException { Message.Request request = new DeleteBlob(UUID.randomUUID(), 1, 2); DefaultResultFuture future = new DefaultResultFuture(null, request); return future; } private DefaultResultFuture createErrorFuture(IMocksControl ctrl) throws Exception { DefaultResultFuture future = ctrl.createMock("errorFuture", DefaultResultFuture.class); Message.Request request = new DeleteBlob(UUID.randomUUID(), 1, 2); expect(future.request()).andReturn(request).anyTimes(); expect(future.get()).andThrow(new ExecutionException("Oops", new RuntimeException())); expect(future.get(anyLong(), isA(TimeUnit.class))).andThrow(new ExecutionException("Oops", new RuntimeException())); return future; } private DefaultResultFuture createResultFuture(IMocksControl ctrl) throws Exception { DefaultResultFuture future = ctrl.createMock("resultFuture", DefaultResultFuture.class); Message.Request request = new DeleteBlob(UUID.randomUUID(), 1, 2); expect(future.request()).andReturn(request).anyTimes(); expect(future.get()).andReturn(null); expect(future.get(anyLong(), isA(TimeUnit.class))).andReturn(null); return future; } }