/** * # Copyright 2016 Infobip * # * # Licensed 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 com.infobip.jira; import com.atlassian.applinks.api.CredentialsRequiredException; import com.atlassian.bitbucket.commit.*; import com.atlassian.bitbucket.hook.repository.RepositoryHookContext; import com.atlassian.bitbucket.repository.*; import com.atlassian.bitbucket.setting.Settings; import com.atlassian.bitbucket.user.TestApplicationUser; import com.atlassian.bitbucket.util.*; import com.atlassian.sal.api.net.ResponseException; import com.google.common.collect.ImmutableList; import com.infobip.bitbucket.JiraVersionGeneratorHook; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.mockito.verification.VerificationMode; import java.io.IOException; import java.time.LocalDate; import java.time.ZoneOffset; import java.util.*; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.refEq; import static org.mockito.Mockito.times; @RunWith(MockitoJUnitRunner.class) public class JiraVersionGeneratorHookTest { private static final LocalDate START_OF_2016 = LocalDate.of(2016, 1, 1); @InjectMocks private JiraVersionGeneratorHook jiraVersionGeneratorHook; @Mock private CommitService commitService; @Mock private JiraService jiraService; @Mock private RepositoryHookContext repositoryHookContext; @Mock private Repository repository; @Mock private RefChange latestRefChange; @Mock private RefChange olderRefChange; @Mock private Settings settings; @Before public void setUp() throws Exception { given(repositoryHookContext.getSettings()).willReturn(settings); given(settings.getString(anyString(), eq(""))).willReturn(""); given(repositoryHookContext.getRepository()).willReturn(repository); given(latestRefChange.getFromHash()).willReturn("latestRefChange"); given(olderRefChange.getFromHash()).willReturn("olderRefChange"); } @Test public void shouldGenerateVersionWithNoIssues() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); Commit secondReleaseCommit = givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare release test-project-1.0.1", START_OF_2016), secondReleaseCommit); givenCommits(olderRefChange, secondReleaseCommit); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.1", "TEST"); whenPostReceive(latestRefChange); whenPostReceive(olderRefChange); then(jiraService).should().findVersion(new ProjectKey("TEST"), "1.0.1"); } @Test public void shouldGenerateJiraVersionWithAPrefix() throws IOException, CredentialsRequiredException, ResponseException { givenSetting("jira-version-prefix", "infobip-test-"); givenSetting("jira-project-key", "TEST"); givenRepositoryName("test-project"); Commit firstReleaseCommit = givenCommit("[maven-release-plugin] prepare release test-project-1.0.1", START_OF_2016); Commit secondReleaseCommit = givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016); givenCommits(latestRefChange, firstReleaseCommit, secondReleaseCommit); givenCommits(olderRefChange, secondReleaseCommit); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "infobip-test-1.0.1", "TEST"); whenPostReceive(latestRefChange); whenPostReceive(olderRefChange); then(jiraService).should().findVersion(new ProjectKey("TEST"), "infobip-test-1.0.1"); thenGetCommits(times(1), latestRefChange); thenGetCommits(times(1), olderRefChange); } @Test public void shouldGenerateJiraVersionWithACustomVersionPattern() throws IOException, CredentialsRequiredException, ResponseException { givenSetting("jira-project-key", "TEST"); givenSetting("release-commit-version-pattern", "Release (?<version>.*)"); givenRepositoryName("test-project"); Commit secondCommit = givenCommit("Release test-project-1.0.0", START_OF_2016); givenCommits(latestRefChange, givenCommit("Release 1.0.1", START_OF_2016), secondCommit); givenCommits(olderRefChange, secondCommit); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.1", "TEST"); whenPostReceive(latestRefChange); whenPostReceive(olderRefChange); then(jiraService).should().findVersion(new ProjectKey("TEST"), "1.0.1"); thenGetCommits(times(1), latestRefChange); thenGetCommits(times(1), olderRefChange); } @Test public void shouldGenerateJiraVersionAndLinkIssuesWhenHookEventOccursAfterAnotherCommit() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); Commit secondCommit = givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016); Commit thirdCommit = givenCommit("TEST-1", START_OF_2016); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare for next development iteration", START_OF_2016), secondCommit, thirdCommit); givenCommits(olderRefChange, secondCommit, thirdCommit); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.0", "TEST"); whenPostReceive(olderRefChange); whenPostReceive(latestRefChange); then(jiraService).should().findVersion(new ProjectKey("TEST"), "1.0.0"); thenGetCommits(times(1), olderRefChange); thenGetCommits(times(1), latestRefChange); } @Test public void shouldGenerateJiraVersionAndLinkIssuesOnlyForLatestRefChange() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); Commit secondCommit = givenCommit("TEST-1", START_OF_2016); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016), secondCommit); givenCommits(olderRefChange, secondCommit); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.0", "TEST"); whenPostReceive(latestRefChange); whenPostReceive(olderRefChange); then(jiraService).should().findVersion(new ProjectKey("TEST"), "1.0.0"); thenGetCommits(times(1), latestRefChange); thenGetCommits(times(1), olderRefChange); } @Test public void shouldGenerateJiraVersionAndLinkIssueWhenThereAreCommitsWithNoIssueKeyInMessage() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016), givenCommit("Merge pull request #3 in TEST/test-project from test to master", START_OF_2016), givenCommit("Merge pull request #2 in TEST/test-project from TEST-1", START_OF_2016), givenCommit("Merge pull request #1 in TEST/test-project from TEST-2", START_OF_2016)); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.0", "TEST"); whenPostReceive(latestRefChange); then(jiraService).should().createJiraVersion(unreleasedSerializedVersion("1.0.0", "TEST")); then(jiraService).should().addVersionToIssues("1.0.0", new ProjectKey("TEST"), Arrays.asList(new IssueKey(new ProjectKey("TEST"), new IssueId("1")), new IssueKey(new ProjectKey("TEST"), new IssueId("2")))); } @Test public void shouldNotLinkIssuesThatAreNotPartOfVersionProject() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016), givenCommit("Merge pull request #298 in TEST/test-project from test to master", START_OF_2016), givenCommit("Merge pull request #2 in TEST/test-project from TEST-1", START_OF_2016), givenCommit("Merge pull request #295 in TEST/test-project from ABCD-1", START_OF_2016), givenCommit("Merge pull request #1 in TEST/test-project from TEST-2", START_OF_2016)); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.0", "TEST"); whenPostReceive(latestRefChange); then(jiraService).should().createJiraVersion(unreleasedSerializedVersion("1.0.0", "TEST")); then(jiraService).should().addVersionToIssues("1.0.0", new ProjectKey("TEST"), Arrays.asList(new IssueKey(new ProjectKey("TEST"), new IssueId("1")), new IssueKey(new ProjectKey("TEST"), new IssueId("2")))); } @Test public void shouldLinkAllRelatedIssuesPresentInACommitMessage() throws IOException, CredentialsRequiredException, ResponseException { givenRepositoryName("test-project"); givenSetting("jira-project-key", "TEST"); givenCommits(latestRefChange, givenCommit("[maven-release-plugin] prepare release test-project-1.0.0", START_OF_2016), givenCommit("Merge pull request #298 in TEST/test-project from test to master", START_OF_2016), givenCommit("Merge pull request #2 in TEST/test-project from TEST-1, TEST-2, TEST-3", START_OF_2016)); givenJiraVersionDoesNotExist(); givenCreatedVersion("1", "1.0.0", "TEST"); whenPostReceive(latestRefChange); then(jiraService).should().createJiraVersion(unreleasedSerializedVersion("1.0.0", "TEST")); then(jiraService).should().addVersionToIssues("1.0.0", new ProjectKey("TEST"), Arrays.asList(new IssueKey(new ProjectKey("TEST"), new IssueId("1")), new IssueKey(new ProjectKey("TEST"), new IssueId("2")), new IssueKey(new ProjectKey("TEST"), new IssueId("3")))); } private void givenCreatedVersion(String id, String name, String project) { given(jiraService.createJiraVersion(any())).willReturn(new SerializedVersion(id, name, project, null, false)); } private void givenSetting(String key, String value) { given(settings.getString(eq(key))).willReturn(value); } private void givenJiraVersionDoesNotExist() throws CredentialsRequiredException, ResponseException, IOException { given(jiraService.findVersion(any(), any())).willReturn(Optional.empty()); } private void givenCommits(RefChange refChange, Commit... commits) { CommitsBetweenRequest request = new CommitsBetweenRequest.Builder(repository).include(refChange.getFromHash()).build(); given(commitService.getCommitsBetween(refEq(request), any())).willReturn(new PageImpl<>(null, Arrays.asList(commits), true)); } private void givenRepositoryName(String value) { given(repository.getName()).willReturn(value); } private void whenPostReceive(RefChange refChange) { jiraVersionGeneratorHook.postReceive(repositoryHookContext, ImmutableList.of(refChange)); } private SerializedVersion unreleasedSerializedVersion(String name, String Project) { return new SerializedVersion(null, name, Project, null, false); } private void thenGetCommits(VerificationMode verificationMode, RefChange refChange) { CommitsBetweenRequest request = new CommitsBetweenRequest.Builder(repository) .include(refChange.getFromHash()) .build(); then(commitService).should(verificationMode).getCommitsBetween(refEq(request), any(PageRequest.class)); } Commit givenCommit(String message, LocalDate authorTimestamp) { return new SimpleCommit.Builder("id") .author(new TestApplicationUser("")) .message(message) .authorTimestamp(Date.from(authorTimestamp.atStartOfDay().toInstant(ZoneOffset.UTC))) .build(); } Commit givenCommit(String message) { return new SimpleCommit.Builder("id") .author(new TestApplicationUser("")) .message(message) .build(); } }