This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/main by this push: new 81213fc [CAMEL-17677]add tests in camel-jira-starter (#439) 81213fc is described below commit 81213fc5e6c8d8a25ff10d0b5039386514e0626b Author: Freeman(Yue) Fang <freeman.f...@gmail.com> AuthorDate: Wed Feb 23 01:09:40 2022 -0500 [CAMEL-17677]add tests in camel-jira-starter (#439) --- components-starter/camel-jira-starter/pom.xml | 23 ++ .../springboot/test/AddCommentProducerTest.java | 175 +++++++++++++ .../springboot/test/AddIssueLinkProducerTest.java | 272 +++++++++++++++++++++ .../jira/springboot/test/AddIssueProducerTest.java | 239 ++++++++++++++++++ .../springboot/test/AddWorkLogProducerTest.java | 251 +++++++++++++++++++ .../springboot/test/AttachFileProducerTest.java | 196 +++++++++++++++ .../springboot/test/DeleteIssueProducerTest.java | 163 ++++++++++++ .../springboot/test/FetchCommentsProducerTest.java | 177 ++++++++++++++ .../springboot/test/FetchIssueProducerTest.java | 174 +++++++++++++ .../jira/springboot/test/JiraTestConstants.java | 28 +++ .../springboot/test/NewCommentsConsumerTest.java | 236 ++++++++++++++++++ .../springboot/test/NewIssuesConsumerTest.java | 205 ++++++++++++++++ .../test/TransitionIssueProducerTest.java | 173 +++++++++++++ .../springboot/test/UpdateIssueProducerTest.java | 216 ++++++++++++++++ .../component/jira/springboot/test/Utils.java | 194 +++++++++++++++ .../springboot/test/WatchUpdatesConsumerTest.java | 220 +++++++++++++++++ .../jira/springboot/test/WatcherProducerTest.java | 264 ++++++++++++++++++++ 17 files changed, 3206 insertions(+) diff --git a/components-starter/camel-jira-starter/pom.xml b/components-starter/camel-jira-starter/pom.xml index 775b48d..7714147 100644 --- a/components-starter/camel-jira-starter/pom.xml +++ b/components-starter/camel-jira-starter/pom.xml @@ -47,6 +47,29 @@ </exclusions> <!--END OF GENERATED CODE--> </dependency> + <!-- Testing dependencies --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-spring-junit5</artifactId> + <exclusions> + <exclusion> + <groupId>org.apache.camel</groupId> + <artifactId>camel-spring-xml</artifactId> + </exclusion> + </exclusions> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <version>${spring-boot-version}</version> + <scope>test</scope> + </dependency> <!--START OF GENERATED CODE--> <dependency> <groupId>org.apache.camel.springboot</groupId> diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddCommentProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddCommentProducerTest.java new file mode 100644 index 0000000..80b8dd8 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddCommentProducerTest.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithComments; +import static org.apache.camel.component.jira.springboot.test.Utils.newComment; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Comment; +import com.atlassian.jira.rest.client.api.domain.Issue; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.mockito.stubbing.Answer; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + AddCommentProducerTest.class, + AddCommentProducerTest.TestConfiguration.class + } +) + +public class AddCommentProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + static Issue issue; + + static String comment; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + when(issueRestClient.addComment(any(), any())).then((Answer<Void>) inv -> { + Collection<Comment> comments = new ArrayList<>(); + for (Comment c : backendIssue.getComments()) { + comments.add(c); + } + comments.add(newComment(backendIssue.getId(), comments.size() + 1, comment)); + backendIssue = createIssueWithComments(backendIssue.getId(), comments); + return null; + }); + backendIssue = createIssueWithComments(1, 1); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void verifyLastComment() throws InterruptedException { + template.sendBodyAndHeader(comment, ISSUE_KEY, backendIssue.getKey()); + + Issue issue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + String lastComment = null; + for (Comment c : issue.getComments()) { + lastComment = c.getBody(); + } + assertEquals(comment, lastComment); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + comment = "A new test comment " + new Date(); + from("direct:start") + .to("jira://addComment?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueLinkProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueLinkProducerTest.java new file mode 100644 index 0000000..177fb6d --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueLinkProducerTest.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.CHILD_ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.JiraConstants.LINK_TYPE; +import static org.apache.camel.component.jira.JiraConstants.PARENT_ISSUE_KEY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithLinks; +import static org.apache.camel.component.jira.springboot.test.Utils.newIssueLink; +import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf; +import static org.apache.camel.test.junit5.TestSupport.assertStringContains; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueLink; +import com.atlassian.jira.rest.client.api.domain.input.LinkIssuesInput; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelExecutionException; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.mockito.stubbing.Answer; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + AddIssueLinkProducerTest.class, + AddIssueLinkProducerTest.TestConfiguration.class + } +) + +public class AddIssueLinkProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue parentIssue; + static Issue childIssue; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + parentIssue = createIssue(1); + childIssue = createIssue(2); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void testAddIssueLink() throws InterruptedException { + String comment = "A new test comment " + new Date(); + String linkType = "Relates"; + Map<String, Object> headers = new HashMap<>(); + headers.put(PARENT_ISSUE_KEY, parentIssue.getKey()); + headers.put(CHILD_ISSUE_KEY, childIssue.getKey()); + headers.put(LINK_TYPE, linkType); + + when(issueRestClient.linkIssue(any(LinkIssuesInput.class))) + .then((Answer<Void>) inv -> { + Collection<IssueLink> links = new ArrayList<>(); + links.add(newIssueLink(childIssue.getId(), 1, comment)); + parentIssue = createIssueWithLinks(parentIssue.getId(), links); + return null; + }); + + template.sendBodyAndHeaders(comment, headers); + + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + + verify(issueRestClient).linkIssue(any(LinkIssuesInput.class)); + } + + @Test + public void testAddIssueLinkNoComment() throws InterruptedException { + String linkType = "Relates"; + Map<String, Object> headers = new HashMap<>(); + headers.put(PARENT_ISSUE_KEY, parentIssue.getKey()); + headers.put(CHILD_ISSUE_KEY, childIssue.getKey()); + headers.put(LINK_TYPE, linkType); + + when(issueRestClient.linkIssue(any(LinkIssuesInput.class))) + .then((Answer<Void>) inv -> { + Collection<IssueLink> links = new ArrayList<>(); + links.add(newIssueLink(childIssue.getId(), 1, null)); + parentIssue = createIssueWithLinks(parentIssue.getId(), links); + return null; + }); + + template.sendBodyAndHeaders(null, headers); + + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + + verify(issueRestClient).linkIssue(any(LinkIssuesInput.class)); + } + + @Test + public void testAddIssueLinkMissingParentIssueKey() throws InterruptedException { + String comment = "A new test comment " + new Date(); + String linkType = "Relates"; + Map<String, Object> headers = new HashMap<>(); + headers.put(CHILD_ISSUE_KEY, childIssue.getKey()); + headers.put(LINK_TYPE, linkType); + + try { + template.sendBodyAndHeaders(comment, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), PARENT_ISSUE_KEY); + } + + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).linkIssue(any(LinkIssuesInput.class)); + } + + @Test + public void testAddIssueLinkMissingChildIssueKey() throws InterruptedException { + String comment = "A new test comment " + new Date(); + String linkType = "Relates"; + Map<String, Object> headers = new HashMap<>(); + headers.put(PARENT_ISSUE_KEY, parentIssue.getKey()); + headers.put(LINK_TYPE, linkType); + + try { + template.sendBodyAndHeaders(comment, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), CHILD_ISSUE_KEY); + } + + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).linkIssue(any(LinkIssuesInput.class)); + } + + @Test + public void testAddIssueLinkMissingLinkType() throws InterruptedException { + String comment = "A new test comment " + new Date(); + Map<String, Object> headers = new HashMap<>(); + headers.put(PARENT_ISSUE_KEY, parentIssue.getKey()); + headers.put(CHILD_ISSUE_KEY, childIssue.getKey()); + + try { + template.sendBodyAndHeaders(comment, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), LINK_TYPE); + } + + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).linkIssue(any(LinkIssuesInput.class)); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .to("jira://addIssueLink?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueProducerTest.java new file mode 100644 index 0000000..b7449d3 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddIssueProducerTest.java @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_ASSIGNEE; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_PRIORITY_ID; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_PRIORITY_NAME; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_PROJECT_KEY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_SUMMARY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_TYPE_ID; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_TYPE_NAME; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.userAssignee; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.MetadataRestClient; +import com.atlassian.jira.rest.client.api.domain.BasicIssue; +import com.atlassian.jira.rest.client.api.domain.BasicPriority; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueType; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.input.ComplexIssueInputFieldValue; +import com.atlassian.jira.rest.client.api.domain.input.IssueInput; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.atlassian.util.concurrent.Promise; +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + AddIssueProducerTest.class, + AddIssueProducerTest.TestConfiguration.class + } +) + +public class AddIssueProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + static MetadataRestClient metadataRestClient; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + metadataRestClient = mock(MetadataRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + lenient().when(jiraClient.getMetadataClient()).thenReturn(metadataRestClient); + + Map<Integer, IssueType> issueTypes = new HashMap<>(); + issueTypes.put(1, new IssueType(null, 1L, "Bug", false, null, null)); + issueTypes.put(2, new IssueType(null, 2L, "Task", false, null, null)); + Promise<Iterable<IssueType>> promiseIssueTypes = Promises.promise(issueTypes.values()); + lenient().when(metadataRestClient.getIssueTypes()).thenReturn(promiseIssueTypes); + + Map<Integer, Priority> issuePriorities = new HashMap<>(); + issuePriorities.put(1, new Priority(null, 1L, "High", null, null, null)); + issuePriorities.put(2, new Priority(null, 2L, "Low", null, null, null)); + Promise<Iterable<Priority>> promisePriorities = Promises.promise(issuePriorities.values()); + lenient().when(metadataRestClient.getPriorities()).thenReturn(promisePriorities); + + lenient().when(issueRestClient.createIssue(any(IssueInput.class))).then(inv -> { + IssueInput issueInput = inv.getArgument(0); + String summary = (String) issueInput.getField("summary").getValue(); + Integer issueTypeId = Integer.parseInt(getValue(issueInput, "issuetype", "id")); + IssueType issueType = issueTypes.get(issueTypeId); + String project = getValue(issueInput, "project", "key"); + String description = (String) issueInput.getField("description").getValue(); + Integer priorityId = Integer.parseInt(getValue(issueInput, "priority", "id")); + BasicPriority priority = issuePriorities.get(priorityId); + backendIssue = createIssue(11L, summary, project, issueType, description, priority, userAssignee, null, null); + BasicIssue basicIssue = new BasicIssue(backendIssue.getSelf(), backendIssue.getKey(), backendIssue.getId()); + return Promises.promise(basicIssue); + }); + lenient().when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + private String getValue(IssueInput issueInput, String field, String key) { + ComplexIssueInputFieldValue complexField = (ComplexIssueInputFieldValue) issueInput.getField(field).getValue(); + return (String) complexField.getValuesMap().get(key); + } + + @Test + public void verifyIssueAdded() throws InterruptedException { + + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_PROJECT_KEY, KEY); + headers.put(ISSUE_TYPE_NAME, "Task"); + headers.put(ISSUE_SUMMARY, "Demo Bug jira " + (new Date())); + headers.put(ISSUE_PRIORITY_NAME, "Low"); + headers.put(ISSUE_ASSIGNEE, "tom"); + + template.sendBodyAndHeaders("Minha descrição jira " + (new Date()), headers); + + Issue issue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, issue); + assertEquals(backendIssue.getIssueType(), issue.getIssueType()); + assertEquals(backendIssue.getPriority(), issue.getPriority()); + assertEquals(backendIssue.getSummary(), issue.getSummary()); + assertEquals(backendIssue.getProject(), issue.getProject()); + assertEquals(backendIssue.getDescription(), issue.getDescription()); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + @Test + public void verifyIssueAddedWithIds() throws InterruptedException { + + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_PROJECT_KEY, KEY); + headers.put(ISSUE_TYPE_ID, 2); + headers.put(ISSUE_SUMMARY, "Demo Bug jira " + (new Date())); + headers.put(ISSUE_PRIORITY_ID, 1); + + template.sendBodyAndHeaders("Minha descrição jira " + (new Date()), headers); + + Issue issue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, issue); + assertEquals(backendIssue.getIssueType(), issue.getIssueType()); + assertEquals(backendIssue.getPriority(), issue.getPriority()); + assertEquals(backendIssue.getSummary(), issue.getSummary()); + assertEquals(backendIssue.getProject(), issue.getProject()); + assertEquals(backendIssue.getDescription(), issue.getDescription()); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .to("jira://addIssue?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddWorkLogProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddWorkLogProducerTest.java new file mode 100644 index 0000000..712bbb6 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AddWorkLogProducerTest.java @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.JiraConstants.MINUTES_SPENT; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithComments; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithWorkLogs; +import static org.apache.camel.component.jira.springboot.test.Utils.newWorkLog; +import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf; +import static org.apache.camel.test.junit5.TestSupport.assertStringContains; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.Worklog; +import com.atlassian.jira.rest.client.api.domain.input.WorklogInput; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelExecutionException; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.mockito.stubbing.Answer; + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + AddWorkLogProducerTest.class, + AddWorkLogProducerTest.TestConfiguration.class + } +) + +public class AddWorkLogProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + backendIssue = createIssueWithComments(1, 1); + lenient().when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void testAddWorkLog() throws InterruptedException { + int minutesSpent = 10; + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(MINUTES_SPENT, minutesSpent); + String comment = "A new test comment " + new Date(); + + when(issueRestClient.addWorklog(any(URI.class), any(WorklogInput.class))) + .then((Answer<Void>) inv -> { + Collection<Worklog> workLogs = new ArrayList<>(); + workLogs.add(newWorkLog(backendIssue.getId(), minutesSpent, comment)); + backendIssue = createIssueWithWorkLogs(backendIssue.getId(), workLogs); + return null; + }); + + template.sendBodyAndHeaders(comment, headers); + + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + + verify(issueRestClient).getIssue(backendIssue.getKey()); + verify(issueRestClient).addWorklog(eq(backendIssue.getWorklogUri()), any(WorklogInput.class)); + } + + @Test + public void testAddWorkLogMissingIssueKey() throws InterruptedException { + int minutesSpent = 3; + Map<String, Object> headers = new HashMap<>(); + headers.put(MINUTES_SPENT, minutesSpent); + String comment = "A new test comment " + new Date(); + + try { + template.sendBodyAndHeaders(comment, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), ISSUE_KEY); + } + mockResult.reset(); + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).getIssue(any(String.class)); + verify(issueRestClient, never()).addWorklog(any(URI.class), any(WorklogInput.class)); + } + + @Test + public void testAddWorkLogMissingMinutesSpent() throws InterruptedException { + + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + String comment = "A new test comment " + new Date(); + + try { + template.sendBodyAndHeaders(comment, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), MINUTES_SPENT); + } + + mockResult.reset(); + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).getIssue(any(String.class)); + verify(issueRestClient, never()).addWorklog(any(URI.class), any(WorklogInput.class)); + } + + @Test + public void testAddWorkLogMissingComment() throws InterruptedException { + int minutesSpent = 60; + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(MINUTES_SPENT, minutesSpent); + + try { + template.sendBodyAndHeaders(null, headers); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), "Missing exchange body"); + } + mockResult.reset(); + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).getIssue(any(String.class)); + verify(issueRestClient, never()).addWorklog(any(URI.class), any(WorklogInput.class)); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("jira://addWorkLog?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AttachFileProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AttachFileProducerTest.java new file mode 100644 index 0000000..7b15884 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/AttachFileProducerTest.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithAttachment; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collection; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Attachment; +import com.atlassian.jira.rest.client.api.domain.Issue; + + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + AttachFileProducerTest.class, + AttachFileProducerTest.TestConfiguration.class + } +) + +public class AttachFileProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static File attachedFile; + + static Issue issue; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + when(issueRestClient.getIssue(any())).then(inv -> { + if (issue == null) { + issue = createIssue(1); + } + return Promises.promise(issue); + }); + when(issueRestClient.addAttachments(any(URI.class), any(File.class))).then(inv -> { + File attachedFileTmp = inv.getArgument(1); + // create a temp destiny file as the attached file is marked for removal on AttachFileProducer + attachedFile = File.createTempFile("camel-jira-test-", null); + Files.copy(attachedFileTmp.toPath(), attachedFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + attachedFile.deleteOnExit(); + Collection<Attachment> attachments = new ArrayList<>(); + attachments.add(new Attachment( + issue.getAttachmentsUri(), attachedFile.getName(), null, null, + Long.valueOf(attachedFile.length()).intValue(), null, null, null)); + // re-create the issue with the attachment sent by the route + issue = createIssueWithAttachment(issue.getId(), issue.getSummary(), issue.getKey(), issue.getIssueType(), + issue.getDescription(), issue.getPriority(), issue.getAssignee(), attachments); + return null; + }); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + private File generateSampleFile() throws IOException { + File sampleRandomFile = File.createTempFile("attach-test", null); + sampleRandomFile.deleteOnExit(); + String text = "A random text to use on the AttachFileProducerTest.java of camel-jira component."; + Files.write(sampleRandomFile.toPath(), text.getBytes(), StandardOpenOption.CREATE); + return sampleRandomFile; + } + + @Test + public void verifyAttachment() throws InterruptedException, IOException { + template.sendBody(generateSampleFile()); + Issue retrievedIssue = issueRestClient.getIssue(issue.getKey()).claim(); + assertEquals(issue, retrievedIssue); + // there is only one attachment + Attachment attachFile = retrievedIssue.getAttachments().iterator().next(); + assertEquals(attachFile.getFilename(), attachedFile.getName()); + assertEquals(attachFile.getSize(), attachedFile.length()); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .setHeader(ISSUE_KEY, () -> KEY + "-1") + .to("jira://attach?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/DeleteIssueProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/DeleteIssueProducerTest.java new file mode 100644 index 0000000..d4c5a6d --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/DeleteIssueProducerTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + DeleteIssueProducerTest.class, + DeleteIssueProducerTest.TestConfiguration.class + } +) + +public class DeleteIssueProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + static Issue issue; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + issue = createIssue(1); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(issue)); + when(issueRestClient.deleteIssue(anyString(), anyBoolean())).then(inv -> { + issue = null; + return null; + }); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void verifyDeleteIssue() throws InterruptedException { + String issueKey = issue.getKey(); + template.sendBody(null); + Issue retrievedIssue = issueRestClient.getIssue(issueKey).claim(); + assertNull(retrievedIssue); + assertEquals(issue, retrievedIssue); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws IOException { + from("direct:start") + .setHeader(ISSUE_KEY, () -> KEY + "-1") + .to("jira://deleteIssue?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchCommentsProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchCommentsProducerTest.java new file mode 100644 index 0000000..97fbaae --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchCommentsProducerTest.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf; +import static org.apache.camel.test.junit5.TestSupport.assertStringContains; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelExecutionException; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + FetchCommentsProducerTest.class, + FetchCommentsProducerTest.TestConfiguration.class + } +) + +public class FetchCommentsProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + backendIssue = mock(Issue.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void testFetchComments() throws InterruptedException { + when(backendIssue.getKey()).thenReturn("TEST-123"); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + + template.sendBodyAndHeader(null, ISSUE_KEY, backendIssue.getKey()); + + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + + verify(issueRestClient).getIssue(backendIssue.getKey()); + verify(backendIssue).getComments(); + } + + @Test + public void testFetchCommentsMissingIssueKey() throws InterruptedException { + try { + template.sendBody(null); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), ISSUE_KEY); + } + + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).getIssue(backendIssue.getKey()); + verify(backendIssue, never()).getComments(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .to("jira://fetchComments?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchIssueProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchIssueProducerTest.java new file mode 100644 index 0000000..88b991f --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/FetchIssueProducerTest.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf; +import static org.apache.camel.test.junit5.TestSupport.assertStringContains; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelExecutionException; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + FetchIssueProducerTest.class, + FetchIssueProducerTest.TestConfiguration.class + } +) + +public class FetchIssueProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + backendIssue = mock(Issue.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void testFetchIssue() throws InterruptedException { + when(backendIssue.getKey()).thenReturn("TEST-123"); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + + template.sendBodyAndHeader(null, ISSUE_KEY, backendIssue.getKey()); + + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + + verify(issueRestClient).getIssue(backendIssue.getKey()); + } + + @Test + public void testFetchIssueMissingIssueKey() throws InterruptedException { + try { + template.sendBody(null); + fail("Should have thrown an exception"); + } catch (CamelExecutionException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertStringContains(cause.getMessage(), ISSUE_KEY); + } + + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + + verify(issueRestClient, never()).getIssue(backendIssue.getKey()); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("jira://fetchIssue?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/JiraTestConstants.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/JiraTestConstants.java new file mode 100644 index 0000000..a21e135 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/JiraTestConstants.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + +public interface JiraTestConstants { + + String KEY = "TST"; + String TEST_JIRA_URL = "https://somerepo.atlassian.net"; + String PROJECT = "TST"; + String USERNAME = "someguy"; + String PASSWORD = "my_password"; + String JIRA_CREDENTIALS = TEST_JIRA_URL + "&username=" + USERNAME + "&password=" + PASSWORD; + String WATCHED_COMPONENTS = "Priority,Status,Resolution"; +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewCommentsConsumerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewCommentsConsumerTest.java new file mode 100644 index 0000000..a814c2f --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewCommentsConsumerTest.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + + +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssueWithComments; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.PROJECT; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.SearchRestClient; +import com.atlassian.jira.rest.client.api.domain.Comment; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.SearchResult; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + + +import io.atlassian.util.concurrent.Promise; +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + NewCommentsConsumerTest.class, + NewCommentsConsumerTest.TestConfiguration.class + } +) + +public class NewCommentsConsumerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static SearchRestClient searchRestClient; + + static List<Issue> issues = new ArrayList<>(); + + + @BeforeAll + public static void beforeAll() { + issues.add(createIssueWithComments(1L, 1)); + issues.add(createIssueWithComments(2L, 1)); + issues.add(createIssueWithComments(3L, 1)); + } + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + searchRestClient = mock(SearchRestClient.class); + SearchResult result = new SearchResult(0, 50, 100, issues); + Promise<SearchResult> promiseSearchResult = Promises.promise(result); + Issue issue = createIssueWithComments(4L, 1); + Promise<Issue> promiseIssue = Promises.promise(issue); + + when(jiraClient.getSearchClient()).thenReturn(searchRestClient); + when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + when(searchRestClient.searchJql(any(), any(), any(), any())).thenReturn(promiseSearchResult); + when(issueRestClient.getIssue(anyString())).thenReturn(promiseIssue); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void emptyAtStartupTest() throws Exception { + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + } + + @Test + public void singleIssueCommentsTest() throws Exception { + Issue issueWithCommends = createIssueWithComments(11L, 3000); + Issue issueWithNoComments = createIssue(51L); + + reset(issueRestClient); + AtomicInteger regulator = new AtomicInteger(); + when(issueRestClient.getIssue(anyString())).then(inv -> { + int idx = regulator.getAndIncrement(); + Issue issue = issueWithNoComments; + if (idx < 1) { + issue = issueWithCommends; + } + return Promises.promise(issue); + }); + List<Comment> comments = new ArrayList<>(); + for (Comment c : issueWithCommends.getComments()) { + comments.add(c); + } + // reverse the order, from oldest comment to recent + Collections.reverse(comments); + // expect 3000 comments + mockResult.expectedBodiesReceived(comments); + mockResult.assertIsSatisfied(); + } + + @Test + public void multipleIssuesTest() throws Exception { + Issue issue1 = createIssueWithComments(20L, 2000); + Issue issue2 = createIssueWithComments(21L, 3000); + Issue issue3 = createIssueWithComments(22L, 1000); + List<Issue> newIssues = new ArrayList<>(); + newIssues.add(issue1); + newIssues.add(issue2); + newIssues.add(issue3); + Issue issueWithNoComments = createIssue(31L); + + reset(searchRestClient); + reset(issueRestClient); + SearchResult searchResult = new SearchResult(0, 50, 3, newIssues); + Promise<SearchResult> searchResultPromise = Promises.promise(searchResult); + when(searchRestClient.searchJql(anyString(), any(), any(), any())).thenReturn(searchResultPromise); + AtomicInteger regulator = new AtomicInteger(); + when(issueRestClient.getIssue(anyString())).then(inv -> { + int idx = regulator.getAndIncrement(); + Issue issue = issueWithNoComments; + if (idx < newIssues.size()) { + issue = newIssues.get(idx); + } + return Promises.promise(issue); + }); + List<Comment> comments = new ArrayList<>(); + for (Issue issue : newIssues) { + for (Comment c : issue.getComments()) { + comments.add(c); + } + } + // reverse the order, from oldest comment to recent + Collections.reverse(comments); + // expect 6000 comments + mockResult.expectedBodiesReceived(comments); + mockResult.assertIsSatisfied(); + } + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("jira://newComments?jiraUrl=" + JIRA_CREDENTIALS + "&jql=project=" + PROJECT + "&delay=1000") + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewIssuesConsumerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewIssuesConsumerTest.java new file mode 100644 index 0000000..69acd3b --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/NewIssuesConsumerTest.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.PROJECT; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.SearchRestClient; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.SearchResult; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + + +import io.atlassian.util.concurrent.Promise; +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + NewIssuesConsumerTest.class, + NewIssuesConsumerTest.TestConfiguration.class + } +) + +public class NewIssuesConsumerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static SearchRestClient searchRestClient; + + static List<Issue> issues = new ArrayList<>(); + + @BeforeAll + public static void beforeAll() { + issues.add(createIssue(1L)); + issues.add(createIssue(2L)); + issues.add(createIssue(3L)); + } + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + searchRestClient = mock(SearchRestClient.class); + SearchResult result = new SearchResult(0, 50, 100, issues); + Promise<SearchResult> promiseSearchResult = Promises.promise(result); + + when(jiraClient.getSearchClient()).thenReturn(searchRestClient); + when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + when(searchRestClient.searchJql(any(), any(), any(), any())).thenReturn(promiseSearchResult); + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void emptyAtStartupTest() throws Exception { + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + } + + @Test + public void singleIssueTest() throws Exception { + Issue issue = createIssue(11); + + reset(searchRestClient); + AtomicBoolean searched = new AtomicBoolean(); + when(searchRestClient.searchJql(any(), any(), any(), any())).then(invocation -> { + List<Issue> newIissues = new ArrayList<>(); + if (!searched.get()) { + newIissues.add(issue); + searched.set(true); + } + SearchResult result = new SearchResult(0, 50, 100, newIissues); + return Promises.promise(result); + }); + mockResult.expectedBodiesReceived(issue); + mockResult.assertIsSatisfied(); + } + + @Test + public void multipleIssuesTest() throws Exception { + Issue issue1 = createIssue(21); + Issue issue2 = createIssue(22); + Issue issue3 = createIssue(23); + + reset(searchRestClient); + AtomicBoolean searched = new AtomicBoolean(); + when(searchRestClient.searchJql(any(), any(), any(), any())).then(invocation -> { + List<Issue> newIssues = new ArrayList<>(); + if (!searched.get()) { + newIssues.add(issue1); + newIssues.add(issue2); + newIssues.add(issue3); + searched.set(true); + } + SearchResult result = new SearchResult(0, 50, 3, newIssues); + return Promises.promise(result); + }); + + mockResult.expectedBodiesReceived(issue3, issue2, issue1); + mockResult.assertIsSatisfied(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("jira://newIssues?jiraUrl=" + JIRA_CREDENTIALS + "&jql=project=" + PROJECT + "&delay=5000") + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/TransitionIssueProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/TransitionIssueProducerTest.java new file mode 100644 index 0000000..71e092e --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/TransitionIssueProducerTest.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_TRANSITION_ID; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.TEST_JIRA_URL; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.transitionIssueDone; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.URI; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.Resolution; +import com.atlassian.jira.rest.client.api.domain.Status; +import com.atlassian.jira.rest.client.api.domain.input.TransitionInput; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + TransitionIssueProducerTest.class, + TransitionIssueProducerTest.TestConfiguration.class + } +) + +public class TransitionIssueProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + static Issue issue; + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + issue = createIssue(1); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(issue)); + when(issueRestClient.transition(any(Issue.class), any(TransitionInput.class))).then(inv -> { + URI doneStatusUri = URI.create(TEST_JIRA_URL + "/rest/api/2/status/1"); + URI doneResolutionUri = URI.create(TEST_JIRA_URL + "/rest/api/2/resolution/1"); + Status status = new Status(doneStatusUri, 1L, "Done", "Done", null, null); + Resolution resolution = new Resolution(doneResolutionUri, 1L, "Resolution", "Resolution"); + issue = transitionIssueDone(issue, status, resolution); + return null; + }); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void verifyTransition() throws InterruptedException { + template.sendBody(null); + Issue retrievedIssue = issueRestClient.getIssue(issue.getKey()).claim(); + assertEquals(issue, retrievedIssue); + assertEquals(issue.getStatus(), retrievedIssue.getStatus()); + assertEquals(issue.getResolution(), retrievedIssue.getResolution()); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws IOException { + from("direct:start") + .setHeader(ISSUE_KEY, () -> KEY + "-1") + .setHeader(ISSUE_TRANSITION_ID, () -> 31) + .to("jira://transitionIssue?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/UpdateIssueProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/UpdateIssueProducerTest.java new file mode 100644 index 0000000..ae736ff --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/UpdateIssueProducerTest.java @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_ASSIGNEE; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_PRIORITY_NAME; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_SUMMARY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_TYPE_NAME; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.userAssignee; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.MetadataRestClient; +import com.atlassian.jira.rest.client.api.domain.BasicIssue; +import com.atlassian.jira.rest.client.api.domain.BasicPriority; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueType; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.input.ComplexIssueInputFieldValue; +import com.atlassian.jira.rest.client.api.domain.input.IssueInput; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.atlassian.util.concurrent.Promise; +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + UpdateIssueProducerTest.class, + UpdateIssueProducerTest.TestConfiguration.class + } +) + +public class UpdateIssueProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static MetadataRestClient metadataRestClient; + + static Issue backendIssue; + + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + metadataRestClient = mock(MetadataRestClient.class); + when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + when(jiraClient.getMetadataClient()).thenReturn(metadataRestClient); + + Map<Integer, IssueType> issueTypes = new HashMap<>(); + issueTypes.put(1, new IssueType(null, 1L, "Bug", false, null, null)); + issueTypes.put(2, new IssueType(null, 2L, "Task", false, null, null)); + Promise<Iterable<IssueType>> promiseIssueTypes = Promises.promise(issueTypes.values()); + when(metadataRestClient.getIssueTypes()).thenReturn(promiseIssueTypes); + + Map<Integer, Priority> issuePriorities = new HashMap<>(); + issuePriorities.put(1, new Priority(null, 1L, "High", null, null, null)); + issuePriorities.put(2, new Priority(null, 2L, "Low", null, null, null)); + Promise<Iterable<Priority>> promisePriorities = Promises.promise(issuePriorities.values()); + when(metadataRestClient.getPriorities()).thenReturn(promisePriorities); + + backendIssue = createIssue(11L); + when(issueRestClient.updateIssue(anyString(), any(IssueInput.class))).then(inv -> { + String issueKey = inv.getArgument(0); + IssueInput issueInput = inv.getArgument(1); + String summary = (String) issueInput.getField("summary").getValue(); + Integer issueTypeId = Integer.parseInt(getValue(issueInput, "issuetype", "id")); + IssueType issueType = issueTypes.get(issueTypeId); + String description = (String) issueInput.getField("description").getValue(); + Integer priorityId = Integer.parseInt(getValue(issueInput, "priority", "id")); + BasicPriority priority = issuePriorities.get(priorityId); + backendIssue = createIssue(11L, summary, issueKey, issueType, description, priority, userAssignee, null, null); + BasicIssue basicIssue = new BasicIssue(backendIssue.getSelf(), backendIssue.getKey(), backendIssue.getId()); + return Promises.promise(basicIssue); + }); + when(issueRestClient.getIssue(any())).then(inv -> Promises.promise(backendIssue)); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void verifyIssueUpdated() throws InterruptedException { + + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(ISSUE_TYPE_NAME, "Task"); + headers.put(ISSUE_SUMMARY, "Demo Bug jira " + (new Date())); + headers.put(ISSUE_PRIORITY_NAME, "Low"); + headers.put(ISSUE_ASSIGNEE, "tom"); + + template.sendBodyAndHeaders("New description " + (new Date()), headers); + + Issue issue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, issue); + assertEquals(backendIssue.getIssueType(), issue.getIssueType()); + assertEquals(backendIssue.getPriority(), issue.getPriority()); + assertEquals(backendIssue.getSummary(), issue.getSummary()); + assertEquals(backendIssue.getProject(), issue.getProject()); + assertEquals(backendIssue.getDescription(), issue.getDescription()); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + private String getValue(IssueInput issueInput, String field, String key) { + ComplexIssueInputFieldValue complexField = (ComplexIssueInputFieldValue) issueInput.getField(field).getValue(); + return (String) complexField.getValuesMap().get(key); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .to("jira://updateIssue?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java new file mode 100644 index 0000000..a26af43 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.StatusCategory; +import com.atlassian.jira.rest.client.api.domain.Attachment; +import com.atlassian.jira.rest.client.api.domain.BasicComponent; +import com.atlassian.jira.rest.client.api.domain.BasicPriority; +import com.atlassian.jira.rest.client.api.domain.BasicWatchers; +import com.atlassian.jira.rest.client.api.domain.Comment; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueLink; +import com.atlassian.jira.rest.client.api.domain.IssueLinkType; +import com.atlassian.jira.rest.client.api.domain.IssueType; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.Resolution; +import com.atlassian.jira.rest.client.api.domain.Status; +import com.atlassian.jira.rest.client.api.domain.User; +import com.atlassian.jira.rest.client.api.domain.Worklog; +import com.google.common.collect.ImmutableMap; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.slf4j.LoggerFactory; + +import static com.atlassian.jira.rest.client.api.domain.User.S48_48; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.TEST_JIRA_URL; + +public final class Utils { + public static User userAssignee; + static { + try { + userAssignee = new User( + null, "user-test", "User Test", "user@test", true, null, buildUserAvatarUris("user-test", 10082L), null); + } catch (Exception e) { + + LoggerFactory.getLogger(Utils.class).debug("Failed to build test user: {}", e.getMessage(), e); + } + } + private static IssueType issueType = new IssueType(null, 1L, "Bug", false, "Bug", null); + + private Utils() { + } + + public static Issue createIssue(long id) { + return createIssueWithComments(id, 0); + } + + public static Issue createIssue( + long id, String summary, String key, IssueType issueType, String description, + BasicPriority priority, User assignee, Collection<BasicComponent> components, BasicWatchers watchers) { + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + return new Issue( + summary, selfUri, KEY + "-" + id, id, null, issueType, null, description, priority, null, null, null, + assignee, null, null, null, null, null, components, null, null, null, null, null, null, null, watchers, + null, null, null, null, null); + } + + public static Issue transitionIssueDone(Issue issue, Status status, Resolution resolution) { + return new Issue( + issue.getSummary(), issue.getSelf(), issue.getKey(), issue.getId(), null, issue.getIssueType(), + status, issue.getDescription(), issue.getPriority(), resolution, null, null, + issue.getAssignee(), null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null); + } + + public static Issue setPriority(Issue issue, Priority p) { + return new Issue( + issue.getSummary(), issue.getSelf(), issue.getKey(), issue.getId(), null, issue.getIssueType(), + issue.getStatus(), issue.getDescription(), p, issue.getResolution(), null, null, + issue.getAssignee(), null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null); + } + + public static Issue transitionIssueDone(Issue issue) { + URI doneStatusUri = URI.create(TEST_JIRA_URL + "/rest/api/2/status/1"); + URI doneResolutionUri = URI.create(TEST_JIRA_URL + "/rest/api/2/resolution/1"); + StatusCategory sc = new StatusCategory(doneResolutionUri, "statusCategory", 1L, "SC-1", "GREEN"); + Status status = new Status(doneStatusUri, 1L, "Done", "Done", null, sc); + Resolution resolution = new Resolution(doneResolutionUri, 5L, "Resolution", "Resolution"); + return transitionIssueDone(issue, status, resolution); + } + + public static Issue createIssueWithAttachment( + long id, String summary, String key, IssueType issueType, String description, + BasicPriority priority, User assignee, Collection<Attachment> attachments) { + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + return new Issue( + summary, selfUri, KEY + "-" + id, id, null, issueType, null, description, priority, null, attachments, null, + assignee, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null); + } + + public static Issue createIssueWithComments(long id, int numComments) { + Collection<Comment> comments = new ArrayList<>(); + if (numComments > 0) { + for (int idx = 1; idx < numComments + 1; idx++) { + Comment c = newComment(id, idx, "A test comment " + idx + " for " + KEY + "-" + id); + comments.add(c); + } + } + return createIssueWithComments(id, comments); + } + + public static Issue createIssueWithComments(long id, Collection<Comment> comments) { + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + return new Issue( + "jira summary test " + id, selfUri, KEY + "-" + id, id, null, issueType, null, "Description " + id, + null, null, null, null, userAssignee, null, null, null, null, null, null, null, null, comments, null, null, + null, null, null, null, null, null, null, null); + } + + public static Issue createIssueWithLinks(long id, Collection<IssueLink> issueLinks) { + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + return new Issue( + "jira summary test " + id, selfUri, KEY + "-" + id, id, null, issueType, null, "Description " + id, + null, null, null, null, userAssignee, null, null, null, null, null, null, null, null, null, null, issueLinks, + null, null, null, null, null, null, null, null); + } + + public static Issue createIssueWithWorkLogs(long id, Collection<Worklog> worklogs) { + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + return new Issue( + "jira summary test " + id, selfUri, KEY + "-" + id, id, null, issueType, null, "Description " + id, + null, null, null, null, userAssignee, null, null, null, null, null, null, null, null, null, null, null, + null, worklogs, null, null, null, null, null, null); + } + + public static Comment newComment(long issueId, int newCommentId, String comment) { + DateTime now = DateTime.now(); + long id = Long.parseLong(issueId + "0" + newCommentId); + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + issueId + "/comment"); + return new Comment(selfUri, comment, null, null, now, null, null, id); + } + + public static IssueLink newIssueLink(long issueId, int newLinkId, String comment) { + long id = Long.parseLong(issueId + "0" + newLinkId); + URI issueUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + id); + IssueLinkType relatesTo = new IssueLinkType("Relates", "relates to", IssueLinkType.Direction.OUTBOUND); + + return new IssueLink(KEY, issueUri, relatesTo); + } + + public static Worklog newWorkLog(long issueId, Integer minutesSpent, String comment) { + DateTime now = DateTime.now(); + URI issueUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + issueId); + URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + issueId + "/comment"); + + return new Worklog(selfUri, issueUri, null, null, comment, now, null, null, minutesSpent, null); + } + + private static Map<String, URI> buildUserAvatarUris(String user, Long avatarId) throws Exception { + final ImmutableMap.Builder<String, URI> builder = ImmutableMap.builder(); + builder.put(S48_48, buildUserAvatarUri(user, avatarId)); + return builder.build(); + } + + private static URI buildUserAvatarUri(String userName, Long avatarId) throws Exception { + // secure/useravatar?size=small&ownerId=admin&avatarId=10054 + final StringBuilder sb = new StringBuilder("secure/useravatar?"); + + // Optional user name + if (StringUtils.isNotBlank(userName)) { + sb.append("ownerId=").append(userName).append("&"); + } + + // avatar Id + sb.append("avatarId=").append(avatarId); + String relativeAvatarUrl = sb.toString(); + URI avatarUrl = new URL(TEST_JIRA_URL + "/" + relativeAvatarUrl).toURI(); + return avatarUrl; + } + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatchUpdatesConsumerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatchUpdatesConsumerTest.java new file mode 100644 index 0000000..cdb6a70 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatchUpdatesConsumerTest.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.PROJECT; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.WATCHED_COMPONENTS; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.apache.camel.component.jira.springboot.test.Utils.setPriority; +import static org.apache.camel.component.jira.springboot.test.Utils.transitionIssueDone; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.SearchRestClient; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.SearchResult; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jira.JiraConstants; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + + +import io.atlassian.util.concurrent.Promise; +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + WatchUpdatesConsumerTest.class, + WatchUpdatesConsumerTest.TestConfiguration.class + } +) + +public class WatchUpdatesConsumerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static SearchRestClient searchRestClient; + + static List<Issue> issues = new ArrayList<>(); + + @BeforeAll + public static void beforeAll() { + issues.clear(); + issues.add(createIssue(1L)); + issues.add(createIssue(2L)); + issues.add(createIssue(3L)); + } + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + searchRestClient = mock(SearchRestClient.class); + SearchResult result = new SearchResult(0, 50, 100, issues); + Promise<SearchResult> promiseSearchResult = Promises.promise(result); + + when(jiraClient.getSearchClient()).thenReturn(searchRestClient); + when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + when(searchRestClient.searchJql(any(), any(), any(), any())).thenReturn(promiseSearchResult); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void emptyAtStartupTest() throws Exception { + mockResult.expectedMessageCount(0); + mockResult.assertIsSatisfied(); + } + + @Test + public void singleChangeTest() throws Exception { + Issue issue = setPriority(issues.get(0), new Priority( + null, 4L, "High", null, null, null)); + reset(searchRestClient); + AtomicBoolean searched = new AtomicBoolean(); + when(searchRestClient.searchJql(any(), any(), any(), any())).then(invocation -> { + + if (!searched.get()) { + issues.remove(0); + issues.add(0, issue); + } + SearchResult result = new SearchResult(0, 50, 100, issues); + return Promises.promise(result); + }); + + mockResult.expectedBodiesReceived(issue.getPriority()); + mockResult.expectedHeaderReceived(JiraConstants.ISSUE_CHANGED, "Priority"); + mockResult.expectedHeaderReceived(JiraConstants.ISSUE_KEY, "TST-1"); + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(0); + } + + @Test + public void multipleChangesWithAddedNewIssueTest() throws Exception { + final Issue issue = transitionIssueDone(issues.get(1)); + final Issue issue2 = setPriority(issues.get(2), new Priority( + null, 4L, "High", null, null, null)); + + reset(searchRestClient); + AtomicBoolean searched = new AtomicBoolean(); + when(searchRestClient.searchJql(any(), any(), any(), any())).then(invocation -> { + if (!searched.get()) { + issues.add(createIssue(4L)); + issues.remove(1); + issues.add(1, issue); + issues.remove(2); + issues.add(2, issue2); + searched.set(true); + } + + SearchResult result = new SearchResult(0, 50, 3, issues); + return Promises.promise(result); + }); + + mockResult.expectedMessageCount(3); + mockResult.expectedBodiesReceivedInAnyOrder(issue.getStatus(), issue.getResolution(), issue2.getPriority()); + mockResult.assertIsSatisfied(1000); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("jira://watchUpdates?jiraUrl=" + JIRA_CREDENTIALS + + "&jql=project=" + PROJECT + "&delay=5000&watchedFields=" + WATCHED_COMPONENTS) + .to(mockResult); + } + }; + } + + + } + + + + +} diff --git a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatcherProducerTest.java b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatcherProducerTest.java new file mode 100644 index 0000000..5fe8fc4 --- /dev/null +++ b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/WatcherProducerTest.java @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.jira.springboot.test; + + +import static org.apache.camel.component.jira.JiraConstants.ISSUE_KEY; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_WATCHERS_ADD; +import static org.apache.camel.component.jira.JiraConstants.ISSUE_WATCHERS_REMOVE; +import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.JIRA_CREDENTIALS; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.KEY; +import static org.apache.camel.component.jira.springboot.test.JiraTestConstants.TEST_JIRA_URL; +import static org.apache.camel.component.jira.springboot.test.Utils.createIssue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.atlassian.jira.rest.client.api.IssueRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; +import com.atlassian.jira.rest.client.api.domain.BasicUser; +import com.atlassian.jira.rest.client.api.domain.BasicWatchers; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.Watchers; + +import org.apache.camel.CamelContext; +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.CamelContextConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.atlassian.util.concurrent.Promises; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; + + + +@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest( + classes = { + CamelAutoConfiguration.class, + WatcherProducerTest.class, + WatcherProducerTest.TestConfiguration.class + } +) + +public class WatcherProducerTest { + + @Autowired + private CamelContext camelContext; + + + + @Autowired + @Produce("direct:start") + ProducerTemplate template; + + @EndpointInject("mock:result") + MockEndpoint mockResult; + + static JiraRestClient jiraClient; + + static JiraRestClientFactory jiraRestClientFactory; + + static IssueRestClient issueRestClient; + + static Issue backendIssue; + + static Issue issue; + + static List<String> backendwatchers = new ArrayList<>(); + + @Bean + CamelContextConfiguration contextConfiguration() { + return new CamelContextConfiguration() { + @Override + public void beforeApplicationStart(CamelContext context) { + //get chance to mock camelContext/Registry + jiraRestClientFactory = mock(JiraRestClientFactory.class); + jiraClient = mock(JiraRestClient.class); + issueRestClient = mock(IssueRestClient.class); + lenient().when(jiraRestClientFactory.createWithBasicHttpAuthentication(any(), any(), any())).thenReturn(jiraClient); + lenient().when(jiraClient.getIssueClient()).thenReturn(issueRestClient); + + backendwatchers.add("user1"); + backendwatchers.add("user2"); + backendwatchers.add("user3"); + backendwatchers.add("user4"); + backendwatchers.add("user5"); + URI watchersUri = URI.create(TEST_JIRA_URL + "/rest/api/2/backendIssue/" + KEY + "-11/backendwatchers"); + BasicWatchers initialBasicWatchers = new BasicWatchers(watchersUri, true, backendwatchers.size()); + backendIssue + = createIssue(11L, "Test backendIssue", KEY + "-" + 11, null, null, null, null, null, initialBasicWatchers); + lenient().when(issueRestClient.addWatcher(any(URI.class), anyString())).then(inv -> { + String username = inv.getArgument(1); + backendwatchers.add(username); + BasicWatchers basicWatchers = new BasicWatchers(watchersUri, true, backendwatchers.size()); + backendIssue = createIssue(backendIssue.getId(), backendIssue.getSummary(), backendIssue.getKey(), + backendIssue.getIssueType(), backendIssue.getDescription(), + backendIssue.getPriority(), backendIssue.getAssignee(), null, basicWatchers); + return null; + }); + lenient().when(issueRestClient.removeWatcher(any(URI.class), anyString())).then(inv -> { + String username = inv.getArgument(1); + backendwatchers.remove(username); + BasicWatchers basicWatchers = new BasicWatchers(watchersUri, true, backendwatchers.size()); + backendIssue = createIssue(backendIssue.getId(), backendIssue.getSummary(), backendIssue.getKey(), + backendIssue.getIssueType(), backendIssue.getDescription(), + backendIssue.getPriority(), backendIssue.getAssignee(), null, basicWatchers); + return null; + }); + lenient().when(issueRestClient.getIssue(anyString())).then(inv -> Promises.promise(backendIssue)); + lenient().when(issueRestClient.getWatchers(any(URI.class))).then(inv -> { + Collection<BasicUser> users = new ArrayList<>(); + for (String watcher : backendwatchers) { + users.add(new BasicUser(null, watcher, watcher)); + } + BasicWatchers basicWatchers = new BasicWatchers(watchersUri, true, users.size()); + Watchers watchers = new Watchers(basicWatchers, users); + return Promises.promise(watchers); + }); + + camelContext.getRegistry().bind(JIRA_REST_CLIENT_FACTORY, jiraRestClientFactory); + } + + @Override + public void afterApplicationStart(CamelContext camelContext) { + //do nothing here + } + }; + } + + @Test + public void addWatchers() throws InterruptedException { + List<String> watchersToAdd = new ArrayList<>(); + watchersToAdd.add("user1A"); + watchersToAdd.add("user1B"); + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(ISSUE_WATCHERS_ADD, watchersToAdd); + template.sendBodyAndHeaders(null, headers); + + Issue retrievedIssue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, retrievedIssue); + assertEquals(retrievedIssue.getWatchers().getNumWatchers(), backendwatchers.size()); + + Watchers watchers = issueRestClient.getWatchers(retrievedIssue.getWatchers().getSelf()).claim(); + for (BasicUser user : watchers.getUsers()) { + assertTrue(backendwatchers.contains(user.getName())); + } + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + @Test + public void removeWatchers() throws InterruptedException { + List<String> watchersToRemove = new ArrayList<>(); + watchersToRemove.add("user2"); + watchersToRemove.add("user3"); + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(ISSUE_WATCHERS_REMOVE, watchersToRemove); + template.sendBodyAndHeaders(null, headers); + + Issue retrievedIssue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, retrievedIssue); + assertEquals(retrievedIssue.getWatchers().getNumWatchers(), backendwatchers.size()); + + Watchers watchers = issueRestClient.getWatchers(retrievedIssue.getWatchers().getSelf()).claim(); + for (BasicUser user : watchers.getUsers()) { + assertTrue(backendwatchers.contains(user.getName())); + } + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + @Test + public void addRemoveWatchers() throws InterruptedException { + List<String> watchersToAdd = new ArrayList<>(); + watchersToAdd.add("user2A"); + watchersToAdd.add("user2B"); + List<String> watchersToRemove = new ArrayList<>(); + watchersToRemove.add("user4"); + watchersToRemove.add("user5"); + Map<String, Object> headers = new HashMap<>(); + headers.put(ISSUE_KEY, backendIssue.getKey()); + headers.put(ISSUE_WATCHERS_ADD, watchersToAdd); + headers.put(ISSUE_WATCHERS_REMOVE, watchersToRemove); + template.sendBodyAndHeaders(null, headers); + + Issue retrievedIssue = issueRestClient.getIssue(backendIssue.getKey()).claim(); + assertEquals(backendIssue, retrievedIssue); + assertEquals(retrievedIssue.getWatchers().getNumWatchers(), backendwatchers.size()); + + Watchers watchers = issueRestClient.getWatchers(retrievedIssue.getWatchers().getSelf()).claim(); + for (BasicUser user : watchers.getUsers()) { + assertTrue(backendwatchers.contains(user.getName())); + } + mockResult.expectedMessageCount(1); + mockResult.assertIsSatisfied(); + } + + + @Configuration + public class TestConfiguration { + + + + @Bean + public RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .to("jira://watchers?jiraUrl=" + JIRA_CREDENTIALS) + .to(mockResult); + } + }; + } + + + } + + + + +}