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