Added support for registering listeners with the database that are

called when new messages are available, and a new method
hasSendableMessages(ContactId) that listeners can call to see whether
it's worth trying to create a batch.
This commit is contained in:
akwizgran
2011-07-27 20:27:43 +01:00
parent e93fbe0b20
commit adee3e121c
10 changed files with 364 additions and 99 deletions

View File

@@ -12,6 +12,7 @@ import net.sf.briar.api.ContactId;
import net.sf.briar.api.Rating;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.MessageListener;
import net.sf.briar.api.db.NoSuchContactException;
import net.sf.briar.api.db.Status;
import net.sf.briar.api.protocol.Ack;
@@ -80,6 +81,7 @@ public abstract class DatabaseComponentTest extends TestCase {
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final Group group = context.mock(Group.class);
final MessageListener listener = context.mock(MessageListener.class);
context.checking(new Expectations() {{
allowing(database).startTransaction();
will(returnValue(txn));
@@ -117,6 +119,7 @@ public abstract class DatabaseComponentTest extends TestCase {
DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.open(false);
db.addListener(listener);
assertEquals(Rating.UNRATED, db.getRating(authorId));
assertEquals(contactId, db.addContact(transports));
assertEquals(Collections.singletonList(contactId), db.getContacts());
@@ -125,6 +128,7 @@ public abstract class DatabaseComponentTest extends TestCase {
assertEquals(Collections.singletonList(groupId), db.getSubscriptions());
db.unsubscribe(groupId);
db.removeContact(contactId);
db.removeListener(listener);
db.close();
context.assertIsSatisfied();
@@ -388,7 +392,7 @@ public abstract class DatabaseComponentTest extends TestCase {
}
@Test
public void testAddingASendableMessageTriggersBackwardInclusion()
public void testAddingSendableMessageTriggersBackwardInclusion()
throws DbException {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
@@ -446,11 +450,11 @@ public abstract class DatabaseComponentTest extends TestCase {
final Transports transportsUpdate = context.mock(Transports.class);
context.checking(new Expectations() {{
// Check whether the contact is still in the DB - which it's not
exactly(11).of(database).startTransaction();
exactly(12).of(database).startTransaction();
will(returnValue(txn));
exactly(11).of(database).containsContact(txn, contactId);
exactly(12).of(database).containsContact(txn, contactId);
will(returnValue(false));
exactly(11).of(database).commitTransaction(txn);
exactly(12).of(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner);
@@ -485,6 +489,11 @@ public abstract class DatabaseComponentTest extends TestCase {
assertTrue(false);
} catch(NoSuchContactException expected) {}
try {
db.hasSendableMessages(contactId);
assertTrue(false);
} catch(NoSuchContactException expected) {}
try {
db.receiveAck(contactId, ack);
assertTrue(false);
@@ -1019,4 +1028,65 @@ public abstract class DatabaseComponentTest extends TestCase {
context.assertIsSatisfied();
}
@Test
public void testAddingMessageCallsListeners() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final MessageListener listener = context.mock(MessageListener.class);
context.checking(new Expectations() {{
// addLocallyGeneratedMessage(message)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsSubscription(txn, groupId);
will(returnValue(true));
oneOf(database).addMessage(txn, message);
will(returnValue(true));
oneOf(database).getContacts(txn);
will(returnValue(Collections.singletonList(contactId)));
oneOf(database).setStatus(txn, contactId, messageId, Status.NEW);
oneOf(database).getRating(txn, authorId);
will(returnValue(Rating.UNRATED));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 0);
oneOf(database).commitTransaction(txn);
// The message was added, so the listener should be called
oneOf(listener).messagesAdded();
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.addListener(listener);
db.addLocallyGeneratedMessage(message);
context.assertIsSatisfied();
}
@Test
public void testDuplicateMessageDoesNotCallListeners() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final MessageListener listener = context.mock(MessageListener.class);
context.checking(new Expectations() {{
// addLocallyGeneratedMessage(message)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsSubscription(txn, groupId);
will(returnValue(true));
oneOf(database).addMessage(txn, message);
will(returnValue(false));
oneOf(database).commitTransaction(txn);
// The message was not added, so the listener should not be called
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.addListener(listener);
db.addLocallyGeneratedMessage(message);
context.assertIsSatisfied();
}
}

View File

@@ -210,12 +210,14 @@ public class H2DatabaseTest extends TestCase {
// The message should not be sendable
assertEquals(0, db.getSendability(txn, messageId));
assertFalse(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
// Changing the sendability to > 0 should make the message sendable
db.setSendability(txn, messageId, 1);
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());
@@ -223,6 +225,7 @@ public class H2DatabaseTest extends TestCase {
// Changing the sendability to 0 should make the message unsendable
db.setSendability(txn, messageId, 0);
assertFalse(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
@@ -244,12 +247,14 @@ public class H2DatabaseTest extends TestCase {
db.setSendability(txn, messageId, 1);
// The message has no status yet, so it should not be sendable
assertFalse(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
// Changing the status to Status.NEW should make the message sendable
db.setStatus(txn, contactId, messageId, Status.NEW);
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());
@@ -257,6 +262,7 @@ public class H2DatabaseTest extends TestCase {
// Changing the status to SENT should make the message unsendable
db.setStatus(txn, contactId, messageId, Status.SENT);
assertFalse(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
@@ -283,12 +289,14 @@ public class H2DatabaseTest extends TestCase {
db.setStatus(txn, contactId, messageId, Status.NEW);
// The contact is not subscribed, so the message should not be sendable
assertFalse(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
// The contact subscribing should make the message sendable
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());
@@ -296,6 +304,7 @@ public class H2DatabaseTest extends TestCase {
// The contact unsubscribing should make the message unsendable
db.setSubscriptions(txn, contactId, Collections.<Group>emptySet(), 2);
assertFalse(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
@@ -317,12 +326,14 @@ public class H2DatabaseTest extends TestCase {
db.setSendability(txn, messageId, 1);
db.setStatus(txn, contactId, messageId, Status.NEW);
// The message is too large to send
// The message is sendable, but too large to send
assertTrue(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, size - 1).iterator();
assertFalse(it.hasNext());
// The message is just the right size to send
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, size).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());
@@ -347,12 +358,14 @@ public class H2DatabaseTest extends TestCase {
// The subscription is not visible to the contact, so the message
// should not be sendable
assertFalse(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
// Making the subscription visible should make the message sendable
db.setVisibility(txn, groupId, Collections.singleton(contactId));
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());