package hudson.plugins.jira;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import hudson.model.BuildListener;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Result;
import hudson.model.User;
import hudson.plugins.jira.soap.RemoteComment;
import hudson.plugins.jira.soap.RemoteGroup;
import hudson.plugins.jira.soap.RemoteIssue;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import javax.xml.rpc.ServiceException;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* Test case for the JIRA {@link Updater}.
*
* @author kutzi
*/
@SuppressWarnings("unchecked")
public class UpdaterTest {
private static class MockEntry extends Entry {
private final String msg;
public MockEntry(String msg) {
this.msg = msg;
}
@Override
public Collection<String> getAffectedPaths() {
return null;
}
@Override
public User getAuthor() {
return null;
}
@Override
public String getMsg() {
return this.msg;
}
}
@Test
public void testFindIssues() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
BuildListener listener = mock(BuildListener.class);
when(changeLogSet.iterator()).thenReturn(Collections.EMPTY_LIST.iterator());
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<String> ids = new HashSet<String>();
Updater.findIssues(build, ids, null, listener);
Assert.assertTrue(ids.isEmpty());
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed JIRA-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, listener);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("JIRA-4711", ids.iterator().next());
// now test multiple ids
entries = Sets.newHashSet(
new MockEntry("Fixed BL-4711"),
new MockEntry("TR-123: foo"),
new MockEntry("[ABC-42] hallo"),
new MockEntry("#123: this one must not match"),
new MockEntry("ABC-: this one must also not match"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = new TreeSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, listener);
Assert.assertEquals(3, ids.size());
Set<String> expected = Sets.newTreeSet(Sets.newHashSet(
"BL-4711", "TR-123", "ABC-42"));
Assert.assertEquals(expected, ids);
}
@Test
@Bug(729)
public void testDigitsInProjectNameAllowed() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed JI123-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
BuildListener listener = mock(BuildListener.class);
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, listener);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("JI123-4711", ids.iterator().next());
}
@Test
@Bug(4092)
public void testUnderscoreInProjectNameAllowed() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed FOO_BAR-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, mock(BuildListener.class));
Assert.assertEquals(1, ids.size());
Assert.assertEquals("FOO_BAR-4711", ids.iterator().next());
}
@Test
@Bug(4132)
public void testLowercaseProjectNameAllowed() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed foo_bar-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
BuildListener listener = mock(BuildListener.class);
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, listener);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("FOO_BAR-4711", ids.iterator().next());
entries = Sets.newHashSet(new MockEntry("Fixed FoO_bAr-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, listener);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("FOO_BAR-4711", ids.iterator().next());
}
/**
* Tests that the generated comment matches the expectations -
* especially that the JIRA id is not stripped from the comment.
*/
@Test
@Bug(4572)
public void testComment() throws IOException, ServiceException, InterruptedException {
// mock JIRA session:
JiraSession session = mock(JiraSession.class);
when(session.existsIssue(Mockito.anyString())).thenReturn(Boolean.TRUE);
when(session.getIssue(Mockito.anyString())).thenReturn(new RemoteIssue());
when(session.getGroup(Mockito.anyString())).thenReturn(new RemoteGroup("Software Development", null));
final List<RemoteComment> comments = new ArrayList<RemoteComment>();
Answer answer = new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
RemoteComment rc = new RemoteComment();
rc.setId((String) invocation.getArguments()[0]);
rc.setBody((String) invocation.getArguments()[1]);
rc.setGroupLevel((String) invocation.getArguments()[2]);
comments.add(rc);
return null;
}
};
doAnswer(answer).when(session).addComment(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
// mock build:
FreeStyleBuild build = mock(FreeStyleBuild.class);
FreeStyleProject project = mock(FreeStyleProject.class);
when(build.getProject()).thenReturn(project);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
when(build.getResult()).thenReturn(Result.SUCCESS);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed FOOBAR-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
// test:
List<JiraIssue> ids = Lists.newArrayList(new JiraIssue("FOOBAR-4711", "Title"));
Updater.submitComments(build,
System.out, "http://hudson" , ids, session, false, false, "");
Assert.assertEquals(1, comments.size());
RemoteComment comment = comments.get(0);
Assert.assertTrue(comment.getBody().contains("FOOBAR-4711"));
Assert.assertTrue(comment.getGroupLevel().equals(""));
// must also work case-insensitively (HUDSON-4132)
comments.clear();
entries = Sets.newHashSet(new MockEntry("Fixed Foobar-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = Lists.newArrayList(new JiraIssue("FOOBAR-4711", "Title"));
Updater.submitComments(build,
System.out, "http://hudson" , ids, session, false, false,"");
Assert.assertEquals(1, comments.size());
comment = comments.get(0);
Assert.assertTrue(comment.getBody().contains("Foobar-4711"));
}
/**
* Tests that the default pattern doesn't match strings like
* 'project-1.1'.
* These patterns are used e.g. by the maven release plugin.
*/
@Test
public void testDoNotMatchDotsInIssueId() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
// commit messages like the one from the Maven release plugin must not match
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("prepare release project-4.7.1"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, null);
Assert.assertEquals(0, ids.size());
// but ids with just a full-stop after it must still match
entries = Sets.newHashSet(new MockEntry("Fixed FOO-4. Did it right this time"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, null);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("FOO-4", ids.iterator().next());
// as well as messages with a full-stop as last character after an issue id
entries = Sets.newHashSet(new MockEntry("Fixed FOO-4."));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
ids = new HashSet<String>();
Updater.findIssues(build, ids, JiraSite.DEFAULT_ISSUE_PATTERN, null);
Assert.assertEquals(1, ids.size());
Assert.assertEquals("FOO-4", ids.iterator().next());
}
@Test
@Bug(6043)
public void testUserPatternNotMatch() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed FOO_BAR-4711"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
Updater.findIssues(build, ids, Pattern.compile("[(w)]"), mock(BuildListener.class));
Assert.assertEquals(0, ids.size());
}
@Test
@Bug(6043)
public void testUserPatternMatch() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed toto [FOOBAR-4711]"), new MockEntry( "[TEST-9] with [dede]" ),new MockEntry("toto [maven-release-plugin] prepare release foo-2.2.3"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
Pattern pat = Pattern.compile("\\[(\\w+-\\d+)\\]");
Updater.findIssues(build, ids, pat, mock(BuildListener.class) );
Assert.assertEquals(2, ids.size());
Assert.assertTrue( ids.contains( "TEST-9" ) );
Assert.assertTrue( ids.contains( "FOOBAR-4711" ) );
}
@Test
@Bug(6043)
public void testUserPatternMatchTwoIssuesInOneComment() {
FreeStyleBuild build = mock(FreeStyleBuild.class);
ChangeLogSet changeLogSet = mock(ChangeLogSet.class);
when(build.getChangeSet()).thenReturn(changeLogSet);
Set<? extends Entry> entries = Sets.newHashSet(new MockEntry("Fixed toto [FOOBAR-4711] [FOOBAR-21] "), new MockEntry( "[TEST-9] with [dede]" ),new MockEntry("toto [maven-release-plugin] prepare release foo-2.2.3"));
when(changeLogSet.iterator()).thenReturn(entries.iterator());
Set<String> ids = new HashSet<String>();
Pattern pat = Pattern.compile("\\[(\\w+-\\d+)\\]");
Updater.findIssues(build, ids, pat, mock(BuildListener.class));
Assert.assertEquals(3, ids.size());
Assert.assertTrue( ids.contains( "TEST-9" ) );
Assert.assertTrue( ids.contains( "FOOBAR-4711" ) );
Assert.assertTrue( ids.contains( "FOOBAR-21" ) );
}
}