halo/application/src/test/java/run/halo/app/content/comment/CommentNotificationReasonPu...

471 lines
18 KiB
Java

package run.halo.app.content.comment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.assertArg;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono;
import run.halo.app.content.NotificationReasonConst;
import run.halo.app.core.extension.User;
import run.halo.app.core.extension.content.Comment;
import run.halo.app.core.extension.content.Post;
import run.halo.app.core.extension.content.Reply;
import run.halo.app.core.extension.content.SinglePage;
import run.halo.app.core.extension.notification.Reason;
import run.halo.app.event.post.CommentCreatedEvent;
import run.halo.app.event.post.ReplyCreatedEvent;
import run.halo.app.extension.ExtensionClient;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.Metadata;
import run.halo.app.extension.Ref;
import run.halo.app.infra.ExternalLinkProcessor;
import run.halo.app.notification.NotificationReasonEmitter;
import run.halo.app.notification.ReasonPayload;
import run.halo.app.notification.UserIdentity;
import run.halo.app.plugin.ExtensionComponentsFinder;
/**
* Tests for {@link CommentNotificationReasonPublisher}.
*
* @author guqing
* @since 2.9.0
*/
@ExtendWith(MockitoExtension.class)
class CommentNotificationReasonPublisherTest {
@Mock
private ExtensionClient client;
@Mock
CommentNotificationReasonPublisher.NewCommentOnPostReasonPublisher
newCommentOnPostReasonPublisher;
@Mock
CommentNotificationReasonPublisher.NewCommentOnPageReasonPublisher
newCommentOnPageReasonPublisher;
@Mock
CommentNotificationReasonPublisher.NewReplyReasonPublisher newReplyReasonPublisher;
@InjectMocks
private CommentNotificationReasonPublisher reasonPublisher;
@Test
void onNewCommentTest() {
var comment = mock(Comment.class);
var spyReasonPublisher = spy(reasonPublisher);
doReturn(true).when(spyReasonPublisher).isPostComment(eq(comment));
var event = new CommentCreatedEvent(this, comment);
spyReasonPublisher.onNewComment(event);
verify(newCommentOnPostReasonPublisher).publishReasonBy(eq(comment));
doReturn(false).when(spyReasonPublisher).isPostComment(eq(comment));
doReturn(true).when(spyReasonPublisher).isPageComment(eq(comment));
spyReasonPublisher.onNewComment(event);
verify(newCommentOnPageReasonPublisher).publishReasonBy(eq(comment));
}
@Test
void onNewReplyTest() {
var reply = mock(Reply.class);
var spec = mock(Reply.ReplySpec.class);
when(reply.getSpec()).thenReturn(spec);
when(spec.getCommentName()).thenReturn("fake-comment");
var spyReasonPublisher = spy(reasonPublisher);
var comment = mock(Comment.class);
when(client.fetch(eq(Comment.class), eq("fake-comment")))
.thenReturn(Optional.of(comment));
var event = new ReplyCreatedEvent(this, reply);
spyReasonPublisher.onNewReply(event);
verify(newReplyReasonPublisher).publishReasonBy(eq(reply), eq(comment));
verify(spec).getCommentName();
verify(client).fetch(eq(Comment.class), eq("fake-comment"));
}
@Test
void isPostCommentTest() {
var comment = createComment();
comment.getSpec()
.setSubjectRef(Ref.of("fake-post", GroupVersionKind.fromExtension(Post.class)));
assertThat(reasonPublisher.isPostComment(comment)).isTrue();
comment.getSpec()
.setSubjectRef(Ref.of("fake-post", GroupVersionKind.fromExtension(SinglePage.class)));
assertThat(reasonPublisher.isPostComment(comment)).isFalse();
}
@Test
void isPageComment() {
var comment = createComment();
comment.getSpec()
.setSubjectRef(Ref.of("fake-post", GroupVersionKind.fromExtension(Post.class)));
assertThat(reasonPublisher.isPageComment(comment)).isFalse();
comment.getSpec()
.setSubjectRef(Ref.of("fake-post", GroupVersionKind.fromExtension(SinglePage.class)));
assertThat(reasonPublisher.isPageComment(comment)).isTrue();
}
@Nested
class NewCommentOnPostReasonPublisherTest {
@Mock
ExtensionClient client;
@Mock
NotificationReasonEmitter emitter;
@Mock
ExtensionComponentsFinder extensionComponentsFinder;
@Mock
ExternalLinkProcessor externalLinkProcessor;
@InjectMocks
CommentNotificationReasonPublisher.NewCommentOnPostReasonPublisher
newCommentOnPostReasonPublisher;
@Test
void publishReasonByTest() {
final var comment = createComment();
comment.getSpec().getOwner().setDisplayName("fake-display-name");
comment.getSpec().setContent("fake-comment-content");
var post = mock(Post.class);
final var spec = mock(Post.PostSpec.class);
var metadata = new Metadata();
metadata.setName("fake-post");
when(post.getMetadata()).thenReturn(metadata);
when(post.getStatusOrDefault()).thenReturn(new Post.PostStatus());
when(post.getSpec()).thenReturn(spec);
when(spec.getTitle()).thenReturn("fake-title");
when(client.fetch(eq(Post.class), eq(metadata.getName())))
.thenReturn(Optional.of(post));
when(emitter.emit(eq("new-comment-on-post"), any()))
.thenReturn(Mono.empty());
newCommentOnPostReasonPublisher.publishReasonBy(comment);
verify(client).fetch(eq(Post.class), eq(metadata.getName()));
verify(emitter).emit(eq("new-comment-on-post"), assertArg(consumer -> {
var builder = ReasonPayload.builder();
consumer.accept(builder);
var reasonPayload = builder.build();
var reasonSubject = Reason.Subject.builder()
.apiVersion(post.getApiVersion())
.kind(post.getKind())
.name(post.getMetadata().getName())
.title(post.getSpec().getTitle())
.build();
assertThat(reasonPayload.getSubject()).isEqualTo(reasonSubject);
assertThat(reasonPayload.getAuthor())
.isEqualTo(
UserIdentity.anonymousWithEmail(comment.getSpec().getOwner().getName()));
assertThat(reasonPayload.getAttributes()).containsAllEntriesOf(Map.of(
"postName", post.getMetadata().getName(),
"postTitle", post.getSpec().getTitle(),
"commenter", comment.getSpec().getOwner().getDisplayName(),
"content", comment.getSpec().getContent(),
"commentName", comment.getMetadata().getName()
));
}));
}
@Test
void doNotEmitReasonTest() {
final var comment = createComment();
var commentOwner = new Comment.CommentOwner();
commentOwner.setKind(User.KIND);
commentOwner.setName("fake-user");
comment.getSpec().setOwner(commentOwner);
var post = new Post();
post.setMetadata(new Metadata());
post.getMetadata().setName("fake-post");
post.setSpec(new Post.PostSpec());
post.getSpec().setOwner("fake-user");
// the username is the same as the comment owner
assertThat(newCommentOnPostReasonPublisher.doNotEmitReason(comment, post)).isTrue();
// not the same username
commentOwner.setName("other");
assertThat(newCommentOnPostReasonPublisher.doNotEmitReason(comment, post)).isFalse();
// the comment owner is email and the same as the post-owner user email
commentOwner.setKind(Comment.CommentOwner.KIND_EMAIL);
commentOwner.setName("example@example.com");
var user = new User();
user.setSpec(new User.UserSpec());
user.getSpec().setEmail("example@example.com");
when(client.fetch(eq(User.class), eq("fake-user")))
.thenReturn(Optional.of(user));
assertThat(newCommentOnPostReasonPublisher.doNotEmitReason(comment, post)).isTrue();
// the comment owner is email and not the same as the post-owner user email
user.getSpec().setEmail("fake@example.com");
assertThat(newCommentOnPostReasonPublisher.doNotEmitReason(comment, post)).isFalse();
}
}
@Nested
class NewCommentOnPageReasonPublisherTest {
@Mock
ExtensionClient client;
@Mock
NotificationReasonEmitter emitter;
@Mock
ExtensionComponentsFinder extensionComponentsFinder;
@Mock
ExternalLinkProcessor externalLinkProcessor;
@InjectMocks
CommentNotificationReasonPublisher.NewCommentOnPageReasonPublisher
newCommentOnPageReasonPublisher;
@Test
void publishReasonByTest() {
final var comment = createComment();
comment.getSpec().getOwner().setDisplayName("fake-display-name");
comment.getSpec().setContent("fake-comment-content");
comment.getSpec().setSubjectRef(
Ref.of("fake-page", GroupVersionKind.fromExtension(SinglePage.class)));
var page = mock(SinglePage.class);
final var spec = mock(SinglePage.SinglePageSpec.class);
var metadata = new Metadata();
metadata.setName("fake-page");
when(page.getMetadata()).thenReturn(metadata);
when(page.getStatusOrDefault()).thenReturn(new SinglePage.SinglePageStatus());
when(page.getSpec()).thenReturn(spec);
when(spec.getTitle()).thenReturn("fake-title");
when(client.fetch(eq(SinglePage.class), eq(metadata.getName())))
.thenReturn(Optional.of(page));
when(emitter.emit(eq("new-comment-on-single-page"), any()))
.thenReturn(Mono.empty());
newCommentOnPageReasonPublisher.publishReasonBy(comment);
verify(client).fetch(eq(SinglePage.class), eq(metadata.getName()));
verify(emitter).emit(eq("new-comment-on-single-page"), assertArg(consumer -> {
var builder = ReasonPayload.builder();
consumer.accept(builder);
var reasonPayload = builder.build();
var reasonSubject = Reason.Subject.builder()
.apiVersion(page.getApiVersion())
.kind(page.getKind())
.name(page.getMetadata().getName())
.title(page.getSpec().getTitle())
.build();
assertThat(reasonPayload.getSubject()).isEqualTo(reasonSubject);
assertThat(reasonPayload.getAuthor())
.isEqualTo(
UserIdentity.anonymousWithEmail(comment.getSpec().getOwner().getName()));
assertThat(reasonPayload.getAttributes()).containsAllEntriesOf(Map.of(
"pageName", page.getMetadata().getName(),
"pageTitle", page.getSpec().getTitle(),
"commenter", comment.getSpec().getOwner().getDisplayName(),
"content", comment.getSpec().getContent(),
"commentName", comment.getMetadata().getName()
));
}));
}
@Test
void doNotEmitReasonTest() {
final var comment = createComment();
var commentOwner = new Comment.CommentOwner();
commentOwner.setKind(User.KIND);
commentOwner.setName("fake-user");
comment.getSpec().setOwner(commentOwner);
var page = new SinglePage();
page.setMetadata(new Metadata());
page.getMetadata().setName("fake-page");
page.setSpec(new SinglePage.SinglePageSpec());
page.getSpec().setOwner("fake-user");
// the username is the same as the comment owner
assertThat(newCommentOnPageReasonPublisher.doNotEmitReason(comment, page)).isTrue();
// not the same username
commentOwner.setName("other");
assertThat(newCommentOnPageReasonPublisher.doNotEmitReason(comment, page)).isFalse();
// the comment owner is email and the same as the page-owner user email
commentOwner.setKind(Comment.CommentOwner.KIND_EMAIL);
commentOwner.setName("example@example.com");
var user = new User();
user.setSpec(new User.UserSpec());
user.getSpec().setEmail("example@example.com");
when(client.fetch(eq(User.class), eq("fake-user")))
.thenReturn(Optional.of(user));
assertThat(newCommentOnPageReasonPublisher.doNotEmitReason(comment, page)).isTrue();
// the comment owner is email and not the same as the post-owner user email
user.getSpec().setEmail("fake@example.com");
assertThat(newCommentOnPageReasonPublisher.doNotEmitReason(comment, page)).isFalse();
}
}
@Nested
class NewReplyReasonPublisherTest {
@Mock
ExtensionClient client;
@Mock
NotificationReasonEmitter notificationReasonEmitter;
@Mock
ExtensionComponentsFinder extensionComponentsFinder;
@InjectMocks
CommentNotificationReasonPublisher.NewReplyReasonPublisher newReplyReasonPublisher;
@Test
void publishReasonByTest() {
var reply = createReply("fake-reply");
reply.getSpec().setQuoteReply("fake-quote-reply");
var quoteReply = createReply("fake-quote-reply");
when(client.fetch(eq(Reply.class), eq("fake-quote-reply")))
.thenReturn(Optional.of(quoteReply));
var spyNewReplyReasonPublisher = spy(newReplyReasonPublisher);
var comment = createComment();
comment.getSpec().setContent("fake-comment-content");
doReturn(false).when(spyNewReplyReasonPublisher)
.doNotEmitReason(any(), any(), any());
when(notificationReasonEmitter.emit(any(), any()))
.thenReturn(Mono.empty());
// execute target method
spyNewReplyReasonPublisher.publishReasonBy(reply, comment);
verify(notificationReasonEmitter)
.emit(eq(NotificationReasonConst.SOMEONE_REPLIED_TO_YOU), assertArg(consumer -> {
var builder = ReasonPayload.builder();
consumer.accept(builder);
var reasonPayload = builder.build();
var reasonSubject = Reason.Subject.builder()
.apiVersion(quoteReply.getApiVersion())
.kind(quoteReply.getKind())
.name(quoteReply.getMetadata().getName())
.title(quoteReply.getSpec().getContent())
.build();
assertThat(reasonPayload.getSubject()).isEqualTo(reasonSubject);
assertThat(reasonPayload.getAuthor())
.isEqualTo(
UserIdentity.of(reply.getSpec().getOwner().getName()));
assertThat(reasonPayload.getAttributes()).containsAllEntriesOf(Map.of(
"commentContent", comment.getSpec().getContent(),
"isQuoteReply", true,
"quoteContent", quoteReply.getSpec().getContent(),
"commentName", comment.getMetadata().getName(),
"replier", reply.getSpec().getOwner().getDisplayName(),
"content", reply.getSpec().getContent(),
"replyName", reply.getMetadata().getName()
));
}));
}
@Test
void doNotEmitReasonTest() {
final var currentReply = createReply("current");
currentReply.getSpec().setQuoteReply("quote");
final var quoteReply = createReply("quote");
final var comment = createComment();
assertThat(newReplyReasonPublisher
.doNotEmitReason(currentReply, quoteReply, comment)).isTrue();
currentReply.getSpec().getOwner().setName("other");
assertThat(newReplyReasonPublisher
.doNotEmitReason(currentReply, quoteReply, comment)).isFalse();
currentReply.getSpec().setQuoteReply(null);
assertThat(newReplyReasonPublisher
.doNotEmitReason(currentReply, quoteReply, comment)).isFalse();
currentReply.getSpec().setOwner(comment.getSpec().getOwner());
assertThat(newReplyReasonPublisher
.doNotEmitReason(currentReply, quoteReply, comment)).isTrue();
}
static Reply createReply(String name) {
var reply = new Reply();
reply.setMetadata(new Metadata());
reply.getMetadata().setName(name);
reply.setSpec(new Reply.ReplySpec());
reply.getSpec().setCommentName("fake-comment");
var owner = new Comment.CommentOwner();
owner.setKind(User.KIND);
owner.setName("fake-user");
owner.setDisplayName("fake-display-name");
reply.getSpec().setOwner(owner);
reply.getSpec().setContent("fake-reply-content");
return reply;
}
}
static Comment createComment() {
var comment = new Comment();
comment.setMetadata(new Metadata());
comment.getMetadata().setName("fake-comment");
comment.setSpec(new Comment.CommentSpec());
var commentOwner = new Comment.CommentOwner();
commentOwner.setKind(Comment.CommentOwner.KIND_EMAIL);
commentOwner.setName("example@example.com");
comment.getSpec().setOwner(commentOwner);
comment.getSpec().setSubjectRef(
Ref.of("fake-post", GroupVersionKind.fromExtension(Post.class)));
return comment;
}
}