From e1842e11c5680605391eb92538122abc5490c905 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Fri, 3 May 2013 12:18:06 +0100 Subject: [PATCH] Unit tests for batched SQL UPDATE and DELETE operations. --- briar-tests/src/net/sf/briar/TestUtils.java | 6 +- .../src/net/sf/briar/db/BasicH2Test.java | 226 ++++++++++++++---- 2 files changed, 176 insertions(+), 56 deletions(-) diff --git a/briar-tests/src/net/sf/briar/TestUtils.java b/briar-tests/src/net/sf/briar/TestUtils.java index 16e05461b1..358bc0f19e 100644 --- a/briar-tests/src/net/sf/briar/TestUtils.java +++ b/briar-tests/src/net/sf/briar/TestUtils.java @@ -76,10 +76,8 @@ public class TestUtils { public static String createRandomString(int length) throws Exception { StringBuilder s = new StringBuilder(length); - for(int i = 0; i < length; i++) { - int letter = (int) (Math.random() * 26); - s.append((char) ('a' + letter)); - } + for(int i = 0; i < length; i++) + s.append((char) ('a' + random.nextInt(26))); return s.toString(); } } diff --git a/briar-tests/src/net/sf/briar/db/BasicH2Test.java b/briar-tests/src/net/sf/briar/db/BasicH2Test.java index e6f398a8fc..eaf4696504 100644 --- a/briar-tests/src/net/sf/briar/db/BasicH2Test.java +++ b/briar-tests/src/net/sf/briar/db/BasicH2Test.java @@ -23,9 +23,8 @@ import org.junit.Test; public class BasicH2Test extends BriarTestCase { private static final String CREATE_TABLE = - "CREATE TABLE foo" - + " (uniqueId BINARY(32)," - + " name VARCHAR NOT NULL)"; + "CREATE TABLE foo (uniqueId BINARY(32), name VARCHAR NOT NULL)"; + private static final int BATCH_SIZE = 100; private final File testDir = TestUtils.getTestDirectory(); private final File db = new File(testDir, "db"); @@ -41,17 +40,65 @@ public class BasicH2Test extends BriarTestCase { } @Test - public void testCreateTableAddRowAndRetrieve() throws Exception { + public void testInsertUpdateAndDelete() throws Exception { // Create the table createTable(connection); - // Generate an ID and a name + // Generate an ID and two names byte[] id = new byte[32]; new Random().nextBytes(id); - String name = TestUtils.createRandomString(50); - // Insert the ID and name into the table - addRow(id, name); - // Check that the name can be retrieved using the ID - assertEquals(name, getName(id)); + String oldName = TestUtils.createRandomString(50); + String newName = TestUtils.createRandomString(50); + // Insert the ID and old name into the table + insertRow(id, oldName); + // Check that the old name can be retrieved using the ID + assertTrue(rowExists(id)); + assertEquals(oldName, getName(id)); + // Update the name + updateRow(id, newName); + // Check that the new name can be retrieved using the ID + assertTrue(rowExists(id)); + assertEquals(newName, getName(id)); + // Delete the row from the table + assertTrue(deleteRow(id)); + // Check that the row no longer exists + assertFalse(rowExists(id)); + // Deleting the row again should have no effect + assertFalse(deleteRow(id)); + } + + @Test + public void testBatchInsertUpdateAndDelete() throws Exception { + // Create the table + createTable(connection); + // Generate some IDs and two sets of names + byte[][] ids = new byte[BATCH_SIZE][32]; + String[] oldNames = new String[BATCH_SIZE]; + String[] newNames = new String[BATCH_SIZE]; + Random random = new Random(); + for(int i = 0; i < BATCH_SIZE; i++) { + random.nextBytes(ids[i]); + oldNames[i] = TestUtils.createRandomString(50); + newNames[i] = TestUtils.createRandomString(50); + } + // Insert the IDs and old names into the table as a batch + insertBatch(ids, oldNames); + // Update the names as a batch + updateBatch(ids, newNames); + // Check that the new names can be retrieved using the IDs + for(int i = 0; i < BATCH_SIZE; i++) { + assertTrue(rowExists(ids[i])); + assertEquals(newNames[i], getName(ids[i])); + } + // Delete the rows as a batch + boolean[] deleted = deleteBatch(ids); + // Check that the rows no longer exist + for(int i = 0; i < BATCH_SIZE; i++) { + assertTrue(deleted[i]); + assertFalse(rowExists(ids[i])); + } + // Deleting the rows again should have no effect + deleted = deleteBatch(ids); + for(int i = 0; i < BATCH_SIZE; i++) assertFalse(deleted[i]); } @Test @@ -77,10 +124,10 @@ public class BasicH2Test extends BriarTestCase { // Create the table createTable(connection); // Insert the rows - addRow(first, "first"); - addRow(second, "second"); - addRow(third, "third"); - addRow(null, "null"); + insertRow(first, "first"); + insertRow(second, "second"); + insertRow(third, "third"); + insertRow(null, "null"); // Check the ordering of the < operator: the null ID is not comparable assertNull(getPredecessor(first)); assertEquals("first", getPredecessor(second)); @@ -95,24 +142,6 @@ public class BasicH2Test extends BriarTestCase { assertEquals("third", names.get(3)); } - @Test - public void testCreateTableAddBatchAndRetrieve() throws Exception { - // Create the table - createTable(connection); - // Generate some IDs and names - byte[][] ids = new byte[10][32]; - String[] names = new String[10]; - Random random = new Random(); - for(int i = 0; i < 10; i++) { - random.nextBytes(ids[i]); - names[i] = TestUtils.createRandomString(50); - } - // Insert the IDs and names into the table as a batch - addBatch(ids, names); - // Check that the names can be retrieved using the IDs - for(int i = 0; i < 10; i++) assertEquals(names[i], getName(ids[i])); - } - private void createTable(Connection connection) throws SQLException { try { Statement s = connection.createStatement(); @@ -124,7 +153,7 @@ public class BasicH2Test extends BriarTestCase { } } - private void addRow(byte[] id, String name) throws SQLException { + private void insertRow(byte[] id, String name) throws SQLException { String sql = "INSERT INTO foo (uniqueId, name) VALUES (?, ?)"; try { PreparedStatement ps = connection.prepareStatement(sql); @@ -140,33 +169,33 @@ public class BasicH2Test extends BriarTestCase { } } - private String getName(byte[] id) throws SQLException { - String sql = "SELECT name FROM foo WHERE uniqueID = ?"; + private boolean rowExists(byte[] id) throws SQLException { + assertNotNull(id); + String sql = "SELECT NULL FROM foo WHERE uniqueID = ?"; try { PreparedStatement ps = connection.prepareStatement(sql); - if(id != null) ps.setBytes(1, id); + ps.setBytes(1, id); ResultSet rs = ps.executeQuery(); - assertTrue(rs.next()); - String name = rs.getString(1); + boolean found = rs.next(); assertFalse(rs.next()); rs.close(); ps.close(); - return name; + return found; } catch(SQLException e) { connection.close(); throw e; } } - private String getPredecessor(byte[] id) throws SQLException { - String sql = "SELECT name FROM foo WHERE uniqueId < ?" - + " ORDER BY uniqueId DESC LIMIT ?"; + private String getName(byte[] id) throws SQLException { + assertNotNull(id); + String sql = "SELECT name FROM foo WHERE uniqueID = ?"; try { PreparedStatement ps = connection.prepareStatement(sql); ps.setBytes(1, id); - ps.setInt(2, 1); ResultSet rs = ps.executeQuery(); - String name = rs.next() ? rs.getString(1) : null; + assertTrue(rs.next()); + String name = rs.getString(1); assertFalse(rs.next()); rs.close(); ps.close(); @@ -177,23 +206,37 @@ public class BasicH2Test extends BriarTestCase { } } - private List<String> getNames() throws SQLException { - String sql = "SELECT name FROM foo ORDER BY uniqueId"; - List<String> names = new ArrayList<String>(); + private void updateRow(byte[] id, String name) throws SQLException { + String sql = "UPDATE foo SET name = ? WHERE uniqueId = ?"; try { PreparedStatement ps = connection.prepareStatement(sql); - ResultSet rs = ps.executeQuery(); - while(rs.next()) names.add(rs.getString(1)); - rs.close(); + if(id == null) ps.setNull(2, BINARY); + else ps.setBytes(2, id); + ps.setString(1, name); + assertEquals(1, ps.executeUpdate()); ps.close(); - return names; } catch(SQLException e) { connection.close(); throw e; } } - private void addBatch(byte[][] ids, String[] names) throws SQLException { + private boolean deleteRow(byte[] id) throws SQLException { + String sql = "DELETE FROM foo WHERE uniqueId = ?"; + try { + PreparedStatement ps = connection.prepareStatement(sql); + if(id == null) ps.setNull(1, BINARY); + else ps.setBytes(1, id); + int affected = ps.executeUpdate(); + ps.close(); + return affected == 1; + } catch(SQLException e) { + connection.close(); + throw e; + } + } + + private void insertBatch(byte[][] ids, String[] names) throws SQLException { assertEquals(ids.length, names.length); String sql = "INSERT INTO foo (uniqueId, name) VALUES (?, ?)"; try { @@ -216,6 +259,85 @@ public class BasicH2Test extends BriarTestCase { } } + private void updateBatch(byte[][] ids, String[] names) throws SQLException { + assertEquals(ids.length, names.length); + String sql = "UPDATE foo SET name = ? WHERE uniqueId = ?"; + try { + PreparedStatement ps = connection.prepareStatement(sql); + for(int i = 0; i < ids.length; i++) { + if(ids[i] == null) ps.setNull(2, BINARY); + else ps.setBytes(2, ids[i]); + ps.setString(1, names[i]); + ps.addBatch(); + } + int[] batchAffected = ps.executeBatch(); + assertEquals(ids.length, batchAffected.length); + for(int i = 0; i < batchAffected.length; i++) + assertEquals(1, batchAffected[i]); + ps.close(); + } catch(SQLException e) { + connection.close(); + throw e; + } + } + + private boolean[] deleteBatch(byte[][] ids) throws SQLException { + String sql = "DELETE FROM foo WHERE uniqueId = ?"; + try { + PreparedStatement ps = connection.prepareStatement(sql); + for(int i = 0; i < ids.length; i++) { + if(ids[i] == null) ps.setNull(1, BINARY); + else ps.setBytes(1, ids[i]); + ps.addBatch(); + } + int[] batchAffected = ps.executeBatch(); + assertEquals(ids.length, batchAffected.length); + boolean[] ret = new boolean[ids.length]; + for(int i = 0; i < batchAffected.length; i++) + ret[i] = batchAffected[i] == 1; + ps.close(); + return ret; + } catch(SQLException e) { + connection.close(); + throw e; + } + } + + private String getPredecessor(byte[] id) throws SQLException { + String sql = "SELECT name FROM foo WHERE uniqueId < ?" + + " ORDER BY uniqueId DESC LIMIT ?"; + try { + PreparedStatement ps = connection.prepareStatement(sql); + ps.setBytes(1, id); + ps.setInt(2, 1); + ResultSet rs = ps.executeQuery(); + String name = rs.next() ? rs.getString(1) : null; + assertFalse(rs.next()); + rs.close(); + ps.close(); + return name; + } catch(SQLException e) { + connection.close(); + throw e; + } + } + + private List<String> getNames() throws SQLException { + String sql = "SELECT name FROM foo ORDER BY uniqueId"; + List<String> names = new ArrayList<String>(); + try { + PreparedStatement ps = connection.prepareStatement(sql); + ResultSet rs = ps.executeQuery(); + while(rs.next()) names.add(rs.getString(1)); + rs.close(); + ps.close(); + return names; + } catch(SQLException e) { + connection.close(); + throw e; + } + } + @After public void tearDown() throws Exception { if(connection != null) connection.close(); -- GitLab