diff --git a/src/main/java/com/devadmin/vicky/event/EventModelWrapper.java b/src/main/java/com/devadmin/vicky/event/EventModelWrapper.java index 650381e..fb690c6 100644 --- a/src/main/java/com/devadmin/vicky/event/EventModelWrapper.java +++ b/src/main/java/com/devadmin/vicky/event/EventModelWrapper.java @@ -5,7 +5,7 @@ /** * An event wrapper holding a model which describes the event. *

- *

This allows listeners to not care about the implementation of the event model. + *

This allows listener to not care about the implementation of the event model. */ abstract class EventModelWrapper extends ApplicationEvent { private T eventModel; diff --git a/src/main/java/com/devadmin/vicky/format/SimpleTaskEventFormatter.java b/src/main/java/com/devadmin/vicky/format/SimpleTaskEventFormatter.java index f02a838..fcecd90 100644 --- a/src/main/java/com/devadmin/vicky/format/SimpleTaskEventFormatter.java +++ b/src/main/java/com/devadmin/vicky/format/SimpleTaskEventFormatter.java @@ -28,7 +28,8 @@ public class SimpleTaskEventFormatter implements TaskEventFormatter { private Properties issueTypeIdToIconsMapping; private static final int COMMENT_CUT_LENGTH = 256; // all comments are cut off at this length for display - private static final String DEFAULT_ICON_KEY = "default"; + public static final String DEFAULT_ICON_KEY = "default"; + static final String EMPTY_COMMENT = "This task does not contain comment"; /** * composes basic part of message (without comment) @@ -88,7 +89,7 @@ protected String getShortDescription(TaskEvent event) { */ private String getIcon(@NotNull Task task) { String icon = issueTypeIdToIconsMapping.getProperty(task.getTypeId()); - if(icon == null){ + if (icon == null) { icon = issueTypeIdToIconsMapping.getProperty(DEFAULT_ICON_KEY); } return icon != null ? icon : ""; @@ -125,7 +126,7 @@ protected String getLastComment(TaskEvent event) { Comment comment = task.getLastComment(); if (comment == null || comment.getBody() == null) { - lastComment = "This task does not contain comment"; + lastComment = EMPTY_COMMENT; } else { String truncatedComment = truncateComment(comment.getBody()); lastComment = truncatedComment.replace("[~", "@").replace("]", ""); diff --git a/src/main/java/com/devadmin/vicky/format/SummaryTaskEventFormatter.java b/src/main/java/com/devadmin/vicky/format/SummaryTaskEventFormatter.java index 87a118f..cbe3d6d 100644 --- a/src/main/java/com/devadmin/vicky/format/SummaryTaskEventFormatter.java +++ b/src/main/java/com/devadmin/vicky/format/SummaryTaskEventFormatter.java @@ -19,7 +19,7 @@ public class SummaryTaskEventFormatter extends SimpleTaskEventFormatter { @Override public String format(TaskEvent event) { final String lastComment = super.getLastComment(event); - if (StringUtils.isNotBlank(lastComment)) { + if (StringUtils.isNotBlank(lastComment) && !lastComment.equals(EMPTY_COMMENT)) { return String.format( "%s %s %s ➠ %s", super.formatBase(event), diff --git a/src/main/java/com/devadmin/vicky/listener/AtReferenceListener.java b/src/main/java/com/devadmin/vicky/listener/AtReferenceListener.java index f50785b..c33d358 100644 --- a/src/main/java/com/devadmin/vicky/listener/AtReferenceListener.java +++ b/src/main/java/com/devadmin/vicky/listener/AtReferenceListener.java @@ -36,6 +36,8 @@ public void onApplicationEvent(TaskEventModelWrapper eventWrapper) { if (commentNotEmpty(event)) { sendMessageToReferencedPersons(event); + } else{ + log.warn("Ignore empty comment"); } } diff --git a/src/main/java/com/devadmin/vicky/listener/LabeledTaskListener.java b/src/main/java/com/devadmin/vicky/listener/LabeledTaskListener.java index 3a2817d..277114d 100644 --- a/src/main/java/com/devadmin/vicky/listener/LabeledTaskListener.java +++ b/src/main/java/com/devadmin/vicky/listener/LabeledTaskListener.java @@ -51,7 +51,7 @@ private boolean shouldListenerReactOnEvent(TaskEvent event, TaskEventModelWrappe private void sendMessage(TaskEvent event) { for (String label : event.getTask().getLabels()) { - log.info("Trying to send channel message about labeled task"); + log.info("Trying to send channel message about labeled task {}", label); messageService.sendChannelMessage(label, formatter.format(event)); } } diff --git a/src/main/java/com/devadmin/vicky/listener/ResolvedTaskListener.java b/src/main/java/com/devadmin/vicky/listener/ResolvedTaskListener.java index 480f4d3..fe1b395 100644 --- a/src/main/java/com/devadmin/vicky/listener/ResolvedTaskListener.java +++ b/src/main/java/com/devadmin/vicky/listener/ResolvedTaskListener.java @@ -50,6 +50,8 @@ public void onApplicationEvent(TaskEventModelWrapper eventWrapper) { * What we want is just to send notification on resolved task , also we check if eventWrapper contain all the data or we should skip it */ private boolean shouldListenerReactOnEvent(TaskEvent event, Task task, TaskEventModelWrapper eventWrapper) { - return task.isResolved() && event.getType() != null && event.getType().equals(TaskEventType.UPDATED) && !this.shouldSkip(eventWrapper); + return task.isResolved() && event.getType() != null + && event.getType() == TaskEventType.UPDATED + && !this.shouldSkip(eventWrapper); } } diff --git a/src/main/java/com/devadmin/vicky/model/jira/status/StatusModel.java b/src/main/java/com/devadmin/vicky/model/jira/status/StatusModel.java index ff69f98..ad316ef 100644 --- a/src/main/java/com/devadmin/vicky/model/jira/status/StatusModel.java +++ b/src/main/java/com/devadmin/vicky/model/jira/status/StatusModel.java @@ -11,6 +11,8 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StatusModel { + public static final String RESOLVED = "Resolved 解決済"; + @JsonProperty("self") private String self; diff --git a/src/main/java/com/devadmin/vicky/model/jira/task/IssueModel.java b/src/main/java/com/devadmin/vicky/model/jira/task/IssueModel.java index 875c580..e55326c 100644 --- a/src/main/java/com/devadmin/vicky/model/jira/task/IssueModel.java +++ b/src/main/java/com/devadmin/vicky/model/jira/task/IssueModel.java @@ -1,7 +1,8 @@ package com.devadmin.vicky.model.jira.task; -import com.devadmin.vicky.model.jira.comment.CommentModel; import com.devadmin.vicky.model.jira.FieldModel; +import com.devadmin.vicky.model.jira.comment.CommentModel; +import com.devadmin.vicky.model.jira.status.StatusModel; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.beans.factory.annotation.Value; @@ -96,7 +97,7 @@ public List getLabels() { */ @Override public Boolean isResolved() { - return "Resolved 解決済".equals(this.fields.getStatus().getName()); + return StatusModel.RESOLVED.equals(this.fields.getStatus().getName()); } @Override diff --git a/src/main/java/com/devadmin/vicky/service/jira/JiraTaskServiceImpl.java b/src/main/java/com/devadmin/vicky/service/jira/JiraTaskServiceImpl.java index 0ce087c..0e16d51 100644 --- a/src/main/java/com/devadmin/vicky/service/jira/JiraTaskServiceImpl.java +++ b/src/main/java/com/devadmin/vicky/service/jira/JiraTaskServiceImpl.java @@ -23,6 +23,32 @@ public class JiraTaskServiceImpl implements TaskService { private final JiraClient jiraClient; + @Override + public List getBlockerTasks() { + try { + Issue.SearchResult searchResult = jiraClient.searchIssues(BLOCKER_TASKS_JQL); + return searchResult.issues.stream() + .map(JiraTaskServiceImpl::convertIssueToIssueModel) + .collect(Collectors.toList()); + } catch (JiraException e) { + return Collections.emptyList(); + } + } + + @Override + public Comment getLastCommentByTaskId(String taskId) { + Comment lastComment = null; + try { + List comments = jiraClient.getIssue(taskId).getComments(); + if (!comments.isEmpty()) { + lastComment = comments.get(comments.size() - 1); + } + } catch (JiraException e) { + log.error("There was a problem getting issue from jira", e.getMessage()); + } + return lastComment; + } + /** * @param issue Issue * @return issueModel which was converted from issue @@ -114,30 +140,4 @@ private static UserModel getAssignee(Issue issue) { return userModel; } - - @Override - public List getBlockerTasks() { - try { - Issue.SearchResult searchResult = jiraClient.searchIssues(BLOCKER_TASKS_JQL); - return searchResult.issues.stream() - .map(JiraTaskServiceImpl::convertIssueToIssueModel) - .collect(Collectors.toList()); - } catch (JiraException e) { - return Collections.emptyList(); - } - } - - @Override - public Comment getLastCommentByTaskId(String taskId) { - Comment lastComment = null; - try { - List comments = jiraClient.getIssue(taskId).getComments(); - if (!comments.isEmpty()) { - lastComment = comments.get(comments.size() - 1); - } - } catch (JiraException e) { - log.error("There was a problem getting issue from jira", e.getMessage()); - } - return lastComment; - } } diff --git a/src/main/java/com/devadmin/vicky/service/slack/MessageService.java b/src/main/java/com/devadmin/vicky/service/slack/MessageService.java index a0e9d6c..e0519ef 100644 --- a/src/main/java/com/devadmin/vicky/service/slack/MessageService.java +++ b/src/main/java/com/devadmin/vicky/service/slack/MessageService.java @@ -5,8 +5,6 @@ */ package com.devadmin.vicky.service.slack; -import com.devadmin.vicky.MessageServiceException; - /** * A generic messaging service. Allows writing string messages to a named channel or privately to a * person. diff --git a/src/main/java/com/devadmin/vicky/service/slack/SlackMessageServiceImpl.java b/src/main/java/com/devadmin/vicky/service/slack/SlackMessageServiceImpl.java index 4ead087..2c8127a 100644 --- a/src/main/java/com/devadmin/vicky/service/slack/SlackMessageServiceImpl.java +++ b/src/main/java/com/devadmin/vicky/service/slack/SlackMessageServiceImpl.java @@ -27,13 +27,18 @@ public class SlackMessageServiceImpl implements MessageService { private final SlackProperties properties; private final SlackApiEndpoints slackApiEndpoints; private final RestTemplate restTemplate; - @Value("${debug.message-service.additional-information:}") - private String additionalMessageInformation; + private final String additionalMessageInformation; - public SlackMessageServiceImpl(SlackProperties properties, SlackApiEndpoints slackApiEndpoints, RestTemplate restTemplate) { + public SlackMessageServiceImpl( + SlackProperties properties, + SlackApiEndpoints slackApiEndpoints, + RestTemplate restTemplate, + @Value("${debug.message-service.additional-information:}") final String additionalMessageInformation + ) { this.properties = properties; this.slackApiEndpoints = slackApiEndpoints; this.restTemplate = restTemplate; + this.additionalMessageInformation = additionalMessageInformation; } /** diff --git a/src/test/java/com/devadmin/vicky/test/TestTasks.java b/src/test/java/com/devadmin/vicky/test/TestTasks.java new file mode 100644 index 0000000..a906b80 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/TestTasks.java @@ -0,0 +1,80 @@ +package com.devadmin.vicky.test; + +import com.devadmin.vicky.model.jira.*; +import com.devadmin.vicky.model.jira.changelog.ChangeLogModel; +import com.devadmin.vicky.model.jira.changelog.JiraChangeLogItemModel; +import com.devadmin.vicky.model.jira.comment.CommentModel; +import com.devadmin.vicky.model.jira.status.StatusModel; +import com.devadmin.vicky.model.jira.task.IssueModel; +import com.devadmin.vicky.model.jira.task.IssueTypeModel; +import com.devadmin.vicky.model.jira.task.TaskEventType; + +import java.util.Collections; + +/** + * Create test tasks. + */ +public final class TestTasks { + + public static final String PROJECT = "vicky"; + + public static final String TEST_ID = "13"; + + public static JiraEventModel taskModel(final String creator, final String assignee, final String body) { + final AuthorModel authorModel = new AuthorModel(); + authorModel.setName(creator); + authorModel.setDisplayName(creator); + authorModel.setEmailAddress(creator); + + final CommentModel comment = new CommentModel(); + comment.setBody(body); + comment.setAuthor(authorModel); + + + final IssueTypeModel issueTypeModel = new IssueTypeModel(); + issueTypeModel.setId(TEST_ID); + + final StatusModel statusModel = new StatusModel(); + statusModel.setName(StatusModel.RESOLVED); + statusModel.setDescription("Bla bla"); + + final UserModel userModel = new UserModel(); + userModel.setName(assignee); + userModel.setDisplayName(assignee); + userModel.setEmailAddress(assignee); + + final ProjectModel projectModel = new ProjectModel(); + projectModel.setName(PROJECT); + + final FieldModel fieldModel = new FieldModel(); + fieldModel.setIssueType(issueTypeModel); + fieldModel.setStatus(statusModel); + fieldModel.setAssignee(userModel); + fieldModel.setSummary("Everything is ok"); + fieldModel.setProject(projectModel); + + final IssueModel issueModel = new IssueModel(); + issueModel.setId(TEST_ID); + issueModel.setKey("test key"); + issueModel.setFields(fieldModel); + + + final JiraChangeLogItemModel logItemModel = new JiraChangeLogItemModel(); + logItemModel.setField("assignee"); + logItemModel.setTo(assignee); + + final ChangeLogModel changeLogModel = new ChangeLogModel(); + changeLogModel.setId(TEST_ID); + changeLogModel.setItems(Collections.singletonList(logItemModel)); + + final JiraEventModel testEventModel = new JiraEventModel(); + testEventModel.setComment(comment); + testEventModel.setUser(userModel); + testEventModel.setIssue(issueModel); + testEventModel.setTimeStamp(System.currentTimeMillis()); + testEventModel.setChangeLog(changeLogModel); + testEventModel.setType(TaskEventType.UPDATED); + + return testEventModel; + } +} diff --git a/src/test/java/com/devadmin/vicky/test/format/AssignTaskEventFormatterTest.java b/src/test/java/com/devadmin/vicky/test/format/AssignTaskEventFormatterTest.java new file mode 100644 index 0000000..cfa68e9 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/format/AssignTaskEventFormatterTest.java @@ -0,0 +1,85 @@ +package com.devadmin.vicky.test.format; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.format.AssignTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.test.TestTasks; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Properties; + +/** + * Test class for {@link AssignTaskEventFormatter} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + AssignTaskEventFormatter.class, + } +) +public class AssignTaskEventFormatterTest { + + /** + * Formatter to use. + */ + @Autowired + @Qualifier("AssignFormatter") + private TaskEventFormatter taskEventFormatter; + + /** + * Mock properties. + */ + @MockBean(name = "issueTypeIdToIconsMapping") + private Properties properties; + + + /** + * Init. + */ + @Before + public void init() { + Mockito.when(this.properties.getProperty(TestTasks.TEST_ID)) + .thenReturn("test icon"); + } + + /** + * Test correct format. + */ + @Test + public void testFormat() { + final JiraEventModel jiraEventModel = TestTasks.taskModel("lollipop", "fin", "Hello world!"); + Assert.assertThat( + this.taskEventFormatter.format(jiraEventModel), + CoreMatchers.is( + String.join( + "", + "fin assigned to you: test icon Resolved 解決済: Everything is ok @fin\n", + " lollipop ➠ Hello world!" + ) + ) + ); + } + + /** + * Test that format will fail without user. + */ + @Test(expected = NullPointerException.class) + public void testFailsWithoutUser() { + final JiraEventModel jiraEventModel = TestTasks.taskModel("lollipop", "fin", "Hello world!"); + jiraEventModel.setUser(null); + this.taskEventFormatter.format(jiraEventModel); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/SimpleTaskEventFormatterTest.java b/src/test/java/com/devadmin/vicky/test/format/SimpleTaskEventFormatterTest.java similarity index 77% rename from src/test/java/com/devadmin/vicky/test/SimpleTaskEventFormatterTest.java rename to src/test/java/com/devadmin/vicky/test/format/SimpleTaskEventFormatterTest.java index 81f82e9..03a31d1 100644 --- a/src/test/java/com/devadmin/vicky/test/SimpleTaskEventFormatterTest.java +++ b/src/test/java/com/devadmin/vicky/test/format/SimpleTaskEventFormatterTest.java @@ -1,21 +1,23 @@ -package com.devadmin.vicky.test; +package com.devadmin.vicky.test.format; import com.devadmin.vicky.config.FormatConfig; import com.devadmin.vicky.format.SimpleTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; import com.devadmin.vicky.model.jira.task.Task; import com.devadmin.vicky.model.jira.task.TaskEvent; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockReset; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import java.util.Properties; +import static com.devadmin.vicky.format.SimpleTaskEventFormatter.DEFAULT_ICON_KEY; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -23,14 +25,19 @@ @SpringBootTest(classes = {SimpleTaskEventFormatter.class, FormatConfig.class}) public class SimpleTaskEventFormatterTest { + /** + * Formatter to test. + * Use qualifier to avoid IDE warning + */ @Autowired - private SimpleTaskEventFormatter simpleTaskEventFormatter; + @Qualifier("SimpleFormatter") + private TaskEventFormatter simpleTaskEventFormatter; @SpyBean(name = "issueTypeIdToIconsMapping") private Properties properties; @Test - public void testFormattedEventHasRightIcon(){ + public void testFormattedEventHasRightIcon() { //Arrange Task task = mock(Task.class, RETURNS_DEEP_STUBS); TaskEvent taskEvent = mock(TaskEvent.class); @@ -42,26 +49,25 @@ public void testFormattedEventHasRightIcon(){ } @Test - public void testFormattedEventHasDefaultIcon(){ + public void testFormattedEventHasDefaultIcon() { //Arrange Task task = mock(Task.class, RETURNS_DEEP_STUBS); TaskEvent taskEvent = mock(TaskEvent.class); when(task.getTypeId()).thenReturn("177"); when(taskEvent.getTask()).thenReturn(task); - //Act + Assert assertThat(simpleTaskEventFormatter.format(taskEvent)).isEqualTo(":rocket: null: null @null\n null ➠ This task does not contain comment"); } @Test @DirtiesContext - public void testFormattedEventHasEmptyIcon(){ + public void testFormattedEventHasEmptyIcon() { //Arrange Task task = mock(Task.class, RETURNS_DEEP_STUBS); TaskEvent taskEvent = mock(TaskEvent.class); when(task.getTypeId()).thenReturn("177"); when(taskEvent.getTask()).thenReturn(task); - when(properties.getProperty("default")).thenReturn(null); + when(properties.getProperty(DEFAULT_ICON_KEY)).thenReturn(null); //Act + Assert assertThat(simpleTaskEventFormatter.format(taskEvent)).isEqualTo(" null: null @null\n null ➠ This task does not contain comment"); diff --git a/src/test/java/com/devadmin/vicky/test/format/SummaryTaskEventFormatterTest.java b/src/test/java/com/devadmin/vicky/test/format/SummaryTaskEventFormatterTest.java new file mode 100644 index 0000000..d5944ad --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/format/SummaryTaskEventFormatterTest.java @@ -0,0 +1,93 @@ +package com.devadmin.vicky.test.format; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.format.SummaryTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.test.TestTasks; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Properties; + +/** + * Test class for {@link com.devadmin.vicky.format.SummaryTaskEventFormatter} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + SummaryTaskEventFormatter.class, + } +) +public class SummaryTaskEventFormatterTest { + + /** + * Formatter to use. + */ + @Autowired + @Qualifier("SummaryFormatter") + private TaskEventFormatter taskEventFormatter; + + /** + * Mock properties. + */ + @MockBean(name = "issueTypeIdToIconsMapping") + private Properties properties; + + + /** + * Init. + */ + @Before + public void init() { + Mockito.when(this.properties.getProperty(TestTasks.TEST_ID)) + .thenReturn("test icon"); + } + + /** + * Test correct format. + */ + @Test + public void testFormat() { + final JiraEventModel jiraEventModel = TestTasks.taskModel("lollipop", "fin", "Hello world!"); + Assert.assertThat( + this.taskEventFormatter.format(jiraEventModel), + CoreMatchers.is( + String.join( + "", + "test icon Resolved 解決済: ", + "Everything is ok @fin Bla bla lollipop ➠ Hello world!" + ) + ) + ); + } + + /** + * Test correct format. + */ + @Test + public void testFormatWithoutComment() { + final JiraEventModel jiraEventModel = TestTasks.taskModel("lollipop", "fin", "Hello world!"); + jiraEventModel.setComment(null); + Assert.assertThat( + this.taskEventFormatter.format(jiraEventModel), + CoreMatchers.is( + String.join( + "", + "test icon Resolved 解決済: Everything is ok @fin Bla bla " + ) + ) + ); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/AtReferenceListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/AtReferenceListenerTest.java new file mode 100644 index 0000000..e45c716 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/AtReferenceListenerTest.java @@ -0,0 +1,178 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.SimpleTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.AtReferenceListener; +import com.devadmin.vicky.model.jira.AuthorModel; +import com.devadmin.vicky.model.jira.FieldModel; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.model.jira.comment.CommentModel; +import com.devadmin.vicky.model.jira.status.StatusModel; +import com.devadmin.vicky.model.jira.task.IssueModel; +import com.devadmin.vicky.model.jira.task.IssueTypeModel; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.mockito.Mockito.*; + +/** + * Test class for {@link AtReferenceListener} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + AtReferenceListener.class, + SimpleTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class, + } +) +public class AtReferenceListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("SimpleFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * Nobody will get message because reference format is incorrect. + */ + @Test + public void testMessageWithInvalidReference() { + final JiraEventModel testEventModel = taskModel("Wrong reference format Lollipop"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } + + /** + * Nobody will get message because comment is null. + */ + @Test + public void testSkipEmptyComment() { + final JiraEventModel testEventModel = taskModel("[~lollipop]"); + testEventModel.setComment(null); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } + + /** + * Test that if reference and author are the same, then don't send notification. + */ + @Test + public void testTheSameReferenceAndAuthor() { + final JiraEventModel testEventModel = taskModel("serpento"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } + + /** + * Test that multiple users will receive private messages. + */ + @Test + public void testMultipleReferences() { + final JiraEventModel testEventModel = taskModel("[~lollipop] and [~vvorski]"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendPrivateMessage( + "lollipop", + this.eventFormatter.format(testEventModel) + ); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendPrivateMessage( + "vvorski", + this.eventFormatter.format(testEventModel) + ); + } + + + /** + * Test that one user will receive private message. + */ + @Test + public void shouldSendPrivateMessage() { + final JiraEventModel testEventModel = taskModel("[~Lollipop]"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, times(1)) + .sendPrivateMessage( + "Lollipop", + this.eventFormatter.format(testEventModel) + ); + } + + /** + * Create task model with given body. + * + * @param body Body to use + * @return Test task + */ + private static JiraEventModel taskModel(final String body) { + final AuthorModel authorModel = new AuthorModel(); + authorModel.setName("serpento"); + + final CommentModel comment = new CommentModel(); + comment.setBody(body); + comment.setAuthor(authorModel); + + final IssueTypeModel issueTypeModel = new IssueTypeModel(); + issueTypeModel.setId("13"); + + final StatusModel statusModel = new StatusModel(); + statusModel.setName("test"); + final FieldModel fieldModel = new FieldModel(); + fieldModel.setIssueType(issueTypeModel); + fieldModel.setStatus(statusModel); + final IssueModel issueModel = new IssueModel(); + issueModel.setId("13"); + issueModel.setFields(fieldModel); + JiraEventModel testEventModel = new JiraEventModel(); + testEventModel.setComment(comment); + testEventModel.setIssue(issueModel); + + return testEventModel; + } +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/CommentedTaskListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/CommentedTaskListenerTest.java new file mode 100644 index 0000000..428060e --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/CommentedTaskListenerTest.java @@ -0,0 +1,103 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.SimpleTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.CommentedTaskListener; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.devadmin.vicky.test.TestTasks.taskModel; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + CommentedTaskListener.class, + SimpleTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class + } +) +public class CommentedTaskListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("SimpleFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * test that listener sends notification. + */ + @Test + public void testSendNotificationOnCreatedEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "This is a simple comment"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendPrivateMessage( + "serpento", + this.eventFormatter.format(testEventModel) + ); + } + + /* + * Test that message service is not called if assignee and author are equal. + */ + @Test + public void testWhenCommenterAndAssigneeAreSameUsers() { + final JiraEventModel testEventModel = taskModel("testUser", "testUser", "This is a simple comment"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } + + /** + * Skip message because comment is null. + */ + @Test + public void testCommentIsNull() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "This is a simple comment"); + testEventModel.setComment(null); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/CreatedTaskListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/CreatedTaskListenerTest.java new file mode 100644 index 0000000..07eb671 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/CreatedTaskListenerTest.java @@ -0,0 +1,112 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.SummaryTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.CreatedTaskListener; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.model.jira.task.TaskEventType; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.devadmin.vicky.test.TestTasks.PROJECT; +import static com.devadmin.vicky.test.TestTasks.taskModel; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; + +/** + * Test class for {@link CreatedTaskListener} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + CreatedTaskListener.class, + SummaryTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class + } +) +@ActiveProfiles("test") // to load yml +public class CreatedTaskListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("SummaryFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * Test that channel will send notification. + */ + @Test + public void testSendNotificationOnCreatedEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.setType(TaskEventType.CREATED); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendChannelMessage( + PROJECT, + this.eventFormatter.format(testEventModel) + ); + } + + /** + * Test that UPDATED type will be skipped. + */ + @Test + public void testWrongEventType() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.setType(TaskEventType.UPDATED); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } + + /** + * Test that unsupported issue ids ae skipped + */ + @Test + public void testSkipIssueId() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.getIssue().getFields().getIssueType().setId("228"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/LabeledTaskListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/LabeledTaskListenerTest.java new file mode 100644 index 0000000..d510dd2 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/LabeledTaskListenerTest.java @@ -0,0 +1,117 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.SimpleTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.LabeledTaskListener; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.model.jira.task.TaskEventType; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.List; + +import static com.devadmin.vicky.test.TestTasks.taskModel; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; + +/** + * Test class for {@link LabeledTaskListener} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + LabeledTaskListener.class, + SimpleTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class + } +) +public class LabeledTaskListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("SimpleFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * Sip event if it doesn't have labels. + */ + @Test + public void eventShouldNotBeHandledWithoutLabelsTest() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.getTask().getFields().setLabels(new String[0]); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } + + /** + * Test that channel skip updated type. + */ + @Test + public void testSendNotificationOnCreatedEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.setType(TaskEventType.UPDATED); + testEventModel.getTask().getFields().setLabels(new String[]{"first", "second"}); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } + + /** + * Tests that the message was sent two times. + */ + @Test + public void testMuptypleLabels() { + final List labels = Arrays.asList("first", "second"); + final JiraEventModel testTaskEventModel = taskModel("serpento", "testUser", "Test task"); + testTaskEventModel.getTask().getFields().setLabels(labels.toArray(new String[0])); + testTaskEventModel.setType(TaskEventType.CREATED); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testTaskEventModel)); + for (final String label : labels) { + Mockito.verify( + this.messageService, atLeastOnce()) + .sendChannelMessage( + label, + this.eventFormatter.format(testTaskEventModel) + ); + } + } +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/PMOnAssignListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/PMOnAssignListenerTest.java new file mode 100644 index 0000000..f7ac847 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/PMOnAssignListenerTest.java @@ -0,0 +1,131 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.AssignTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.PMOnAssignListener; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.model.jira.changelog.JiraChangeLogItemModel; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.List; + +import static com.devadmin.vicky.test.TestTasks.taskModel; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; + +/** + * Test fpr {@link com.devadmin.vicky.listener.PMOnAssignListener} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + PMOnAssignListener.class, + AssignTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class + } +) +public class PMOnAssignListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("AssignFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * Test that sends notification. + */ + @Test + public void testSendNotificationOnCreatedEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendPrivateMessage( + "testUser", + this.eventFormatter.format(testEventModel) + ); + } + + /** + * Test that not assignee field is skipped. + */ + @Test + public void testNotAssigneeEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + ((JiraChangeLogItemModel) testEventModel.getChangeLog().getItems().get(0)).setField("not assignee"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendPrivateMessage( + any(), + any() + ); + } + + /** + * Test multiple change logs. + */ + @Test + public void testMultipleChangeLogs() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + final List itemModels = this.multipleItems(); + + Assert.assertThat(itemModels.size(), CoreMatchers.is(2)); + + testEventModel.getChangeLog().setItems(itemModels); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, times(2)) + .sendPrivateMessage( + any(), + any() + ); + } + + private List multipleItems() { + final JiraChangeLogItemModel logItemModel = new JiraChangeLogItemModel(); + logItemModel.setField("assignee"); + logItemModel.setTo("testUser2"); + + final JiraChangeLogItemModel logItemModel2 = new JiraChangeLogItemModel(); + logItemModel2.setField("assignee"); + logItemModel2.setTo("testUser3"); + + return Arrays.asList(logItemModel, logItemModel2); + } + +} diff --git a/src/test/java/com/devadmin/vicky/test/listener/ResolvedTestListenerTest.java b/src/test/java/com/devadmin/vicky/test/listener/ResolvedTestListenerTest.java new file mode 100644 index 0000000..2758f2f --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/listener/ResolvedTestListenerTest.java @@ -0,0 +1,111 @@ +package com.devadmin.vicky.test.listener; + +import com.devadmin.vicky.config.FormatConfig; +import com.devadmin.vicky.event.TaskEventModelWrapper; +import com.devadmin.vicky.format.SimpleTaskEventFormatter; +import com.devadmin.vicky.format.TaskEventFormatter; +import com.devadmin.vicky.listener.ResolvedTaskListener; +import com.devadmin.vicky.model.jira.JiraEventModel; +import com.devadmin.vicky.model.jira.task.TaskEventType; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import com.devadmin.vicky.test.TestTasks; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.devadmin.vicky.test.TestTasks.taskModel; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; + +/** + * Test fpr {@link com.devadmin.vicky.listener.ResolvedTaskListener} + */ +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = { + FormatConfig.class, + ResolvedTaskListener.class, + SimpleTaskEventFormatter.class, + SlackMessageServiceImpl.class, + ApplicationEventPublisher.class + } +) +@ActiveProfiles("test")// to load yml +public class ResolvedTestListenerTest { + + /** + * Event publisher. + */ + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * Event formatter to test. + * Add qualifier to avoid warning from IDEA + */ + @Autowired + @Qualifier("SimpleFormatter") + private TaskEventFormatter eventFormatter; + + /** + * Mocked slack message sender. + */ + @MockBean + private MessageService messageService; + + /** + * Test that sends notification. + */ + @Test + public void testSendNotificationOnCreatedEvent() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, atLeastOnce()) + .sendChannelMessage( + TestTasks.PROJECT, + this.eventFormatter.format(testEventModel) + ); + } + + /** + * Test that listener skip non updated status. + */ + @Test + public void testSkipByStatus() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.setType(TaskEventType.COMMENT); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } + + /** + * Test that listener skip non updated status. + */ + @Test + public void testSkipUnsupportedId() { + final JiraEventModel testEventModel = taskModel("serpento", "testUser", "Test task"); + testEventModel.getIssue().getFields().getIssueType().setId("228"); + this.applicationEventPublisher.publishEvent(new TaskEventModelWrapper(testEventModel)); + Mockito.verify( + this.messageService, never()) + .sendChannelMessage( + any(), + any() + ); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/service/JiraServiceTest.java b/src/test/java/com/devadmin/vicky/test/service/JiraServiceTest.java new file mode 100644 index 0000000..21ef603 --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/service/JiraServiceTest.java @@ -0,0 +1,162 @@ +package com.devadmin.vicky.test.service; + +import com.devadmin.vicky.model.jira.FieldModel; +import com.devadmin.vicky.model.jira.task.Task; +import com.devadmin.vicky.service.jira.JiraTaskServiceImpl; +import com.devadmin.vicky.service.jira.TaskService; +import net.rcarz.jiraclient.*; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import static org.mockito.Mockito.*; + +/** + * Test {@link JiraTaskServiceImpl}. + */ +public final class JiraServiceTest { + + /** + * Id of empty comment. + */ + private static final String EMPTY_COMMENT = "empty"; + + /** + * Id of existing comment. + */ + private static final String EXISTING_COMMENT = "exist"; + + /** + * Id of comment that throws exception. + */ + private static final String EXCEPTIONAL_COMMENT = "exception"; + + /** + * Jira service. + */ + private TaskService taskService; + + /** + * Init jira service. + * + * @throws JiraException if failed + */ + @Before + public void init() throws JiraException { + this.taskService = new JiraTaskServiceImpl(this.prepareClient()); + } + + /** + * Test that service returns blocker tasks. + */ + @Test + public void testBlockerTasks() { + final List blockerTasks = this.taskService.getBlockerTasks(); + Assert.assertThat( + blockerTasks.size(), + CoreMatchers.is(1) + ); + final FieldModel fields = blockerTasks.get(0).getFields(); + Assert.assertNotNull(fields); + Assert.assertNotNull(fields.getAssignee()); + Assert.assertNotNull(fields.getStatus()); + Assert.assertNotNull(fields.getPriority()); + } + + /** + * Test that service returns comments. + */ + @Test + public void testComments() { + Assert.assertNotNull(this.taskService.getLastCommentByTaskId(EXISTING_COMMENT)); + Assert.assertNull(this.taskService.getLastCommentByTaskId(EMPTY_COMMENT)); + Assert.assertNull(this.taskService.getLastCommentByTaskId(EXCEPTIONAL_COMMENT)); + } + + /** + * Prepare mocked jira client. + * + * @return Mocked jira client + * @throws JiraException if failed + */ + private JiraClient prepareClient() throws JiraException { + final Issue.SearchResult searchResult = Mockito.mock(Issue.SearchResult.class); + final Issue issue = Mockito.mock(Issue.class); + this.prepareIssue(issue); + searchResult.issues = Collections.singletonList(issue); + final JiraClient jiraClient = Mockito.mock(JiraClient.class, RETURNS_DEEP_STUBS); + when(jiraClient.searchIssues(any())).thenReturn(searchResult); + when(jiraClient.getIssue(EMPTY_COMMENT).getComments()).thenReturn(Collections.emptyList()); + when(jiraClient.getIssue(EXISTING_COMMENT).getComments()).thenReturn(Collections.singletonList(Mockito.mock(Comment.class))); + when(jiraClient.getIssue(EXCEPTIONAL_COMMENT)).thenThrow(new JiraException("Comment doesn't exist")); + return jiraClient; + } + + /** + * Prepare mocked jira issue + * + * @param issue Mocked issue + */ + private void prepareIssue(final Issue issue) { + final User user = Mockito.mock(User.class); + this.prepareUserMock(user); + + final Status status = Mockito.mock(Status.class); + this.prepareStatus(status); + + final Priority priority = Mockito.mock(Priority.class); + this.preparePriority(priority); + + when(issue.getCreatedDate()).thenReturn(new Date()); + when(issue.getUpdatedDate()).thenReturn(new Date()); + when(issue.getLabels()).thenReturn(Arrays.asList("1", "2", "3")); + when(issue.getAssignee()).thenReturn(user); + when(issue.getPriority()).thenReturn(priority); + when(issue.getStatus()).thenReturn(status); + } + + /** + * Prepare mocked jira priority. + * + * @param priority Mocked priority + */ + private void preparePriority(final Priority priority) { + when(priority.getId()).thenReturn("1"); + when(priority.getIconUrl()).thenReturn("example.com"); + when(priority.getName()).thenReturn("Test"); + when(priority.getSelf()).thenReturn("example.com"); + } + + /** + * Prepare mocked jira status. + * + * @param status Mocked status + */ + private void prepareStatus(final Status status) { + when(status.getId()).thenReturn("1"); + when(status.getDescription()).thenReturn("Test"); + when(status.getIconUrl()).thenReturn("example.com"); + when(status.getName()).thenReturn("Test"); + when(status.getSelf()).thenReturn("example.com"); + } + + /** + * Prepare mocked jira user. + * + * @param user Mocked user + */ + private void prepareUserMock(final User user) { + when(user.getId()).thenReturn("1"); + when(user.getSelf()).thenReturn("example.com"); + when(user.getName()).thenReturn("almas"); + when(user.getEmail()).thenReturn("Lollipop@devadmin.com"); + when(user.getDisplayName()).thenReturn("Lollipop"); + } +} diff --git a/src/test/java/com/devadmin/vicky/test/service/SlackServiceTest.java b/src/test/java/com/devadmin/vicky/test/service/SlackServiceTest.java new file mode 100644 index 0000000..20892ae --- /dev/null +++ b/src/test/java/com/devadmin/vicky/test/service/SlackServiceTest.java @@ -0,0 +1,193 @@ +package com.devadmin.vicky.test.service; + +import com.devadmin.vicky.config.slack.SlackApiEndpoints; +import com.devadmin.vicky.config.slack.SlackProperties; +import com.devadmin.vicky.model.slack.Event; +import com.devadmin.vicky.service.slack.MessageService; +import com.devadmin.vicky.service.slack.SlackMessageServiceImpl; +import me.ramswaroop.jbot.core.slack.models.User; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.*; + +/** + * Test {@link SlackMessageServiceImpl}. + */ +@RunWith(MockitoJUnitRunner.class) +public final class SlackServiceTest { + + /** + * Email to test. + */ + private static final String TEST_EMAIL = "Lollipop@devadmin.com"; + + /** + * User id to test. + */ + private static final String TEST_ID = "1"; + + /** + * MessageService to test. + */ + private MessageService messageService; + + /** + * Slack properties with fake data. + */ + private SlackProperties properties; + + /** + * Mocked rest template. + */ + @Mock + private RestTemplate restTemplate; + + /** + * Mocked slack endpoints. + */ + @Mock + private SlackApiEndpoints endpoints; + + /** + * Init objects. + */ + @Before + public void init() { + this.prepareProperties(); + this.prepareEndpoints(); + this.prepareRestTemplate(); + + this.messageService = new SlackMessageServiceImpl( + this.properties, + this.endpoints, + this.restTemplate, + "" + ); + } + + /** + * Test that service sends channel message using rest template. + */ + @Test + public void testChannelMessage() { + this.messageService.sendChannelMessage("dev", "Good morning"); + verify(this.restTemplate, atLeastOnce()) + .postForEntity( + eq(this.endpoints.getChatPostMessageApi()), + isNull(), + eq(String.class), + eq(this.properties.getToken().getBot()), + any(), + any() + ); + } + + /** + * Test private message. + * Firstly gets list of users using rest template + * Then sends message to user with TEST_EMAIL using rest template + */ + @Test + public void testPrivateMessage() { + this.messageService.sendPrivateMessage(TEST_EMAIL, "Good morning"); + verify(this.restTemplate, atLeastOnce()) + .postForEntity( + eq(this.endpoints.getUserListApi()), + isNull(), + eq(Event.class), + eq(this.properties.getToken().getBot()) + ); + verify(this.restTemplate, atLeastOnce()) + .postForEntity( + eq(this.endpoints.getChatPostMessageApi()), + isNull(), + eq(String.class), + eq(this.properties.getToken().getBot()), + eq(TEST_ID), + any() + ); + } + + /** + * Prepare mocked rest template. + */ + private void prepareRestTemplate() { + final Event event = this.prepareEvent(); + //send Channel message + when( + this.restTemplate.postForEntity( + eq(this.endpoints.getChatPostMessageApi()), + isNull(), + eq(String.class), + eq(this.properties.getToken().getBot()), + any(), + any() + ) + ).thenReturn(ResponseEntity.ok("Success")); + //send private message to get users + when( + this.restTemplate + .postForEntity( + eq(this.endpoints.getUserListApi()), + isNull(), + eq(Event.class), + eq(this.properties.getToken().getBot()) + ) + ).thenReturn(ResponseEntity.ok(event)); + //send private message to one user from list + when( + this.restTemplate + .postForEntity( + eq(this.endpoints.getChatPostMessageApi()), + isNull(), + eq(String.class), + eq(this.properties.getToken().getBot()), + eq(TEST_ID), + any() + ) + ).thenReturn(ResponseEntity.ok("Success")); + } + + /** + * Prepare mocked event. + * + * @return Mocked event + */ + private Event prepareEvent() { + final User user = Mockito.mock(User.class, RETURNS_DEEP_STUBS); + when(user.getProfile().getEmail()).thenReturn(TEST_EMAIL); + when(user.getId()).thenReturn(TEST_ID); + final Event event = Mockito.mock(Event.class, RETURNS_DEEP_STUBS); + when(event.getMembers()).thenReturn(new User[]{user}); + return event; + } + + /** + * Prepare mocked endpoints. + */ + private void prepareEndpoints() { + when(this.endpoints.getChatPostMessageApi()).thenReturn("www.example.com"); + when(this.endpoints.getUserListApi()).thenReturn("www.example.com"); + } + + /** + * Prepare properties with fake data. + */ + private void prepareProperties() { + this.properties = new SlackProperties(); + this.properties.setApiUrl("example.com"); + final SlackProperties.Token token = new SlackProperties.Token(); + token.setBot("bot"); + this.properties.setToken(token); + } +} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..e258602 --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,5 @@ +slack: + notification: + task-types: + createdTask: 13 + resolvedTask: 13 \ No newline at end of file