1
0
Fork 0

Merge pull request #185 from marius-m/feature/worklog_ext3

Ability to create worklogs
master
Bob Carroll 2017-07-02 12:21:34 -07:00 committed by GitHub
commit 1c7d4a73d3
5 changed files with 271 additions and 7 deletions

View File

@ -23,11 +23,16 @@ import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.*;
import net.rcarz.utils.WorklogUtils;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* Represents a JIRA issue.
@ -1077,6 +1082,36 @@ public class Issue extends Resource {
return new Comment(restclient, (JSONObject) result, key);
}
/**
* Adds {@link WorkLog} to this issue
* @param comment provided comment
* @param startDate provided start date
* @param timeSpentSeconds provided time spent. This cannot be lower than 1m inute
* @return
* @throws JiraException when worklog creation fails
*/
public WorkLog addWorkLog(String comment, DateTime startDate, long timeSpentSeconds) throws JiraException {
try {
if (comment == null)
throw new IllegalArgumentException("Invalid comment.");
if (startDate == null)
throw new IllegalArgumentException("Invalid start time.");
if (timeSpentSeconds < 60) // We do not add a worklog that duration is below a minute
throw new IllegalArgumentException("Time spent cannot be lower than 1 minute.");
JSONObject req = new JSONObject();
req.put("comment", comment);
req.put("started", DateTimeFormat.forPattern(Field.DATETIME_FORMAT).print(startDate.getMillis()));
req.put("timeSpent", WorklogUtils.formatDurationFromSeconds(timeSpentSeconds));
JSON result = restclient.post(getRestUri(key) + "/worklog", req);
JSONObject jo = (JSONObject) result;
return new WorkLog(restclient, jo);
} catch (Exception ex) {
throw new JiraException("Failed add worklog to issue " + key, ex);
}
}
/**
* Links this issue with another issue.
*

View File

@ -0,0 +1,40 @@
package net.rcarz.utils;
import net.rcarz.jiraclient.WorkLog;
import org.joda.time.DurationFieldType;
import org.joda.time.Period;
import org.joda.time.PeriodType;
/**
* Created by mariusmerkevicius on 1/30/16.
* A set of utils static methods help set {@link WorkLog}
*/
public class WorklogUtils {
/**
* Formats duration time into pretty string format
* Does not output seconds
*
* @param durationInSeconds provided duration to format
* @return formatted duration
*/
public static String formatDurationFromSeconds(long durationInSeconds) {
if (durationInSeconds < 60)
return "0m";
StringBuilder builder = new StringBuilder();
PeriodType type = PeriodType.forFields(new DurationFieldType[]{
DurationFieldType.hours(),
DurationFieldType.minutes()
});
Period period = new Period(1000 * durationInSeconds, type);
if (period.getHours() != 0)
builder.append(period.getHours()).append("h").append(" ");
if (period.getMinutes() != 0)
builder.append(period.getMinutes()).append("m").append(" ");
if ((builder.length() > 0) && builder.charAt(builder.length() - 1) == " ".charAt(0))
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
}

View File

@ -0,0 +1,109 @@
package net.rcarz.jiraclient;
import net.sf.json.JSON;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.joda.time.DateTime;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
/**
* Created by mariusmerkevicius on 1/30/16.
*/
public class IssueWorklogTest {
@Test
public void testParsing_inputValid_shouldCreateJsonObject() throws Exception {
// Arrange
// Act
JSONObject worklogObject = (JSONObject) JSONSerializer.toJSON(RESPONSE_WORKLOG_BODY);
// Assert
assertNotNull(worklogObject);
}
@Test
public void testParsing_inputValidJson_shouldCreateWorklog() throws Exception {
// Arrange
// Act
WorkLog workLog = new WorkLog(mock(RestClient.class), (JSONObject) JSONSerializer.toJSON(RESPONSE_WORKLOG_BODY));
// Assert
assertNotNull(workLog);
assertNotNull(workLog.getAuthor());
assertEquals("https://jira.test.lt/rest/api/2/issue/32374/worklog/80720", workLog.getSelf());
assertEquals("80720", workLog.getId());
assertEquals("Test", workLog.getComment());
assertEquals(1454179576583L, workLog.getCreatedDate().getTime());
assertEquals(1454179576583L, workLog.getUpdatedDate().getTime());
assertEquals(1453879853201L, workLog.getStarted().getTime());
assertEquals("5m", workLog.getTimeSpent());
assertEquals(300, workLog.getTimeSpentSeconds());
}
@Test
public void testAdding_inputValid_shouldInvokeAdding() throws Exception {
// Arrange
Issue issue = mock(Issue.class);
issue.restclient = mock(RestClient.class);
doCallRealMethod().when(issue).addWorkLog(anyString(), any(DateTime.class), anyLong());
// Act
issue.addWorkLog("test", DateTime.now(), 60);
// Assert
verify(issue.restclient).post(anyString(), any(JSON.class));
}
@Test(expected = JiraException.class)
public void testAdding_inputNullComment_shouldNotAdd() throws Exception {
// Arrange
Issue issue = mock(Issue.class);
issue.restclient = mock(RestClient.class);
doCallRealMethod().when(issue).addWorkLog(anyString(), any(DateTime.class), anyLong());
// Act
// Assert
issue.addWorkLog(null, DateTime.now(), 120);
}
@Test(expected = JiraException.class)
public void testAdding_inputNullDateTime_shouldNotAdd() throws Exception {
// Arrange
Issue issue = mock(Issue.class);
issue.restclient = mock(RestClient.class);
doCallRealMethod().when(issue).addWorkLog(anyString(), any(DateTime.class), anyLong());
// Act
// Assert
issue.addWorkLog("asdf", null, 120);
}
@Test(expected = JiraException.class)
public void testAdding_inputDurationTooLow_shouldNotAdd() throws Exception {
// Arrange
Issue issue = mock(Issue.class);
issue.restclient = mock(RestClient.class);
doCallRealMethod().when(issue).addWorkLog(anyString(), any(DateTime.class), anyLong());
// Act
// Assert
issue.addWorkLog("asdf", DateTime.now(), 30);
}
//region Constants
// Mock response from jira
public static final String RESPONSE_WORKLOG_BODY = "{\"self\":\"https://jira.test.lt/rest/api/2/issue/32374/worklog/80720\",\"author\":{\"self\":\"https://jira.test.lt/rest/api/2/user?username=test%40test.lt\",\"name\":\"test@test.lt\",\"key\":\"test@test.lt\",\"emailAddress\":\"test@test.lt\",\"avatarUrls\":{\"48x48\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=48\",\"24x24\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=24\",\"16x16\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=16\",\"32x32\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=32\"},\"displayName\":\"Marius Merkevicius\",\"active\":true,\"timeZone\":\"Europe/Vilnius\"},\"updateAuthor\":{\"self\":\"https://jira.test.lt/rest/api/2/user?username=test%40test.lt\",\"name\":\"test@test.lt\",\"key\":\"test@test.lt\",\"emailAddress\":\"test@test.lt\",\"avatarUrls\":{\"48x48\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=48\",\"24x24\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=24\",\"16x16\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=16\",\"32x32\":\"https://secure.gravatar.com/avatar/e4dacfe8f27cb89341bf990e556a4be0?d=mm&s=32\"},\"displayName\":\"Marius Merkevicius\",\"active\":true,\"timeZone\":\"Europe/Vilnius\"},\"comment\":\"Test\",\"created\":\"2016-01-30T20:46:16.583+0200\",\"updated\":\"2016-01-30T20:46:16.583+0200\",\"started\":\"2016-01-27T09:30:53.201+0200\",\"timeSpent\":\"5m\",\"timeSpentSeconds\":300,\"id\":\"80720\"}";
//endregion
}

View File

@ -10,6 +10,7 @@ import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
@ -17,7 +18,7 @@ import static org.mockito.Matchers.anyString;
@RunWith(PowerMockRunner.class)
public class WorklogTest {
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Field.DATETIME_FORMAT);
@Test(expected = JiraException.class)
public void testJiraExceptionFromRestException() throws Exception {
@ -48,7 +49,7 @@ public class WorklogTest {
}
@Test
public void testWorklog() {
public void testWorklog() throws Exception {
List<WorkLog> workLogs = Field.getResourceArray(WorkLog.class, Utils.getTestIssueWorklogs().get("worklogs"), null);
assertEquals(2, workLogs.size());
@ -59,11 +60,10 @@ public class WorklogTest {
assertEquals("45517", workLog.getId());
String author = "joseph";
assertEquals(author, workLog.getAuthor().getName());
final long expectedStartedUnixTimeStamp = 1439803140000L; //unix timestamp in millis of 2015-08-17T13:19:00.000+0400
assertEquals(expectedStartedUnixTimeStamp, workLog.getStarted().getTime());
final long expectedCreatedAndUpdatedUnitTimeStamp = 1440062384000L; //unix timestamp in millis of 2015-08-20T13:19:44.000+0400
assertEquals(expectedCreatedAndUpdatedUnitTimeStamp, workLog.getCreatedDate().getTime());
assertEquals(expectedCreatedAndUpdatedUnitTimeStamp, workLog.getUpdatedDate().getTime());
String started = "2015-08-17T13:19:00.000+0400";
assertEquals(simpleDateFormat.parse(started), workLog.getStarted());
String created = "2015-08-20T13:19:44.000+0400";
assertEquals(simpleDateFormat.parse(created), workLog.getCreatedDate());
assertEquals(21600, workLog.getTimeSpentSeconds());
assertEquals(author, workLog.getUpdateAuthor().getName());
}

View File

@ -0,0 +1,80 @@
package net.rcarz.utils;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Created by mariusmerkevicius on 1/30/16.
*/
public class WorklogUtilsFormatDurationTest {
@Test
public void testEmpty() throws Exception {
assertEquals("0m", WorklogUtils.formatDurationFromSeconds(0));
}
@Test
public void testNegative() throws Exception {
assertEquals("0m", WorklogUtils.formatDurationFromSeconds(-200));
}
@Test
public void testLowSecond() throws Exception {
assertEquals("0m", WorklogUtils.formatDurationFromSeconds(1));
}
@Test
public void testSeconds() throws Exception {
assertEquals("0m", WorklogUtils.formatDurationFromSeconds(59));
}
@Test
public void testMinutes() throws Exception {
assertEquals("1m", WorklogUtils.formatDurationFromSeconds(60));
}
@Test
public void testMinutesAndSeconds() throws Exception {
assertEquals("1m", WorklogUtils.formatDurationFromSeconds(
60 // 1 minute
+ 2) // 2 seconds
);
}
@Test
public void testMinutesAndSeconds2() throws Exception {
assertEquals("2m", WorklogUtils.formatDurationFromSeconds(
60 // 1 minute
+ 72) // 72 seconds
);
}
@Test
public void testHours() throws Exception {
assertEquals("1h 10m", WorklogUtils.formatDurationFromSeconds(
(60 * 60) // 1 hour
+ (10 * 60) // 10 minutes
+ 3) // 3 seconds
);
}
@Test
public void testDays() throws Exception {
assertEquals("50h 20m", WorklogUtils.formatDurationFromSeconds(
(60 * 60 * 50) // 50 hours
+ (60 * 20) // 20 minutes
+ (3) // s seconds
));
}
@Test
public void testDays2() throws Exception {
assertEquals("50h 22m", WorklogUtils.formatDurationFromSeconds(
(60 * 60 * 50) // 50 hours
+ (60 * 20) // 20 minutes
+ (125) // 125 seconds
));
}
}