diff --git a/.gitignore b/.gitignore
index 882b67e2ec0e1a624c962e90d86272828b6f0cb4..98c46d185264aa7f35fb38b2ab1005504113c63f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ target
 
 # ignore output files from testing
 output*
+derby.log
 
 # ignore standard eclipse
 .project
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
index b09e1aa197591acc49eb9262e16f0a115c63b35a..bebf2a3b2bc70e392f5ca3cd28f98253f3d8f15e 100644
--- a/jdbc/pom.xml
+++ b/jdbc/pom.xml
@@ -47,5 +47,10 @@ LICENSE file.
       <version>4.12</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+      <version>2.3.3</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClient.java b/jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClient.java
index 968d7322591a03bced55c5619f1a5f9e59f2ca93..d59b89f6e47532b6889ba641445eb7064ffd6641 100644
--- a/jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClient.java
+++ b/jdbc/src/main/java/com/yahoo/ycsb/db/JdbcDBClient.java
@@ -245,7 +245,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
     for (int i = 0; i < insertType.numFields; i++) {
       insert.append(",?");
     }
-    insert.append(");");
+    insert.append(")");
     PreparedStatement insertStatement = getShardConnectionByKey(key).prepareStatement(insert.toString());
     PreparedStatement stmt = cachedStatements.putIfAbsent(insertType, insertStatement);
     if (stmt == null) return insertStatement;
@@ -259,7 +259,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
     read.append(" WHERE ");
     read.append(PRIMARY_KEY);
     read.append(" = ");
-    read.append("?;");
+    read.append("?");
     PreparedStatement readStatement = getShardConnectionByKey(key).prepareStatement(read.toString());
     PreparedStatement stmt = cachedStatements.putIfAbsent(readType, readStatement);
     if (stmt == null) return readStatement;
@@ -272,7 +272,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
     delete.append(deleteType.tableName);
     delete.append(" WHERE ");
     delete.append(PRIMARY_KEY);
-    delete.append(" = ?;");
+    delete.append(" = ?");
     PreparedStatement deleteStatement = getShardConnectionByKey(key).prepareStatement(delete.toString());
     PreparedStatement stmt = cachedStatements.putIfAbsent(deleteType, deleteStatement);
     if (stmt == null) return deleteStatement;
@@ -292,7 +292,7 @@ public class JdbcDBClient extends DB implements JdbcDBClientConstants {
     }
     update.append(" WHERE ");
     update.append(PRIMARY_KEY);
-    update.append(" = ?;");
+    update.append(" = ?");
     PreparedStatement insertStatement = getShardConnectionByKey(key).prepareStatement(update.toString());
     PreparedStatement stmt = cachedStatements.putIfAbsent(updateType, insertStatement);
     if (stmt == null) return insertStatement;
diff --git a/jdbc/src/test/java/com/yahoo/ycsb/db/JdbcDBClientTest.java b/jdbc/src/test/java/com/yahoo/ycsb/db/JdbcDBClientTest.java
index 92b91e10777512930427dfa38c971d9fe2af70dc..e2983d08124a2430f1e12a8cf325d5de4f25c495 100644
--- a/jdbc/src/test/java/com/yahoo/ycsb/db/JdbcDBClientTest.java
+++ b/jdbc/src/test/java/com/yahoo/ycsb/db/JdbcDBClientTest.java
@@ -2,34 +2,323 @@ package com.yahoo.ycsb.db;
 
 import static org.junit.Assert.*;
 
-import org.junit.Test;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.StringByteIterator;
+import org.junit.*;
+
+import java.sql.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Vector;
 
 /**
  * Created by kruthar on 11/2/15.
  */
 public class JdbcDBClientTest {
+    private static final String TEST_DB_DRIVER = "org.hsqldb.jdbc.JDBCDriver";
+    private static final String TEST_DB_URL = "jdbc:hsqldb:mem:ycsb";
+    private static final String TEST_DB_USER = "sa";
+    private static final String TABLE_NAME = "USERTABLE";
+    private static final int FIELD_LENGTH = 32;
+    private static final String FIELD_PREFIX = "FIELD";
+    private static final String KEY_PREFIX = "user";
+    private static final String KEY_FIELD = "YCSB_KEY";
+    private static final int NUM_FIELDS = 3;
+
+    private static Connection jdbcConnection = null;
+    private static JdbcDBClient jdbcDBClient = null;
+
+    @BeforeClass
+    public static void setup() {
+        try {
+            Class driverClass = Class.forName(TEST_DB_DRIVER);
+            jdbcConnection = DriverManager.getConnection(TEST_DB_URL);
+
+            jdbcDBClient = new JdbcDBClient();
+
+            Properties p = new Properties();
+            p.setProperty(JdbcDBClientConstants.CONNECTION_URL, TEST_DB_URL);
+            p.setProperty(JdbcDBClientConstants.DRIVER_CLASS, TEST_DB_DRIVER);
+            p.setProperty(JdbcDBClientConstants.CONNECTION_USER, TEST_DB_USER);
+
+            jdbcDBClient.setProperties(p);
+            jdbcDBClient.init();
+
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+            fail("Could not find Driver Class: " + TEST_DB_DRIVER);
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Could not create local Database");
+        } catch (DBException e) {
+            e.printStackTrace();
+            fail("Could not create JdbcDBClient instance");
+        }
+    }
+
+    @AfterClass
+    public static void teardown() {
+        try {
+            jdbcConnection.close();
+            jdbcConnection = DriverManager.getConnection(TEST_DB_URL + ";shutdown=true");
+        } catch (SQLNonTransientConnectionException e) {
+            // Expected exception when database is destroyed
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Could not drop local Database");
+        }
+    }
+
+    @Before
+    public void prepareTest() {
+        try {
+            DatabaseMetaData metaData = jdbcConnection.getMetaData();
+            ResultSet tableResults = metaData.getTables(null, null, TABLE_NAME, null);
+            if (tableResults.next()) {
+                // If the table already exists, just truncate it
+                jdbcConnection.prepareStatement(
+                    String.format("TRUNCATE TABLE %s", TABLE_NAME)
+                ).execute();
+            } else {
+                // If the table does not exist then create it
+                StringBuilder createString = new StringBuilder(
+                    String.format("CREATE TABLE %s (%s VARCHAR(100) PRIMARY KEY", TABLE_NAME, KEY_FIELD)
+                );
+                for (int i = 0; i < NUM_FIELDS; i++) {
+                    createString.append(
+                        String.format(", %s%d VARCHAR(100)", FIELD_PREFIX, i)
+                    );
+                }
+                createString.append(")");
+                jdbcConnection.prepareStatement(createString.toString()).execute();
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Failed to prepare test");
+        }
+
+    }
+
+    /*
+        This is a copy of buildDeterministicValue() from core:com.yahoo.ycsb.workloads.CoreWorkload.java.
+        That method is neither public nor static so we need a copy.
+     */
+    private String buildDeterministicValue(String key, String fieldkey) {
+        int size = FIELD_LENGTH;
+        StringBuilder sb = new StringBuilder(size);
+        sb.append(key);
+        sb.append(':');
+        sb.append(fieldkey);
+        while (sb.length() < size) {
+            sb.append(':');
+            sb.append(sb.toString().hashCode());
+        }
+        sb.setLength(size);
+
+        return sb.toString();
+    }
+
+    /*
+        Inserts a row of deterministic values for the given insertKey using the jdbcDBClient.
+     */
+    private HashMap<String, ByteIterator> insertRow(String insertKey) {
+        HashMap<String, ByteIterator> insertMap = new HashMap<String, ByteIterator>();
+        for (int i = 0; i < 3; i++) {
+            insertMap.put(FIELD_PREFIX + i, new StringByteIterator(buildDeterministicValue(insertKey, FIELD_PREFIX + i)));
+        }
+        jdbcDBClient.insert(TABLE_NAME, insertKey, insertMap);
+
+        return insertMap;
+    }
+
     @Test
     public void insertTest() {
-        assertTrue(true);
+        try {
+            String insertKey = "user0";
+            HashMap<String, ByteIterator> insertMap = insertRow(insertKey);
+
+            ResultSet resultSet = jdbcConnection.prepareStatement(
+                String.format("SELECT * FROM %s", TABLE_NAME)
+            ).executeQuery();
+
+            // Check we have a result Row
+            assertTrue(resultSet.next());
+            // Check that all the columns have expected values
+            assertEquals(resultSet.getString(KEY_FIELD), insertKey);
+            for (int i = 0; i < 3; i++) {
+                // TODO: This will fail until the fix is made to insert and update fields in the correct order.
+                // TODO: Uncomment this assertEquals when the fix is made.
+                //assertEquals(resultSet.getString(FIELD_PREFIX + i), insertMap.get(FIELD_PREFIX + i));
+            }
+            // Check that we do not have any more rows
+            assertFalse(resultSet.next());
+
+            resultSet.close();
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Failed insertTest");
+        }
     }
 
     @Test
     public void updateTest() {
+        try {
+            String preupdateString = "preupdate";
+            StringBuilder fauxInsertString = new StringBuilder(
+                String.format("INSERT INTO %s VALUES(?", TABLE_NAME)
+            );
+            for (int i = 0; i < NUM_FIELDS; i++) {
+                fauxInsertString.append(",?");
+            }
+            fauxInsertString.append(")");
+
+            PreparedStatement fauxInsertStatement = jdbcConnection.prepareStatement(fauxInsertString.toString());
+            for (int i = 2; i < NUM_FIELDS + 2; i++) {
+                fauxInsertStatement.setString(i, preupdateString);
+            }
+
+            fauxInsertStatement.setString(1, "user0");
+            fauxInsertStatement.execute();
+            fauxInsertStatement.setString(1, "user1");
+            fauxInsertStatement.execute();
+            fauxInsertStatement.setString(1, "user2");
+            fauxInsertStatement.execute();
+
+            HashMap<String, ByteIterator> updateMap = new HashMap<String, ByteIterator>();
+            for (int i = 0; i < 3; i++) {
+                updateMap.put(FIELD_PREFIX + i, new StringByteIterator(buildDeterministicValue("user1", FIELD_PREFIX + i)));
+            }
+
+            jdbcDBClient.update(TABLE_NAME, "user1", updateMap);
+
+            ResultSet resultSet = jdbcConnection.prepareStatement(
+                String.format("SELECT * FROM %s ORDER BY %s", TABLE_NAME, KEY_FIELD)
+            ).executeQuery();
+
+            // Ensure that user0 record was not changed
+            resultSet.next();
+            assertEquals("Assert first row key is user0", resultSet.getString(KEY_FIELD), "user0");
+            for (int i = 0; i < 3; i++) {
+                assertEquals("Assert first row fields contain preupdateString", resultSet.getString(FIELD_PREFIX + i), preupdateString);
+            }
+
+            // Check that all the columns have expected values for user1 record
+            resultSet.next();
+            assertEquals(resultSet.getString(KEY_FIELD), "user1");
+            for (int i = 0; i < 3; i++) {
+                // TODO: This will fail until the fix is made to insert and update fields in the correct order.
+                // TODO: Uncomment this assertEquals when the fix is made.
+                //assertEquals(resultSet.getString(FIELD_PREFIX + i), updateMap.get(FIELD_PREFIX + i));
+            }
+
+            // Ensure that user2 record was not changed
+            resultSet.next();
+            assertEquals("Assert third row key is user2", resultSet.getString(KEY_FIELD), "user2");
+            for (int i = 0; i < 3; i++) {
+                assertEquals("Assert third row fields contain preupdateString", resultSet.getString(FIELD_PREFIX + i), preupdateString);
+            }
+            resultSet.close();
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Failed updateTest");
+        }
+
+
         assertTrue(true);
     }
 
     @Test
     public void readTest() {
-        assertTrue(true);
+        String insertKey = "user0";
+        HashMap<String, ByteIterator> insertMap = insertRow(insertKey);
+        HashSet<String> readFields = new HashSet<String>();
+        HashMap<String, ByteIterator> readResultMap = new HashMap<String, ByteIterator>();
+
+        // Test reading a single field
+        readFields.add("FIELD0");
+        jdbcDBClient.read(TABLE_NAME, insertKey, readFields, readResultMap);
+        assertEquals("Assert that result has correct number of fields", readFields.size(), readResultMap.size());
+        for (String field: readFields) {
+            // TODO: This will fail until the fix is made to insert and update fields in the correct order.
+            // TODO: Uncomment this assertEquals when the fix is made.
+            //assertEquals("Assert " + field + " was read correctly", insertMap.get(field), readResultMap.get(field));
+        }
+
+        readResultMap = new HashMap<String, ByteIterator>();
+
+        // Test reading all fields
+        readFields.add("FIELD1");
+        readFields.add("FIELD2");
+        jdbcDBClient.read(TABLE_NAME, insertKey, readFields, readResultMap);
+        assertEquals("Assert that result has correct number of fields", readFields.size(), readResultMap.size());
+        for (String field: readFields) {
+            // TODO: This will fail until the fix is made to insert and update fields in the correct order.
+            // TODO: Uncomment this assertEquals when the fix is made.
+            //assertEquals("Assert " + field + " was read correctly", insertMap.get(field), readResultMap.get(field));
+        }
     }
 
     @Test
     public void deleteTest() {
-        assertTrue(true);
+        try {
+            String insertBeforeKey = "user0";
+            HashMap<String, ByteIterator> insertBeforeMap = insertRow(insertBeforeKey);
+            String deleteKey = "user1";
+            insertRow(deleteKey);
+            String insertAfterKey = "user2";
+            HashMap<String, ByteIterator> insertAfterMap = insertRow(insertAfterKey);
+
+            jdbcDBClient.delete(TABLE_NAME, deleteKey);
+
+            ResultSet resultSet = jdbcConnection.prepareStatement(
+                String.format("SELECT * FROM %s", TABLE_NAME)
+            ).executeQuery();
+
+            int totalRows = 0;
+            while (resultSet.next()) {
+                assertNotEquals("Assert this is not the deleted row key", deleteKey, resultSet.getString(KEY_FIELD));
+                totalRows++;
+            }
+            // Check we do not have a result Row
+            assertEquals("Assert we ended with the correct number of rows", totalRows, 2);
+
+            resultSet.close();
+        } catch (SQLException e) {
+            e.printStackTrace();
+            fail("Failed deleteTest");
+        }
     }
 
     @Test
-    public void scanTest() {
-        assertTrue(true);
+    public void scanTest() throws SQLException {
+        HashMap<String, HashMap<String, ByteIterator>> keyMap = new HashMap<String, HashMap<String, ByteIterator>>();
+        for (int i = 0; i < 5; i++) {
+            String insertKey = KEY_PREFIX + i;
+            keyMap.put(insertKey, insertRow(insertKey));
+        }
+        HashSet<String> fieldSet = new HashSet<String>();
+        fieldSet.add("FIELD0");
+        fieldSet.add("FIELD1");
+        int startIndex = 1;
+        int resultRows = 3;
+
+        Vector<HashMap<String, ByteIterator>> resultVector = new Vector<HashMap<String, ByteIterator>>();
+        jdbcDBClient.scan(TABLE_NAME, KEY_PREFIX + startIndex, resultRows, fieldSet, resultVector);
+
+        // Check the resultVector is the correct size
+        assertEquals("Assert the correct number of results rows were returned", resultRows, resultVector.size());
+        // Check each vector row to make sure we have the correct fields
+        int testIndex = startIndex;
+        for (HashMap<String, ByteIterator> result: resultVector) {
+            assertEquals("Assert that this row has the correct number of fields", fieldSet.size(), result.size());
+            for (String field: fieldSet) {
+                // TODO: This will fail until the fix is made to insert and update fields in the correct order.
+                // TODO: Uncomment this assertEquals when the fix is made.
+                //assertEquals("Assert this field is correct in this row", keyMap.get(KEY_PREFIX + testIndex).get(field), result.get(field));
+            }
+            testIndex++;
+        }
     }
 }