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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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.bouncycastle.util.Arrays;
  23. import org.eclipse.jgit.util.FileUtils;
  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. if (dir.exists()) {
  61. FileUtils.delete(dir, FileUtils.RECURSIVE | FileUtils.RETRY);
  62. }
  63. JGitUtils.createRepository(GitBlitSuite.REPOSITORIES, getRepository().name).close();
  64. }
  65. File luceneDir = new File(dir, "tickets/lucene");
  66. luceneDir.mkdirs();
  67. Map<String, Object> map = new HashMap<String, Object>();
  68. map.put(Keys.git.repositoriesFolder, GitBlitSuite.REPOSITORIES.getAbsolutePath());
  69. map.put(Keys.tickets.indexFolder, luceneDir.getAbsolutePath());
  70. IStoredSettings settings = new MemorySettings(map);
  71. return settings;
  72. }
  73. @Before
  74. public void setup() throws Exception {
  75. service = getService(true);
  76. }
  77. @After
  78. public void cleanup() {
  79. service.stop();
  80. }
  81. @Test
  82. public void testLifecycle() throws Exception {
  83. // query non-existent ticket
  84. TicketModel nonExistent = service.getTicket(getRepository(), 0);
  85. assertNull(nonExistent);
  86. // create and insert a ticket
  87. Change c1 = newChange("testCreation() " + Long.toHexString(System.currentTimeMillis()));
  88. TicketModel ticket = service.createTicket(getRepository(), c1);
  89. assertTrue(ticket.number > 0);
  90. // retrieve ticket and compare
  91. TicketModel constructed = service.getTicket(getRepository(), ticket.number);
  92. compare(ticket, constructed);
  93. assertEquals(1, constructed.changes.size());
  94. // C1: create the ticket
  95. int changeCount = 0;
  96. c1 = newChange("testUpdates() " + Long.toHexString(System.currentTimeMillis()));
  97. ticket = service.createTicket(getRepository(), c1);
  98. assertTrue(ticket.number > 0);
  99. changeCount++;
  100. constructed = service.getTicket(getRepository(), ticket.number);
  101. compare(ticket, constructed);
  102. assertEquals(1, constructed.changes.size());
  103. // C2: set owner
  104. Change c2 = new Change("C2");
  105. c2.comment("I'll fix this");
  106. c2.setField(Field.responsible, c2.author);
  107. constructed = service.updateTicket(getRepository(), ticket.number, c2);
  108. assertNotNull(constructed);
  109. assertEquals(2, constructed.changes.size());
  110. assertEquals(c2.author, constructed.responsible);
  111. changeCount++;
  112. // C3: add a note
  113. Change c3 = new Change("C3");
  114. c3.comment("yeah, this is working");
  115. constructed = service.updateTicket(getRepository(), ticket.number, c3);
  116. assertNotNull(constructed);
  117. assertEquals(3, constructed.changes.size());
  118. changeCount++;
  119. if (service.supportsAttachments()) {
  120. // C4: add attachment
  121. Change c4 = new Change("C4");
  122. Attachment a = newAttachment();
  123. c4.addAttachment(a);
  124. constructed = service.updateTicket(getRepository(), ticket.number, c4);
  125. assertNotNull(constructed);
  126. assertTrue(constructed.hasAttachments());
  127. Attachment a1 = service.getAttachment(getRepository(), ticket.number, a.name);
  128. assertEquals(a.content.length, a1.content.length);
  129. assertTrue(Arrays.areEqual(a.content, a1.content));
  130. changeCount++;
  131. }
  132. // C5: close the issue
  133. Change c5 = new Change("C5");
  134. c5.comment("closing issue");
  135. c5.setField(Field.status, Status.Resolved);
  136. constructed = service.updateTicket(getRepository(), ticket.number, c5);
  137. assertNotNull(constructed);
  138. changeCount++;
  139. assertTrue(constructed.isClosed());
  140. assertEquals(changeCount, constructed.changes.size());
  141. List<TicketModel> allTickets = service.getTickets(getRepository());
  142. List<TicketModel> openTickets = service.getTickets(getRepository(), new TicketFilter() {
  143. @Override
  144. public boolean accept(TicketModel ticket) {
  145. return ticket.isOpen();
  146. }
  147. });
  148. List<TicketModel> closedTickets = service.getTickets(getRepository(), new TicketFilter() {
  149. @Override
  150. public boolean accept(TicketModel ticket) {
  151. return ticket.isClosed();
  152. }
  153. });
  154. assertTrue(allTickets.size() > 0);
  155. assertEquals(1, openTickets.size());
  156. assertEquals(1, closedTickets.size());
  157. // build a new Lucene index
  158. service.reindex(getRepository());
  159. List<QueryResult> hits = service.searchFor(getRepository(), "working", 1, 10);
  160. assertEquals(1, hits.size());
  161. // reindex a ticket
  162. ticket = allTickets.get(0);
  163. Change change = new Change("reindex");
  164. change.comment("this is a test of reindexing a ticket");
  165. service.updateTicket(getRepository(), ticket.number, change);
  166. ticket = service.getTicket(getRepository(), ticket.number);
  167. hits = service.searchFor(getRepository(), "reindexing", 1, 10);
  168. assertEquals(1, hits.size());
  169. service.stop();
  170. service = getService(false);
  171. // Lucene field query
  172. List<QueryResult> results = service.queryFor(Lucene.status.matches(Status.New.name()), 1, 10, Lucene.created.name(), true);
  173. assertEquals(1, results.size());
  174. assertTrue(results.get(0).title.startsWith("testCreation"));
  175. // Lucene field query
  176. results = service.queryFor(Lucene.status.matches(Status.Resolved.name()), 1, 10, Lucene.created.name(), true);
  177. assertEquals(1, results.size());
  178. assertTrue(results.get(0).title.startsWith("testUpdates"));
  179. // check the ids
  180. assertEquals("[1, 2]", service.getIds(getRepository()).toString());
  181. // delete all tickets
  182. for (TicketModel aTicket : allTickets) {
  183. assertTrue(service.deleteTicket(getRepository(), aTicket.number, "D"));
  184. }
  185. }
  186. @Test
  187. public void testChangeComment() throws Exception {
  188. // C1: create the ticket
  189. Change c1 = newChange("testChangeComment() " + Long.toHexString(System.currentTimeMillis()));
  190. TicketModel ticket = service.createTicket(getRepository(), c1);
  191. assertTrue(ticket.number > 0);
  192. assertTrue(ticket.changes.get(0).hasComment());
  193. ticket = service.updateComment(ticket, c1.comment.id, "E1", "I changed the comment");
  194. assertNotNull(ticket);
  195. assertTrue(ticket.changes.get(0).hasComment());
  196. assertEquals("I changed the comment", ticket.changes.get(0).comment.text);
  197. assertTrue(service.deleteTicket(getRepository(), ticket.number, "D"));
  198. }
  199. @Test
  200. public void testDeleteComment() throws Exception {
  201. // C1: create the ticket
  202. Change c1 = newChange("testDeleteComment() " + Long.toHexString(System.currentTimeMillis()));
  203. TicketModel ticket = service.createTicket(getRepository(), c1);
  204. assertTrue(ticket.number > 0);
  205. assertTrue(ticket.changes.get(0).hasComment());
  206. ticket = service.deleteComment(ticket, c1.comment.id, "D1");
  207. assertNotNull(ticket);
  208. assertEquals(1, ticket.changes.size());
  209. assertFalse(ticket.changes.get(0).hasComment());
  210. assertTrue(service.deleteTicket(getRepository(), ticket.number, "D"));
  211. }
  212. @Test
  213. public void testMilestones() throws Exception {
  214. service.createMilestone(getRepository(), "M1", "james");
  215. service.createMilestone(getRepository(), "M2", "frank");
  216. service.createMilestone(getRepository(), "M3", "joe");
  217. List<TicketMilestone> milestones = service.getMilestones(getRepository(), Status.Open);
  218. assertEquals("Unexpected open milestones count", 3, milestones.size());
  219. for (TicketMilestone milestone : milestones) {
  220. milestone.status = Status.Resolved;
  221. milestone.due = new Date();
  222. assertTrue("failed to update milestone " + milestone.name, service.updateMilestone(getRepository(), milestone, "ted"));
  223. }
  224. milestones = service.getMilestones(getRepository(), Status.Open);
  225. assertEquals("Unexpected open milestones count", 0, milestones.size());
  226. milestones = service.getMilestones(getRepository(), Status.Resolved);
  227. assertEquals("Unexpected resolved milestones count", 3, milestones.size());
  228. for (TicketMilestone milestone : milestones) {
  229. assertTrue("failed to delete milestone " + milestone.name, service.deleteMilestone(getRepository(), milestone.name, "lucifer"));
  230. }
  231. }
  232. @Test
  233. public void testLabels() throws Exception {
  234. service.createLabel(getRepository(), "L1", "james");
  235. service.createLabel(getRepository(), "L2", "frank");
  236. service.createLabel(getRepository(), "L3", "joe");
  237. List<TicketLabel> labels = service.getLabels(getRepository());
  238. assertEquals("Unexpected open labels count", 3, labels.size());
  239. for (TicketLabel label : labels) {
  240. label.color = "#ffff00";
  241. assertTrue("failed to update label " + label.name, service.updateLabel(getRepository(), label, "ted"));
  242. }
  243. labels = service.getLabels(getRepository());
  244. assertEquals("Unexpected labels count", 3, labels.size());
  245. for (TicketLabel label : labels) {
  246. assertTrue("failed to delete label " + label.name, service.deleteLabel(getRepository(), label.name, "lucifer"));
  247. }
  248. }
  249. @Test
  250. public void testPriorityAndSeverity() throws Exception {
  251. // C1: create and insert a ticket
  252. Change c1 = newChange("testPriorityAndSeverity() " + Long.toHexString(System.currentTimeMillis()));
  253. TicketModel ticket = service.createTicket(getRepository(), c1);
  254. assertTrue(ticket.number > 0);
  255. assertEquals(TicketModel.Priority.Normal, ticket.priority);
  256. assertEquals(TicketModel.Severity.Unrated, ticket.severity);
  257. TicketModel constructed = service.getTicket(getRepository(), ticket.number);
  258. compare(ticket, constructed);
  259. // C2: Change Priority max
  260. Change c2 = new Change("C2");
  261. c2.setField(Field.priority, TicketModel.Priority.Urgent);
  262. constructed = service.updateTicket(getRepository(), ticket.number, c2);
  263. assertNotNull(constructed);
  264. assertEquals(2, constructed.changes.size());
  265. assertEquals(TicketModel.Priority.Urgent, constructed.priority);
  266. assertEquals(TicketModel.Severity.Unrated, constructed.severity);
  267. // C3: Change Severity max
  268. Change c3 = new Change("C3");
  269. c3.setField(Field.severity, TicketModel.Severity.Catastrophic);
  270. constructed = service.updateTicket(getRepository(), ticket.number, c3);
  271. assertNotNull(constructed);
  272. assertEquals(3, constructed.changes.size());
  273. assertEquals(TicketModel.Priority.Urgent, constructed.priority);
  274. assertEquals(TicketModel.Severity.Catastrophic, constructed.severity);
  275. // C4: Change Priority min
  276. Change c4 = new Change("C3");
  277. c4.setField(Field.priority, TicketModel.Priority.Low);
  278. constructed = service.updateTicket(getRepository(), ticket.number, c4);
  279. assertNotNull(constructed);
  280. assertEquals(4, constructed.changes.size());
  281. assertEquals(TicketModel.Priority.Low, constructed.priority);
  282. assertEquals(TicketModel.Severity.Catastrophic, constructed.severity);
  283. }
  284. private Change newChange(String summary) {
  285. Change change = new Change("C1");
  286. change.setField(Field.title, summary);
  287. change.setField(Field.body, "this is my description");
  288. change.setField(Field.labels, "helpdesk");
  289. change.comment("my comment");
  290. return change;
  291. }
  292. private Attachment newAttachment() {
  293. Attachment attachment = new Attachment("test1.txt");
  294. attachment.content = new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
  295. 0x4a };
  296. return attachment;
  297. }
  298. private void compare(TicketModel ticket, TicketModel constructed) {
  299. assertEquals(ticket.number, constructed.number);
  300. assertEquals(ticket.createdBy, constructed.createdBy);
  301. assertEquals(ticket.responsible, constructed.responsible);
  302. assertEquals(ticket.title, constructed.title);
  303. assertEquals(ticket.body, constructed.body);
  304. assertEquals(ticket.created, constructed.created);
  305. assertTrue(ticket.hasLabel("helpdesk"));
  306. }
  307. @Test
  308. public void testNotifier() throws Exception {
  309. Change kernel = new Change("james");
  310. kernel.setField(Field.title, "Sample ticket");
  311. kernel.setField(Field.body, "this **is** my sample body\n\n- I hope\n- you really\n- *really* like it");
  312. kernel.setField(Field.status, Status.New);
  313. kernel.setField(Field.type, Type.Proposal);
  314. kernel.comment("this is a sample comment on a kernel change");
  315. Patchset patchset = new Patchset();
  316. patchset.insertions = 100;
  317. patchset.deletions = 10;
  318. patchset.number = 1;
  319. patchset.rev = 25;
  320. patchset.tip = "50f57913f816d04a16b7407134de5d8406421f37";
  321. kernel.patchset = patchset;
  322. TicketModel ticket = service.createTicket(getRepository(), 0L, kernel);
  323. Change merge = new Change("james");
  324. merge.setField(Field.mergeSha, patchset.tip);
  325. merge.setField(Field.mergeTo, "master");
  326. merge.setField(Field.status, Status.Merged);
  327. ticket = service.updateTicket(getRepository(), ticket.number, merge);
  328. ticket.repository = getRepository().name;
  329. TicketNotifier notifier = service.createNotifier();
  330. Mailing mailing = notifier.queueMailing(ticket);
  331. assertNotNull(mailing);
  332. }
  333. }