mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 04:18:53 +01:00
351 lines
10 KiB
Java
351 lines
10 KiB
Java
package org.briarproject.db;
|
|
|
|
import org.briarproject.BriarTestCase;
|
|
import org.briarproject.TestUtils;
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
|
|
import java.io.File;
|
|
import java.sql.Connection;
|
|
import java.sql.DriverManager;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
|
|
import static java.sql.Types.BINARY;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertFalse;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertNull;
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
public class BasicH2Test extends BriarTestCase {
|
|
|
|
private static final String CREATE_TABLE =
|
|
"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");
|
|
private final String url = "jdbc:h2:" + db.getAbsolutePath();
|
|
|
|
private Connection connection = null;
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
testDir.mkdirs();
|
|
Class.forName("org.h2.Driver");
|
|
connection = DriverManager.getConnection(url);
|
|
}
|
|
|
|
@Test
|
|
public void testInsertUpdateAndDelete() throws Exception {
|
|
// Create the table
|
|
createTable(connection);
|
|
// Generate an ID and two names
|
|
byte[] id = new byte[32];
|
|
new Random().nextBytes(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
|
|
public void testSortOrder() throws Exception {
|
|
byte[] first = new byte[] {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
byte[] second = new byte[] {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 127
|
|
};
|
|
byte[] third = new byte[] {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, (byte) 255
|
|
};
|
|
// Create the table
|
|
createTable(connection);
|
|
// Insert the rows
|
|
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));
|
|
assertEquals("second", getPredecessor(third));
|
|
assertNull(getPredecessor(null));
|
|
// Check the ordering of ORDER BY: nulls come first
|
|
List<String> names = getNames();
|
|
assertEquals(4, names.size());
|
|
assertEquals("null", names.get(0));
|
|
assertEquals("first", names.get(1));
|
|
assertEquals("second", names.get(2));
|
|
assertEquals("third", names.get(3));
|
|
}
|
|
|
|
private void createTable(Connection connection) throws SQLException {
|
|
try {
|
|
Statement s = connection.createStatement();
|
|
s.executeUpdate(CREATE_TABLE);
|
|
s.close();
|
|
} catch (SQLException e) {
|
|
connection.close();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private void insertRow(byte[] id, String name) throws SQLException {
|
|
String sql = "INSERT INTO foo (uniqueId, name) VALUES (?, ?)";
|
|
try {
|
|
PreparedStatement ps = connection.prepareStatement(sql);
|
|
if (id == null) ps.setNull(1, BINARY);
|
|
else ps.setBytes(1, id);
|
|
ps.setString(2, name);
|
|
int affected = ps.executeUpdate();
|
|
assertEquals(1, affected);
|
|
ps.close();
|
|
} catch (SQLException e) {
|
|
connection.close();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private boolean rowExists(byte[] id) throws SQLException {
|
|
assertNotNull(id);
|
|
String sql = "SELECT NULL FROM foo WHERE uniqueID = ?";
|
|
try {
|
|
PreparedStatement ps = connection.prepareStatement(sql);
|
|
ps.setBytes(1, id);
|
|
ResultSet rs = ps.executeQuery();
|
|
boolean found = rs.next();
|
|
assertFalse(rs.next());
|
|
rs.close();
|
|
ps.close();
|
|
return found;
|
|
} catch (SQLException e) {
|
|
connection.close();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
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);
|
|
ResultSet rs = ps.executeQuery();
|
|
assertTrue(rs.next());
|
|
String name = rs.getString(1);
|
|
assertFalse(rs.next());
|
|
rs.close();
|
|
ps.close();
|
|
return name;
|
|
} catch (SQLException e) {
|
|
connection.close();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private void updateRow(byte[] id, String name) throws SQLException {
|
|
String sql = "UPDATE foo SET name = ? WHERE uniqueId = ?";
|
|
try {
|
|
PreparedStatement ps = connection.prepareStatement(sql);
|
|
if (id == null) ps.setNull(2, BINARY);
|
|
else ps.setBytes(2, id);
|
|
ps.setString(1, name);
|
|
assertEquals(1, ps.executeUpdate());
|
|
ps.close();
|
|
} catch (SQLException e) {
|
|
connection.close();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
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.setString(2, 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 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();
|
|
TestUtils.deleteTestDirectory(testDir);
|
|
}
|
|
}
|