package kvstore; import static autograder.TestUtils.*; import static kvstore.KVConstants.*; import static kvstore.Utils.*; import static org.junit.Assert.*; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import static org.powermock.api.mockito.PowerMockito.whenNew; import java.io.IOException; import java.net.*; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import autograder.AGCategories.AGTestDetails; import autograder.AGCategories.AG_PROJ3_CODE; @RunWith(PowerMockRunner.class) @PrepareForTest(KVClient.class) public class KVClientTest { KVClient client; KVMessage msg; Socket sock; @Before public void setupClient() throws IOException { String hostname = InetAddress.getLocalHost().getHostAddress(); client = new KVClient(hostname, 8080); } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "Client should raise ERROR_COULD_NOT_CONNECT on UnknownHostException") public void testInvalidHost() throws Exception { setupSocketHostException(); try { client = new KVClient("not_a_real_host", 8000); client.put("this should", "fail now"); fail("Put did not throw a KVException!"); } catch (KVException kve) { // Flexible since the sp14 spec was too vague. String errMsg = kve.getKVMessage().getMessage(); assertTrue(errMsg.equals(ERROR_COULD_NOT_CONNECT) || errMsg.equals(ERROR_COULD_NOT_CREATE_SOCKET)); } } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "Client should raise ERROR_COULD_NOT_CREATE_SOCKET on IOException") public void testSocketErrors() throws Exception { setupSocketIOException(); try { client.put("foo", "bar"); fail("Expected error on IOException during Socket creation"); } catch (KVException kve) { // Flexible since the sp14 spec was too vague. String errMsg = kve.getKVMessage().getMessage(); assertTrue(errMsg.equals(ERROR_COULD_NOT_CONNECT) || errMsg.equals(ERROR_COULD_NOT_CREATE_SOCKET)); } } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "Client should accept successful put response") public void testPut() throws Exception { setupSocketSuccess(); when(msg.getMsgType()).thenReturn(RESP); when(msg.getMessage()).thenReturn(SUCCESS); try { client.put("foo", "bar"); } catch (KVException e) { fail("unexpected KVException on valid put request"); } } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "Client should accept successful get response") public void testGet() throws Exception { setupSocketSuccess(); String key = "foo"; String val = "bar"; when(msg.getMsgType()).thenReturn(RESP); when(msg.getKey()).thenReturn(key); when(msg.getValue()).thenReturn(val); try { assertEquals(val, client.get(key)); } catch (KVException e) { fail("Client threw unexpected exception!"); } } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "Client should raise KVException on failed get response") public void testGetFail() throws Exception { setupSocketSuccess(); when(msg.getMsgType()).thenReturn(RESP); when(msg.getMessage()).thenReturn(ERROR_NO_SUCH_KEY); try { client.get("key"); fail("Client did not throw exception!"); } catch (KVException kve) { assertKVExceptionEquals(ERROR_NO_SUCH_KEY, kve); } } @Test(timeout = kTimeoutQuick) @Category(AG_PROJ3_CODE.class) @AGTestDetails(points = 1, desc = "IOException on socket close should be handled cleanly") public void testCloseFail() throws Exception { setupSocketSuccess(); when(msg.getMsgType()).thenReturn(RESP); when(msg.getMessage()).thenReturn(SUCCESS); doThrow(new IOException()).when(sock).close(); try { client.put("key", "value"); } catch (Exception e) { fail("Unexpected exception thrown!"); } } /* ----------------------- BEGIN HELPER METHODS ------------------------ */ private void setupSocketSuccess() throws Exception { sock = mock(Socket.class); whenNew(Socket.class).withArguments(anyString(), anyInt()).thenReturn(sock); msg = mock(KVMessage.class); whenNew(KVMessage.class).withAnyArguments().thenReturn(msg); whenNew(KVMessage.class).withArguments(any(Socket.class), anyInt()).thenReturn(msg); } private void setupSocketHostException() throws Exception { whenNew(Socket.class).withArguments(anyString(), anyInt()) .thenThrow(new UnknownHostException()); } private void setupSocketIOException() throws Exception { whenNew(Socket.class).withArguments(anyString(), anyInt()) .thenThrow(new IOException()); } }