| 1 | #!/usr/bin/python |
|---|
| 2 | # |
|---|
| 3 | # Test program for the multiprojectcommitticketupdater plugin to Trac. |
|---|
| 4 | # |
|---|
| 5 | # Ruth Trevor-Allen, NAG Oxford, 2011. |
|---|
| 6 | import sys |
|---|
| 7 | sys.path.append('..') |
|---|
| 8 | |
|---|
| 9 | from multicommitupdater.commitupdater import MultiProjectCommitTicketUpdater |
|---|
| 10 | import trac.env |
|---|
| 11 | import time, unittest |
|---|
| 12 | from trac.core import ComponentManager |
|---|
| 13 | from trac.versioncontrol.api import Repository, Changeset |
|---|
| 14 | |
|---|
| 15 | class TestMultiProjectCommitTicketUpdater(unittest.TestCase): |
|---|
| 16 | # Component architecture plumbing - load environments and components |
|---|
| 17 | # under test (check that each environment matches the right tickets) |
|---|
| 18 | comp_mgr1 = trac.env.open_environment('./testenv/') |
|---|
| 19 | comp_mgr2 = trac.env.open_environment('./testenv2/') |
|---|
| 20 | obj1 = MultiProjectCommitTicketUpdater(comp_mgr1) |
|---|
| 21 | obj2 = MultiProjectCommitTicketUpdater(comp_mgr2) |
|---|
| 22 | # Create fake repository for changesets (note that both fake projects |
|---|
| 23 | # need to use the same fake repository) |
|---|
| 24 | test_repo = Repository("Test_repo",{'name': "Test_repo", 'id': 4321},"tmp.log") |
|---|
| 25 | |
|---|
| 26 | def setUp(self): |
|---|
| 27 | # Set all component objects to defaults |
|---|
| 28 | self.obj1.config.set("multicommitupdater","envelope","") |
|---|
| 29 | self.obj2.config.set("multicommitupdater","envelope","") |
|---|
| 30 | self.obj1.config.set("multicommitupdater","commands.close", |
|---|
| 31 | "close closed closes fix fixed fixes") |
|---|
| 32 | self.obj2.config.set("multicommitupdater","commands.close", |
|---|
| 33 | "close closed closes fix fixed fixes") |
|---|
| 34 | self.obj1.config.set("multicommitupdater","commands.refs", |
|---|
| 35 | "addresses re references refs see") |
|---|
| 36 | self.obj2.config.set("multicommitupdater","commands.refs", |
|---|
| 37 | "addresses re references refs see") |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | def test_simple_case(self): |
|---|
| 41 | message = "Fixed some stuff. Re test:#1, closes test2:#2" |
|---|
| 42 | test_changeset = Changeset(None,1234,message,"test_person",time.time()) |
|---|
| 43 | self.check_ticket_comment(test_changeset) |
|---|
| 44 | # For each object in turn: |
|---|
| 45 | # Get tickets and commands |
|---|
| 46 | tickets = self.obj1._parse_message(message) |
|---|
| 47 | # First, check we've got the tickets we were expecting |
|---|
| 48 | self.assertEqual(tickets.keys(),[1]) |
|---|
| 49 | # Now check the actions are right |
|---|
| 50 | self.assertEqual(tickets.get(1),[self.obj1.cmd_refs]) |
|---|
| 51 | # Same checks for obj2: |
|---|
| 52 | tickets = self.obj2._parse_message(message) |
|---|
| 53 | self.assertEqual(tickets.keys(),[2]) |
|---|
| 54 | self.assertEqual(tickets.get(2),[self.obj2.cmd_close]) |
|---|
| 55 | |
|---|
| 56 | def test_erroneous_capital_letters(self): |
|---|
| 57 | message = "Did some more stuff. Fixes Test:#3, refs test2:#4" |
|---|
| 58 | test_changeset2 = Changeset(None,1235,message,"test_person",time.time()) |
|---|
| 59 | self.check_ticket_comment(test_changeset2) |
|---|
| 60 | |
|---|
| 61 | tickets = self.obj1._parse_message(message) |
|---|
| 62 | self.assertEqual(tickets.keys(),[3]) |
|---|
| 63 | self.assertEqual(tickets.get(3),[self.obj1.cmd_close]) |
|---|
| 64 | |
|---|
| 65 | tickets = self.obj2._parse_message(message) |
|---|
| 66 | self.assertEqual(tickets.keys(),[4]) |
|---|
| 67 | self.assertEqual(tickets.get(4),[self.obj2.cmd_refs]) |
|---|
| 68 | |
|---|
| 69 | def test_all_documented_synonyms_close(self): |
|---|
| 70 | message = "More things. close test:#5, closed test2:#6, closes " + \ |
|---|
| 71 | "test:#7, fix test2:#8, fixed test:#9, fixes test2:#10." |
|---|
| 72 | test_changeset3 = Changeset(None,1236,message,"test_person",time.time()) |
|---|
| 73 | self.check_ticket_comment(test_changeset3) |
|---|
| 74 | |
|---|
| 75 | tickets = self.obj1._parse_message(message) |
|---|
| 76 | sorted_keys = tickets.keys() |
|---|
| 77 | sorted_keys.sort() |
|---|
| 78 | self.assertEqual(sorted_keys,[5,7,9]) |
|---|
| 79 | self.assertEqual(tickets.get(5),[self.obj1.cmd_close]) |
|---|
| 80 | self.assertEqual(tickets.get(7),[self.obj1.cmd_close]) |
|---|
| 81 | self.assertEqual(tickets.get(9),[self.obj1.cmd_close]) |
|---|
| 82 | |
|---|
| 83 | tickets = self.obj2._parse_message(message) |
|---|
| 84 | sorted_keys = tickets.keys() |
|---|
| 85 | sorted_keys.sort() |
|---|
| 86 | self.assertEqual(sorted_keys,[6,8,10]) |
|---|
| 87 | self.assertEqual(tickets.get(6),[self.obj2.cmd_close]) |
|---|
| 88 | self.assertEqual(tickets.get(8),[self.obj2.cmd_close]) |
|---|
| 89 | self.assertEqual(tickets.get(10),[self.obj2.cmd_close]) |
|---|
| 90 | |
|---|
| 91 | def test_all_documented_synonyms_ref(self): |
|---|
| 92 | message = "Yet more things. references test:#11, refs test2:#12, " + \ |
|---|
| 93 | "addresses test:#13, re test2:#14, see test:#15" |
|---|
| 94 | test_changeset4 = Changeset(None,1237,message,"test_person",time.time()) |
|---|
| 95 | self.check_ticket_comment(test_changeset4) |
|---|
| 96 | |
|---|
| 97 | tickets = self.obj1._parse_message(message) |
|---|
| 98 | sorted_keys = tickets.keys() |
|---|
| 99 | sorted_keys.sort() |
|---|
| 100 | self.assertEqual(sorted_keys,[11,13,15]) |
|---|
| 101 | self.assertEqual(tickets.get(11),[self.obj1.cmd_refs]) |
|---|
| 102 | self.assertEqual(tickets.get(13),[self.obj1.cmd_refs]) |
|---|
| 103 | self.assertEqual(tickets.get(15),[self.obj1.cmd_refs]) |
|---|
| 104 | |
|---|
| 105 | tickets = self.obj2._parse_message(message) |
|---|
| 106 | sorted_keys = tickets.keys() |
|---|
| 107 | sorted_keys.sort() |
|---|
| 108 | self.assertEqual(sorted_keys,[12,14]) |
|---|
| 109 | self.assertEqual(tickets.get(12),[self.obj2.cmd_refs]) |
|---|
| 110 | self.assertEqual(tickets.get(14),[self.obj2.cmd_refs]) |
|---|
| 111 | |
|---|
| 112 | # TODO: def test_all_synonyms_ticket(self): |
|---|
| 113 | |
|---|
| 114 | def test_multiple_tickets_one_command_simple(self): |
|---|
| 115 | message = "And even more things. re test:#16,#17,#18. Closes " + \ |
|---|
| 116 | "test2:#19,#20" |
|---|
| 117 | test_changeset5 = Changeset(None,1238,message,"test_person",time.time()) |
|---|
| 118 | self.check_ticket_comment(test_changeset5) |
|---|
| 119 | |
|---|
| 120 | tickets = self.obj1._parse_message(message) |
|---|
| 121 | sorted_keys = tickets.keys() |
|---|
| 122 | sorted_keys.sort() |
|---|
| 123 | self.assertEqual(sorted_keys,[16,17,18]) |
|---|
| 124 | self.assertEqual(tickets.get(16),[self.obj1.cmd_refs]) |
|---|
| 125 | self.assertEqual(tickets.get(17),[self.obj1.cmd_refs]) |
|---|
| 126 | self.assertEqual(tickets.get(18),[self.obj1.cmd_refs]) |
|---|
| 127 | |
|---|
| 128 | tickets = self.obj2._parse_message(message) |
|---|
| 129 | sorted_keys = tickets.keys() |
|---|
| 130 | sorted_keys.sort() |
|---|
| 131 | self.assertEqual(sorted_keys,[19,20]) |
|---|
| 132 | self.assertEqual(tickets.get(19),[self.obj2.cmd_close]) |
|---|
| 133 | self.assertEqual(tickets.get(20),[self.obj2.cmd_close]) |
|---|
| 134 | |
|---|
| 135 | def test_multiple_tickets_one_command_complex(self): |
|---|
| 136 | message = "Woo, even more things. Look at us go! Refs test:#21 & " + \ |
|---|
| 137 | "#22, closes test:#23. See test2:#24,#25 and #26." |
|---|
| 138 | test_changeset6 = Changeset(None,1239,message,"test_person",time.time()) |
|---|
| 139 | self.check_ticket_comment(test_changeset6) |
|---|
| 140 | |
|---|
| 141 | tickets = self.obj1._parse_message(message) |
|---|
| 142 | sorted_keys = tickets.keys() |
|---|
| 143 | sorted_keys.sort() |
|---|
| 144 | self.assertEqual(sorted_keys,[21,22,23]) |
|---|
| 145 | self.assertEqual(tickets.get(21),[self.obj1.cmd_refs]) |
|---|
| 146 | self.assertEqual(tickets.get(22),[self.obj1.cmd_refs]) |
|---|
| 147 | self.assertEqual(tickets.get(23),[self.obj1.cmd_close]) |
|---|
| 148 | |
|---|
| 149 | tickets = self.obj2._parse_message(message) |
|---|
| 150 | sorted_keys = tickets.keys() |
|---|
| 151 | sorted_keys.sort() |
|---|
| 152 | self.assertEqual(sorted_keys,[24,25,26]) |
|---|
| 153 | self.assertEqual(tickets.get(24),[self.obj2.cmd_refs]) |
|---|
| 154 | self.assertEqual(tickets.get(25),[self.obj2.cmd_refs]) |
|---|
| 155 | self.assertEqual(tickets.get(26),[self.obj2.cmd_refs]) |
|---|
| 156 | |
|---|
| 157 | def test_one_env(self): |
|---|
| 158 | message = "These things are only applicable to test2. See test" + \ |
|---|
| 159 | "2:#27, closes test2:#28" |
|---|
| 160 | test_changeset7 = Changeset(None,1240,message,"test_person",time.time()) |
|---|
| 161 | self.check_ticket_comment(test_changeset7) |
|---|
| 162 | |
|---|
| 163 | tickets = self.obj1._parse_message(message) |
|---|
| 164 | self.assertEqual(tickets,{}) |
|---|
| 165 | |
|---|
| 166 | tickets = self.obj2._parse_message(message) |
|---|
| 167 | sorted_keys = tickets.keys() |
|---|
| 168 | sorted_keys.sort() |
|---|
| 169 | self.assertEqual(sorted_keys,[27,28]) |
|---|
| 170 | self.assertEqual(tickets.get(27),[self.obj2.cmd_refs]) |
|---|
| 171 | self.assertEqual(tickets.get(28),[self.obj2.cmd_close]) |
|---|
| 172 | |
|---|
| 173 | def test_spaces(self): |
|---|
| 174 | message = "Today I am feeling spacey! Closes test:#29, #30. See " + \ |
|---|
| 175 | "test2:#31" |
|---|
| 176 | test_changeset8 = Changeset(None,1241,message,"test_person",time.time()) |
|---|
| 177 | self.check_ticket_comment(test_changeset8) |
|---|
| 178 | |
|---|
| 179 | tickets = self.obj1._parse_message(message) |
|---|
| 180 | sorted_keys = tickets.keys() |
|---|
| 181 | sorted_keys.sort() |
|---|
| 182 | self.assertEqual(sorted_keys,[29,30]) |
|---|
| 183 | self.assertEqual(tickets.get(29),[self.obj1.cmd_close]) |
|---|
| 184 | self.assertEqual(tickets.get(30),[self.obj1.cmd_close]) |
|---|
| 185 | |
|---|
| 186 | tickets = self.obj2._parse_message(message) |
|---|
| 187 | self.assertEqual(tickets.keys(),[31]) |
|---|
| 188 | self.assertEqual(tickets.get(31),[self.obj2.cmd_refs]) |
|---|
| 189 | |
|---|
| 190 | # |
|---|
| 191 | # Tests of other documented committicketupdater functionality |
|---|
| 192 | # |
|---|
| 193 | def test_envelope(self): |
|---|
| 194 | message = "Today, I shall be putting my messages in an envelope. " + \ |
|---|
| 195 | "[re test:#32], [re test2:#33]" |
|---|
| 196 | test_changeset9 = Changeset(None,1242,message,"test_person",time.time()) |
|---|
| 197 | self.check_ticket_comment(test_changeset9) |
|---|
| 198 | |
|---|
| 199 | # With no envelope set, this works as normal |
|---|
| 200 | tickets = self.obj1._parse_message(message) |
|---|
| 201 | self.assertEqual(tickets.keys(),[32]) |
|---|
| 202 | self.assertEqual(tickets.get(32),[self.obj1.cmd_refs]) |
|---|
| 203 | |
|---|
| 204 | tickets = self.obj2._parse_message(message) |
|---|
| 205 | self.assertEqual(tickets.keys(),[33]) |
|---|
| 206 | self.assertEqual(tickets.get(33),[self.obj2.cmd_refs]) |
|---|
| 207 | |
|---|
| 208 | # With a different envelope set, the messages should be ignored |
|---|
| 209 | self.obj1.config.set("multicommitupdater","envelope","{}") |
|---|
| 210 | self.obj2.config.set("multicommitupdater","envelope","<>") |
|---|
| 211 | |
|---|
| 212 | tickets = self.obj1._parse_message(message) |
|---|
| 213 | self.assertEqual(tickets.keys(),[]) |
|---|
| 214 | |
|---|
| 215 | tickets = self.obj2._parse_message(message) |
|---|
| 216 | self.assertEqual(tickets.keys(),[]) |
|---|
| 217 | |
|---|
| 218 | # Changing one envelope to '[]' should mean only that environment |
|---|
| 219 | # picks up the message |
|---|
| 220 | self.obj1.config.set("multicommitupdater","envelope","[]") |
|---|
| 221 | |
|---|
| 222 | tickets = self.obj1._parse_message(message) |
|---|
| 223 | self.assertEqual(tickets.keys(),[32]) |
|---|
| 224 | self.assertEqual(tickets.get(32),[self.obj1.cmd_refs]) |
|---|
| 225 | |
|---|
| 226 | tickets = self.obj2._parse_message(message) |
|---|
| 227 | self.assertEqual(tickets.keys(),[]) |
|---|
| 228 | |
|---|
| 229 | # When both envelopes are '[]', both environments pick up the actions |
|---|
| 230 | self.obj2.config.set("multicommitupdater","envelope","[]") |
|---|
| 231 | tickets = self.obj1._parse_message(message) |
|---|
| 232 | self.assertEqual(tickets.keys(),[32]) |
|---|
| 233 | self.assertEqual(tickets.get(32),[self.obj1.cmd_refs]) |
|---|
| 234 | |
|---|
| 235 | tickets = self.obj2._parse_message(message) |
|---|
| 236 | self.assertEqual(tickets.keys(),[33]) |
|---|
| 237 | self.assertEqual(tickets.get(33),[self.obj2.cmd_refs]) |
|---|
| 238 | |
|---|
| 239 | def test_custom_commands_close(self): |
|---|
| 240 | message = "this time, we're going to use some close commands that " + \ |
|---|
| 241 | "aren't on the default list. Nukes test:#34, #35 and " + \ |
|---|
| 242 | "obliterates test2:#36" |
|---|
| 243 | test_changeset10 = Changeset(None,1243,message,"test_person",time.time()) |
|---|
| 244 | self.check_ticket_comment(test_changeset10) |
|---|
| 245 | |
|---|
| 246 | # Nothing happens if we stick with the default commands |
|---|
| 247 | tickets = self.obj1._parse_message(message) |
|---|
| 248 | self.assertEqual(tickets.keys(),[]) |
|---|
| 249 | |
|---|
| 250 | tickets = self.obj2._parse_message(message) |
|---|
| 251 | self.assertEqual(tickets.keys(),[]) |
|---|
| 252 | |
|---|
| 253 | # Adding 'nukes' to the list should make our first command work |
|---|
| 254 | self.obj1.config.set("multicommitupdater","commands.close", |
|---|
| 255 | "ends nukes completes") |
|---|
| 256 | self.obj2.config.set("multicommitupdater","commands.close", |
|---|
| 257 | "ends nukes completes") |
|---|
| 258 | |
|---|
| 259 | tickets = self.obj1._parse_message(message) |
|---|
| 260 | sorted_keys = tickets.keys() |
|---|
| 261 | sorted_keys.sort() |
|---|
| 262 | self.assertEqual(sorted_keys,[34,35]) |
|---|
| 263 | self.assertEqual(tickets.get(34),[self.obj1.cmd_close]) |
|---|
| 264 | self.assertEqual(tickets.get(35),[self.obj1.cmd_close]) |
|---|
| 265 | |
|---|
| 266 | tickets = self.obj2._parse_message(message) |
|---|
| 267 | self.assertEqual(tickets.keys(),[]) |
|---|
| 268 | |
|---|
| 269 | # And adding 'obliterates' should take care of the second |
|---|
| 270 | self.obj1.config.set("multicommitupdater","commands.close", |
|---|
| 271 | "ends nukes obliterates completes") |
|---|
| 272 | self.obj2.config.set("multicommitupdater","commands.close", |
|---|
| 273 | "ends nukes obliterates completes") |
|---|
| 274 | |
|---|
| 275 | tickets = self.obj1._parse_message(message) |
|---|
| 276 | sorted_keys = tickets.keys() |
|---|
| 277 | sorted_keys.sort() |
|---|
| 278 | self.assertEqual(sorted_keys,[34,35]) |
|---|
| 279 | self.assertEqual(tickets.get(34),[self.obj1.cmd_close]) |
|---|
| 280 | self.assertEqual(tickets.get(35),[self.obj1.cmd_close]) |
|---|
| 281 | |
|---|
| 282 | tickets = self.obj2._parse_message(message) |
|---|
| 283 | self.assertEqual(tickets.keys(),[36]) |
|---|
| 284 | self.assertEqual(tickets.get(36),[self.obj2.cmd_close]) |
|---|
| 285 | |
|---|
| 286 | # Sad path test |
|---|
| 287 | message = "now we're checking that tickets aren't closed by " + \ |
|---|
| 288 | "default commands when the list has been overwritten. " + \ |
|---|
| 289 | "closes test:#37, fixes test2:#38" |
|---|
| 290 | test_changeset11 = Changeset(None,1244,message,"test_person",time.time()) |
|---|
| 291 | self.check_ticket_comment(test_changeset11) |
|---|
| 292 | |
|---|
| 293 | tickets = self.obj1._parse_message(message) |
|---|
| 294 | self.assertEqual(tickets.keys(),[]) |
|---|
| 295 | |
|---|
| 296 | tickets = self.obj2._parse_message(message) |
|---|
| 297 | self.assertEqual(tickets.keys(),[]) |
|---|
| 298 | |
|---|
| 299 | def test_custom_commands_refs(self): |
|---|
| 300 | message = "And now something very similar wth refs. Lookit test:#39" + \ |
|---|
| 301 | "affects test2:#40 & #41" |
|---|
| 302 | test_changeset12 = Changeset(None,1245,message,"test_person",time.time()) |
|---|
| 303 | self.check_ticket_comment(test_changeset12) |
|---|
| 304 | |
|---|
| 305 | tickets = self.obj1._parse_message(message) |
|---|
| 306 | self.assertEqual(tickets.keys(),[]) |
|---|
| 307 | |
|---|
| 308 | tickets = self.obj2._parse_message(message) |
|---|
| 309 | self.assertEqual(tickets.keys(),[]) |
|---|
| 310 | |
|---|
| 311 | self.obj1.config.set("multicommitupdater","commands.refs", |
|---|
| 312 | "relevant-to lookit affects related") |
|---|
| 313 | self.obj2.config.set("multicommitupdater","commands.refs", |
|---|
| 314 | "relevant-to lookit affects related") |
|---|
| 315 | |
|---|
| 316 | tickets = self.obj1._parse_message(message) |
|---|
| 317 | self.assertEqual(tickets.keys(),[39]) |
|---|
| 318 | self.assertEqual(tickets.get(39),[self.obj1.cmd_refs]) |
|---|
| 319 | |
|---|
| 320 | tickets = self.obj2._parse_message(message) |
|---|
| 321 | sorted_keys = tickets.keys() |
|---|
| 322 | sorted_keys.sort() |
|---|
| 323 | self.assertEqual(sorted_keys,[40,41]) |
|---|
| 324 | self.assertEqual(tickets.get(40),[self.obj2.cmd_refs]) |
|---|
| 325 | self.assertEqual(tickets.get(41),[self.obj2.cmd_refs]) |
|---|
| 326 | |
|---|
| 327 | # :( |
|---|
| 328 | message = "can we still ref tickets using one of the old " + \ |
|---|
| 329 | "commands? re test:#42, re test2:#43" |
|---|
| 330 | test_changeset13 = Changeset(None,1246,message,"test_person",time.time()) |
|---|
| 331 | self.check_ticket_comment(test_changeset13) |
|---|
| 332 | |
|---|
| 333 | tickets = self.obj1._parse_message(message) |
|---|
| 334 | self.assertEqual(tickets.keys(),[]) |
|---|
| 335 | |
|---|
| 336 | tickets = self.obj2._parse_message(message) |
|---|
| 337 | self.assertEqual(tickets.keys(),[]) |
|---|
| 338 | |
|---|
| 339 | #------------------------------------------------------------------------------ |
|---|
| 340 | # Utilities |
|---|
| 341 | def build_comment(self,changeset): |
|---|
| 342 | return """In [%d/%s]: |
|---|
| 343 | {{{ |
|---|
| 344 | #!CommitTicketReference repository="%s" revision="%d" |
|---|
| 345 | %s |
|---|
| 346 | }}}""" % (changeset.rev, self.test_repo.name, self.test_repo.name, \ |
|---|
| 347 | changeset.rev, changeset.message) |
|---|
| 348 | |
|---|
| 349 | def check_ticket_comment(self,changeset): |
|---|
| 350 | for obj in [self.obj1,self.obj2]: |
|---|
| 351 | self.assertEqual(obj.make_ticket_comment(self.test_repo,changeset), |
|---|
| 352 | self.build_comment(changeset)) |
|---|
| 353 | |
|---|
| 354 | # Allow these tests to be run from the command line |
|---|
| 355 | if __name__ == '__main__': |
|---|
| 356 | unittest.main() |
|---|