IssueTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using Padi.RedmineApi.Tests.Infrastructure;
  5. using Redmine.Net.Api;
  6. using Redmine.Net.Api.Exceptions;
  7. using Redmine.Net.Api.Types;
  8. using Xunit;
  9. namespace Padi.RedmineApi.Tests.Tests.Sync
  10. {
  11. [Trait("Redmine-Net-Api", "Issues")]
  12. #if !(NET20 || NET40)
  13. [Collection("RedmineCollection")]
  14. #endif
  15. public class IssueTests
  16. {
  17. public IssueTests(RedmineFixture fixture)
  18. {
  19. this.fixture = fixture;
  20. }
  21. private readonly RedmineFixture fixture;
  22. //filters
  23. private const string PROJECT_ID = "redmine-net-testq";
  24. //watcher
  25. private const int WATCHER_ISSUE_ID = 96;
  26. private const int WATCHER_USER_ID = 8;
  27. [Fact, Order(1)]
  28. public void Should_Get_All_Issues()
  29. {
  30. var issues = fixture.RedmineManager.GetObjects<Issue>();
  31. Assert.NotNull(issues);
  32. }
  33. [Fact, Order(2)]
  34. public void Should_Get_Paginated_Issues()
  35. {
  36. const int NUMBER_OF_PAGINATED_ISSUES = 3;
  37. const int OFFSET = 1;
  38. var issues = fixture.RedmineManager.GetPaginatedObjects<Issue>(new NameValueCollection
  39. {
  40. { RedmineKeys.OFFSET, OFFSET.ToString() }, { RedmineKeys.LIMIT, NUMBER_OF_PAGINATED_ISSUES.ToString() }, { "sort", "id:desc" }
  41. });
  42. Assert.NotNull(issues.Items);
  43. //Assert.True(issues.Items.Count <= NUMBER_OF_PAGINATED_ISSUES, "number of issues ( "+ issues.Items.Count +" ) != " + NUMBER_OF_PAGINATED_ISSUES.ToString());
  44. }
  45. [Fact, Order(3)]
  46. public void Should_Get_Issues_By_Project_Id()
  47. {
  48. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { RedmineKeys.PROJECT_ID, PROJECT_ID } });
  49. Assert.NotNull(issues);
  50. }
  51. [Fact, Order(4)]
  52. public void Should_Get_Issues_By_SubProject_Id()
  53. {
  54. const string SUB_PROJECT_ID_VALUE = "redmine-net-testr";
  55. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { RedmineKeys.SUB_PROJECT_ID, SUB_PROJECT_ID_VALUE } });
  56. Assert.NotNull(issues);
  57. }
  58. [Fact, Order(5)]
  59. public void Should_Get_Issues_By_Project_Without_SubProject()
  60. {
  61. const string ALL_SUB_PROJECTS = "!*";
  62. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection
  63. {
  64. { RedmineKeys.PROJECT_ID, PROJECT_ID }, { RedmineKeys.SUB_PROJECT_ID, ALL_SUB_PROJECTS }
  65. });
  66. Assert.NotNull(issues);
  67. }
  68. [Fact, Order(6)]
  69. public void Should_Get_Issues_By_Tracker()
  70. {
  71. const string TRACKER_ID = "3";
  72. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { RedmineKeys.TRACKER_ID, TRACKER_ID } });
  73. Assert.NotNull(issues);
  74. }
  75. [Fact, Order(7)]
  76. public void Should_Get_Issues_By_Status()
  77. {
  78. const string STATUS_ID = "*";
  79. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { RedmineKeys.STATUS_ID, STATUS_ID } });
  80. Assert.NotNull(issues);
  81. }
  82. [Fact, Order(8)]
  83. public void Should_Get_Issues_By_Assignee()
  84. {
  85. const string ASSIGNED_TO_ID = "me";
  86. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { RedmineKeys.ASSIGNED_TO_ID, ASSIGNED_TO_ID } });
  87. Assert.NotNull(issues);
  88. }
  89. [Fact, Order(9)]
  90. public void Should_Get_Issues_By_Custom_Field()
  91. {
  92. const string CUSTOM_FIELD_NAME = "cf_13";
  93. const string CUSTOM_FIELD_VALUE = "Testx";
  94. var issues = fixture.RedmineManager.GetObjects<Issue>(new NameValueCollection { { CUSTOM_FIELD_NAME, CUSTOM_FIELD_VALUE } });
  95. Assert.NotNull(issues);
  96. }
  97. [Fact, Order(10)]
  98. public void Should_Get_Issue_By_Id()
  99. {
  100. const string ISSUE_ID = "96";
  101. var issue = fixture.RedmineManager.GetObject<Issue>(ISSUE_ID, new NameValueCollection
  102. {
  103. { RedmineKeys.INCLUDE, $"{RedmineKeys.CHILDREN},{RedmineKeys.ATTACHMENTS},{RedmineKeys.RELATIONS},{RedmineKeys.CHANGE_SETS},{RedmineKeys.JOURNALS},{RedmineKeys.WATCHERS}" }
  104. });
  105. Assert.NotNull(issue);
  106. }
  107. [Fact, Order(11)]
  108. public void Should_Add_Issue()
  109. {
  110. const bool NEW_ISSUE_IS_PRIVATE = true;
  111. const int NEW_ISSUE_PROJECT_ID = 1;
  112. const int NEW_ISSUE_TRACKER_ID = 1;
  113. const int NEW_ISSUE_STATUS_ID = 1;
  114. const int NEW_ISSUE_PRIORITY_ID = 9;
  115. const int NEW_ISSUE_CATEGORY_ID = 18;
  116. const int NEW_ISSUE_FIXED_VERSION_ID = 9;
  117. const int NEW_ISSUE_ASSIGNED_TO_ID = 8;
  118. const int NEW_ISSUE_PARENT_ISSUE_ID = 96;
  119. const int NEW_ISSUE_CUSTOM_FIELD_ID = 13;
  120. const int NEW_ISSUE_ESTIMATED_HOURS = 12;
  121. const int NEW_ISSUE_FIRST_WATCHER_ID = 2;
  122. const int NEW_ISSUE_SECOND_WATCHER_ID = 8;
  123. const string NEW_ISSUE_CUSTOM_FIELD_VALUE = "Issue custom field completed";
  124. const string NEW_ISSUE_SUBJECT = "Issue created using Rest API";
  125. const string NEW_ISSUE_DESCRIPTION = "Issue description...";
  126. var newIssueStartDate = DateTime.Now;
  127. var newIssueDueDate = DateTime.Now.AddDays(10);
  128. var icf = IdentifiableName.Create<IssueCustomField>(NEW_ISSUE_CUSTOM_FIELD_ID);
  129. if (icf != null)
  130. {
  131. icf.Values = new List<CustomFieldValue> {new CustomFieldValue {Info = NEW_ISSUE_CUSTOM_FIELD_VALUE}};
  132. }
  133. var issue = new Issue
  134. {
  135. Project = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_PROJECT_ID),
  136. Tracker = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_TRACKER_ID),
  137. Status = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_STATUS_ID),
  138. Priority = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_PRIORITY_ID),
  139. Subject = NEW_ISSUE_SUBJECT,
  140. Description = NEW_ISSUE_DESCRIPTION,
  141. Category = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_CATEGORY_ID),
  142. FixedVersion = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_FIXED_VERSION_ID),
  143. AssignedTo = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_ASSIGNED_TO_ID),
  144. ParentIssue = IdentifiableName.Create<IdentifiableName>(NEW_ISSUE_PARENT_ISSUE_ID),
  145. CustomFields = new List<IssueCustomField> {icf},
  146. IsPrivate = NEW_ISSUE_IS_PRIVATE,
  147. EstimatedHours = NEW_ISSUE_ESTIMATED_HOURS,
  148. StartDate = newIssueStartDate,
  149. DueDate = newIssueDueDate,
  150. Watchers = new List<Watcher>
  151. {
  152. IdentifiableName.Create<Watcher>(NEW_ISSUE_FIRST_WATCHER_ID),
  153. IdentifiableName.Create<Watcher>(NEW_ISSUE_SECOND_WATCHER_ID)
  154. }
  155. };
  156. var savedIssue = fixture.RedmineManager.CreateObject(issue);
  157. Assert.NotNull(savedIssue);
  158. Assert.True(issue.Subject.Equals(savedIssue.Subject), "Issue subject is invalid.");
  159. Assert.NotEqual(issue, savedIssue);
  160. }
  161. [Fact, Order(12)]
  162. public void Should_Update_Issue()
  163. {
  164. const string UPDATED_ISSUE_ID = "98";
  165. const string UPDATED_ISSUE_SUBJECT = "Issue updated subject";
  166. const string UPDATED_ISSUE_DESCRIPTION = null;
  167. const int UPDATED_ISSUE_PROJECT_ID = 9;
  168. const int UPDATED_ISSUE_TRACKER_ID = 3;
  169. const int UPDATED_ISSUE_PRIORITY_ID = 8;
  170. const int UPDATED_ISSUE_CATEGORY_ID = 18;
  171. const int UPDATED_ISSUE_ASSIGNED_TO_ID = 2;
  172. const int UPDATED_ISSUE_PARENT_ISSUE_ID = 91;
  173. const int UPDATED_ISSUE_CUSTOM_FIELD_ID = 13;
  174. const string UPDATED_ISSUE_CUSTOM_FIELD_VALUE = "Another custom field completed";
  175. const int UPDATED_ISSUE_ESTIMATED_HOURS = 23;
  176. const string UPDATED_ISSUE_NOTES = "A lot is changed";
  177. const bool UPDATED_ISSUE_PRIVATE_NOTES = true;
  178. DateTime? updatedIssueStartDate = default(DateTime?);
  179. var updatedIssueDueDate = DateTime.Now.AddMonths(1);
  180. var issue = fixture.RedmineManager.GetObject<Issue>(UPDATED_ISSUE_ID, new NameValueCollection
  181. {
  182. { RedmineKeys.INCLUDE, $"{RedmineKeys.CHILDREN},{RedmineKeys.ATTACHMENTS},{RedmineKeys.RELATIONS},{RedmineKeys.CHANGE_SETS},{RedmineKeys.JOURNALS},{RedmineKeys.WATCHERS}" }
  183. });
  184. issue.Subject = UPDATED_ISSUE_SUBJECT;
  185. issue.Description = UPDATED_ISSUE_DESCRIPTION;
  186. issue.StartDate = updatedIssueStartDate;
  187. issue.DueDate = updatedIssueDueDate;
  188. issue.Project = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_PROJECT_ID);
  189. issue.Tracker = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_TRACKER_ID);
  190. issue.Priority = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_PRIORITY_ID);
  191. issue.Category = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_CATEGORY_ID);
  192. issue.AssignedTo = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_ASSIGNED_TO_ID);
  193. issue.ParentIssue = IdentifiableName.Create<IdentifiableName>(UPDATED_ISSUE_PARENT_ISSUE_ID);
  194. var icf = (IssueCustomField)IdentifiableName.Create<IssueCustomField>(UPDATED_ISSUE_CUSTOM_FIELD_ID);
  195. icf.Values = new List<CustomFieldValue> { new CustomFieldValue { Info = UPDATED_ISSUE_CUSTOM_FIELD_VALUE } };
  196. issue.CustomFields?.Add(icf);
  197. issue.EstimatedHours = UPDATED_ISSUE_ESTIMATED_HOURS;
  198. issue.Notes = UPDATED_ISSUE_NOTES;
  199. issue.PrivateNotes = UPDATED_ISSUE_PRIVATE_NOTES;
  200. fixture.RedmineManager.UpdateObject(UPDATED_ISSUE_ID, issue);
  201. var updatedIssue = fixture.RedmineManager.GetObject<Issue>(UPDATED_ISSUE_ID, new NameValueCollection
  202. {
  203. { RedmineKeys.INCLUDE, $"{RedmineKeys.CHILDREN},{RedmineKeys.ATTACHMENTS},{RedmineKeys.RELATIONS},{RedmineKeys.CHANGE_SETS},{RedmineKeys.JOURNALS},{RedmineKeys.WATCHERS}" }
  204. });
  205. Assert.NotNull(updatedIssue);
  206. Assert.True(issue.Subject.Equals(updatedIssue.Subject), "Issue subject is invalid.");
  207. }
  208. [Fact, Order(99)]
  209. public void Should_Delete_Issue()
  210. {
  211. const string DELETED_ISSUE_ID = "90";
  212. var exception = (RedmineException)Record.Exception(() => fixture.RedmineManager.DeleteObject<Issue>(DELETED_ISSUE_ID));
  213. Assert.Null(exception);
  214. Assert.Throws<NotFoundException>(() => fixture.RedmineManager.GetObject<Issue>(DELETED_ISSUE_ID, null));
  215. }
  216. [Fact, Order(13)]
  217. public void Should_Add_Watcher_To_Issue()
  218. {
  219. fixture.RedmineManager.AddWatcherToIssue(WATCHER_ISSUE_ID, WATCHER_USER_ID);
  220. var issue = fixture.RedmineManager.GetObject<Issue>(WATCHER_ISSUE_ID.ToString(), new NameValueCollection { { RedmineKeys.INCLUDE, RedmineKeys.WATCHERS } });
  221. Assert.NotNull(issue);
  222. Assert.NotNull(issue.Watchers);
  223. Assert.True(((List<Watcher>)issue.Watchers).Find(w => w.Id == WATCHER_USER_ID) != null, "Watcher was not added.");
  224. }
  225. [Fact, Order(14)]
  226. public void Should_Remove_Watcher_From_Issue()
  227. {
  228. fixture.RedmineManager.RemoveWatcherFromIssue(WATCHER_ISSUE_ID, WATCHER_USER_ID);
  229. var issue = fixture.RedmineManager.GetObject<Issue>(WATCHER_ISSUE_ID.ToString(), new NameValueCollection { { RedmineKeys.INCLUDE, RedmineKeys.WATCHERS } });
  230. Assert.NotNull(issue);
  231. Assert.True(issue.Watchers == null || ((List<Watcher>)issue.Watchers).Find(w => w.Id == WATCHER_USER_ID) == null, "Watcher was not removed.");
  232. }
  233. [Fact, Order(15)]
  234. public void Should_Clone_Issue()
  235. {
  236. const string ISSUE_TO_CLONE_SUBJECT = "Issue to clone";
  237. const int ISSUE_TO_CLONE_CUSTOM_FIELD_ID = 13;
  238. const string ISSUE_TO_CLONE_CUSTOM_FIELD_VALUE = "Issue to clone custom field value";
  239. const int CLONED_ISSUE_CUSTOM_FIELD_ID = 13;
  240. const string CLONED_ISSUE_CUSTOM_FIELD_VALUE = "Cloned issue custom field value";
  241. var icfc = (IssueCustomField)IdentifiableName.Create<IssueCustomField>(ISSUE_TO_CLONE_CUSTOM_FIELD_ID);
  242. icfc.Values = new List<CustomFieldValue> { new CustomFieldValue { Info = ISSUE_TO_CLONE_CUSTOM_FIELD_VALUE } };
  243. var issueToClone = new Issue
  244. {
  245. Subject = ISSUE_TO_CLONE_SUBJECT,
  246. CustomFields = new List<IssueCustomField>() { icfc }
  247. };
  248. var clonedIssue = (Issue)issueToClone.Clone();
  249. var icf = (IssueCustomField)IdentifiableName.Create<IssueCustomField>(CLONED_ISSUE_CUSTOM_FIELD_ID);
  250. icf.Values = new List<CustomFieldValue> { new CustomFieldValue { Info = CLONED_ISSUE_CUSTOM_FIELD_VALUE } };
  251. clonedIssue.CustomFields.Add(icf);
  252. Assert.True(issueToClone.CustomFields.Count != clonedIssue.CustomFields.Count);
  253. }
  254. [Fact]
  255. public void Should_Get_Issue_With_Hours()
  256. {
  257. const string ISSUE_ID = "1";
  258. var issue = fixture.RedmineManager.GetObject<Issue>(ISSUE_ID, null);
  259. Assert.Equal(8.0f, issue.EstimatedHours);
  260. Assert.Equal(8.0f, issue.TotalEstimatedHours);
  261. Assert.Equal(5.0f, issue.TotalSpentHours);
  262. Assert.Equal(5.0f, issue.SpentHours);
  263. }
  264. }
  265. }