package edu.brown.protorpc; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import ca.evanjones.protorpc.Counter; import ca.evanjones.protorpc.Protocol; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import com.google.protobuf.RpcCallback; public class ProtoRpcControllerTest { private final NIOEventLoop eventLoop = new NIOEventLoop(); private final StoreResultCallback<Message> callback = new StoreResultCallback<Message>(); private ProtoRpcController rpc; private static final ByteString COUNTER_VALUE = Counter.Value.newBuilder().setValue(42).build().toByteString(); @Before public void setUp() { rpc = new ProtoRpcController(); } @Test public void testFailedErrorTextSuccess() { try { rpc.failed(); fail("expected exception"); } catch (IllegalStateException e) {} try { rpc.errorText(); fail("expected exception"); } catch (IllegalStateException e) {} rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); try { rpc.failed(); fail("expected exception"); } catch (IllegalStateException e) {} try { rpc.errorText(); fail("expected exception"); } catch (IllegalStateException e) {} rpc.finishRpcSuccess(COUNTER_VALUE); assertFalse(rpc.failed()); assertEquals(42, ((Counter.Value) callback.getResult()).getValue()); try { rpc.errorText(); fail("expected exception"); } catch (IllegalStateException e) {} } @Test public void testFailedRpc() { rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); try { rpc.failed(); fail("expected exception"); } catch (IllegalStateException e) {} String message = "Some user error"; rpc.finishRpcFailure(Protocol.Status.ERROR_USER, message); assertTrue(rpc.failed()); assertEquals(message, rpc.errorText()); rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); try { rpc.errorText(); fail("expected exception"); } catch (IllegalStateException e) {} } @Test public void testReuseInCallback() { // Callback that reuses the controller. RpcCallback<Message> reuseCallback = new RpcCallback<Message>() { @Override public void run(Message parameter) { rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); } }; rpc.startRpc(eventLoop, Counter.Value.newBuilder(), reuseCallback); // triggers the reuse callback, then the "real" callback rpc.finishRpcSuccess(COUNTER_VALUE); assertNull(callback.getResult()); rpc.finishRpcSuccess(COUNTER_VALUE); assertFalse(rpc.failed()); assertEquals(42, ((Counter.Value) callback.getResult()).getValue()); } @Test public void testFailedInCallback() { // Test that calling rpc.failed() works in the result callback RpcCallback<Message> callback = new RpcCallback<Message>() { public void run(Message arg) { assertFalse(rpc.failed()); } }; rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); rpc.finishRpcSuccess(COUNTER_VALUE); } @Test public void testSetFailed() { try { rpc.setFailed(null); fail("expected exception"); } catch (UnsupportedOperationException e) {} } @Test public void testMockFinishRpcForTest() { // failed() does not work if the RPC has not completed try { rpc.failed(); fail("expected exception"); } catch (IllegalStateException e) {} // this "fakes" the transaction being done rpc.mockFinishRpcForTest(); assertFalse(rpc.failed()); // Re-using the RPC controller is okay: calling this again works rpc.mockFinishRpcForTest(); } @Test public void testBadStartRpc() { try { rpc.startRpc(eventLoop, Counter.Value.newBuilder(), null); fail("expected exception"); } catch (NullPointerException e) {} rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); try { rpc.startRpc(eventLoop, Counter.Value.newBuilder(), callback); fail("expected exception"); } catch (IllegalStateException e) {} } @Test public void testBlockTestCallback() { // For tests, we want to "hack" rpc.block() by making it return immediately rpc.mockFinishRpcForTest(); rpc.block(); } }