mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-22 15:49:53 +01:00
Unit tests and bugfixes for DatabaseComponent. Merged code from various unique ID classes into a common superclass.
This commit is contained in:
@@ -3,26 +3,10 @@ package net.sf.briar.api.protocol;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Type-safe wrapper for a byte array that uniquely identifies an author. */
|
/** Type-safe wrapper for a byte array that uniquely identifies an author. */
|
||||||
public class AuthorId {
|
public class AuthorId extends UniqueId {
|
||||||
|
|
||||||
public static final int LENGTH = 32;
|
|
||||||
|
|
||||||
// FIXME: Replace this with an isSelf() method that compares an AuthorId
|
|
||||||
// to any and all local AuthorIds.
|
|
||||||
public static final AuthorId SELF = new AuthorId(new byte[] {
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
|
||||||
});
|
|
||||||
|
|
||||||
private final byte[] id;
|
|
||||||
|
|
||||||
public AuthorId(byte[] id) {
|
public AuthorId(byte[] id) {
|
||||||
assert id.length == LENGTH;
|
super(id);
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -31,9 +15,4 @@ public class AuthorId {
|
|||||||
return Arrays.equals(id, ((AuthorId) o).id);
|
return Arrays.equals(id, ((AuthorId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,10 @@ import java.util.Arrays;
|
|||||||
* Type-safe wrapper for a byte array that uniquely identifies a batch of
|
* Type-safe wrapper for a byte array that uniquely identifies a batch of
|
||||||
* messages.
|
* messages.
|
||||||
*/
|
*/
|
||||||
public class BatchId {
|
public class BatchId extends UniqueId {
|
||||||
|
|
||||||
public static final int LENGTH = 32;
|
|
||||||
|
|
||||||
private final byte[] id;
|
|
||||||
|
|
||||||
public BatchId(byte[] id) {
|
public BatchId(byte[] id) {
|
||||||
assert id.length == LENGTH;
|
super(id);
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,9 +18,4 @@ public class BatchId {
|
|||||||
return Arrays.equals(id, ((BatchId) o).id);
|
return Arrays.equals(id, ((BatchId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,15 @@ import java.util.Arrays;
|
|||||||
* Type-safe wrapper for a byte array that uniquely identifies a bundle of
|
* Type-safe wrapper for a byte array that uniquely identifies a bundle of
|
||||||
* acknowledgements, subscriptions, and batches of messages.
|
* acknowledgements, subscriptions, and batches of messages.
|
||||||
*/
|
*/
|
||||||
public class BundleId {
|
public class BundleId extends UniqueId {
|
||||||
|
|
||||||
public static final BundleId NONE = new BundleId(new byte[] {
|
public static final BundleId NONE = new BundleId(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,
|
||||||
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
|
||||||
});
|
});
|
||||||
|
|
||||||
public static final int LENGTH = 32;
|
|
||||||
|
|
||||||
private final byte[] id;
|
|
||||||
|
|
||||||
public BundleId(byte[] id) {
|
public BundleId(byte[] id) {
|
||||||
assert id.length == LENGTH;
|
super(id);
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -32,9 +23,4 @@ public class BundleId {
|
|||||||
return Arrays.equals(id, ((BundleId) o).id);
|
return Arrays.equals(id, ((BundleId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,10 @@ import java.util.Arrays;
|
|||||||
* Type-safe wrapper for a byte array that uniquely identifies a group to which
|
* Type-safe wrapper for a byte array that uniquely identifies a group to which
|
||||||
* users may subscribe.
|
* users may subscribe.
|
||||||
*/
|
*/
|
||||||
public class GroupId {
|
public class GroupId extends UniqueId {
|
||||||
|
|
||||||
public static final int LENGTH = 32;
|
|
||||||
|
|
||||||
private final byte[] id;
|
|
||||||
|
|
||||||
public GroupId(byte[] id) {
|
public GroupId(byte[] id) {
|
||||||
assert id.length == LENGTH;
|
super(id);
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,9 +18,4 @@ public class GroupId {
|
|||||||
return Arrays.equals(id, ((GroupId) o).id);
|
return Arrays.equals(id, ((GroupId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package net.sf.briar.api.protocol;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Type-safe wrapper for a byte array that uniquely identifies a message. */
|
/** Type-safe wrapper for a byte array that uniquely identifies a message. */
|
||||||
public class MessageId {
|
public class MessageId extends UniqueId {
|
||||||
|
|
||||||
/** Used to indicate that the first message in a thread has no parent. */
|
/** Used to indicate that the first message in a thread has no parent. */
|
||||||
public static final MessageId NONE = new MessageId(new byte[] {
|
public static final MessageId NONE = new MessageId(new byte[] {
|
||||||
@@ -11,17 +11,8 @@ public class MessageId {
|
|||||||
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
|
||||||
});
|
});
|
||||||
|
|
||||||
public static final int LENGTH = 32;
|
|
||||||
|
|
||||||
private final byte[] id;
|
|
||||||
|
|
||||||
public MessageId(byte[] id) {
|
public MessageId(byte[] id) {
|
||||||
assert id.length == LENGTH;
|
super(id);
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -30,9 +21,4 @@ public class MessageId {
|
|||||||
return Arrays.equals(id, ((MessageId) o).id);
|
return Arrays.equals(id, ((MessageId) o).id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
24
api/net/sf/briar/api/protocol/UniqueId.java
Normal file
24
api/net/sf/briar/api/protocol/UniqueId.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public abstract class UniqueId {
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
protected final byte[] id;
|
||||||
|
|
||||||
|
protected UniqueId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ DatabaseCleaner.Callback {
|
|||||||
private int calculateSendability(Txn txn, Message m) throws DbException {
|
private int calculateSendability(Txn txn, Message m) throws DbException {
|
||||||
int sendability = 0;
|
int sendability = 0;
|
||||||
// One point for a good rating
|
// One point for a good rating
|
||||||
if(getRating(m.getAuthor()) == Rating.GOOD) sendability++;
|
if(db.getRating(txn, m.getAuthor()) == Rating.GOOD) sendability++;
|
||||||
// One point per sendable child (backward inclusion)
|
// One point per sendable child (backward inclusion)
|
||||||
sendability += db.getNumberOfSendableChildren(txn, m.getId());
|
sendability += db.getNumberOfSendableChildren(txn, m.getId());
|
||||||
return sendability;
|
return sendability;
|
||||||
|
|||||||
519
test/net/sf/briar/db/DatabaseComponentTest.java
Normal file
519
test/net/sf/briar/db/DatabaseComponentTest.java
Normal file
@@ -0,0 +1,519 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import net.sf.briar.TestUtils;
|
||||||
|
import net.sf.briar.api.db.ContactId;
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
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.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
import net.sf.briar.protocol.MessageImpl;
|
||||||
|
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.Mockery;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
public abstract class DatabaseComponentTest extends TestCase {
|
||||||
|
|
||||||
|
private final File testDir = TestUtils.getTestDirectory();
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final AuthorId authorId;
|
||||||
|
private final ContactId contactId;
|
||||||
|
private final GroupId groupId;
|
||||||
|
private final MessageId messageId, parentId;
|
||||||
|
private final long timestamp;
|
||||||
|
private final int size;
|
||||||
|
private final byte[] body;
|
||||||
|
private final Message message;
|
||||||
|
private final Object txn = new Object();
|
||||||
|
|
||||||
|
public DatabaseComponentTest() {
|
||||||
|
super();
|
||||||
|
authorId = new AuthorId(getRandomId());
|
||||||
|
contactId = new ContactId(123);
|
||||||
|
groupId = new GroupId(getRandomId());
|
||||||
|
messageId = new MessageId(getRandomId());
|
||||||
|
parentId = new MessageId(getRandomId());
|
||||||
|
timestamp = System.currentTimeMillis();
|
||||||
|
size = 1234;
|
||||||
|
body = new byte[size];
|
||||||
|
random.nextBytes(body);
|
||||||
|
message = new MessageImpl(messageId, MessageId.NONE, groupId, authorId,
|
||||||
|
timestamp, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract <T> DatabaseComponent createDatabaseComponent(
|
||||||
|
Database<T> database, DatabaseCleaner cleaner,
|
||||||
|
Provider<Batch> batchProvider);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
testDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleCalls() throws DbException {
|
||||||
|
final Set<GroupId> subs = Collections.singleton(groupId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
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);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
assertEquals(Rating.UNRATED, db.getRating(authorId));
|
||||||
|
db.addContact(contactId);
|
||||||
|
db.subscribe(groupId);
|
||||||
|
assertEquals(Collections.singleton(groupId), db.getSubscriptions());
|
||||||
|
db.unsubscribe(groupId);
|
||||||
|
db.removeContact(contactId);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoParentStopsBackwardInclusion() throws DbException {
|
||||||
|
final Set<MessageId> messages = Collections.singleton(messageId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// setRating(Rating.GOOD)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||||
|
// The sendability of the author's messages should be incremented
|
||||||
|
oneOf(database).getMessagesByAuthor(txn, authorId);
|
||||||
|
will(returnValue(messages));
|
||||||
|
oneOf(database).getSendability(txn, messageId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 1);
|
||||||
|
// Backward inclusion stops when the message has no parent
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(MessageId.NONE));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.setRating(authorId, Rating.GOOD);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMissingParentStopsBackwardInclusion() throws DbException {
|
||||||
|
final Set<MessageId> messages = Collections.singleton(messageId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// setRating(Rating.GOOD)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||||
|
// The sendability of the author's messages should be incremented
|
||||||
|
oneOf(database).getMessagesByAuthor(txn, authorId);
|
||||||
|
will(returnValue(messages));
|
||||||
|
oneOf(database).getSendability(txn, messageId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 1);
|
||||||
|
// The parent exists
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(parentId));
|
||||||
|
// The parent isn't in the DB
|
||||||
|
oneOf(database).containsMessage(txn, parentId);
|
||||||
|
will(returnValue(false));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.setRating(authorId, Rating.GOOD);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangingGroupsStopsBackwardInclusion() throws DbException {
|
||||||
|
final GroupId groupId1 = new GroupId(getRandomId());
|
||||||
|
final Set<MessageId> messages = Collections.singleton(messageId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// setRating(Rating.GOOD)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||||
|
// The sendability of the author's messages should be incremented
|
||||||
|
oneOf(database).getMessagesByAuthor(txn, authorId);
|
||||||
|
will(returnValue(messages));
|
||||||
|
oneOf(database).getSendability(txn, messageId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 1);
|
||||||
|
// The parent exists and is in the database
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(parentId));
|
||||||
|
oneOf(database).containsMessage(txn, parentId);
|
||||||
|
will(returnValue(true));
|
||||||
|
// The parent is in a different group
|
||||||
|
oneOf(database).getGroup(txn, messageId);
|
||||||
|
will(returnValue(groupId));
|
||||||
|
oneOf(database).getGroup(txn, parentId);
|
||||||
|
will(returnValue(groupId1));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.setRating(authorId, Rating.GOOD);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnaffectedParentStopsBackwardInclusion()
|
||||||
|
throws DbException {
|
||||||
|
final Set<MessageId> messages = Collections.singleton(messageId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// setRating(Rating.GOOD)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||||
|
// The sendability of the author's messages should be incremented
|
||||||
|
oneOf(database).getMessagesByAuthor(txn, authorId);
|
||||||
|
will(returnValue(messages));
|
||||||
|
oneOf(database).getSendability(txn, messageId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 1);
|
||||||
|
// The parent exists, is in the DB, and is in the same group
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(parentId));
|
||||||
|
oneOf(database).containsMessage(txn, parentId);
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(database).getGroup(txn, messageId);
|
||||||
|
will(returnValue(groupId));
|
||||||
|
oneOf(database).getGroup(txn, parentId);
|
||||||
|
will(returnValue(groupId));
|
||||||
|
// The parent is already sendable
|
||||||
|
oneOf(database).getSendability(txn, parentId);
|
||||||
|
will(returnValue(1));
|
||||||
|
oneOf(database).setSendability(txn, parentId, 2);
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.setRating(authorId, Rating.GOOD);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAffectedParentContinuesBackwardInclusion()
|
||||||
|
throws DbException {
|
||||||
|
final Set<MessageId> messages = Collections.singleton(messageId);
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// setRating(Rating.GOOD)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||||
|
// The sendability of the author's messages should be incremented
|
||||||
|
oneOf(database).getMessagesByAuthor(txn, authorId);
|
||||||
|
will(returnValue(messages));
|
||||||
|
oneOf(database).getSendability(txn, messageId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 1);
|
||||||
|
// The parent exists, is in the DB, and is in the same group
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(parentId));
|
||||||
|
oneOf(database).containsMessage(txn, parentId);
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(database).getGroup(txn, messageId);
|
||||||
|
will(returnValue(groupId));
|
||||||
|
oneOf(database).getGroup(txn, parentId);
|
||||||
|
will(returnValue(groupId));
|
||||||
|
// The parent is not already sendable
|
||||||
|
oneOf(database).getSendability(txn, parentId);
|
||||||
|
will(returnValue(0));
|
||||||
|
oneOf(database).setSendability(txn, parentId, 1);
|
||||||
|
oneOf(database).getParent(txn, parentId);
|
||||||
|
will(returnValue(MessageId.NONE));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.setRating(authorId, Rating.GOOD);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessagesAreNotStoredUnlessSubscribed()
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// addLocallyGeneratedMessage(message)
|
||||||
|
oneOf(database).startTransaction();
|
||||||
|
will(returnValue(txn));
|
||||||
|
oneOf(database).containsSubscription(txn, groupId);
|
||||||
|
will(returnValue(false));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.addLocallyGeneratedMessage(message);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDuplicateMessagesAreNotStored() 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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// 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);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.addLocallyGeneratedMessage(message);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddLocallyGeneratedMessage() 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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// 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.singleton(contactId)));
|
||||||
|
oneOf(database).setStatus(txn, contactId, messageId, Status.NEW);
|
||||||
|
// The author is unrated and there are no sendable children
|
||||||
|
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);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.addLocallyGeneratedMessage(message);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddingASendableMessageTriggersBackwardInclusion()
|
||||||
|
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);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(database).open(false);
|
||||||
|
oneOf(cleaner).startCleaning();
|
||||||
|
// 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.singleton(contactId)));
|
||||||
|
oneOf(database).setStatus(txn, contactId, messageId, Status.NEW);
|
||||||
|
// The author is rated GOOD and there are two sendable children
|
||||||
|
oneOf(database).getRating(txn, authorId);
|
||||||
|
will(returnValue(Rating.GOOD));
|
||||||
|
oneOf(database).getNumberOfSendableChildren(txn, messageId);
|
||||||
|
will(returnValue(2));
|
||||||
|
oneOf(database).setSendability(txn, messageId, 3);
|
||||||
|
// The sendability of the message's ancestors should be updated
|
||||||
|
oneOf(database).getParent(txn, messageId);
|
||||||
|
will(returnValue(MessageId.NONE));
|
||||||
|
oneOf(database).commitTransaction(txn);
|
||||||
|
oneOf(cleaner).stopCleaning();
|
||||||
|
oneOf(database).close();
|
||||||
|
}});
|
||||||
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
|
||||||
|
db.open(false);
|
||||||
|
db.addLocallyGeneratedMessage(message);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getRandomId() {
|
||||||
|
byte[] b = new byte[32];
|
||||||
|
random.nextBytes(b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
TestUtils.deleteTestDirectory(testDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ public class H2DatabaseTest extends TestCase {
|
|||||||
private final File testDir = TestUtils.getTestDirectory();
|
private final File testDir = TestUtils.getTestDirectory();
|
||||||
// The password has the format <file password> <space> <user password>
|
// The password has the format <file password> <space> <user password>
|
||||||
private final String passwordString = "foo bar";
|
private final String passwordString = "foo bar";
|
||||||
private final Random random;
|
private final Random random = new Random();
|
||||||
private final AuthorId authorId;
|
private final AuthorId authorId;
|
||||||
private final BatchId batchId;
|
private final BatchId batchId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
@@ -53,7 +53,6 @@ public class H2DatabaseTest extends TestCase {
|
|||||||
|
|
||||||
public H2DatabaseTest() {
|
public H2DatabaseTest() {
|
||||||
super();
|
super();
|
||||||
random = new Random();
|
|
||||||
authorId = new AuthorId(getRandomId());
|
authorId = new AuthorId(getRandomId());
|
||||||
batchId = new BatchId(getRandomId());
|
batchId = new BatchId(getRandomId());
|
||||||
contactId = new ContactId(123);
|
contactId = new ContactId(123);
|
||||||
|
|||||||
17
test/net/sf/briar/db/ReadWriteLockDatabaseComponentTest.java
Normal file
17
test/net/sf/briar/db/ReadWriteLockDatabaseComponentTest.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
public class ReadWriteLockDatabaseComponentTest extends DatabaseComponentTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> DatabaseComponent createDatabaseComponent(
|
||||||
|
Database<T> database, DatabaseCleaner cleaner,
|
||||||
|
Provider<Batch> batchProvider) {
|
||||||
|
return new ReadWriteLockDatabaseComponent<T>(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
test/net/sf/briar/db/SynchronizedDatabaseComponentTest.java
Normal file
18
test/net/sf/briar/db/SynchronizedDatabaseComponentTest.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
public class SynchronizedDatabaseComponentTest extends DatabaseComponentTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> DatabaseComponent createDatabaseComponent(
|
||||||
|
Database<T> database, DatabaseCleaner cleaner,
|
||||||
|
Provider<Batch> batchProvider) {
|
||||||
|
return new SynchronizedDatabaseComponent<T>(database, cleaner,
|
||||||
|
batchProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user