diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/Bytes.java b/bramble-api/src/main/java/org/briarproject/bramble/api/Bytes.java index 5c9b61f40873694903dfb9a393ede6af72069fcb..1a862bbd87b28d70d0d5121f08a2d1378c95a27d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/Bytes.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/Bytes.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.api; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.util.StringUtils; import java.util.Arrays; import java.util.Comparator; @@ -53,6 +54,12 @@ public class Bytes implements Comparable<Bytes> { return aBytes.length - bBytes.length; } + @Override + public String toString() { + return getClass().getSimpleName() + + "(" + StringUtils.toHexString(getBytes()) + ")"; + } + public static class BytesComparator implements Comparator<Bytes> { @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java index cc7dc13fc319b466cc28437c25ebdf0695795488..bc56ac377b7139a14d31518c763a169769ac7a0c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java @@ -60,7 +60,7 @@ public interface BlogManager { * Adds a comment to an existing blog post or reblogs it. */ void addLocalComment(LocalAuthor author, GroupId groupId, - @Nullable String comment, BlogPostHeader wHeader) + @Nullable String comment, BlogPostHeader parentHeader) throws DbException; /** diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostFactory.java index 4a64c27323232acff7bf2d957ecbdc4c2f4432f8..6a07a18c22f4dcee7a275e010bc598cd5d5c5a6a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostFactory.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostFactory.java @@ -25,7 +25,8 @@ public interface BlogPostFactory { throws FormatException, GeneralSecurityException; Message createBlogComment(GroupId groupId, LocalAuthor author, - @Nullable String comment, MessageId originalId, MessageId wrappedId) + @Nullable String comment, MessageId parentOriginalId, + MessageId parentCurrentId) throws FormatException, GeneralSecurityException; /** @@ -44,11 +45,11 @@ public interface BlogPostFactory { * Wraps a blog comment */ 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 */ Message rewrapWrappedComment(GroupId groupId, BdfList body, - MessageId currentId) throws FormatException; + MessageId parentCurrentId) throws FormatException; } diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index 02e4f1eae7ca22012e7cae4f336401a0ba7a94a1..cad04aa7ea64eb23156db131649029475e9e12a5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -232,7 +232,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, addLocalPost(txn, p); db.commitTransaction(txn); } finally { - //noinspection ThrowFromFinallyBlock db.endTransaction(txn); } } @@ -255,8 +254,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, MessageId postId = p.getMessage().getId(); BlogPostHeader h = getPostHeaderFromMetadata(txn, groupId, postId, meta); - BlogPostAddedEvent event = - new BlogPostAddedEvent(groupId, h, true); + BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true); txn.attach(event); } catch (FormatException e) { throw new DbException(e); @@ -265,42 +263,39 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Override public void addLocalComment(LocalAuthor author, GroupId groupId, - @Nullable String comment, BlogPostHeader pOriginalHeader) + @Nullable String comment, BlogPostHeader parentHeader) throws DbException { - MessageType type = pOriginalHeader.getType(); + MessageType type = parentHeader.getType(); if (type != POST && type != COMMENT) throw new IllegalArgumentException("Comment on unknown type!"); Transaction txn = db.startTransaction(false); try { // Wrap post that we are commenting on - MessageId parentId = wrapMessage(txn, groupId, pOriginalHeader); - - // Get ID of new parent's original message. - // Assumes that pOriginalHeader is a POST or COMMENT - MessageId pOriginalId = pOriginalHeader.getId(); + MessageId parentOriginalId = + getOriginalMessageId(txn, parentHeader); + MessageId parentCurrentId = + wrapMessage(txn, groupId, parentHeader, parentOriginalId); // Create actual comment - Message message = blogPostFactory - .createBlogComment(groupId, author, comment, pOriginalId, - parentId); + Message message = blogPostFactory.createBlogComment(groupId, author, + comment, parentOriginalId, parentCurrentId); BdfDictionary meta = new BdfDictionary(); meta.put(KEY_TYPE, COMMENT.getInt()); if (comment != null) meta.put(KEY_COMMENT, comment); meta.put(KEY_TIMESTAMP, message.getTimestamp()); meta.put(KEY_ORIGINAL_MSG_ID, message.getId()); - meta.put(KEY_ORIGINAL_PARENT_MSG_ID, pOriginalId); - meta.put(KEY_PARENT_MSG_ID, parentId); + meta.put(KEY_ORIGINAL_PARENT_MSG_ID, parentOriginalId); + meta.put(KEY_PARENT_MSG_ID, parentCurrentId); meta.put(KEY_AUTHOR, authorToBdfDictionary(author)); // Send comment clientHelper.addLocalMessage(txn, message, meta, true); // broadcast event - BlogPostHeader h = - getPostHeaderFromMetadata(txn, groupId, message.getId(), - meta); + BlogPostHeader h = getPostHeaderFromMetadata(txn, groupId, + message.getId(), meta); BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true); txn.attach(event); db.commitTransaction(txn); @@ -309,81 +304,94 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, } catch (GeneralSecurityException e) { throw new IllegalArgumentException("Invalid key of author", e); } finally { - //noinspection ThrowFromFinallyBlock 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, - BlogPostHeader pOriginalHeader) + BlogPostHeader header, MessageId originalId) 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. // This is unnecessary, so just return the post's MessageId - return pOriginalHeader.getId(); + return header.getId(); } // Get body of message to be wrapped - BdfList body = - clientHelper.getMessageAsList(txn, pOriginalHeader.getId()); + BdfList body = clientHelper.getMessageAsList(txn, header.getId()); if (body == null) throw new DbException(); - long wTimestamp = pOriginalHeader.getTimestamp(); - Message wMessage; + long timestamp = header.getTimestamp(); + Message wrappedMessage; BdfDictionary meta = new BdfDictionary(); - MessageType type = pOriginalHeader.getType(); + MessageType type = header.getType(); if (type == POST) { - Group wGroup = db.getGroup(txn, pOriginalHeader.getGroupId()); - byte[] wDescriptor = wGroup.getDescriptor(); // Wrap post - wMessage = blogPostFactory - .wrapPost(groupId, wDescriptor, wTimestamp, body); + Group group = db.getGroup(txn, header.getGroupId()); + byte[] descriptor = group.getDescriptor(); + wrappedMessage = blogPostFactory.wrapPost(groupId, descriptor, + timestamp, body); 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) { - Group wGroup = db.getGroup(txn, pOriginalHeader.getGroupId()); - byte[] wDescriptor = wGroup.getDescriptor(); - BlogCommentHeader wComment = (BlogCommentHeader) pOriginalHeader; - MessageId wrappedId = - wrapMessage(txn, groupId, wComment.getParent()); + // Recursively wrap parent + BlogCommentHeader commentHeader = (BlogCommentHeader) header; + BlogPostHeader parentHeader = commentHeader.getParent(); + MessageId parentOriginalId = + getOriginalMessageId(txn, parentHeader); + MessageId parentCurrentId = + wrapMessage(txn, groupId, parentHeader, parentOriginalId); // Wrap comment - wMessage = blogPostFactory - .wrapComment(groupId, wDescriptor, wTimestamp, - body, wrappedId); + Group group = db.getGroup(txn, header.getGroupId()); + byte[] descriptor = group.getDescriptor(); + wrappedMessage = blogPostFactory.wrapComment(groupId, descriptor, + timestamp, body, parentCurrentId); meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt()); - if (wComment.getComment() != null) - meta.put(KEY_COMMENT, wComment.getComment()); - meta.put(KEY_PARENT_MSG_ID, wrappedId); + if (commentHeader.getComment() != null) + meta.put(KEY_COMMENT, commentHeader.getComment()); + meta.put(KEY_PARENT_MSG_ID, parentCurrentId); } else if (type == WRAPPED_POST) { // 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_RSS_FEED, pOriginalHeader.isRssFeed()); + meta.put(KEY_RSS_FEED, header.isRssFeed()); } else if (type == WRAPPED_COMMENT) { - BlogCommentHeader wComment = (BlogCommentHeader) pOriginalHeader; - MessageId wrappedId = - wrapMessage(txn, groupId, wComment.getParent()); + // Recursively wrap parent + BlogCommentHeader commentHeader = (BlogCommentHeader) header; + BlogPostHeader parentHeader = commentHeader.getParent(); + MessageId parentOriginalId = + getOriginalMessageId(txn, parentHeader); + MessageId parentCurrentId = + wrapMessage(txn, groupId, parentHeader, parentOriginalId); // Re-wrap wrapped comment - wMessage = blogPostFactory - .rewrapWrappedComment(groupId, body, wrappedId); + wrappedMessage = blogPostFactory.rewrapWrappedComment(groupId, body, + parentCurrentId); meta.put(KEY_TYPE, WRAPPED_COMMENT.getInt()); - if (wComment.getComment() != null) - meta.put(KEY_COMMENT, wComment.getComment()); - meta.put(KEY_PARENT_MSG_ID, wrappedId); + if (commentHeader.getComment() != null) + meta.put(KEY_COMMENT, commentHeader.getComment()); + meta.put(KEY_PARENT_MSG_ID, parentCurrentId); } else { throw new IllegalArgumentException( "Unknown Message Type: " + type); } - meta.put(KEY_ORIGINAL_MSG_ID, pOriginalHeader.getId()); - meta.put(KEY_AUTHOR, - authorToBdfDictionary(pOriginalHeader.getAuthor())); - meta.put(KEY_TIMESTAMP, pOriginalHeader.getTimestamp()); - meta.put(KEY_TIME_RECEIVED, pOriginalHeader.getTimeReceived()); + meta.put(KEY_ORIGINAL_MSG_ID, originalId); + meta.put(KEY_AUTHOR, authorToBdfDictionary(header.getAuthor())); + meta.put(KEY_TIMESTAMP, header.getTimestamp()); + meta.put(KEY_TIME_RECEIVED, header.getTimeReceived()); // Send wrapped message and store metadata - clientHelper.addLocalMessage(txn, wMessage, meta, true); - return wMessage.getId(); + clientHelper.addLocalMessage(txn, wrappedMessage, meta, true); + return wrappedMessage.getId(); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostFactoryImpl.java index b8fd8b7e32e85c816ec766921d043dcbd4b58b08..bd89a0ba81930ea31b2416f1386a642938d1e0f3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostFactoryImpl.java @@ -65,7 +65,8 @@ class BlogPostFactoryImpl implements BlogPostFactory { @Override public Message createBlogComment(GroupId groupId, LocalAuthor author, - @Nullable String comment, MessageId pOriginalId, MessageId parentId) + @Nullable String comment, MessageId parentOriginalId, + MessageId parentCurrentId) throws FormatException, GeneralSecurityException { if (comment != null) { @@ -78,22 +79,20 @@ class BlogPostFactoryImpl implements BlogPostFactory { long timestamp = clock.currentTimeMillis(); // Generate the signature - BdfList signed = - BdfList.of(groupId, timestamp, comment, pOriginalId, parentId); + BdfList signed = BdfList.of(groupId, timestamp, comment, + parentOriginalId, parentCurrentId); byte[] sig = clientHelper .sign(SIGNING_LABEL_COMMENT, signed, author.getPrivateKey()); // Serialise the signed message - BdfList message = - BdfList.of(COMMENT.getInt(), comment, pOriginalId, parentId, - sig); + BdfList message = BdfList.of(COMMENT.getInt(), comment, + parentOriginalId, parentCurrentId, sig); return clientHelper.createMessage(groupId, timestamp, message); } @Override public Message wrapPost(GroupId groupId, byte[] descriptor, - long timestamp, BdfList body) - throws FormatException { + long timestamp, BdfList body) throws FormatException { if (getType(body) != POST) throw new IllegalArgumentException("Needs to wrap a POST"); @@ -101,9 +100,8 @@ class BlogPostFactoryImpl implements BlogPostFactory { // Serialise the message String content = body.getString(1); byte[] signature = body.getRaw(2); - BdfList message = - BdfList.of(WRAPPED_POST.getInt(), descriptor, timestamp, - content, signature); + BdfList message = BdfList.of(WRAPPED_POST.getInt(), descriptor, + timestamp, content, signature); return clientHelper .createMessage(groupId, clock.currentTimeMillis(), message); } @@ -120,16 +118,15 @@ class BlogPostFactoryImpl implements BlogPostFactory { long timestamp = body.getLong(2); String content = body.getString(3); byte[] signature = body.getRaw(4); - BdfList message = - BdfList.of(WRAPPED_POST.getInt(), descriptor, timestamp, - content, signature); + BdfList message = BdfList.of(WRAPPED_POST.getInt(), descriptor, + timestamp, content, signature); return clientHelper .createMessage(groupId, clock.currentTimeMillis(), message); } @Override public Message wrapComment(GroupId groupId, byte[] descriptor, - long timestamp, BdfList body, MessageId parentId) + long timestamp, BdfList body, MessageId parentCurrentId) throws FormatException { if (getType(body) != COMMENT) @@ -140,16 +137,16 @@ class BlogPostFactoryImpl implements BlogPostFactory { byte[] pOriginalId = body.getRaw(2); byte[] oldParentId = body.getRaw(3); byte[] signature = body.getRaw(4); - BdfList message = - BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, timestamp, - comment, pOriginalId, oldParentId, signature, parentId); + BdfList message = BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, + timestamp, comment, pOriginalId, oldParentId, signature, + parentCurrentId); return clientHelper .createMessage(groupId, clock.currentTimeMillis(), message); } @Override public Message rewrapWrappedComment(GroupId groupId, BdfList body, - MessageId parentId) throws FormatException { + MessageId parentCurrentId) throws FormatException { if (getType(body) != WRAPPED_COMMENT) throw new IllegalArgumentException( @@ -162,9 +159,9 @@ class BlogPostFactoryImpl implements BlogPostFactory { byte[] pOriginalId = body.getRaw(4); byte[] oldParentId = body.getRaw(5); byte[] signature = body.getRaw(6); - BdfList message = - BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, timestamp, - comment, pOriginalId, oldParentId, signature, parentId); + BdfList message = BdfList.of(WRAPPED_COMMENT.getInt(), descriptor, + timestamp, comment, pOriginalId, oldParentId, signature, + parentCurrentId); return clientHelper .createMessage(groupId, clock.currentTimeMillis(), message); } diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java index 5b9cee48ccac949bf0f0a4887825a52a8a7c45e9..3678f1aba2bfa5e2a794935ceee7843f6a19a0da 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java @@ -20,6 +20,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; 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.BlogPost; import org.briarproject.briar.api.blog.BlogPostFactory; @@ -33,24 +34,38 @@ import org.junit.Test; import java.util.Collection; 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.AuthorConstants.MAX_AUTHOR_NAME_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.SyncConstants.MAX_MESSAGE_LENGTH; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; 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_ID; 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_READ; 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_TIME_RECEIVED; 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.MessageType.COMMENT; 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.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class BlogManagerImplTest extends BriarTestCase { @@ -62,21 +77,40 @@ public class BlogManagerImplTest extends BriarTestCase { context.mock(IdentityManager.class); private final ClientHelper clientHelper = context.mock(ClientHelper.class); private final BlogFactory blogFactory = context.mock(BlogFactory.class); + private final BlogPostFactory blogPostFactory = + context.mock(BlogPostFactory.class); - private final Blog blog1, blog2; - private final Message message; - private final MessageId messageId; + private final LocalAuthor localAuthor1, localAuthor2, rssLocalAuthor; + private final BdfDictionary authorDict1, authorDict2, rssAuthorDict; + 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() { MetadataParser metadataParser = context.mock(MetadataParser.class); - BlogPostFactory blogPostFactory = context.mock(BlogPostFactory.class); blogManager = new BlogManagerImpl(db, identityManager, clientHelper, metadataParser, blogFactory, blogPostFactory); - blog1 = createBlog(); - blog2 = createBlog(); + localAuthor1 = createLocalAuthor(); + 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()); - 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 @@ -135,23 +169,22 @@ public class BlogManagerImplTest extends BriarTestCase { @Test public void testIncomingMessage() throws DbException, FormatException { final Transaction txn = new Transaction(null, false); - BdfList list = new BdfList(); - BdfDictionary author = authorToBdfDictionary(blog1.getAuthor()); + BdfList body = BdfList.of("body"); BdfDictionary meta = BdfDictionary.of( new BdfEntry(KEY_TYPE, POST.getInt()), - new BdfEntry(KEY_TIMESTAMP, 0), - new BdfEntry(KEY_TIME_RECEIVED, 1), - new BdfEntry(KEY_AUTHOR, author), - new BdfEntry(KEY_READ, false) + new BdfEntry(KEY_TIMESTAMP, timestamp), + new BdfEntry(KEY_TIME_RECEIVED, timeReceived), + new BdfEntry(KEY_AUTHOR, authorDict1), + new BdfEntry(KEY_READ, false), + new BdfEntry(KEY_RSS_FEED, false) ); context.checking(new Expectations() {{ - oneOf(identityManager) - .getAuthorStatus(txn, blog1.getAuthor().getId()); + oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId()); will(returnValue(VERIFIED)); }}); - blogManager.incomingMessage(txn, message, list, meta); + blogManager.incomingMessage(txn, message, body, meta); context.assertIsSatisfied(); assertEquals(1, txn.getEvents().size()); @@ -161,11 +194,49 @@ public class BlogManagerImplTest extends BriarTestCase { assertEquals(blog1.getId(), e.getGroupId()); 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(null, h.getParentId()); + assertEquals(blog1.getId(), h.getGroupId()); + assertNull(h.getParentId()); 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 @@ -189,13 +260,11 @@ public class BlogManagerImplTest extends BriarTestCase { @Test public void testAddLocalPost() throws DbException, FormatException { final Transaction txn = new Transaction(null, false); - final BlogPost post = - new BlogPost(message, null, blog1.getAuthor()); - BdfDictionary authorMeta = authorToBdfDictionary(blog1.getAuthor()); + final BlogPost post = new BlogPost(message, null, localAuthor1); final BdfDictionary meta = BdfDictionary.of( new BdfEntry(KEY_TYPE, POST.getInt()), - new BdfEntry(KEY_TIMESTAMP, message.getTimestamp()), - new BdfEntry(KEY_AUTHOR, authorMeta), + new BdfEntry(KEY_TIMESTAMP, timestamp), + new BdfEntry(KEY_AUTHOR, authorDict1), new BdfEntry(KEY_READ, true), new BdfEntry(KEY_RSS_FEED, false) ); @@ -207,11 +276,9 @@ public class BlogManagerImplTest extends BriarTestCase { will(returnValue(blog1.getGroup())); oneOf(blogFactory).parseBlog(blog1.getGroup()); will(returnValue(blog1)); - oneOf(clientHelper) - .addLocalMessage(txn, message, meta, true); - oneOf(identityManager) - .getAuthorStatus(txn, blog1.getAuthor().getId()); - will(returnValue(VERIFIED)); + oneOf(clientHelper).addLocalMessage(txn, message, meta, true); + oneOf(identityManager).getAuthorStatus(txn, localAuthor1.getId()); + will(returnValue(OURSELVES)); oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); }}); @@ -226,11 +293,504 @@ public class BlogManagerImplTest extends BriarTestCase { assertEquals(blog1.getId(), e.getGroupId()); 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(null, h.getParentId()); - assertEquals(VERIFIED, h.getAuthorStatus()); - assertEquals(blog1.getAuthor(), h.getAuthor()); + assertEquals(blog1.getId(), h.getGroupId()); + assertNull(h.getParentId()); + 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 @@ -262,17 +822,17 @@ public class BlogManagerImplTest extends BriarTestCase { context.assertIsSatisfied(); } - private Blog createBlog() { - final GroupId groupId = new GroupId(getRandomId()); - final Group group = new Group(groupId, CLIENT_ID, getRandomBytes(42)); - final AuthorId authorId = new AuthorId(getRandomId()); - final byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); - final byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); - final long created = System.currentTimeMillis(); - final LocalAuthor localAuthor = - new LocalAuthor(authorId, "Author", publicKey, privateKey, - created); - return new Blog(group, localAuthor, false); + private LocalAuthor createLocalAuthor() { + return new LocalAuthor(new AuthorId(getRandomId()), + getRandomString(MAX_AUTHOR_NAME_LENGTH), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH), + getRandomBytes(123), System.currentTimeMillis()); + } + + private Blog createBlog(LocalAuthor localAuthor, boolean rssFeed) { + GroupId groupId = new GroupId(getRandomId()); + Group group = new Group(groupId, CLIENT_ID, getRandomBytes(42)); + return new Blog(group, localAuthor, rssFeed); } private BdfDictionary authorToBdfDictionary(Author a) { @@ -283,4 +843,4 @@ public class BlogManagerImplTest extends BriarTestCase { ); } -} +} \ No newline at end of file