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.

TicketServiceTest.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Copyright 2014 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit.tests;
  17. import java.io.File;
  18. import java.util.Date;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. import org.apache.commons.io.FileUtils;
  23. import org.bouncycastle.util.Arrays;
  24. import org.junit.After;
  25. import org.junit.Before;
  26. import org.junit.Test;
  27. import com.gitblit.IStoredSettings;
  28. import com.gitblit.Keys;
  29. import com.gitblit.models.Mailing;
  30. import com.gitblit.models.RepositoryModel;
  31. import com.gitblit.models.TicketModel;
  32. import com.gitblit.models.TicketModel.Attachment;
  33. import com.gitblit.models.TicketModel.Change;
  34. import com.gitblit.models.TicketModel.Field;
  35. import com.gitblit.models.TicketModel.Patchset;
  36. import com.gitblit.models.TicketModel.Status;
  37. import com.gitblit.models.TicketModel.Type;
  38. import com.gitblit.tests.mock.MemorySettings;
  39. import com.gitblit.tickets.ITicketService;
  40. import com.gitblit.tickets.ITicketService.TicketFilter;
  41. import com.gitblit.tickets.QueryResult;
  42. import com.gitblit.tickets.TicketIndexer.Lucene;
  43. import com.gitblit.tickets.TicketLabel;
  44. import com.gitblit.tickets.TicketMilestone;
  45. import com.gitblit.tickets.TicketNotifier;
  46. import com.gitblit.utils.JGitUtils;
  47. /**
  48. * Tests the mechanics of Gitblit ticket management.
  49. *
  50. * @author James Moger
  51. *
  52. */
  53. public abstract class TicketServiceTest extends GitblitUnitTest {
  54. private ITicketService service;
  55. protected abstract RepositoryModel getRepository();
  56. protected abstract ITicketService getService(boolean deleteAll) throws Exception;
  57. protected IStoredSettings getSettings(boolean deleteAll) throws Exception {
  58. File dir = new File(GitBlitSuite.REPOSITORIES, getRepository().name);
  59. if (deleteAll) {
  60. FileUtils.deleteDirectory(dir);
  61. JGitUtils.createRepository(GitBlitSuite.REPOSITORIES, getRepository().name).close();
  62. }
  63. File luceneDir = new File(dir, "tickets/lucene");
  64. luceneDir.mkdirs();
  65. Map<String, Object> map = new HashMap<String, Object>();
  66. map.put(Keys.git.repositoriesFolder, GitBlitSuite.REPOSITORIES.getAbsolutePath());
  67. map.put(Keys.tickets.indexFolder, luceneDir.getAbsolutePath());
  68. IStoredSettings settings = new MemorySettings(map);
  69. return settings;
  70. }
  71. @Before
  72. public void setup() throws Exception {
  73. service = getService(true);
  74. }
  75. @After
  76. public void cleanup() {
  77. service.stop();
  78. }
  79. @Test
  80. public void testLifecycle() throws Exception {
  81. // query non-existent ticket
  82. TicketModel nonExistent = service.getTicket(getRepository(), 0);
  83. assertNull(nonExistent);
  84. // create and insert a ticket
  85. Change c1 = newChange("testCreation() " + Long.toHexString(System.currentTimeMillis()));
  86. TicketModel ticket = service.createTicket(getRepository(), c1);
  87. assertTrue(ticket.number > 0);
  88. // retrieve ticket and compare
  89. TicketModel constructed = service.getTicket(getRepository(), ticket.number);
  90. compare(ticket, constructed);
  91. assertEquals(1, constructed.changes.size());
  92. // C1: create the ticket
  93. int changeCount = 0;
  94. c1 = newChange("testUpdates() " + Long.toHexString(System.currentTimeMillis()));
  95. ticket = service.createTicket(getRepository(), c1);
  96. assertTrue(ticket.number > 0);
  97. changeCount++;
  98. constructed = service.getTicket(getRepository(), ticket.number);
  99. compare(ticket, constructed);
  100. assertEquals(1, constructed.changes.size());
  101. // C2: set owner
  102. Change c2 = new Change("C2");
  103. c2.comment("I'll fix this");
  104. c2.setField(Field.responsible, c2.author);
  105. constructed = service.updateTicket(getRepository(), ticket.number, c2);
  106. assertNotNull(constructed);
  107. assertEquals(2, constructed.changes.size());
  108. assertEquals(c2.author, constructed.responsible);
  109. changeCount++;
  110. // C3: add a note
  111. Change c3 = new Change("C3");
  112. c3.comment("yeah, this is working");
  113. constructed = service.updateTicket(getRepository(), ticket.number, c3);
  114. assertNotNull(constructed);
  115. assertEquals(3, constructed.changes.size());
  116. changeCount++;
  117. if (service.supportsAttachments()) {
  118. // C4: add attachment
  119. Change c4 = new Change("C4");
  120. Attachment a = newAttachment();
  121. c4.addAttachment(a);
  122. constructed = service.updateTicket(getRepository(), ticket.number, c4);
  123. assertNotNull(constructed);
  124. assertTrue(constructed.hasAttachments());
  125. Attachment a1 = service.getAttachment(getRepository(), ticket.number, a.name);
  126. assertEquals(a.content.length, a1.content.length);
  127. assertTrue(Arrays.areEqual(a.content, a1.content));
  128. changeCount++;
  129. }
  130. // C5: close the issue
  131. Change c5 = new Change("C5");
  132. c5.comment("closing issue");
  133. c5.setField(Field.status, Status.Resolved);
  134. constructed = service.updateTicket(getRepository(), ticket.number, c5);
  135. assertNotNull(constructed);
  136. changeCount++;
  137. assertTrue(constructed.isClosed());
  138. assertEquals(changeCount, constructed.changes.size());
  139. List<TicketModel> allTickets = service.getTickets(getRepository());
  140. List<TicketModel> openTickets = service.getTickets(getRepository(), new TicketFilter() {
  141. @Override
  142. public boolean accept(TicketModel ticket) {
  143. return ticket.isOpen();
  144. }
  145. });
  146. List<TicketModel> closedTickets = service.getTickets(getRepository(), new TicketFilter() {
  147. @Override
  148. public boolean accept(TicketModel ticket) {
  149. return ticket.isClosed();
  150. }
  151. });
  152. assertTrue(allTickets.size() > 0);
  153. assertEquals(1, openTickets.size());
  154. assertEquals(1, closedTickets.size());
  155. // build a new Lucene index
  156. service.reindex(getRepository());
  157. List<QueryResult> hits = service.searchFor(getRepository(), "working", 1, 10);
  158. assertEquals(1, hits.size());
  159. // reindex a ticket
  160. ticket = allTickets.get(0);
  161. Change change = new Change("reindex");
  162. change.comment("this is a test of reindexing a ticket");
  163. service.updateTicket(getRepository(), ticket.number, change);
  164. ticket = service.getTicket(getRepository(), ticket.number);
  165. hits = service.searchFor(getRepository(), "reindexing", 1, 10);
  166. assertEquals(1, hits.size());
  167. service.stop();
  168. service = getService(false);
  169. // Lucene field query
  170. List<QueryResult> results = service.queryFor(Lucene.status.matches(Status.New.name()), 1, 10, Lucene.created.name(), true);
  171. assertEquals(1, results.size());
  172. assertTrue(results.get(0).title.startsWith("testCreation"));
  173. // Lucene field query
  174. results = service.queryFor(Lucene.status.matches(Status.Resolved.name()), 1, 10, Lucene.created.name(), true);
  175. assertEquals(1, results.size());
  176. assertTrue(results.get(0).title.startsWith("testUpdates"));
  177. // check the ids
  178. assertEquals("[1, 2]", service.getIds(getRepository()).toString());
  179. // delete all tickets
  180. for (TicketModel aTicket : allTickets) {
  181. assertTrue(service.deleteTicket(getRepository(), aTicket.number, "D"));
  182. }
  183. }
  184. @Test
  185. public void testChangeComment() throws Exception {
  186. // C1: create the ticket
  187. Change c1 = newChange("testChangeComment() " + Long.toHexString(System.currentTimeMillis()));
  188. TicketModel ticket = service.createTicket(getRepository(), c1);
  189. assertTrue(ticket.number > 0);
  190. assertTrue(ticket.changes.get(0).hasComment());
  191. ticket = service.updateComment(ticket, c1.comment.id, "E1", "I changed the comment");
  192. assertNotNull(ticket);
  193. assertTrue(ticket.changes.get(0).hasComment());
  194. assertEquals("I changed the comment", ticket.changes.get(0).comment.text);
  195. assertTrue(service.deleteTicket(getRepository(), ticket.number, "D"));
  196. }
  197. @Test
  198. public void testDeleteComment() throws Exception {
  199. // C1: create the ticket
  200. Change c1 = newChange("testDeleteComment() " + Long.toHexString(System.currentTimeMillis()));
  201. TicketModel ticket = service.createTicket(getRepository(), c1);
  202. assertTrue(ticket.number > 0);
  203. assertTrue(ticket.changes.get(0).hasComment());
  204. ticket = service.deleteComment(ticket, c1.comment.id, "D1");
  205. assertNotNull(ticket);
  206. assertEquals(1, ticket.changes.size());
  207. assertFalse(ticket.changes.get(0).hasComment());
  208. assertTrue(service.deleteTicket(getRepository(), ticket.number, "D"));
  209. }
  210. @Test
  211. public void testMilestones() throws Exception {
  212. service.createMilestone(getRepository(), "M1", "james");
  213. service.createMilestone(getRepository(), "M2", "frank");
  214. service.createMilestone(getRepository(), "M3", "joe");
  215. List<TicketMilestone> milestones = service.getMilestones(getRepository(), Status.Open);
  216. assertEquals("Unexpected open milestones count", 3, milestones.size());
  217. for (TicketMilestone milestone : milestones) {
  218. milestone.status = Status.Resolved;
  219. milestone.due = new Date();
  220. assertTrue("failed to update milestone " + milestone.name, service.updateMilestone(getRepository(), milestone, "ted"));
  221. }
  222. milestones = service.getMilestones(getRepository(), Status.Open);
  223. assertEquals("Unexpected open milestones count", 0, milestones.size());
  224. milestones = service.getMilestones(getRepository(), Status.Resolved);
  225. assertEquals("Unexpected resolved milestones count", 3, milestones.size());
  226. for (TicketMilestone milestone : milestones) {
  227. assertTrue("failed to delete milestone " + milestone.name, service.deleteMilestone(getRepository(), milestone.name, "lucifer"));
  228. }
  229. }
  230. @Test
  231. public void testLabels() throws Exception {
  232. service.createLabel(getRepository(), "L1", "james");
  233. service.createLabel(getRepository(), "L2", "frank");
  234. service.createLabel(getRepository(), "L3", "joe");
  235. List<TicketLabel> labels = service.getLabels(getRepository());
  236. assertEquals("Unexpected open labels count", 3, labels.size());
  237. for (TicketLabel label : labels) {
  238. label.color = "#ffff00";
  239. assertTrue("failed to update label " + label.name, service.updateLabel(getRepository(), label, "ted"));
  240. }
  241. labels = service.getLabels(getRepository());
  242. assertEquals("Unexpected labels count", 3, labels.size());
  243. for (TicketLabel label : labels) {
  244. assertTrue("failed to delete label " + label.name, service.deleteLabel(getRepository(), label.name, "lucifer"));
  245. }
  246. }
  247. @Test
  248. public void testPriorityAndSeverity() throws Exception {
  249. // C1: create and insert a ticket
  250. Change c1 = newChange("testPriorityAndSeverity() " + Long.toHexString(System.currentTimeMillis()));
  251. TicketModel ticket = service.createTicket(getRepository(), c1);
  252. assertTrue(ticket.number > 0);
  253. assertEquals(TicketModel.Priority.Normal, ticket.priority);
  254. assertEquals(TicketModel.Severity.Unrated, ticket.severity);
  255. TicketModel constructed = service.getTicket(getRepository(), ticket.number);
  256. compare(ticket, constructed);
  257. // C2: Change Priority max
  258. Change c2 = new Change("C2");
  259. c2.setField(Field.priority, TicketModel.Priority.Urgent);
  260. constructed = service.updateTicket(getRepository(), ticket.number, c2);
  261. assertNotNull(constructed);
  262. assertEquals(2, constructed.changes.size());
  263. assertEquals(TicketModel.Priority.Urgent, constructed.priority);
  264. assertEquals(TicketModel.Severity.Unrated, constructed.severity);
  265. // C3: Change Severity max
  266. Change c3 = new Change("C3");
  267. c3.setField(Field.severity, TicketModel.Severity.Catastrophic);
  268. constructed = service.updateTicket(getRepository(), ticket.number, c3);
  269. assertNotNull(constructed);
  270. assertEquals(3, constructed.changes.size());
  271. assertEquals(TicketModel.Priority.Urgent, constructed.priority);
  272. assertEquals(TicketModel.Severity.Catastrophic, constructed.severity);
  273. // C4: Change Priority min
  274. Change c4 = new Change("C3");
  275. c4.setField(Field.priority, TicketModel.Priority.Low);
  276. constructed = service.updateTicket(getRepository(), ticket.number, c4);
  277. assertNotNull(constructed);
  278. assertEquals(4, constructed.changes.size());
  279. assertEquals(TicketModel.Priority.Low, constructed.priority);
  280. assertEquals(TicketModel.Severity.Catastrophic, constructed.severity);
  281. }
  282. private Change newChange(String summary) {
  283. Change change = new Change("C1");
  284. change.setField(Field.title, summary);
  285. change.setField(Field.body, "this is my description");
  286. change.setField(Field.labels, "helpdesk");
  287. change.comment("my comment");
  288. return change;
  289. }
  290. private Attachment newAttachment() {
  291. Attachment attachment = new Attachment("test1.txt");
  292. attachment.content = new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
  293. 0x4a };
  294. return attachment;
  295. }
  296. private void compare(TicketModel ticket, TicketModel constructed) {
  297. assertEquals(ticket.number, constructed.number);
  298. assertEquals(ticket.createdBy, constructed.createdBy);
  299. assertEquals(ticket.responsible, constructed.responsible);
  300. assertEquals(ticket.title, constructed.title);
  301. assertEquals(ticket.body, constructed.body);
  302. assertEquals(ticket.created, constructed.created);
  303. assertTrue(ticket.hasLabel("helpdesk"));
  304. }
  305. @Test
  306. public void testNotifier() throws Exception {
  307. Change kernel = new Change("james");
  308. kernel.setField(Field.title, "Sample ticket");
  309. kernel.setField(Field.body, "this **is** my sample body\n\n- I hope\n- you really\n- *really* like it");
  310. kernel.setField(Field.status, Status.New);
  311. kernel.setField(Field.type, Type.Proposal);
  312. kernel.comment("this is a sample comment on a kernel change");
  313. Patchset patchset = new Patchset();
  314. patchset.insertions = 100;
  315. patchset.deletions = 10;
  316. patchset.number = 1;
  317. patchset.rev = 25;
  318. patchset.tip = "50f57913f816d04a16b7407134de5d8406421f37";
  319. kernel.patchset = patchset;
  320. TicketModel ticket = service.createTicket(getRepository(), 0L, kernel);
  321. Change merge = new Change("james");
  322. merge.setField(Field.mergeSha, patchset.tip);
  323. merge.setField(Field.mergeTo, "master");
  324. merge.setField(Field.status, Status.Merged);
  325. ticket = service.updateTicket(getRepository(), ticket.number, merge);
  326. ticket.repository = getRepository().name;
  327. TicketNotifier notifier = service.createNotifier();
  328. Mailing mailing = notifier.queueMailing(ticket);
  329. assertNotNull(mailing);
  330. }
  331. }