Merge branch '941-store-correct-parent-id' into 'master'

Store correct original parent ID when rewrapping blog posts

See merge request !534
This commit is contained in:
akwizgran
2017-05-12 09:53:27 +00:00
6 changed files with 704 additions and 131 deletions

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api; package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@@ -53,6 +54,12 @@ public class Bytes implements Comparable<Bytes> {
return aBytes.length - bBytes.length; return aBytes.length - bBytes.length;
} }
@Override
public String toString() {
return getClass().getSimpleName() +
"(" + StringUtils.toHexString(getBytes()) + ")";
}
public static class BytesComparator implements Comparator<Bytes> { public static class BytesComparator implements Comparator<Bytes> {
@Override @Override

View File

@@ -60,7 +60,7 @@ public interface BlogManager {
* Adds a comment to an existing blog post or reblogs it. * Adds a comment to an existing blog post or reblogs it.
*/ */
void addLocalComment(LocalAuthor author, GroupId groupId, void addLocalComment(LocalAuthor author, GroupId groupId,
@Nullable String comment, BlogPostHeader wHeader) @Nullable String comment, BlogPostHeader parentHeader)
throws DbException; throws DbException;
/** /**

View File

@@ -25,7 +25,8 @@ public interface BlogPostFactory {
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
Message createBlogComment(GroupId groupId, LocalAuthor author, Message createBlogComment(GroupId groupId, LocalAuthor author,
@Nullable String comment, MessageId originalId, MessageId wrappedId) @Nullable String comment, MessageId parentOriginalId,
MessageId parentCurrentId)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
/** /**
@@ -44,11 +45,11 @@ public interface BlogPostFactory {
* Wraps a blog comment * Wraps a blog comment
*/ */
Message wrapComment(GroupId groupId, byte[] descriptor, long timestamp, Message wrapComment(GroupId groupId, byte[] descriptor, long timestamp,
BdfList body, MessageId currentId) throws FormatException; BdfList body, MessageId parentCurrentId) throws FormatException;
/** /**
* Re-wraps a previously wrapped comment * Re-wraps a previously wrapped comment
*/ */
Message rewrapWrappedComment(GroupId groupId, BdfList body, Message rewrapWrappedComment(GroupId groupId, BdfList body,
MessageId currentId) throws FormatException; MessageId parentCurrentId) throws FormatException;
} }

View File

@@ -232,7 +232,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
addLocalPost(txn, p); addLocalPost(txn, p);
db.commitTransaction(txn); db.commitTransaction(txn);
} finally { } finally {
//noinspection ThrowFromFinallyBlock
db.endTransaction(txn); db.endTransaction(txn);
} }
} }
@@ -255,8 +254,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
MessageId postId = p.getMessage().getId(); MessageId postId = p.getMessage().getId();
BlogPostHeader h = BlogPostHeader h =
getPostHeaderFromMetadata(txn, groupId, postId, meta); getPostHeaderFromMetadata(txn, groupId, postId, meta);
BlogPostAddedEvent event = BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true);
new BlogPostAddedEvent(groupId, h, true);
txn.attach(event); txn.attach(event);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
@@ -265,42 +263,39 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
@Override @Override
public void addLocalComment(LocalAuthor author, GroupId groupId, public void addLocalComment(LocalAuthor author, GroupId groupId,
@Nullable String comment, BlogPostHeader pOriginalHeader) @Nullable String comment, BlogPostHeader parentHeader)
throws DbException { throws DbException {
MessageType type = pOriginalHeader.getType(); MessageType type = parentHeader.getType();
if (type != POST && type != COMMENT) if (type != POST && type != COMMENT)
throw new IllegalArgumentException("Comment on unknown type!"); throw new IllegalArgumentException("Comment on unknown type!");
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
// Wrap post that we are commenting on // Wrap post that we are commenting on
MessageId parentId = wrapMessage(txn, groupId, pOriginalHeader); MessageId parentOriginalId =
getOriginalMessageId(txn, parentHeader);
// Get ID of new parent's original message. MessageId parentCurrentId =
// Assumes that pOriginalHeader is a POST or COMMENT wrapMessage(txn, groupId, parentHeader, parentOriginalId);
MessageId pOriginalId = pOriginalHeader.getId();
// Create actual comment // Create actual comment
Message message = blogPostFactory Message message = blogPostFactory.createBlogComment(groupId, author,
.createBlogComment(groupId, author, comment, pOriginalId, comment, parentOriginalId, parentCurrentId);
parentId);
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TYPE, COMMENT.getInt()); meta.put(KEY_TYPE, COMMENT.getInt());
if (comment != null) meta.put(KEY_COMMENT, comment); if (comment != null) meta.put(KEY_COMMENT, comment);
meta.put(KEY_TIMESTAMP, message.getTimestamp()); meta.put(KEY_TIMESTAMP, message.getTimestamp());
meta.put(KEY_ORIGINAL_MSG_ID, message.getId()); meta.put(KEY_ORIGINAL_MSG_ID, message.getId());
meta.put(KEY_ORIGINAL_PARENT_MSG_ID, pOriginalId); meta.put(KEY_ORIGINAL_PARENT_MSG_ID, parentOriginalId);
meta.put(KEY_PARENT_MSG_ID, parentId); meta.put(KEY_PARENT_MSG_ID, parentCurrentId);
meta.put(KEY_AUTHOR, authorToBdfDictionary(author)); meta.put(KEY_AUTHOR, authorToBdfDictionary(author));
// Send comment // Send comment
clientHelper.addLocalMessage(txn, message, meta, true); clientHelper.addLocalMessage(txn, message, meta, true);
// broadcast event // broadcast event
BlogPostHeader h = BlogPostHeader h = getPostHeaderFromMetadata(txn, groupId,
getPostHeaderFromMetadata(txn, groupId, message.getId(), message.getId(), meta);
meta);
BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true); BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true);
txn.attach(event); txn.attach(event);
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -309,81 +304,94 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new IllegalArgumentException("Invalid key of author", e); throw new IllegalArgumentException("Invalid key of author", e);
} finally { } finally {
//noinspection ThrowFromFinallyBlock
db.endTransaction(txn); db.endTransaction(txn);
} }
} }
private MessageId getOriginalMessageId(Transaction txn, BlogPostHeader h)
throws DbException, FormatException {
MessageType type = h.getType();
if (type == POST || type == COMMENT) return h.getId();
BdfDictionary meta = clientHelper.getMessageMetadataAsDictionary(txn,
h.getId());
return new MessageId(meta.getRaw(KEY_ORIGINAL_MSG_ID));
}
private MessageId wrapMessage(Transaction txn, GroupId groupId, private MessageId wrapMessage(Transaction txn, GroupId groupId,
BlogPostHeader pOriginalHeader) BlogPostHeader header, MessageId originalId)
throws DbException, FormatException { throws DbException, FormatException {
if (groupId.equals(pOriginalHeader.getGroupId())) { if (groupId.equals(header.getGroupId())) {
// We are trying to wrap a post that is already in our group. // We are trying to wrap a post that is already in our group.
// This is unnecessary, so just return the post's MessageId // This is unnecessary, so just return the post's MessageId
return pOriginalHeader.getId(); return header.getId();
} }
// Get body of message to be wrapped // Get body of message to be wrapped
BdfList body = BdfList body = clientHelper.getMessageAsList(txn, header.getId());
clientHelper.getMessageAsList(txn, pOriginalHeader.getId());
if (body == null) throw new DbException(); if (body == null) throw new DbException();
long wTimestamp = pOriginalHeader.getTimestamp(); long timestamp = header.getTimestamp();
Message wMessage; Message wrappedMessage;
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
MessageType type = pOriginalHeader.getType(); MessageType type = header.getType();
if (type == POST) { if (type == POST) {
Group wGroup = db.getGroup(txn, pOriginalHeader.getGroupId());
byte[] wDescriptor = wGroup.getDescriptor();
// Wrap post // Wrap post
wMessage = blogPostFactory Group group = db.getGroup(txn, header.getGroupId());
.wrapPost(groupId, wDescriptor, wTimestamp, body); byte[] descriptor = group.getDescriptor();
wrappedMessage = blogPostFactory.wrapPost(groupId, descriptor,
timestamp, body);
meta.put(KEY_TYPE, WRAPPED_POST.getInt()); meta.put(KEY_TYPE, WRAPPED_POST.getInt());
meta.put(KEY_RSS_FEED, pOriginalHeader.isRssFeed()); meta.put(KEY_RSS_FEED, header.isRssFeed());
} else if (type == COMMENT) { } else if (type == COMMENT) {
Group wGroup = db.getGroup(txn, pOriginalHeader.getGroupId()); // Recursively wrap parent
byte[] wDescriptor = wGroup.getDescriptor(); BlogCommentHeader commentHeader = (BlogCommentHeader) header;
BlogCommentHeader wComment = (BlogCommentHeader) pOriginalHeader; BlogPostHeader parentHeader = commentHeader.getParent();
MessageId wrappedId = MessageId parentOriginalId =
wrapMessage(txn, groupId, wComment.getParent()); getOriginalMessageId(txn, parentHeader);
MessageId parentCurrentId =
wrapMessage(txn, groupId, parentHeader, parentOriginalId);
// Wrap comment // Wrap comment
wMessage = blogPostFactory Group group = db.getGroup(txn, header.getGroupId());
.wrapComment(groupId, wDescriptor, wTimestamp, byte[] descriptor = group.getDescriptor();
body, wrappedId); wrappedMessage = blogPostFactory.wrapComment(groupId, descriptor,
timestamp, body, parentCurrentId);
meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt()); meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt());
if (wComment.getComment() != null) if (commentHeader.getComment() != null)
meta.put(KEY_COMMENT, wComment.getComment()); meta.put(KEY_COMMENT, commentHeader.getComment());
meta.put(KEY_PARENT_MSG_ID, wrappedId); meta.put(KEY_PARENT_MSG_ID, parentCurrentId);
} else if (type == WRAPPED_POST) { } else if (type == WRAPPED_POST) {
// Re-wrap wrapped post without adding another wrapping layer // Re-wrap wrapped post without adding another wrapping layer
wMessage = blogPostFactory.rewrapWrappedPost(groupId, body); wrappedMessage = blogPostFactory.rewrapWrappedPost(groupId, body);
meta.put(KEY_TYPE, WRAPPED_POST.getInt()); meta.put(KEY_TYPE, WRAPPED_POST.getInt());
meta.put(KEY_RSS_FEED, pOriginalHeader.isRssFeed()); meta.put(KEY_RSS_FEED, header.isRssFeed());
} else if (type == WRAPPED_COMMENT) { } else if (type == WRAPPED_COMMENT) {
BlogCommentHeader wComment = (BlogCommentHeader) pOriginalHeader; // Recursively wrap parent
MessageId wrappedId = BlogCommentHeader commentHeader = (BlogCommentHeader) header;
wrapMessage(txn, groupId, wComment.getParent()); BlogPostHeader parentHeader = commentHeader.getParent();
MessageId parentOriginalId =
getOriginalMessageId(txn, parentHeader);
MessageId parentCurrentId =
wrapMessage(txn, groupId, parentHeader, parentOriginalId);
// Re-wrap wrapped comment // Re-wrap wrapped comment
wMessage = blogPostFactory wrappedMessage = blogPostFactory.rewrapWrappedComment(groupId, body,
.rewrapWrappedComment(groupId, body, wrappedId); parentCurrentId);
meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt()); meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt());
if (wComment.getComment() != null) if (commentHeader.getComment() != null)
meta.put(KEY_COMMENT, wComment.getComment()); meta.put(KEY_COMMENT, commentHeader.getComment());
meta.put(KEY_PARENT_MSG_ID, wrappedId); meta.put(KEY_PARENT_MSG_ID, parentCurrentId);
} else { } else {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Unknown Message Type: " + type); "Unknown Message Type: " + type);
} }
meta.put(KEY_ORIGINAL_MSG_ID, pOriginalHeader.getId()); meta.put(KEY_ORIGINAL_MSG_ID, originalId);
meta.put(KEY_AUTHOR, meta.put(KEY_AUTHOR, authorToBdfDictionary(header.getAuthor()));
authorToBdfDictionary(pOriginalHeader.getAuthor())); meta.put(KEY_TIMESTAMP, header.getTimestamp());
meta.put(KEY_TIMESTAMP, pOriginalHeader.getTimestamp()); meta.put(KEY_TIME_RECEIVED, header.getTimeReceived());
meta.put(KEY_TIME_RECEIVED, pOriginalHeader.getTimeReceived());
// Send wrapped message and store metadata // Send wrapped message and store metadata
clientHelper.addLocalMessage(txn, wMessage, meta, true); clientHelper.addLocalMessage(txn, wrappedMessage, meta, true);
return wMessage.getId(); return wrappedMessage.getId();
} }
@Override @Override

View File

@@ -65,7 +65,8 @@ class BlogPostFactoryImpl implements BlogPostFactory {
@Override @Override
public Message createBlogComment(GroupId groupId, LocalAuthor author, public Message createBlogComment(GroupId groupId, LocalAuthor author,
@Nullable String comment, MessageId pOriginalId, MessageId parentId) @Nullable String comment, MessageId parentOriginalId,
MessageId parentCurrentId)
throws FormatException, GeneralSecurityException { throws FormatException, GeneralSecurityException {
if (comment != null) { if (comment != null) {
@@ -78,22 +79,20 @@ class BlogPostFactoryImpl implements BlogPostFactory {
long timestamp = clock.currentTimeMillis(); long timestamp = clock.currentTimeMillis();
// Generate the signature // Generate the signature
BdfList signed = BdfList signed = BdfList.of(groupId, timestamp, comment,
BdfList.of(groupId, timestamp, comment, pOriginalId, parentId); parentOriginalId, parentCurrentId);
byte[] sig = clientHelper byte[] sig = clientHelper
.sign(SIGNING_LABEL_COMMENT, signed, author.getPrivateKey()); .sign(SIGNING_LABEL_COMMENT, signed, author.getPrivateKey());
// Serialise the signed message // Serialise the signed message
BdfList message = BdfList message = BdfList.of(COMMENT.getInt(), comment,
BdfList.of(COMMENT.getInt(), comment, pOriginalId, parentId, parentOriginalId, parentCurrentId, sig);
sig);
return clientHelper.createMessage(groupId, timestamp, message); return clientHelper.createMessage(groupId, timestamp, message);
} }
@Override @Override
public Message wrapPost(GroupId groupId, byte[] descriptor, public Message wrapPost(GroupId groupId, byte[] descriptor,
long timestamp, BdfList body) long timestamp, BdfList body) throws FormatException {
throws FormatException {
if (getType(body) != POST) if (getType(body) != POST)
throw new IllegalArgumentException("Needs to wrap a POST"); throw new IllegalArgumentException("Needs to wrap a POST");
@@ -101,9 +100,8 @@ class BlogPostFactoryImpl implements BlogPostFactory {
// Serialise the message // Serialise the message
String content = body.getString(1); String content = body.getString(1);
byte[] signature = body.getRaw(2); byte[] signature = body.getRaw(2);
BdfList message = BdfList message = BdfList.of(WRAPPED_POST.getInt(), descriptor,
BdfList.of(WRAPPED_POST.getInt(), descriptor, timestamp, timestamp, content, signature);
content, signature);
return clientHelper return clientHelper
.createMessage(groupId, clock.currentTimeMillis(), message); .createMessage(groupId, clock.currentTimeMillis(), message);
} }
@@ -120,16 +118,15 @@ class BlogPostFactoryImpl implements BlogPostFactory {
long timestamp = body.getLong(2); long timestamp = body.getLong(2);
String content = body.getString(3); String content = body.getString(3);
byte[] signature = body.getRaw(4); byte[] signature = body.getRaw(4);
BdfList message = BdfList message = BdfList.of(WRAPPED_POST.getInt(), descriptor,
BdfList.of(WRAPPED_POST.getInt(), descriptor, timestamp, timestamp, content, signature);
content, signature);
return clientHelper return clientHelper
.createMessage(groupId, clock.currentTimeMillis(), message); .createMessage(groupId, clock.currentTimeMillis(), message);
} }
@Override @Override
public Message wrapComment(GroupId groupId, byte[] descriptor, public Message wrapComment(GroupId groupId, byte[] descriptor,
long timestamp, BdfList body, MessageId parentId) long timestamp, BdfList body, MessageId parentCurrentId)
throws FormatException { throws FormatException {
if (getType(body) != COMMENT) if (getType(body) != COMMENT)
@@ -140,16 +137,16 @@ class BlogPostFactoryImpl implements BlogPostFactory {
byte[] pOriginalId = body.getRaw(2); byte[] pOriginalId = body.getRaw(2);
byte[] oldParentId = body.getRaw(3); byte[] oldParentId = body.getRaw(3);
byte[] signature = body.getRaw(4); byte[] signature = body.getRaw(4);
BdfList message = BdfList message = BdfList.of(WRAPPED_COMMENT.getInt(), descriptor,
BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, timestamp, timestamp, comment, pOriginalId, oldParentId, signature,
comment, pOriginalId, oldParentId, signature, parentId); parentCurrentId);
return clientHelper return clientHelper
.createMessage(groupId, clock.currentTimeMillis(), message); .createMessage(groupId, clock.currentTimeMillis(), message);
} }
@Override @Override
public Message rewrapWrappedComment(GroupId groupId, BdfList body, public Message rewrapWrappedComment(GroupId groupId, BdfList body,
MessageId parentId) throws FormatException { MessageId parentCurrentId) throws FormatException {
if (getType(body) != WRAPPED_COMMENT) if (getType(body) != WRAPPED_COMMENT)
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -162,9 +159,9 @@ class BlogPostFactoryImpl implements BlogPostFactory {
byte[] pOriginalId = body.getRaw(4); byte[] pOriginalId = body.getRaw(4);
byte[] oldParentId = body.getRaw(5); byte[] oldParentId = body.getRaw(5);
byte[] signature = body.getRaw(6); byte[] signature = body.getRaw(6);
BdfList message = BdfList message = BdfList.of(WRAPPED_COMMENT.getInt(), descriptor,
BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, timestamp, timestamp, comment, pOriginalId, oldParentId, signature,
comment, pOriginalId, oldParentId, signature, parentId); parentCurrentId);
return clientHelper return clientHelper
.createMessage(groupId, clock.currentTimeMillis(), message); .createMessage(groupId, clock.currentTimeMillis(), message);
} }

View File

@@ -20,6 +20,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogCommentHeader;
import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.blog.BlogPost; import org.briarproject.briar.api.blog.BlogPost;
import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.blog.BlogPostFactory;
@@ -33,24 +34,38 @@ import org.junit.Test;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import static org.briarproject.bramble.api.identity.Author.Status.NONE;
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED; import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getRandomString;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR; import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR_ID; import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR_ID;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR_NAME; import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR_NAME;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_COMMENT;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_ORIGINAL_MSG_ID;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_ORIGINAL_PARENT_MSG_ID;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_PARENT_MSG_ID;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ; import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIMESTAMP; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIMESTAMP;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED;
import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE;
import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID; import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
import static org.briarproject.briar.api.blog.MessageType.COMMENT;
import static org.briarproject.briar.api.blog.MessageType.POST; import static org.briarproject.briar.api.blog.MessageType.POST;
import static org.briarproject.briar.api.blog.MessageType.WRAPPED_COMMENT;
import static org.briarproject.briar.api.blog.MessageType.WRAPPED_POST;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BlogManagerImplTest extends BriarTestCase { public class BlogManagerImplTest extends BriarTestCase {
@@ -62,21 +77,40 @@ public class BlogManagerImplTest extends BriarTestCase {
context.mock(IdentityManager.class); context.mock(IdentityManager.class);
private final ClientHelper clientHelper = context.mock(ClientHelper.class); private final ClientHelper clientHelper = context.mock(ClientHelper.class);
private final BlogFactory blogFactory = context.mock(BlogFactory.class); private final BlogFactory blogFactory = context.mock(BlogFactory.class);
private final BlogPostFactory blogPostFactory =
context.mock(BlogPostFactory.class);
private final Blog blog1, blog2; private final LocalAuthor localAuthor1, localAuthor2, rssLocalAuthor;
private final Message message; private final BdfDictionary authorDict1, authorDict2, rssAuthorDict;
private final MessageId messageId; private final Blog blog1, blog2, rssBlog;
private final long timestamp, timeReceived;
private final MessageId messageId, rssMessageId;
private final Message message, rssMessage;
private final String comment;
public BlogManagerImplTest() { public BlogManagerImplTest() {
MetadataParser metadataParser = context.mock(MetadataParser.class); MetadataParser metadataParser = context.mock(MetadataParser.class);
BlogPostFactory blogPostFactory = context.mock(BlogPostFactory.class);
blogManager = new BlogManagerImpl(db, identityManager, clientHelper, blogManager = new BlogManagerImpl(db, identityManager, clientHelper,
metadataParser, blogFactory, blogPostFactory); metadataParser, blogFactory, blogPostFactory);
blog1 = createBlog(); localAuthor1 = createLocalAuthor();
blog2 = createBlog(); localAuthor2 = createLocalAuthor();
rssLocalAuthor = createLocalAuthor();
authorDict1 = authorToBdfDictionary(localAuthor1);
authorDict2 = authorToBdfDictionary(localAuthor2);
rssAuthorDict = authorToBdfDictionary(rssLocalAuthor);
blog1 = createBlog(localAuthor1, false);
blog2 = createBlog(localAuthor2, false);
rssBlog = createBlog(rssLocalAuthor, true);
timestamp = System.currentTimeMillis();
timeReceived = timestamp + 1;
messageId = new MessageId(getRandomId()); messageId = new MessageId(getRandomId());
message = new Message(messageId, blog1.getId(), 42, getRandomBytes(42)); rssMessageId = new MessageId(getRandomId());
message = new Message(messageId, blog1.getId(), timestamp,
getRandomBytes(MAX_MESSAGE_LENGTH));
rssMessage = new Message(rssMessageId, rssBlog.getId(), timestamp,
getRandomBytes(MAX_MESSAGE_LENGTH));
comment = getRandomString(MAX_BLOG_COMMENT_LENGTH);
} }
@Test @Test
@@ -135,23 +169,22 @@ public class BlogManagerImplTest extends BriarTestCase {
@Test @Test
public void testIncomingMessage() throws DbException, FormatException { public void testIncomingMessage() throws DbException, FormatException {
final Transaction txn = new Transaction(null, false); final Transaction txn = new Transaction(null, false);
BdfList list = new BdfList(); BdfList body = BdfList.of("body");
BdfDictionary author = authorToBdfDictionary(blog1.getAuthor());
BdfDictionary meta = BdfDictionary.of( BdfDictionary meta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, POST.getInt()), new BdfEntry(KEY_TYPE, POST.getInt()),
new BdfEntry(KEY_TIMESTAMP, 0), new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, 1), new BdfEntry(KEY_TIME_RECEIVED, timeReceived),
new BdfEntry(KEY_AUTHOR, author), new BdfEntry(KEY_AUTHOR, authorDict1),
new BdfEntry(KEY_READ, false) new BdfEntry(KEY_READ, false),
new BdfEntry(KEY_RSS_FEED, false)
); );
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(identityManager) oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
.getAuthorStatus(txn, blog1.getAuthor().getId());
will(returnValue(VERIFIED)); will(returnValue(VERIFIED));
}}); }});
blogManager.incomingMessage(txn, message, list, meta); blogManager.incomingMessage(txn, message, body, meta);
context.assertIsSatisfied(); context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size()); assertEquals(1, txn.getEvents().size());
@@ -161,11 +194,49 @@ public class BlogManagerImplTest extends BriarTestCase {
assertEquals(blog1.getId(), e.getGroupId()); assertEquals(blog1.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader(); BlogPostHeader h = e.getHeader();
assertEquals(1, h.getTimeReceived()); assertEquals(POST, h.getType());
assertFalse(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timeReceived, h.getTimeReceived());
assertEquals(messageId, h.getId()); assertEquals(messageId, h.getId());
assertEquals(null, h.getParentId()); assertEquals(blog1.getId(), h.getGroupId());
assertNull(h.getParentId());
assertEquals(VERIFIED, h.getAuthorStatus()); assertEquals(VERIFIED, h.getAuthorStatus());
assertEquals(blog1.getAuthor(), h.getAuthor()); assertEquals(localAuthor1, h.getAuthor());
}
@Test
public void testIncomingRssMessage() throws DbException, FormatException {
final Transaction txn = new Transaction(null, false);
BdfList body = BdfList.of("body");
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, POST.getInt()),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived),
new BdfEntry(KEY_AUTHOR, rssAuthorDict),
new BdfEntry(KEY_READ, false),
new BdfEntry(KEY_RSS_FEED, true)
);
blogManager.incomingMessage(txn, rssMessage, body, meta);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(rssBlog.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(POST, h.getType());
assertTrue(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timeReceived, h.getTimeReceived());
assertEquals(rssMessageId, h.getId());
assertEquals(rssBlog.getId(), h.getGroupId());
assertNull(h.getParentId());
assertEquals(NONE, h.getAuthorStatus());
assertEquals(rssLocalAuthor, h.getAuthor());
} }
@Test @Test
@@ -189,13 +260,11 @@ public class BlogManagerImplTest extends BriarTestCase {
@Test @Test
public void testAddLocalPost() throws DbException, FormatException { public void testAddLocalPost() throws DbException, FormatException {
final Transaction txn = new Transaction(null, false); final Transaction txn = new Transaction(null, false);
final BlogPost post = final BlogPost post = new BlogPost(message, null, localAuthor1);
new BlogPost(message, null, blog1.getAuthor());
BdfDictionary authorMeta = authorToBdfDictionary(blog1.getAuthor());
final BdfDictionary meta = BdfDictionary.of( final BdfDictionary meta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, POST.getInt()), new BdfEntry(KEY_TYPE, POST.getInt()),
new BdfEntry(KEY_TIMESTAMP, message.getTimestamp()), new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_AUTHOR, authorMeta), new BdfEntry(KEY_AUTHOR, authorDict1),
new BdfEntry(KEY_READ, true), new BdfEntry(KEY_READ, true),
new BdfEntry(KEY_RSS_FEED, false) new BdfEntry(KEY_RSS_FEED, false)
); );
@@ -207,11 +276,9 @@ public class BlogManagerImplTest extends BriarTestCase {
will(returnValue(blog1.getGroup())); will(returnValue(blog1.getGroup()));
oneOf(blogFactory).parseBlog(blog1.getGroup()); oneOf(blogFactory).parseBlog(blog1.getGroup());
will(returnValue(blog1)); will(returnValue(blog1));
oneOf(clientHelper) oneOf(clientHelper).addLocalMessage(txn, message, meta, true);
.addLocalMessage(txn, message, meta, true); oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
oneOf(identityManager) will(returnValue(OURSELVES));
.getAuthorStatus(txn, blog1.getAuthor().getId());
will(returnValue(VERIFIED));
oneOf(db).commitTransaction(txn); oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn); oneOf(db).endTransaction(txn);
}}); }});
@@ -226,11 +293,504 @@ public class BlogManagerImplTest extends BriarTestCase {
assertEquals(blog1.getId(), e.getGroupId()); assertEquals(blog1.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader(); BlogPostHeader h = e.getHeader();
assertEquals(message.getTimestamp(), h.getTimeReceived()); assertEquals(POST, h.getType());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(messageId, h.getId()); assertEquals(messageId, h.getId());
assertEquals(null, h.getParentId()); assertEquals(blog1.getId(), h.getGroupId());
assertEquals(VERIFIED, h.getAuthorStatus()); assertNull(h.getParentId());
assertEquals(blog1.getAuthor(), h.getAuthor()); assertEquals(OURSELVES, h.getAuthorStatus());
assertEquals(localAuthor1, h.getAuthor());
}
@Test
public void testAddLocalRssPost() throws DbException, FormatException {
final Transaction txn = new Transaction(null, false);
final BlogPost post = new BlogPost(rssMessage, null, rssLocalAuthor);
final BdfDictionary meta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, POST.getInt()),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_AUTHOR, rssAuthorDict),
new BdfEntry(KEY_READ, true),
new BdfEntry(KEY_RSS_FEED, true)
);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).getGroup(txn, rssBlog.getId());
will(returnValue(rssBlog.getGroup()));
oneOf(blogFactory).parseBlog(rssBlog.getGroup());
will(returnValue(rssBlog));
oneOf(clientHelper).addLocalMessage(txn, rssMessage, meta, true);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
blogManager.addLocalPost(post);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(rssBlog.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(POST, h.getType());
assertTrue(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(rssMessageId, h.getId());
assertEquals(rssBlog.getId(), h.getGroupId());
assertNull(h.getParentId());
assertEquals(NONE, h.getAuthorStatus());
assertEquals(rssLocalAuthor, h.getAuthor());
}
@Test
public void testAddLocalCommentToLocalPost() throws Exception {
final Transaction txn = new Transaction(null, false);
// The post was originally posted to blog 1, then reblogged to the
// same blog (commenting on own post)
final BdfDictionary postMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, POST.getInt()),
new BdfEntry(KEY_RSS_FEED, false),
new BdfEntry(KEY_ORIGINAL_MSG_ID, messageId),
new BdfEntry(KEY_AUTHOR, authorDict1),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived)
);
final MessageId commentId = new MessageId(getRandomId());
final Message commentMsg = new Message(commentId, blog1.getId(),
timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary commentMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, COMMENT.getInt()),
new BdfEntry(KEY_COMMENT, comment),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
new BdfEntry(KEY_PARENT_MSG_ID, messageId),
new BdfEntry(KEY_AUTHOR, authorDict1)
);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
// Create the comment
oneOf(blogPostFactory).createBlogComment(blog1.getId(),
localAuthor1, comment, messageId, messageId);
will(returnValue(commentMsg));
// Store the comment
oneOf(clientHelper).addLocalMessage(txn, commentMsg, commentMeta,
true);
// Create the headers for the comment and its parent
oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
will(returnValue(OURSELVES));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, messageId);
will(returnValue(postMeta));
oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
will(returnValue(OURSELVES));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
BlogPostHeader postHeader = new BlogPostHeader(POST, blog1.getId(),
messageId, null, timestamp, timeReceived, localAuthor1,
OURSELVES, false, true);
blogManager.addLocalComment(localAuthor1, blog1.getId(), comment,
postHeader);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(blog1.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(COMMENT, h.getType());
assertFalse(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(commentId, h.getId());
assertEquals(blog1.getId(), h.getGroupId());
assertEquals(messageId, h.getParentId());
assertEquals(OURSELVES, h.getAuthorStatus());
assertEquals(localAuthor1, h.getAuthor());
assertTrue(h instanceof BlogCommentHeader);
BlogPostHeader h1 = ((BlogCommentHeader) h).getParent();
assertEquals(POST, h1.getType());
assertFalse(h1.isRssFeed());
assertEquals(timestamp, h1.getTimestamp());
assertEquals(timeReceived, h1.getTimeReceived());
assertEquals(messageId, h1.getId());
assertEquals(blog1.getId(), h.getGroupId());
assertNull(h1.getParentId());
assertEquals(OURSELVES, h1.getAuthorStatus());
assertEquals(localAuthor1, h1.getAuthor());
assertEquals(h1.getId(), ((BlogCommentHeader) h).getRootPost().getId());
}
@Test
public void testAddLocalCommentToRemotePost() throws Exception {
final Transaction txn = new Transaction(null, false);
// The post was originally posted to blog 1, then reblogged to
// blog 2 with a comment
final BdfList originalPostBody = BdfList.of("originalPostBody");
final MessageId wrappedPostId = new MessageId(getRandomId());
final Message wrappedPostMsg = new Message(wrappedPostId, blog2.getId(),
timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary wrappedPostMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, WRAPPED_POST.getInt()),
new BdfEntry(KEY_RSS_FEED, false),
new BdfEntry(KEY_ORIGINAL_MSG_ID, messageId),
new BdfEntry(KEY_AUTHOR, authorDict1),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived)
);
final MessageId commentId = new MessageId(getRandomId());
final Message commentMsg = new Message(commentId, blog2.getId(),
timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary commentMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, COMMENT.getInt()),
new BdfEntry(KEY_COMMENT, comment),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
new BdfEntry(KEY_AUTHOR, authorDict2)
);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
// Wrap the original post for blog 2
oneOf(clientHelper).getMessageAsList(txn, messageId);
will(returnValue(originalPostBody));
oneOf(db).getGroup(txn, blog1.getId());
will(returnValue(blog1.getGroup()));
oneOf(blogPostFactory).wrapPost(blog2.getId(),
blog1.getGroup().getDescriptor(), timestamp,
originalPostBody);
will(returnValue(wrappedPostMsg));
// Store the wrapped post
oneOf(clientHelper).addLocalMessage(txn, wrappedPostMsg,
wrappedPostMeta, true);
// Create the comment
oneOf(blogPostFactory).createBlogComment(blog2.getId(),
localAuthor2, comment, messageId, wrappedPostId);
will(returnValue(commentMsg));
// Store the comment
oneOf(clientHelper).addLocalMessage(txn, commentMsg, commentMeta,
true);
// Create the headers for the comment and the wrapped post
oneOf(identityManager).getAuthorStatus(txn, localAuthor2.getId());
will(returnValue(OURSELVES));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
wrappedPostId);
will(returnValue(wrappedPostMeta));
oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
will(returnValue(VERIFIED));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
blog1.getId(), messageId, null, timestamp, timeReceived,
localAuthor1, VERIFIED, false, true);
blogManager.addLocalComment(localAuthor2, blog2.getId(), comment,
originalPostHeader);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(blog2.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(COMMENT, h.getType());
assertFalse(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(commentId, h.getId());
assertEquals(blog2.getId(), h.getGroupId());
assertEquals(wrappedPostId, h.getParentId());
assertEquals(OURSELVES, h.getAuthorStatus());
assertEquals(localAuthor2, h.getAuthor());
assertTrue(h instanceof BlogCommentHeader);
BlogPostHeader h1 = ((BlogCommentHeader) h).getParent();
assertEquals(WRAPPED_POST, h1.getType());
assertFalse(h1.isRssFeed());
assertEquals(timestamp, h1.getTimestamp());
assertEquals(timeReceived, h1.getTimeReceived());
assertEquals(wrappedPostId, h1.getId());
assertEquals(blog2.getId(), h1.getGroupId());
assertNull(h1.getParentId());
assertEquals(VERIFIED, h1.getAuthorStatus());
assertEquals(localAuthor1, h1.getAuthor());
assertEquals(h1.getId(), ((BlogCommentHeader) h).getRootPost().getId());
}
@Test
public void testAddLocalCommentToRemoteRssPost() throws Exception {
final Transaction txn = new Transaction(null, false);
// The post was originally posted to the RSS blog, then reblogged to
// blog 1 with a comment
final BdfList originalPostBody = BdfList.of("originalPostBody");
final MessageId wrappedPostId = new MessageId(getRandomId());
final Message wrappedPostMsg = new Message(wrappedPostId, blog1.getId(),
timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary wrappedPostMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, WRAPPED_POST.getInt()),
new BdfEntry(KEY_RSS_FEED, true),
new BdfEntry(KEY_ORIGINAL_MSG_ID, rssMessageId),
new BdfEntry(KEY_AUTHOR, rssAuthorDict),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived)
);
final MessageId commentId = new MessageId(getRandomId());
final Message commentMsg = new Message(commentId, blog1.getId(),
timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary commentMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, COMMENT.getInt()),
new BdfEntry(KEY_COMMENT, comment),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, rssMessageId),
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
new BdfEntry(KEY_AUTHOR, authorDict1)
);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
// Wrap the original post for blog 1
oneOf(clientHelper).getMessageAsList(txn, rssMessageId);
will(returnValue(originalPostBody));
oneOf(db).getGroup(txn, rssBlog.getId());
will(returnValue(rssBlog.getGroup()));
oneOf(blogPostFactory).wrapPost(blog1.getId(),
rssBlog.getGroup().getDescriptor(), timestamp,
originalPostBody);
will(returnValue(wrappedPostMsg));
// Store the wrapped post
oneOf(clientHelper).addLocalMessage(txn, wrappedPostMsg,
wrappedPostMeta, true);
// Create the comment
oneOf(blogPostFactory).createBlogComment(blog1.getId(),
localAuthor1, comment, rssMessageId, wrappedPostId);
will(returnValue(commentMsg));
// Store the comment
oneOf(clientHelper).addLocalMessage(txn, commentMsg, commentMeta,
true);
// Create the headers for the comment and the wrapped post
oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
will(returnValue(OURSELVES));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
wrappedPostId);
will(returnValue(wrappedPostMeta));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
rssBlog.getId(), rssMessageId, null, timestamp, timeReceived,
rssLocalAuthor, NONE, true, true);
blogManager.addLocalComment(localAuthor1, blog1.getId(), comment,
originalPostHeader);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(blog1.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(COMMENT, h.getType());
assertFalse(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(commentId, h.getId());
assertEquals(blog1.getId(), h.getGroupId());
assertEquals(wrappedPostId, h.getParentId());
assertEquals(OURSELVES, h.getAuthorStatus());
assertEquals(localAuthor1, h.getAuthor());
assertTrue(h instanceof BlogCommentHeader);
BlogPostHeader h1 = ((BlogCommentHeader) h).getParent();
assertEquals(WRAPPED_POST, h1.getType());
assertTrue(h1.isRssFeed());
assertEquals(timestamp, h1.getTimestamp());
assertEquals(timeReceived, h1.getTimeReceived());
assertEquals(wrappedPostId, h1.getId());
assertEquals(blog1.getId(), h1.getGroupId());
assertNull(h1.getParentId());
assertEquals(NONE, h1.getAuthorStatus());
assertEquals(rssLocalAuthor, h1.getAuthor());
assertEquals(h1.getId(), ((BlogCommentHeader) h).getRootPost().getId());
}
@Test
public void testAddLocalCommentToRebloggedRemoteRssPost() throws Exception {
final Transaction txn = new Transaction(null, false);
// The post was originally posted to the RSS blog, then reblogged to
// blog 1 with a comment
final MessageId wrappedPostId = new MessageId(getRandomId());
final BdfList wrappedPostBody = BdfList.of("wrappedPostBody");
final MessageId originalCommentId = new MessageId(getRandomId());
final BdfList originalCommentBody = BdfList.of("originalCommentBody");
// The post and comment were reblogged to blog 2 with another comment
final MessageId rewrappedPostId = new MessageId(getRandomId());
final Message rewrappedPostMsg = new Message(rewrappedPostId,
blog2.getId(), timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary rewrappedPostMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, WRAPPED_POST.getInt()),
new BdfEntry(KEY_RSS_FEED, true),
new BdfEntry(KEY_ORIGINAL_MSG_ID, messageId),
new BdfEntry(KEY_AUTHOR, rssAuthorDict),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived)
);
final MessageId wrappedCommentId = new MessageId(getRandomId());
final Message wrappedCommentMsg = new Message(wrappedCommentId,
blog2.getId(), timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary wrappedCommentMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, WRAPPED_COMMENT.getInt()),
new BdfEntry(KEY_COMMENT, comment),
new BdfEntry(KEY_PARENT_MSG_ID, rewrappedPostId),
new BdfEntry(KEY_ORIGINAL_MSG_ID, originalCommentId),
new BdfEntry(KEY_AUTHOR, authorDict1),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_TIME_RECEIVED, timeReceived)
);
final String localComment = getRandomString(MAX_BLOG_COMMENT_LENGTH);
final MessageId localCommentId = new MessageId(getRandomId());
final Message localCommentMsg = new Message(localCommentId,
blog2.getId(), timestamp, getRandomBytes(MAX_MESSAGE_LENGTH));
final BdfDictionary localCommentMeta = BdfDictionary.of(
new BdfEntry(KEY_TYPE, COMMENT.getInt()),
new BdfEntry(KEY_COMMENT, localComment),
new BdfEntry(KEY_TIMESTAMP, timestamp),
new BdfEntry(KEY_ORIGINAL_MSG_ID, localCommentId),
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, originalCommentId),
new BdfEntry(KEY_PARENT_MSG_ID, wrappedCommentId),
new BdfEntry(KEY_AUTHOR, authorDict2)
);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
// Rewrap the wrapped post for blog 2
oneOf(clientHelper).getMessageAsList(txn, wrappedPostId);
will(returnValue(wrappedPostBody));
oneOf(blogPostFactory).rewrapWrappedPost(blog2.getId(),
wrappedPostBody);
will(returnValue(rewrappedPostMsg));
// Store the rewrapped post
oneOf(clientHelper).addLocalMessage(txn, rewrappedPostMsg,
rewrappedPostMeta, true);
// Wrap the original comment for blog 2
oneOf(clientHelper).getMessageAsList(txn, originalCommentId);
will(returnValue(originalCommentBody));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
wrappedPostId);
will(returnValue(rewrappedPostMeta));
oneOf(db).getGroup(txn, blog1.getId());
will(returnValue(blog1.getGroup()));
oneOf(blogPostFactory).wrapComment(blog2.getId(),
blog1.getGroup().getDescriptor(), timestamp,
originalCommentBody, rewrappedPostId);
will(returnValue(wrappedCommentMsg));
// Store the wrapped comment
oneOf(clientHelper).addLocalMessage(txn, wrappedCommentMsg,
wrappedCommentMeta, true);
// Create the new comment
oneOf(blogPostFactory).createBlogComment(blog2.getId(),
localAuthor2, localComment, originalCommentId,
wrappedCommentId);
will(returnValue(localCommentMsg));
// Store the new comment
oneOf(clientHelper).addLocalMessage(txn, localCommentMsg,
localCommentMeta, true);
// Create the headers for the new comment, the wrapped comment and
// the rewrapped post
oneOf(identityManager).getAuthorStatus(txn, localAuthor2.getId());
will(returnValue(OURSELVES));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
wrappedCommentId);
will(returnValue(wrappedCommentMeta));
oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId());
will(returnValue(VERIFIED));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
rewrappedPostId);
will(returnValue(rewrappedPostMeta));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
BlogPostHeader wrappedPostHeader = new BlogPostHeader(WRAPPED_POST,
blog1.getId(), wrappedPostId, null, timestamp, timeReceived,
rssLocalAuthor, NONE, true, true);
BlogCommentHeader originalCommentHeader = new BlogCommentHeader(COMMENT,
blog1.getId(), comment, wrappedPostHeader, originalCommentId,
timestamp, timeReceived, localAuthor1, VERIFIED, true);
blogManager.addLocalComment(localAuthor2, blog2.getId(), localComment,
originalCommentHeader);
context.assertIsSatisfied();
assertEquals(1, txn.getEvents().size());
assertTrue(txn.getEvents().get(0) instanceof BlogPostAddedEvent);
BlogPostAddedEvent e = (BlogPostAddedEvent) txn.getEvents().get(0);
assertEquals(blog2.getId(), e.getGroupId());
BlogPostHeader h = e.getHeader();
assertEquals(COMMENT, h.getType());
assertFalse(h.isRssFeed());
assertEquals(timestamp, h.getTimestamp());
assertEquals(timestamp, h.getTimeReceived());
assertEquals(localCommentId, h.getId());
assertEquals(blog2.getId(), h.getGroupId());
assertEquals(wrappedCommentId, h.getParentId());
assertEquals(OURSELVES, h.getAuthorStatus());
assertEquals(localAuthor2, h.getAuthor());
assertTrue(h instanceof BlogCommentHeader);
BlogPostHeader h1 = ((BlogCommentHeader) h).getParent();
assertEquals(WRAPPED_COMMENT, h1.getType());
assertFalse(h1.isRssFeed());
assertEquals(timestamp, h1.getTimestamp());
assertEquals(timeReceived, h1.getTimeReceived());
assertEquals(wrappedCommentId, h1.getId());
assertEquals(blog2.getId(), h1.getGroupId());
assertEquals(rewrappedPostId, h1.getParentId());
assertEquals(VERIFIED, h1.getAuthorStatus());
assertEquals(localAuthor1, h1.getAuthor());
assertTrue(h1 instanceof BlogCommentHeader);
BlogPostHeader h2 = ((BlogCommentHeader) h1).getParent();
assertEquals(WRAPPED_POST, h2.getType());
assertTrue(h2.isRssFeed());
assertEquals(timestamp, h2.getTimestamp());
assertEquals(timeReceived, h2.getTimeReceived());
assertEquals(rewrappedPostId, h2.getId());
assertEquals(blog2.getId(), h2.getGroupId());
assertNull(h2.getParentId());
assertEquals(NONE, h2.getAuthorStatus());
assertEquals(rssLocalAuthor, h2.getAuthor());
assertEquals(h2.getId(), ((BlogCommentHeader) h).getRootPost().getId());
assertEquals(h2.getId(),
((BlogCommentHeader) h1).getRootPost().getId());
} }
@Test @Test
@@ -262,17 +822,17 @@ public class BlogManagerImplTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
private Blog createBlog() { private LocalAuthor createLocalAuthor() {
final GroupId groupId = new GroupId(getRandomId()); return new LocalAuthor(new AuthorId(getRandomId()),
final Group group = new Group(groupId, CLIENT_ID, getRandomBytes(42)); getRandomString(MAX_AUTHOR_NAME_LENGTH),
final AuthorId authorId = new AuthorId(getRandomId()); getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
final byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); getRandomBytes(123), System.currentTimeMillis());
final byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); }
final long created = System.currentTimeMillis();
final LocalAuthor localAuthor = private Blog createBlog(LocalAuthor localAuthor, boolean rssFeed) {
new LocalAuthor(authorId, "Author", publicKey, privateKey, GroupId groupId = new GroupId(getRandomId());
created); Group group = new Group(groupId, CLIENT_ID, getRandomBytes(42));
return new Blog(group, localAuthor, false); return new Blog(group, localAuthor, rssFeed);
} }
private BdfDictionary authorToBdfDictionary(Author a) { private BdfDictionary authorToBdfDictionary(Author a) {
@@ -283,4 +843,4 @@ public class BlogManagerImplTest extends BriarTestCase {
); );
} }
} }