Commit 36cd0212 authored by akwizgran's avatar akwizgran

Unit tests and fixes for DatabaseComponent(Impl).

parent b2ee1b53
...@@ -51,6 +51,9 @@ public interface DatabaseComponent { ...@@ -51,6 +51,9 @@ public interface DatabaseComponent {
*/ */
ContactId addContact() throws DbException; ContactId addContact() throws DbException;
/** Adds a contact transport to the database. */
void addContactTransport(ContactTransport ct) throws DbException;
/** Adds a locally generated group message to the database. */ /** Adds a locally generated group message to the database. */
void addLocalGroupMessage(Message m) throws DbException; void addLocalGroupMessage(Message m) throws DbException;
...@@ -130,6 +133,9 @@ public interface DatabaseComponent { ...@@ -130,6 +133,9 @@ public interface DatabaseComponent {
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t) Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException; throws DbException;
/** Returns all temporary secrets. */
Collection<TemporarySecret> getSecrets() throws DbException;
/** Returns the set of groups to which the user subscribes. */ /** Returns the set of groups to which the user subscribes. */
Collection<Group> getSubscriptions() throws DbException; Collection<Group> getSubscriptions() throws DbException;
......
...@@ -61,7 +61,6 @@ import net.sf.briar.api.protocol.SubscriptionUpdate; ...@@ -61,7 +61,6 @@ import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.util.ByteUtils;
import com.google.inject.Inject; import com.google.inject.Inject;
...@@ -173,7 +172,6 @@ DatabaseCleaner.Callback { ...@@ -173,7 +172,6 @@ DatabaseCleaner.Callback {
public ContactId addContact() throws DbException { public ContactId addContact() throws DbException {
ContactId c; ContactId c;
Collection<byte[]> erase = new ArrayList<byte[]>();
contactLock.writeLock().lock(); contactLock.writeLock().lock();
try { try {
subscriptionLock.writeLock().lock(); subscriptionLock.writeLock().lock();
...@@ -201,8 +199,6 @@ DatabaseCleaner.Callback { ...@@ -201,8 +199,6 @@ DatabaseCleaner.Callback {
} }
} finally { } finally {
contactLock.writeLock().unlock(); contactLock.writeLock().unlock();
// Erase the secrets after committing or aborting the transaction
for(byte[] b : erase) ByteUtils.erase(b);
} }
// Call the listeners outside the lock // Call the listeners outside the lock
callListeners(new ContactAddedEvent(c)); callListeners(new ContactAddedEvent(c));
...@@ -214,6 +210,29 @@ DatabaseCleaner.Callback { ...@@ -214,6 +210,29 @@ DatabaseCleaner.Callback {
for(DatabaseListener d : listeners) d.eventOccurred(e); for(DatabaseListener d : listeners) d.eventOccurred(e);
} }
public void addContactTransport(ContactTransport ct) throws DbException {
contactLock.readLock().lock();
try {
windowLock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if(!db.containsContact(txn, ct.getContactId()))
throw new NoSuchContactException();
db.addContactTransport(txn, ct);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
windowLock.writeLock().unlock();
}
} finally {
contactLock.readLock().unlock();
}
}
public void addLocalGroupMessage(Message m) throws DbException { public void addLocalGroupMessage(Message m) throws DbException {
boolean added = false; boolean added = false;
contactLock.readLock().lock(); contactLock.readLock().lock();
...@@ -398,7 +417,7 @@ DatabaseCleaner.Callback { ...@@ -398,7 +417,7 @@ DatabaseCleaner.Callback {
windowLock.writeLock().unlock(); windowLock.writeLock().unlock();
} }
} finally { } finally {
contactLock.writeLock().unlock(); contactLock.readLock().unlock();
} }
} }
...@@ -862,6 +881,28 @@ DatabaseCleaner.Callback { ...@@ -862,6 +881,28 @@ DatabaseCleaner.Callback {
} }
} }
public Collection<TemporarySecret> getSecrets() throws DbException {
contactLock.readLock().lock();
try {
windowLock.readLock().lock();
try {
T txn = db.startTransaction();
try {
Collection<TemporarySecret> secrets = db.getSecrets(txn);
db.commitTransaction(txn);
return secrets;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
windowLock.readLock().unlock();
}
} finally {
contactLock.readLock().unlock();
}
}
public Collection<Group> getSubscriptions() throws DbException { public Collection<Group> getSubscriptions() throws DbException {
subscriptionLock.readLock().lock(); subscriptionLock.readLock().lock();
try { try {
...@@ -977,6 +1018,7 @@ DatabaseCleaner.Callback { ...@@ -977,6 +1018,7 @@ DatabaseCleaner.Callback {
db.commitTransaction(txn); db.commitTransaction(txn);
} catch(DbException e) { } catch(DbException e) {
db.abortTransaction(txn); db.abortTransaction(txn);
throw e;
} }
} finally { } finally {
windowLock.writeLock().unlock(); windowLock.writeLock().unlock();
...@@ -1274,6 +1316,7 @@ DatabaseCleaner.Callback { ...@@ -1274,6 +1316,7 @@ DatabaseCleaner.Callback {
db.commitTransaction(txn); db.commitTransaction(txn);
} catch(DbException e) { } catch(DbException e) {
db.abortTransaction(txn); db.abortTransaction(txn);
throw e;
} }
} finally { } finally {
windowLock.writeLock().unlock(); windowLock.writeLock().unlock();
......
...@@ -5,18 +5,18 @@ import java.util.Arrays; ...@@ -5,18 +5,18 @@ import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import java.util.Random;
import net.sf.briar.BriarTestCase; import net.sf.briar.BriarTestCase;
import net.sf.briar.TestUtils; import net.sf.briar.TestUtils;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.Rating; import net.sf.briar.api.Rating;
import net.sf.briar.api.TransportProperties; import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.db.ContactTransport;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.MessageHeader;
import net.sf.briar.api.db.NoSuchContactException; import net.sf.briar.api.db.NoSuchContactException;
import net.sf.briar.api.db.NoSuchContactTransportException;
import net.sf.briar.api.db.Status; import net.sf.briar.api.db.Status;
import net.sf.briar.api.db.TemporarySecret;
import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactAddedEvent;
import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent;
import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.DatabaseListener;
...@@ -61,8 +61,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -61,8 +61,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
private final Group group; private final Group group;
private final TransportId transportId; private final TransportId transportId;
private final Collection<Transport> transports; private final Collection<Transport> transports;
private final Map<ContactId, TransportProperties> remoteProperties; private final ContactTransport contactTransport;
private final byte[] inSecret, outSecret; private final TemporarySecret temporarySecret;
public DatabaseComponentTest() { public DatabaseComponentTest() {
super(); super();
...@@ -84,14 +84,12 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -84,14 +84,12 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
transportId = new TransportId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId());
TransportProperties properties = new TransportProperties( TransportProperties properties = new TransportProperties(
Collections.singletonMap("foo", "bar")); Collections.singletonMap("foo", "bar"));
remoteProperties = Collections.singletonMap(contactId, properties);
Transport transport = new Transport(transportId, properties); Transport transport = new Transport(transportId, properties);
transports = Collections.singletonList(transport); transports = Collections.singletonList(transport);
Random r = new Random(); contactTransport = new ContactTransport(contactId, transportId, 123L,
inSecret = new byte[32]; 234L, 345L, true);
r.nextBytes(inSecret); temporarySecret = new TemporarySecret(contactId, transportId, 0L,
outSecret = new byte[32]; new byte[32], 0L, 0L, new byte[4]);
r.nextBytes(outSecret);
} }
protected abstract <T> DatabaseComponent createDatabaseComponent( protected abstract <T> DatabaseComponent createDatabaseComponent(
...@@ -101,7 +99,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -101,7 +99,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void testSimpleCalls() throws Exception { public void testSimpleCalls() throws Exception {
// FIXME: Test new methods
final int shutdownHandle = 12345; final int shutdownHandle = 12345;
Mockery context = new Mockery(); Mockery context = new Mockery();
final Database<Object> database = context.mock(Database.class); final Database<Object> database = context.mock(Database.class);
...@@ -128,7 +125,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -128,7 +125,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
oneOf(database).setRating(txn, authorId, Rating.GOOD); oneOf(database).setRating(txn, authorId, Rating.GOOD);
will(returnValue(Rating.UNRATED)); will(returnValue(Rating.UNRATED));
oneOf(database).getMessagesByAuthor(txn, authorId); oneOf(database).getMessagesByAuthor(txn, authorId);
will(returnValue(Collections.<MessageId>emptyList())); will(returnValue(Collections.emptyList()));
oneOf(listener).eventOccurred(with(any(RatingChangedEvent.class))); oneOf(listener).eventOccurred(with(any(RatingChangedEvent.class)));
// setRating(authorId, Rating.GOOD) again // setRating(authorId, Rating.GOOD) again
oneOf(database).setRating(txn, authorId, Rating.GOOD); oneOf(database).setRating(txn, authorId, Rating.GOOD);
...@@ -142,7 +139,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -142,7 +139,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(Collections.singletonList(contactId))); will(returnValue(Collections.singletonList(contactId)));
// getTransportProperties(transportId) // getTransportProperties(transportId)
oneOf(database).getRemoteProperties(txn, transportId); oneOf(database).getRemoteProperties(txn, transportId);
will(returnValue(remoteProperties)); will(returnValue(Collections.emptyMap()));
// subscribe(group) // subscribe(group)
oneOf(group).getId(); oneOf(group).getId();
will(returnValue(groupId)); will(returnValue(groupId));
...@@ -156,7 +153,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -156,7 +153,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(true)); will(returnValue(true));
// getMessageHeaders(groupId) // getMessageHeaders(groupId)
oneOf(database).getMessageHeaders(txn, groupId); oneOf(database).getMessageHeaders(txn, groupId);
will(returnValue(Collections.<MessageHeader>emptyList())); will(returnValue(Collections.emptyList()));
// getSubscriptions() // getSubscriptions()
oneOf(database).getSubscriptions(txn); oneOf(database).getSubscriptions(txn);
will(returnValue(Collections.singletonList(groupId))); will(returnValue(Collections.singletonList(groupId)));
...@@ -164,7 +161,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -164,7 +161,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
oneOf(database).containsSubscription(txn, groupId); oneOf(database).containsSubscription(txn, groupId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getVisibility(txn, groupId); oneOf(database).getVisibility(txn, groupId);
will(returnValue(Collections.<ContactId>emptyList())); will(returnValue(Collections.emptyList()));
oneOf(database).removeSubscription(txn, groupId); oneOf(database).removeSubscription(txn, groupId);
// unsubscribe(groupId) again // unsubscribe(groupId) again
oneOf(database).containsSubscription(txn, groupId); oneOf(database).containsSubscription(txn, groupId);
...@@ -189,7 +186,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -189,7 +186,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
db.setRating(authorId, Rating.GOOD); // Second time - not called db.setRating(authorId, Rating.GOOD); // Second time - not called
assertEquals(contactId, db.addContact()); assertEquals(contactId, db.addContact());
assertEquals(Collections.singletonList(contactId), db.getContacts()); assertEquals(Collections.singletonList(contactId), db.getContacts());
assertEquals(remoteProperties, db.getRemoteProperties(transportId)); assertEquals(Collections.emptyMap(),
db.getRemoteProperties(transportId));
db.subscribe(group); // First time - listeners called db.subscribe(group); // First time - listeners called
db.subscribe(group); // Second time - not called db.subscribe(group); // Second time - not called
assertEquals(Collections.emptyList(), db.getMessageHeaders(groupId)); assertEquals(Collections.emptyList(), db.getMessageHeaders(groupId));
...@@ -495,7 +493,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -495,7 +493,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
@Test @Test
public void testVariousMethodsThrowExceptionIfContactIsMissing() public void testVariousMethodsThrowExceptionIfContactIsMissing()
throws Exception { throws Exception {
// FIXME: Test new methods
Mockery context = new Mockery(); Mockery context = new Mockery();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class); final Database<Object> database = context.mock(Database.class);
...@@ -510,16 +507,21 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -510,16 +507,21 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
final TransportUpdate transportUpdate = final TransportUpdate transportUpdate =
context.mock(TransportUpdate.class); context.mock(TransportUpdate.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is still in the DB (which it's not) // Check whether the contact is in the DB (which it's not)
exactly(15).of(database).startTransaction(); exactly(16).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(15).of(database).containsContact(txn, contactId); exactly(16).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(15).of(database).abortTransaction(txn); exactly(16).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, cleaner, DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown, packetFactory); shutdown, packetFactory);
try {
db.addContactTransport(contactTransport);
fail();
} catch(NoSuchContactException expected) {}
try { try {
db.addLocalPrivateMessage(privateMessage, contactId); db.addLocalPrivateMessage(privateMessage, contactId);
fail(); fail();
...@@ -599,6 +601,40 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -599,6 +601,40 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@Test
public void testVariousMethodsThrowExceptionIfContactTransportIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final PacketFactory packetFactory = context.mock(PacketFactory.class);
context.checking(new Expectations() {{
// Check whether the contact transport is in the DB (which it's not)
exactly(2).of(database).startTransaction();
will(returnValue(txn));
exactly(2).of(database).containsContactTransport(txn, contactId,
transportId);
will(returnValue(false));
exactly(2).of(database).abortTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown, packetFactory);
try {
db.incrementConnectionCounter(contactId, transportId, 0L);
fail();
} catch(NoSuchContactTransportException expected) {}
try {
db.setConnectionWindow(contactId, transportId, 0L, 0L, new byte[4]);
fail();
} catch(NoSuchContactTransportException expected) {}
context.assertIsSatisfied();
}
@Test @Test
public void testGenerateAck() throws Exception { public void testGenerateAck() throws Exception {
final BatchId batchId1 = new BatchId(TestUtils.getRandomId()); final BatchId batchId1 = new BatchId(TestUtils.getRandomId());
...@@ -779,7 +815,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -779,7 +815,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
// Get the visible holes and subscriptions // Get the visible holes and subscriptions
oneOf(database).getVisibleHoles(with(txn), with(contactId), oneOf(database).getVisibleHoles(with(txn), with(contactId),
with(any(long.class))); with(any(long.class)));
will(returnValue(Collections.<GroupId, GroupId>emptyMap())); will(returnValue(Collections.emptyMap()));
oneOf(database).getVisibleSubscriptions(with(txn), with(contactId), oneOf(database).getVisibleSubscriptions(with(txn), with(contactId),
with(any(long.class))); with(any(long.class)));
will(returnValue(Collections.singletonMap(group, 0L))); will(returnValue(Collections.singletonMap(group, 0L)));
...@@ -1533,4 +1569,39 @@ public abstract class DatabaseComponentTest extends BriarTestCase { ...@@ -1533,4 +1569,39 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@Test
public void testTemporarySecrets() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final PacketFactory packetFactory = context.mock(PacketFactory.class);
context.checking(new Expectations() {{
// addSecrets()
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContactTransport(txn, contactId,
transportId);
will(returnValue(true));
oneOf(database).addSecrets(txn,
Collections.singletonList(temporarySecret));
oneOf(database).commitTransaction(txn);
// getSecrets()
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).getSecrets(txn);
will(returnValue(Collections.singletonList(temporarySecret)));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown, packetFactory);
db.addSecrets(Collections.singletonList(temporarySecret));
assertEquals(Collections.singletonList(temporarySecret),
db.getSecrets());
context.assertIsSatisfied();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment