You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

467 lines
34 KiB

  1. package jira
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. )
  11. func TestIssueService_Get_Success(t *testing.T) {
  12. setup()
  13. defer teardown()
  14. testMux.HandleFunc("/rest/api/2/issue/10002", func(w http.ResponseWriter, r *http.Request) {
  15. testMethod(t, r, "GET")
  16. testRequestURL(t, r, "/rest/api/2/issue/10002")
  17. fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group","value":"jira-developer
  18. })
  19. issue, _, err := testClient.Issue.Get("10002")
  20. if issue == nil {
  21. t.Error("Expected issue. Issue is nil")
  22. }
  23. if err != nil {
  24. t.Errorf("Error given: %s", err)
  25. }
  26. }
  27. func TestIssueService_Create(t *testing.T) {
  28. setup()
  29. defer teardown()
  30. testMux.HandleFunc("/rest/api/2/issue/", func(w http.ResponseWriter, r *http.Request) {
  31. testMethod(t, r, "POST")
  32. testRequestURL(t, r, "/rest/api/2/issue/")
  33. w.WriteHeader(http.StatusCreated)
  34. fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group","value":"jira-developer
  35. })
  36. i := &Issue{
  37. Fields: &IssueFields{
  38. Description: "example bug report",
  39. },
  40. }
  41. issue, _, err := testClient.Issue.Create(i)
  42. if issue == nil {
  43. t.Error("Expected issue. Issue is nil")
  44. }
  45. if err != nil {
  46. t.Errorf("Error given: %s", err)
  47. }
  48. }
  49. func TestIssueService_AddComment(t *testing.T) {
  50. setup()
  51. defer teardown()
  52. testMux.HandleFunc("/rest/api/2/issue/10000/comment", func(w http.ResponseWriter, r *http.Request) {
  53. testMethod(t, r, "POST")
  54. testRequestURL(t, r, "/rest/api/2/issue/10000/comment")
  55. w.WriteHeader(http.StatusCreated)
  56. fmt.Fprint(w, `{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}`)
  57. })
  58. c := &Comment{
  59. Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.",
  60. Visibility: CommentVisibility{
  61. Type: "role",
  62. Value: "Administrators",
  63. },
  64. }
  65. comment, _, err := testClient.Issue.AddComment("10000", c)
  66. if comment == nil {
  67. t.Error("Expected Comment. Comment is nil")
  68. }
  69. if err != nil {
  70. t.Errorf("Error given: %s", err)
  71. }
  72. }
  73. func TestIssueService_AddLink(t *testing.T) {
  74. setup()
  75. defer teardown()
  76. testMux.HandleFunc("/rest/api/2/issueLink", func(w http.ResponseWriter, r *http.Request) {
  77. testMethod(t, r, "POST")
  78. testRequestURL(t, r, "/rest/api/2/issueLink")
  79. w.WriteHeader(http.StatusOK)
  80. })
  81. il := &IssueLink{
  82. Type: IssueLinkType{
  83. Name: "Duplicate",
  84. },
  85. InwardIssue: &Issue{
  86. Key: "HSP-1",
  87. },
  88. OutwardIssue: &Issue{
  89. Key: "MKY-1",
  90. },
  91. Comment: &Comment{
  92. Body: "Linked related issue!",
  93. Visibility: CommentVisibility{
  94. Type: "group",
  95. Value: "jira-software-users",
  96. },
  97. },
  98. }
  99. resp, err := testClient.Issue.AddLink(il)
  100. if resp == nil {
  101. t.Error("Expected response. Response is nil")
  102. }
  103. if resp.StatusCode != 200 {
  104. t.Errorf("Expected Status code 200. Given %d", resp.StatusCode)
  105. }
  106. if err != nil {
  107. t.Errorf("Error given: %s", err)
  108. }
  109. }
  110. func TestIssueService_Get_Fields(t *testing.T) {
  111. setup()
  112. defer teardown()
  113. testMux.HandleFunc("/rest/api/2/issue/10002", func(w http.ResponseWriter, r *http.Request) {
  114. testMethod(t, r, "GET")
  115. testRequestURL(t, r, "/rest/api/2/issue/10002")
  116. fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"labels":["test"],"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"epic": {"id": 19415,"key": "EPIC-77","self": "https://example.atlassian.net/rest/agile/1.0/epic/19415","name": "Epic Name","summary": "Do it","color": {"key": "color_11"},"done": false},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/u
  117. })
  118. issue, _, err := testClient.Issue.Get("10002")
  119. if issue == nil {
  120. t.Error("Expected issue. Issue is nil")
  121. }
  122. if !reflect.DeepEqual(issue.Fields.Labels, []string{"test"}) {
  123. t.Error("Expected labels for the returned issue")
  124. }
  125. if len(issue.Fields.Comments.Comments) != 1 {
  126. t.Errorf("Expected one comment, %v found", len(issue.Fields.Comments.Comments))
  127. }
  128. if issue.Fields.Epic == nil {
  129. t.Error("Epic expected but not found")
  130. }
  131. if err != nil {
  132. t.Errorf("Error given: %s", err)
  133. }
  134. }
  135. func TestIssueService_DownloadAttachment(t *testing.T) {
  136. var testAttachment = "Here is an attachment"
  137. setup()
  138. defer teardown()
  139. testMux.HandleFunc("/secure/attachment/", func(w http.ResponseWriter, r *http.Request) {
  140. testMethod(t, r, "GET")
  141. testRequestURL(t, r, "/secure/attachment/10000/")
  142. w.WriteHeader(http.StatusOK)
  143. w.Write([]byte(testAttachment))
  144. })
  145. resp, err := testClient.Issue.DownloadAttachment("10000")
  146. if resp == nil {
  147. t.Error("Expected response. Response is nil")
  148. }
  149. defer resp.Body.Close()
  150. attachment, err := ioutil.ReadAll(resp.Body)
  151. if err != nil {
  152. t.Error("Expected attachment text", err)
  153. }
  154. if string(attachment) != testAttachment {
  155. t.Errorf("Expecting an attachment: %s", string(attachment))
  156. }
  157. if resp.StatusCode != 200 {
  158. t.Errorf("Expected Status code 200. Given %d", resp.StatusCode)
  159. }
  160. if err != nil {
  161. t.Errorf("Error given: %s", err)
  162. }
  163. }
  164. func TestIssueService_DownloadAttachment_BadStatus(t *testing.T) {
  165. setup()
  166. defer teardown()
  167. testMux.HandleFunc("/secure/attachment/", func(w http.ResponseWriter, r *http.Request) {
  168. testMethod(t, r, "GET")
  169. testRequestURL(t, r, "/secure/attachment/10000/")
  170. w.WriteHeader(http.StatusForbidden)
  171. })
  172. resp, err := testClient.Issue.DownloadAttachment("10000")
  173. if resp == nil {
  174. t.Error("Expected response. Response is nil")
  175. }
  176. defer resp.Body.Close()
  177. if resp.StatusCode != http.StatusForbidden {
  178. t.Errorf("Expected Status code %d. Given %d", http.StatusForbidden, resp.StatusCode)
  179. }
  180. if err == nil {
  181. t.Errorf("Error expected")
  182. }
  183. }
  184. func TestIssueService_PostAttachment(t *testing.T) {
  185. var testAttachment = "Here is an attachment"
  186. setup()
  187. defer teardown()
  188. testMux.HandleFunc("/rest/api/2/issue/10000/attachments", func(w http.ResponseWriter, r *http.Request) {
  189. testMethod(t, r, "POST")
  190. testRequestURL(t, r, "/rest/api/2/issue/10000/attachments")
  191. status := http.StatusOK
  192. file, _, err := r.FormFile("file")
  193. if err != nil {
  194. status = http.StatusNotAcceptable
  195. }
  196. if file == nil {
  197. status = http.StatusNoContent
  198. } else {
  199. // Read the file into memory
  200. data, err := ioutil.ReadAll(file)
  201. if err != nil {
  202. status = http.StatusInternalServerError
  203. }
  204. if string(data) != testAttachment {
  205. status = http.StatusNotAcceptable
  206. }
  207. w.WriteHeader(status)
  208. fmt.Fprint(w, `[{"self":"http://jira/jira/rest/api/2/attachment/228924","id":"228924","filename":"example.jpg","author":{"self":"http://jira/jira/rest/api/2/user?username=test","name":"test","emailAddress":"test@test.com","avatarUrls":{"16x16":"http://jira/jira/secure/useravatar?size=small&avatarId=10082","48x48":"http://jira/jira/secure/useravatar?avatarId=10082"},"displayName":"Tester","active":true},"created":"2016-05-24T00:25:17.000-0700","size":32280,"mimeType":"image/jpeg","content":"http://jira/jira/secure/attachment/228924/example.jpg","thumbnail":"http://jira/jira/secure/thumbnail/228924/_thumb_228924.png"}]`)
  209. file.Close()
  210. }
  211. })
  212. reader := strings.NewReader(testAttachment)
  213. issue, resp, err := testClient.Issue.PostAttachment("10000", reader, "attachment")
  214. if issue == nil {
  215. t.Error("Expected response. Response is nil")
  216. }
  217. if resp.StatusCode != 200 {
  218. t.Errorf("Expected Status code 200. Given %d", resp.StatusCode)
  219. }
  220. if err != nil {
  221. t.Errorf("Error given: %s", err)
  222. }
  223. }
  224. func TestIssueService_PostAttachment_NoResponse(t *testing.T) {
  225. var testAttachment = "Here is an attachment"
  226. setup()
  227. defer teardown()
  228. testMux.HandleFunc("/rest/api/2/issue/10000/attachments", func(w http.ResponseWriter, r *http.Request) {
  229. testMethod(t, r, "POST")
  230. testRequestURL(t, r, "/rest/api/2/issue/10000/attachments")
  231. w.WriteHeader(http.StatusOK)
  232. })
  233. reader := strings.NewReader(testAttachment)
  234. _, _, err := testClient.Issue.PostAttachment("10000", reader, "attachment")
  235. if err == nil {
  236. t.Errorf("Error expected: %s", err)
  237. }
  238. }
  239. func TestIssueService_PostAttachment_NoFilename(t *testing.T) {
  240. var testAttachment = "Here is an attachment"
  241. setup()
  242. defer teardown()
  243. testMux.HandleFunc("/rest/api/2/issue/10000/attachments", func(w http.ResponseWriter, r *http.Request) {
  244. testMethod(t, r, "POST")
  245. testRequestURL(t, r, "/rest/api/2/issue/10000/attachments")
  246. w.WriteHeader(http.StatusOK)
  247. fmt.Fprint(w, `[{"self":"http://jira/jira/rest/api/2/attachment/228924","id":"228924","filename":"example.jpg","author":{"self":"http://jira/jira/rest/api/2/user?username=test","name":"test","emailAddress":"test@test.com","avatarUrls":{"16x16":"http://jira/jira/secure/useravatar?size=small&avatarId=10082","48x48":"http://jira/jira/secure/useravatar?avatarId=10082"},"displayName":"Tester","active":true},"created":"2016-05-24T00:25:17.000-0700","size":32280,"mimeType":"image/jpeg","content":"http://jira/jira/secure/attachment/228924/example.jpg","thumbnail":"http://jira/jira/secure/thumbnail/228924/_thumb_228924.png"}]`)
  248. })
  249. reader := strings.NewReader(testAttachment)
  250. _, _, err := testClient.Issue.PostAttachment("10000", reader, "")
  251. if err != nil {
  252. t.Errorf("Error expected: %s", err)
  253. }
  254. }
  255. func TestIssueService_PostAttachment_NoAttachment(t *testing.T) {
  256. setup()
  257. defer teardown()
  258. testMux.HandleFunc("/rest/api/2/issue/10000/attachments", func(w http.ResponseWriter, r *http.Request) {
  259. testMethod(t, r, "POST")
  260. testRequestURL(t, r, "/rest/api/2/issue/10000/attachments")
  261. w.WriteHeader(http.StatusOK)
  262. fmt.Fprint(w, `[{"self":"http://jira/jira/rest/api/2/attachment/228924","id":"228924","filename":"example.jpg","author":{"self":"http://jira/jira/rest/api/2/user?username=test","name":"test","emailAddress":"test@test.com","avatarUrls":{"16x16":"http://jira/jira/secure/useravatar?size=small&avatarId=10082","48x48":"http://jira/jira/secure/useravatar?avatarId=10082"},"displayName":"Tester","active":true},"created":"2016-05-24T00:25:17.000-0700","size":32280,"mimeType":"image/jpeg","content":"http://jira/jira/secure/attachment/228924/example.jpg","thumbnail":"http://jira/jira/secure/thumbnail/228924/_thumb_228924.png"}]`)
  263. })
  264. _, _, err := testClient.Issue.PostAttachment("10000", nil, "attachment")
  265. if err != nil {
  266. t.Errorf("Error given: %s", err)
  267. }
  268. }
  269. func TestIssueService_Search(t *testing.T) {
  270. setup()
  271. defer teardown()
  272. testMux.HandleFunc("/rest/api/2/search", func(w http.ResponseWriter, r *http.Request) {
  273. testMethod(t, r, "GET")
  274. testRequestURL(t, r, "/rest/api/2/search?jql=something&startAt=1&maxResults=40")
  275. w.WriteHeader(http.StatusOK)
  276. fmt.Fprint(w, `{"expand": "schema,names","startAt": 1,"maxResults": 40,"total": 6,"issues": [{"expand": "html","id": "10230","self": "http://kelpie9:8081/rest/api/2/issue/BULK-62","key": "BULK-62","fields": {"summary": "testing","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/5","id": "5","description": "The sub-task of the issue","iconUrl": "http://kelpie9:8081/images/icons/issue_subtask.gif","name": "Sub-task","subtask": true},"customfield_10071": null}},{"expand": "html","id": "10004","self": "http://kelpie9:8081/rest/api/2/issue/BULK-47","key": "BULK-47","fields": {"summary": "Cheese v1 2.0 issue","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/3","id": "3","description": "A task that needs to be done.","iconUrl": "http://kelpie9:8081/images/icons/task.gif","name": "Task","subtask": false}}}]}`)
  277. })
  278. opt := &SearchOptions{StartAt: 1, MaxResults: 40}
  279. _, resp, err := testClient.Issue.Search("something", opt)
  280. if resp == nil {
  281. t.Errorf("Response given: %+v", resp)
  282. }
  283. if err != nil {
  284. t.Errorf("Error given: %s", err)
  285. }
  286. if resp.StartAt != 1 {
  287. t.Errorf("StartAt should populate with 1, %v given", resp.StartAt)
  288. }
  289. if resp.MaxResults != 40 {
  290. t.Errorf("StartAt should populate with 40, %v given", resp.MaxResults)
  291. }
  292. if resp.Total != 6 {
  293. t.Errorf("StartAt should populate with 6, %v given", resp.Total)
  294. }
  295. }
  296. func TestIssueService_Search_WithoutPaging(t *testing.T) {
  297. setup()
  298. defer teardown()
  299. testMux.HandleFunc("/rest/api/2/search", func(w http.ResponseWriter, r *http.Request) {
  300. testMethod(t, r, "GET")
  301. testRequestURL(t, r, "/rest/api/2/search?jql=something")
  302. w.WriteHeader(http.StatusOK)
  303. fmt.Fprint(w, `{"expand": "schema,names","startAt": 0,"maxResults": 50,"total": 6,"issues": [{"expand": "html","id": "10230","self": "http://kelpie9:8081/rest/api/2/issue/BULK-62","key": "BULK-62","fields": {"summary": "testing","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/5","id": "5","description": "The sub-task of the issue","iconUrl": "http://kelpie9:8081/images/icons/issue_subtask.gif","name": "Sub-task","subtask": true},"customfield_10071": null}},{"expand": "html","id": "10004","self": "http://kelpie9:8081/rest/api/2/issue/BULK-47","key": "BULK-47","fields": {"summary": "Cheese v1 2.0 issue","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/3","id": "3","description": "A task that needs to be done.","iconUrl": "http://kelpie9:8081/images/icons/task.gif","name": "Task","subtask": false}}}]}`)
  304. })
  305. _, resp, err := testClient.Issue.Search("something", nil)
  306. if resp == nil {
  307. t.Errorf("Response given: %+v", resp)
  308. }
  309. if err != nil {
  310. t.Errorf("Error given: %s", err)
  311. }
  312. if resp.StartAt != 0 {
  313. t.Errorf("StartAt should populate with 0, %v given", resp.StartAt)
  314. }
  315. if resp.MaxResults != 50 {
  316. t.Errorf("StartAt should populate with 50, %v given", resp.MaxResults)
  317. }
  318. if resp.Total != 6 {
  319. t.Errorf("StartAt should populate with 6, %v given", resp.Total)
  320. }
  321. }
  322. func TestIssueService_GetCustomFields(t *testing.T) {
  323. setup()
  324. defer teardown()
  325. testMux.HandleFunc("/rest/api/2/issue/10002", func(w http.ResponseWriter, r *http.Request) {
  326. testMethod(t, r, "GET")
  327. testRequestURL(t, r, "/rest/api/2/issue/10002")
  328. fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"customfield_123":"test","watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group
  329. })
  330. issue, _, err := testClient.Issue.GetCustomFields("10002")
  331. if err != nil {
  332. t.Errorf("Error given: %s", err)
  333. }
  334. if issue == nil {
  335. t.Error("Expected Customfields")
  336. }
  337. cf := issue["customfield_123"]
  338. if cf != "test" {
  339. t.Error("Expected \"test\" for custom field")
  340. }
  341. }
  342. func TestIssueService_GetTransitions(t *testing.T) {
  343. setup()
  344. defer teardown()
  345. testAPIEndpoint := "/rest/api/2/issue/123/transitions"
  346. raw, err := ioutil.ReadFile("./mocks/transitions.json")
  347. if err != nil {
  348. t.Error(err.Error())
  349. }
  350. testMux.HandleFunc(testAPIEndpoint, func(w http.ResponseWriter, r *http.Request) {
  351. testMethod(t, r, "GET")
  352. testRequestURL(t, r, testAPIEndpoint)
  353. fmt.Fprint(w, string(raw))
  354. })
  355. transitions, _, err := testClient.Issue.GetTransitions("123")
  356. if err != nil {
  357. t.Errorf("Got error: %v", err)
  358. }
  359. if transitions == nil {
  360. t.Error("Expected transition list. Got nil.")
  361. }
  362. if len(transitions) != 2 {
  363. t.Errorf("Expected 2 transitions. Got %d", len(transitions))
  364. }
  365. if transitions[0].Fields["summary"].Required != false {
  366. t.Errorf("First transition summary field should not be required")
  367. }
  368. }
  369. func TestIssueService_DoTransition(t *testing.T) {
  370. setup()
  371. defer teardown()
  372. testAPIEndpoint := "/rest/api/2/issue/123/transitions"
  373. transitionID := "22"
  374. testMux.HandleFunc(testAPIEndpoint, func(w http.ResponseWriter, r *http.Request) {
  375. testMethod(t, r, "POST")
  376. testRequestURL(t, r, testAPIEndpoint)
  377. decoder := json.NewDecoder(r.Body)
  378. var payload CreateTransitionPayload
  379. err := decoder.Decode(&payload)
  380. if err != nil {
  381. t.Errorf("Got error: %v", err)
  382. }
  383. if payload.Transition.ID != transitionID {
  384. t.Errorf("Expected %s to be in payload, got %s instead", transitionID, payload.Transition.ID)
  385. }
  386. })
  387. _, err := testClient.Issue.DoTransition("123", transitionID)
  388. if err != nil {
  389. t.Errorf("Got error: %v", err)
  390. }
  391. }