From 5e0d580d00fca2b3fc223e28b908da5e73f651e8 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Tue, 5 Jul 2011 20:57:28 +0100 Subject: [PATCH] More unit tests for DatabaseComponent. --- .../db/ReadWriteLockDatabaseComponent.java | 5 +- .../db/SynchronizedDatabaseComponent.java | 5 +- .../sf/briar/db/DatabaseComponentTest.java | 174 ++++++++++++++++-- 3 files changed, 161 insertions(+), 23 deletions(-) diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index 921e7fb026..a61cfaa6cb 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -236,10 +236,11 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Batch batch = fillBatch(c, capacity); if(batch == null) break; // No more messages to send b.addBatch(batch); - capacity -= batch.getSize(); + long size = batch.getSize(); + capacity -= size; // If the batch is less than half full, stop trying - there may be // more messages trickling in but we can't wait forever - if(batch.getSize() * 2 < Batch.CAPACITY) break; + if(size * 2 < Batch.CAPACITY) break; } b.seal(); if(LOG.isLoggable(Level.FINE)) diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index 959b3be61d..bfe67f0a59 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -176,10 +176,11 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Batch batch = fillBatch(c, capacity); if(batch == null) break; // No more messages to send b.addBatch(batch); - capacity -= batch.getSize(); + long size = batch.getSize(); + capacity -= size; // If the batch is less than half full, stop trying - there may be // more messages trickling in but we can't wait forever - if(batch.getSize() * 2 < Batch.CAPACITY) break; + if(size * 2 < Batch.CAPACITY) break; } b.seal(); if(LOG.isLoggable(Level.FINE)) diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index ea3b011bf5..a432ab88e3 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -13,7 +13,9 @@ import net.sf.briar.api.db.Rating; import net.sf.briar.api.db.Status; import net.sf.briar.api.protocol.AuthorId; import net.sf.briar.api.protocol.Batch; +import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Bundle; +import net.sf.briar.api.protocol.BundleId; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; @@ -27,8 +29,12 @@ import com.google.inject.Provider; public abstract class DatabaseComponentTest extends TestCase { + private static final int ONE_MEGABYTE = 1024 * 1024; + protected final Object txn = new Object(); protected final AuthorId authorId; + protected final BatchId batchId; + protected final BundleId bundleId; protected final ContactId contactId; protected final GroupId groupId; protected final MessageId messageId, parentId; @@ -40,6 +46,8 @@ public abstract class DatabaseComponentTest extends TestCase { public DatabaseComponentTest() { super(); authorId = new AuthorId(TestUtils.getRandomId()); + batchId = new BatchId(TestUtils.getRandomId()); + bundleId = new BundleId(TestUtils.getRandomId()); contactId = new ContactId(123); groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); @@ -65,40 +73,27 @@ public abstract class DatabaseComponentTest extends TestCase { @SuppressWarnings("unchecked") final Provider<Batch> batchProvider = context.mock(Provider.class); context.checking(new Expectations() {{ + allowing(database).startTransaction(); + will(returnValue(txn)); + allowing(database).commitTransaction(txn); + // open(false) oneOf(database).open(false); oneOf(cleaner).startCleaning(); // getRating(authorId) - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).getRating(txn, authorId); will(returnValue(Rating.UNRATED)); - oneOf(database).commitTransaction(txn); // addContact(contactId) - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).addContact(txn, contactId); - oneOf(database).commitTransaction(txn); // subscribe(groupId) - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).addSubscription(txn, groupId); - oneOf(database).commitTransaction(txn); // getSubscriptions() - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).getSubscriptions(txn); will(returnValue(subs)); - oneOf(database).commitTransaction(txn); // unsubscribe(groupId) - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).removeSubscription(txn, groupId); - oneOf(database).commitTransaction(txn); // removeContact(contactId) - oneOf(database).startTransaction(); - will(returnValue(txn)); oneOf(database).removeContact(txn, contactId); - oneOf(database).commitTransaction(txn); + // close() oneOf(cleaner).stopCleaning(); oneOf(database).close(); }}); @@ -128,7 +123,7 @@ public abstract class DatabaseComponentTest extends TestCase { final Provider<Batch> batchProvider = context.mock(Provider.class); context.checking(new Expectations() {{ // setRating(Rating.GOOD) - oneOf(database).startTransaction(); + allowing(database).startTransaction(); will(returnValue(txn)); oneOf(database).setRating(txn, authorId, Rating.GOOD); // The sendability of the author's messages should be incremented @@ -453,6 +448,7 @@ public abstract class DatabaseComponentTest extends TestCase { final Provider<Batch> batchProvider = context.mock(Provider.class); final Bundle bundle = context.mock(Bundle.class); context.checking(new Expectations() {{ + // Check that the contact is still in the DB oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsContact(txn, contactId); @@ -469,4 +465,144 @@ public abstract class DatabaseComponentTest extends TestCase { context.assertIsSatisfied(); } + + @Test + public void testGenerateBundle() throws DbException { + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database<Object> database = context.mock(Database.class); + final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); + @SuppressWarnings("unchecked") + final Provider<Batch> batchProvider = context.mock(Provider.class); + final Bundle bundle = context.mock(Bundle.class); + final Batch batch = context.mock(Batch.class); + context.checking(new Expectations() {{ + allowing(database).startTransaction(); + will(returnValue(txn)); + allowing(database).commitTransaction(txn); + allowing(database).containsContact(txn, contactId); + will(returnValue(true)); + // Add acks to the bundle + oneOf(database).removeBatchesToAck(txn, contactId); + will(returnValue(Collections.singleton(batchId))); + oneOf(bundle).addAck(batchId); + // Add subscriptions to the bundle + oneOf(database).getSubscriptions(txn); + will(returnValue(Collections.singleton(groupId))); + oneOf(bundle).addSubscription(groupId); + // Prepare to add batches to the bundle + oneOf(bundle).getCapacity(); + will(returnValue((long) ONE_MEGABYTE)); + // Add messages to the batch + oneOf(database).getSendableMessages(txn, contactId, ONE_MEGABYTE); + will(returnValue(Collections.singleton(messageId))); + oneOf(batchProvider).get(); + will(returnValue(batch)); + oneOf(database).getMessage(txn, messageId); + will(returnValue(message)); + oneOf(batch).addMessage(message); + oneOf(batch).seal(); + // Record the batch as outstanding + oneOf(batch).getId(); + will(returnValue(batchId)); + oneOf(database).addOutstandingBatch(txn, contactId, batchId, + Collections.singleton(messageId)); + // Add the batch to the bundle + oneOf(bundle).addBatch(batch); + // Check whether to add another batch + oneOf(batch).getSize(); + will(returnValue((long) message.getSize())); + // Nope + oneOf(bundle).seal(); + }}); + DatabaseComponent db = createDatabaseComponent(database, cleaner, + batchProvider); + + db.generateBundle(contactId, bundle); + + context.assertIsSatisfied(); + } + + @Test + public void testReceiveBundleThrowsExceptionIfContactIsMissing() + throws DbException { + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database<Object> database = context.mock(Database.class); + final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); + @SuppressWarnings("unchecked") + final Provider<Batch> batchProvider = context.mock(Provider.class); + final Bundle bundle = context.mock(Bundle.class); + context.checking(new Expectations() {{ + // Check that the contact is still in the DB + oneOf(database).startTransaction(); + will(returnValue(txn)); + oneOf(database).containsContact(txn, contactId); + will(returnValue(false)); + oneOf(database).commitTransaction(txn); + }}); + DatabaseComponent db = createDatabaseComponent(database, cleaner, + batchProvider); + + try { + db.receiveBundle(contactId, bundle); + assertTrue(false); + } catch(NoSuchContactException expected) {} + + context.assertIsSatisfied(); + } + + @Test + public void testReceivedBundle() throws DbException { + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database<Object> database = context.mock(Database.class); + final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); + @SuppressWarnings("unchecked") + final Provider<Batch> batchProvider = context.mock(Provider.class); + final Bundle bundle = context.mock(Bundle.class); + final Batch batch = context.mock(Batch.class); + context.checking(new Expectations() {{ + allowing(database).startTransaction(); + will(returnValue(txn)); + allowing(database).commitTransaction(txn); + allowing(database).containsContact(txn, contactId); + will(returnValue(true)); + // Acks + oneOf(bundle).getAcks(); + will(returnValue(Collections.singleton(batchId))); + oneOf(database).removeAckedBatch(txn, contactId, batchId); + // Subscriptions + oneOf(database).clearSubscriptions(txn, contactId); + oneOf(bundle).getSubscriptions(); + will(returnValue(Collections.singleton(groupId))); + oneOf(database).addSubscription(txn, contactId, groupId); + // Batches + oneOf(bundle).getBatches(); + will(returnValue(Collections.singleton(batch))); + oneOf(batch).getMessages(); + will(returnValue(Collections.singleton(message))); + oneOf(database).containsSubscription(txn, groupId); + will(returnValue(true)); + oneOf(database).addMessage(txn, message); + will(returnValue(false)); // Duplicate message + oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); + // Batch to ack + oneOf(batch).getId(); + will(returnValue(batchId)); + oneOf(database).addBatchToAck(txn, contactId, batchId); + // Lost batches + oneOf(bundle).getId(); + will(returnValue(bundleId)); + oneOf(database).addReceivedBundle(txn, contactId, bundleId); + will(returnValue(Collections.singleton(batchId))); + oneOf(database).removeLostBatch(txn, contactId, batchId); + }}); + DatabaseComponent db = createDatabaseComponent(database, cleaner, + batchProvider); + + db.receiveBundle(contactId, bundle); + + context.assertIsSatisfied(); + } } -- GitLab