From b301c8e0748fa39437ea0e97d0f114655903bbe1 Mon Sep 17 00:00:00 2001 From: Mingjie Shao Date: Wed, 24 Nov 2021 09:31:57 +0000 Subject: [PATCH] Mark email as not required parameter in BaseComment (#1535) * Removing email field from the required arguments in comments * Fixed gravatar and added database migration script * Adding validation test cases for PostCommentParam * Added unit test for PostCommentServiceImpl * Address comments: removing identicon in gravatar, renaming migration script * Address comment: removing gravata identicon from CommentProperties * Address comments: Adding more unit tests for comment API * Address comments: Adding integration tests for comment API --- .../halo/app/model/entity/BaseComment.java | 2 +- .../app/model/params/BaseCommentParam.java | 1 - .../service/impl/BaseCommentServiceImpl.java | 4 +- ...ve_notnull_for_email_in_comments_table.sql | 4 + .../java/run/halo/app/it/BaseApiTest.java | 4 +- .../run/halo/app/it/PostCommentApiTest.java | 117 ++++++++++++++++ .../PostCommentParamValidationTest.java | 66 +++++++++ .../impl/PostCommentServiceImplTest.java | 128 ++++++++++++++++++ 8 files changed, 321 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/migration/V5__migrate_remove_notnull_for_email_in_comments_table.sql create mode 100644 src/test/java/run/halo/app/it/PostCommentApiTest.java create mode 100644 src/test/java/run/halo/app/model/params/validation/PostCommentParamValidationTest.java create mode 100644 src/test/java/run/halo/app/service/impl/PostCommentServiceImplTest.java diff --git a/src/main/java/run/halo/app/model/entity/BaseComment.java b/src/main/java/run/halo/app/model/entity/BaseComment.java index 4c8bdd3e..c2151160 100644 --- a/src/main/java/run/halo/app/model/entity/BaseComment.java +++ b/src/main/java/run/halo/app/model/entity/BaseComment.java @@ -51,7 +51,7 @@ public class BaseComment extends BaseEntity { /** * Commentator's email. */ - @Column(name = "email", nullable = false) + @Column(name = "email") private String email; /** diff --git a/src/main/java/run/halo/app/model/params/BaseCommentParam.java b/src/main/java/run/halo/app/model/params/BaseCommentParam.java index 4536a4a2..2cfec172 100644 --- a/src/main/java/run/halo/app/model/params/BaseCommentParam.java +++ b/src/main/java/run/halo/app/model/params/BaseCommentParam.java @@ -24,7 +24,6 @@ public abstract class BaseCommentParam implements InputConverter } if (comment.getGravatarMd5() == null) { - comment.setGravatarMd5(DigestUtils.md5Hex(comment.getEmail())); + comment.setGravatarMd5( + DigestUtils.md5Hex(Optional.ofNullable(comment.getEmail()).orElse(""))); } if (StringUtils.isNotEmpty(comment.getAuthorUrl())) { diff --git a/src/main/resources/migration/V5__migrate_remove_notnull_for_email_in_comments_table.sql b/src/main/resources/migration/V5__migrate_remove_notnull_for_email_in_comments_table.sql new file mode 100644 index 00000000..14fdfbeb --- /dev/null +++ b/src/main/resources/migration/V5__migrate_remove_notnull_for_email_in_comments_table.sql @@ -0,0 +1,4 @@ +-- Remove notnull for email in comments table + +-- Migrate comments Table +alter table comments modify email VARCHAR(255); diff --git a/src/test/java/run/halo/app/it/BaseApiTest.java b/src/test/java/run/halo/app/it/BaseApiTest.java index aac15ac3..69b49a5d 100644 --- a/src/test/java/run/halo/app/it/BaseApiTest.java +++ b/src/test/java/run/halo/app/it/BaseApiTest.java @@ -3,9 +3,9 @@ package run.halo.app.it; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.client.RestTemplate; import run.halo.app.model.params.InstallParam; /** @@ -18,7 +18,7 @@ import run.halo.app.model.params.InstallParam; class BaseApiTest { @Autowired - RestTemplate restTemplate; + TestRestTemplate restTemplate; @LocalServerPort int port; diff --git a/src/test/java/run/halo/app/it/PostCommentApiTest.java b/src/test/java/run/halo/app/it/PostCommentApiTest.java new file mode 100644 index 00000000..cfb350a3 --- /dev/null +++ b/src/test/java/run/halo/app/it/PostCommentApiTest.java @@ -0,0 +1,117 @@ +package run.halo.app.it; + +import java.util.Objects; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; +import run.halo.app.model.dto.BaseCommentDTO; +import run.halo.app.model.params.PostCommentParam; +import run.halo.app.model.support.BaseResponse; + +public class PostCommentApiTest extends BaseApiTest { + + private static final String COMMENT_NULL_EMAIL_GRAVATAR_MD5 = + "d41d8cd98f00b204e9800998ecf8427e"; + + private static final String COMMENT_NULL_EMAIL_AVATAR = + "//gravatar.com/avatar/" + COMMENT_NULL_EMAIL_GRAVATAR_MD5 + "?s=256&d="; + + private static final String COMMENT_AUTHOR_TEST = "TestAuthor"; + + private static final String COMMENT_CONTENT_TEST = "TestContent"; + + private static final String COMMENT_VALID_EMAIL_TEST = "test@example.com"; + + private static final String COMMENT_INVALID_EMAIL_TEST = "hello world"; + + private static final Integer COMMENT_POST_ID_TEST = 1; + + private static final String COMMENT_API_ROUTE = "/api/content/posts/comments"; + + private static final String VALIDATION_VIOLATION_MESSAGE = "字段验证错误,请完善后重试!"; + + private PostCommentParam postCommentParam; + + @BeforeEach + private void setUp() { + installBlog(); + postCommentParam = new PostCommentParam(); + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) + public void testCommentWithNullEmail() { + // Arrange + postCommentParam.setContent(COMMENT_CONTENT_TEST); + postCommentParam.setAuthor(COMMENT_AUTHOR_TEST); + postCommentParam.setPostId(COMMENT_POST_ID_TEST); + HttpEntity request = new HttpEntity<>(postCommentParam); + + // Act + ResponseEntity> + result = restTemplate.exchange(blogUrl + COMMENT_API_ROUTE, HttpMethod.POST, request, + new ParameterizedTypeReference<>() {} + ); + BaseCommentDTO comment = Objects.requireNonNull(result.getBody()).getData(); + + // Assert + Assertions.assertEquals(HttpStatus.OK, result.getStatusCode()); + Assertions.assertEquals(COMMENT_AUTHOR_TEST, comment.getAuthor()); + Assertions.assertEquals(COMMENT_CONTENT_TEST, comment.getContent()); + Assertions.assertNull(comment.getEmail()); + Assertions.assertEquals(COMMENT_NULL_EMAIL_GRAVATAR_MD5, comment.getGravatarMd5()); + Assertions.assertEquals(COMMENT_NULL_EMAIL_AVATAR, comment.getAvatar()); + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) + public void testCommentWithInvalidEmail() { + // Arrange + postCommentParam.setContent(COMMENT_CONTENT_TEST); + postCommentParam.setAuthor(COMMENT_AUTHOR_TEST); + postCommentParam.setPostId(COMMENT_POST_ID_TEST); + postCommentParam.setEmail(COMMENT_INVALID_EMAIL_TEST); + HttpEntity request = new HttpEntity<>(postCommentParam); + + // Act + ResponseEntity> + result = restTemplate.exchange(blogUrl + COMMENT_API_ROUTE, HttpMethod.POST, request, + new ParameterizedTypeReference<>() {} + ); + + // Assert + Assertions.assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + Assertions.assertEquals(VALIDATION_VIOLATION_MESSAGE, + Objects.requireNonNull(result.getBody()).getMessage()); + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) + public void testCommentWithValidEmail() { + // Arrange + postCommentParam.setContent(COMMENT_CONTENT_TEST); + postCommentParam.setAuthor(COMMENT_AUTHOR_TEST); + postCommentParam.setPostId(COMMENT_POST_ID_TEST); + postCommentParam.setEmail(COMMENT_VALID_EMAIL_TEST); + HttpEntity request = new HttpEntity<>(postCommentParam); + + // Act + ResponseEntity> + result = restTemplate.exchange(blogUrl + COMMENT_API_ROUTE, HttpMethod.POST, request, + new ParameterizedTypeReference<>() {} + ); + BaseCommentDTO comment = Objects.requireNonNull(result.getBody()).getData(); + + // Assert + Assertions.assertEquals(HttpStatus.OK, result.getStatusCode()); + Assertions.assertEquals(COMMENT_AUTHOR_TEST, comment.getAuthor()); + Assertions.assertEquals(COMMENT_CONTENT_TEST, comment.getContent()); + Assertions.assertEquals(COMMENT_VALID_EMAIL_TEST, comment.getEmail()); + } +} diff --git a/src/test/java/run/halo/app/model/params/validation/PostCommentParamValidationTest.java b/src/test/java/run/halo/app/model/params/validation/PostCommentParamValidationTest.java new file mode 100644 index 00000000..93f090f1 --- /dev/null +++ b/src/test/java/run/halo/app/model/params/validation/PostCommentParamValidationTest.java @@ -0,0 +1,66 @@ +package run.halo.app.model.params.validation; + +import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import run.halo.app.model.params.PostCommentParam; + +@SpringBootTest +@ActiveProfiles("test") +public class PostCommentParamValidationTest { + + private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + private static final String TEST_CONTENT = "TestContent"; + private static final String TEST_AUTHOR = "TestAuthor"; + private static final String TEST_INVALID_EMAIL = "example.com"; + + private Validator validator; + private PostCommentParam postCommentParam; + + @BeforeEach + public void setUp() { + validator = factory.getValidator(); + postCommentParam = new PostCommentParam(); + } + + @Test + public void nullEmailValidationTest() { + // Arrange + setupDefaultValuesForPostCommentParam(); + + // Act + Set> violations = + validator.validate(postCommentParam); + + // Assert + Assertions.assertEquals(0, violations.size()); + } + + @Test + public void invalidEmailValidationTest() { + // Arrange + setupDefaultValuesForPostCommentParam(); + postCommentParam.setEmail(TEST_INVALID_EMAIL); + + // Act + Set> violations = + validator.validate(postCommentParam); + + // Assert + Assertions.assertEquals(1, violations.size()); + Assertions.assertEquals("email", violations.iterator().next().getPropertyPath().toString()); + Assertions.assertEquals("邮箱格式不正确", violations.iterator().next().getMessage()); + } + + public void setupDefaultValuesForPostCommentParam() { + postCommentParam.setContent(TEST_CONTENT); + postCommentParam.setAuthor(TEST_AUTHOR); + } +} diff --git a/src/test/java/run/halo/app/service/impl/PostCommentServiceImplTest.java b/src/test/java/run/halo/app/service/impl/PostCommentServiceImplTest.java new file mode 100644 index 00000000..2764510b --- /dev/null +++ b/src/test/java/run/halo/app/service/impl/PostCommentServiceImplTest.java @@ -0,0 +1,128 @@ +package run.halo.app.service.impl; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.ActiveProfiles; +import run.halo.app.model.dto.BaseCommentDTO; +import run.halo.app.model.entity.PostComment; +import run.halo.app.model.params.PostCommentParam; +import run.halo.app.model.properties.CommentProperties; +import run.halo.app.repository.PostCommentRepository; +import run.halo.app.repository.PostRepository; +import run.halo.app.service.CommentBlackListService; +import run.halo.app.service.OptionService; +import run.halo.app.service.UserService; + +@SpringBootTest +@ActiveProfiles("test") +public class PostCommentServiceImplTest { + + private static final String POST_COMMENT_CONTENT_TEST = "TestContent"; + + private static final String POST_COMMENT_AUTHOR_TEST = "TestAuthor"; + + private static final String POST_COMMENT_GRAVATAR_MD5_TEST = "d41d8cd98f00b204e9800998ecf8427e"; + + private static final String GRAVATAR_SOURCE_TEST = "//example.com/avatar/"; + + private static final String GRAVATAR_DEFAULT_TEST = ""; + + @Mock + private PostCommentRepository mockPostCommentRepository; + + @Mock + private PostRepository mockPostRepository; + + @Mock + private UserService mockUserService; + + @Mock + private OptionService mockOptionService; + + @Mock + private CommentBlackListService mockCommentBlackListService; + + @Mock + private ApplicationEventPublisher mockApplicationEventPublisher; + + @Mock + private PostComment mockPostComment; + + private PostCommentServiceImpl postCommentService; + + private PostCommentParam postCommentParam; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + postCommentService = new PostCommentServiceImpl( + mockPostCommentRepository, + mockPostRepository, + mockUserService, + mockOptionService, + mockCommentBlackListService, + mockApplicationEventPublisher + ); + postCommentParam = new PostCommentParam(); + } + + @Test + public void nullEmailWithAuditCreatedByTest() { + // Arrange + postCommentParam.setContent(POST_COMMENT_CONTENT_TEST); + postCommentParam.setAuthor(POST_COMMENT_AUTHOR_TEST); + when(mockOptionService.getByPropertyOrDefault(CommentProperties.NEW_NEED_CHECK, + Boolean.class, true)).thenReturn(true); + when(mockPostComment.getId()).thenReturn(1L); + when(mockPostCommentRepository.save(any(PostComment.class))).thenReturn(mockPostComment); + + // Act + PostComment result = postCommentService.createBy(postCommentParam); + + // Assert + Assertions.assertEquals(mockPostComment, result); + } + + @Test + public void nullEmailWithoutAuditCreatedByTest() { + // Arrange + postCommentParam.setContent(POST_COMMENT_CONTENT_TEST); + postCommentParam.setAuthor(POST_COMMENT_AUTHOR_TEST); + when(mockOptionService.getByPropertyOrDefault(CommentProperties.NEW_NEED_CHECK, + Boolean.class, true)).thenReturn(false); + when(mockPostComment.getId()).thenReturn(1L); + when(mockPostCommentRepository.save(any(PostComment.class))).thenReturn(mockPostComment); + + // Act + PostComment result = postCommentService.createBy(postCommentParam); + + // Assert + Assertions.assertEquals(mockPostComment, result); + } + + @Test + public void nullEmailConvertToTest() { + // Arrange + when(mockPostComment.getGravatarMd5()).thenReturn(POST_COMMENT_GRAVATAR_MD5_TEST); + when(mockOptionService.getByPropertyOrDefault(CommentProperties.GRAVATAR_SOURCE, + String.class)).thenReturn(GRAVATAR_SOURCE_TEST); + when(mockOptionService.getByPropertyOrDefault(CommentProperties.GRAVATAR_DEFAULT, + String.class)).thenReturn(GRAVATAR_DEFAULT_TEST); + + // Act + BaseCommentDTO result = postCommentService.convertTo(mockPostComment); + + // Assert + Assertions.assertEquals( + GRAVATAR_SOURCE_TEST + POST_COMMENT_GRAVATAR_MD5_TEST + "?s=256&d=" + + GRAVATAR_DEFAULT_TEST, result.getAvatar()); + } +} -- GitLab