1
# Copyright 2010 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Tests for automatic landing thing."""
10
from launchpadlib.uris import (
11
DEV_SERVICE_ROOT, EDGE_SERVICE_ROOT, LPNET_SERVICE_ROOT,
14
from bzrlib.plugins.tarmac_land.tarmac_land import (
15
get_bugs_clause, get_reviewer_clause,
16
get_reviewer_handle, get_testfix_clause, get_qa_clause,
17
MissingReviewError, MissingBugsError, MissingBugsIncrementalError,
20
from fakemethod import FakeMethod
24
"""Fake launchpadlib Bug object.
26
Only used for the purposes of testing.
29
def __init__(self, id):
34
"""Fake launchpadlib Person object.
36
Only used for the purposes of testing.
39
def __init__(self, name, irc_handles):
41
self.irc_nicknames = list(irc_handles)
47
Only used for the purposes of testing.
50
def __init__(self, nickname, network):
51
self.nickname = nickname
52
self.network = network
55
class FakeLPMergeProposal:
56
"""Fake launchpadlib MergeProposal object.
58
Only used for the purposes of testing.
61
def __init__(self, root=None):
63
self.commit_message = None
69
class TestBugsClaused(unittest.TestCase):
70
"""Tests for `get_bugs_clause`."""
72
def test_no_bugs(self):
73
# If there are no bugs, then there is no bugs clause.
74
bugs_clause = get_bugs_clause([])
75
self.assertEqual('', bugs_clause)
77
def test_one_bug(self):
78
# If there's a bug, then the bugs clause is [bug=$ID].
80
bugs_clause = get_bugs_clause([bug])
81
self.assertEqual('[bug=45]', bugs_clause)
83
def test_two_bugs(self):
84
# If there are two bugs, then the bugs clause is [bug=$ID,$ID].
87
bugs_clause = get_bugs_clause([bug1, bug2])
88
self.assertEqual('[bug=20,45]', bugs_clause)
91
class TestSetStatusApproved(unittest.TestCase):
94
self.mp = MergeProposal(FakeLPMergeProposal())
95
self.mp._mp.setStatus(status="Work in progress")
97
def test_set_status_approved(self):
98
self.mp.set_status_approved()
99
self.assertEqual(self.mp._mp.queue_status, "Approved")
102
class TestGetTestfixClause(unittest.TestCase):
103
"""Tests for `get_testfix_clause`"""
105
def test_no_testfix(self):
107
self.assertEqual('', get_testfix_clause(testfix))
109
def test_is_testfix(self):
111
self.assertEqual('[testfix]', get_testfix_clause(testfix))
114
class TestGetQaClause(unittest.TestCase):
115
"""Tests for `get_qa_clause`"""
117
def test_no_bugs_no_option_given(self):
121
self.assertRaises(MissingBugsError, get_qa_clause, bugs, no_qa,
124
def test_bugs_noqa_option_given(self):
128
self.assertEqual('[no-qa]',
129
get_qa_clause([bug1], no_qa, incr))
131
def test_no_bugs_noqa_option_given(self):
135
self.assertEqual('[no-qa]',
136
get_qa_clause(bugs, no_qa, incr))
138
def test_bugs_no_option_given(self):
143
get_qa_clause([bug1], no_qa, incr))
145
def test_bugs_incr_option_given(self):
149
self.assertEqual('[incr]',
150
get_qa_clause([bug1], no_qa, incr))
152
def test_no_bugs_incr_option_given(self):
156
self.assertRaises(MissingBugsIncrementalError,
157
get_qa_clause, bugs, no_qa, incr)
159
def test_bugs_incr_and_noqa_option_given(self):
163
self.assertEqual('[no-qa][incr]',
164
get_qa_clause([bug1], no_qa, incr))
166
def test_rollback_given(self):
168
self.assertEqual('[rollback=123]',
169
get_qa_clause(bugs, rollback=123))
171
def test_rollback_and_noqa_and_incr_given(self):
175
self.assertEqual('[rollback=123]',
176
get_qa_clause(bugs, rollback=123))
179
class TestGetReviewerHandle(unittest.TestCase):
180
"""Tests for `get_reviewer_handle`."""
182
def makePerson(self, name, irc_handles):
183
return FakePerson(name, irc_handles)
185
def test_no_irc_nicknames(self):
186
# If the person has no IRC nicknames, their reviewer handle is their
187
# Launchpad user name.
188
person = self.makePerson(name='foo', irc_handles=[])
189
self.assertEqual('foo', get_reviewer_handle(person))
191
def test_freenode_irc_nick_preferred(self):
192
# If the person has a Freenode IRC nickname, then that is preferred as
194
person = self.makePerson(
195
name='foo', irc_handles=[FakeIRC('bar', 'irc.freenode.net')])
196
self.assertEqual('bar', get_reviewer_handle(person))
198
def test_non_freenode_nicks_ignored(self):
199
# If the person has IRC nicks that aren't freenode, we ignore them.
200
person = self.makePerson(
201
name='foo', irc_handles=[FakeIRC('bar', 'irc.efnet.net')])
202
self.assertEqual('foo', get_reviewer_handle(person))
205
class TestGetCommitMessage(unittest.TestCase):
208
self.mp = MergeProposal(FakeLPMergeProposal())
209
self.fake_bug = FakeBug(20)
210
self.fake_person = self.makePerson('foo')
212
def makePerson(self, name):
213
return FakePerson(name, [])
215
def test_commit_with_bugs(self):
220
self.mp.get_bugs = FakeMethod([self.fake_bug])
221
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
223
self.assertEqual("[r=foo][ui=none][bug=20] Foobaring the sbrubble.",
224
self.mp.build_commit_message("Foobaring the sbrubble.",
225
testfix, no_qa, incr))
227
def test_commit_no_bugs_no_noqa(self):
232
self.mp.get_bugs = FakeMethod([])
233
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
235
self.assertRaises(MissingBugsError, self.mp.build_commit_message,
236
testfix, no_qa, incr)
238
def test_commit_no_bugs_with_noqa(self):
243
self.mp.get_bugs = FakeMethod([])
244
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
246
self.assertEqual("[r=foo][ui=none][no-qa] Foobaring the sbrubble.",
247
self.mp.build_commit_message("Foobaring the sbrubble.",
248
testfix, no_qa, incr))
250
def test_commit_bugs_with_noqa(self):
255
self.mp.get_bugs = FakeMethod([self.fake_bug])
256
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
259
"[r=foo][ui=none][bug=20][no-qa] Foobaring the sbrubble.",
260
self.mp.build_commit_message("Foobaring the sbrubble.",
261
testfix, no_qa, incr))
263
def test_commit_bugs_with_incr(self):
268
self.mp.get_bugs = FakeMethod([self.fake_bug])
269
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
272
"[r=foo][ui=none][bug=20][incr] Foobaring the sbrubble.",
273
self.mp.build_commit_message("Foobaring the sbrubble.",
274
testfix, no_qa, incr))
276
def test_commit_no_bugs_with_incr(self):
281
self.mp.get_bugs = FakeMethod([self.fake_bug])
282
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
285
"[r=foo][ui=none][bug=20][incr] Foobaring the sbrubble.",
286
self.mp.build_commit_message("Foobaring the sbrubble.",
287
testfix, no_qa, incr))
289
def test_commit_with_noqa_and_incr(self):
294
self.mp.get_bugs = FakeMethod([self.fake_bug])
295
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
298
"[r=foo][ui=none][bug=20][no-qa][incr] Foobaring the sbrubble.",
299
self.mp.build_commit_message("Foobaring the sbrubble.",
300
testfix, no_qa, incr))
302
def test_commit_with_rollback(self):
303
self.mp.get_bugs = FakeMethod([self.fake_bug])
304
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
307
"[r=foo][ui=none][bug=20][rollback=123] Foobaring the sbrubble.",
308
self.mp.build_commit_message("Foobaring the sbrubble.",
311
def test_takes_into_account_existing_tags_on_commit_text(self):
312
self.mp.get_bugs = FakeMethod([self.fake_bug])
313
self.mp.get_reviews = FakeMethod({None : [self.fake_person]})
316
"[r=foo][ui=none][bug=20][rollback=123] Foobaring the sbrubble.",
317
self.mp.build_commit_message(
318
"[r=foo][ui=none][bug=20][rollback=123] Foobaring the sbrubble.",
322
class TestSetCommitMessage(unittest.TestCase):
325
self.mp = MergeProposal(FakeLPMergeProposal())
327
def test_set_commit_message(self):
328
commit_message = "Foobaring the sbrubble."
329
self.mp.set_commit_message(commit_message)
330
self.assertEqual(self.mp._mp.commit_message, commit_message)
333
class TestGetReviewerClause(unittest.TestCase):
334
"""Tests for `get_reviewer_clause`."""
336
def makePerson(self, name):
337
return FakePerson(name, [])
339
def get_reviewer_clause(self, reviewers):
340
return get_reviewer_clause(reviewers)
342
def test_one_reviewer_no_type(self):
343
# It's very common for a merge proposal to be reviewed by one person
344
# with no specified type of review. It such cases the review clause is
345
# '[r=<person>][ui=none]'.
346
clause = self.get_reviewer_clause({None: [self.makePerson('foo')]})
347
self.assertEqual('[r=foo][ui=none]', clause)
349
def test_two_reviewers_no_type(self):
350
# Branches can have more than one reviewer.
351
clause = self.get_reviewer_clause(
352
{None: [self.makePerson('foo'), self.makePerson('bar')]})
353
self.assertEqual('[r=bar,foo][ui=none]', clause)
355
def test_mentat_reviewers(self):
356
# A mentat review sometimes is marked like 'ui*'. Due to the
357
# unordered nature of dictionaries, the reviewers are sorted before
358
# being put into the clause for predictability.
359
clause = self.get_reviewer_clause(
360
{None: [self.makePerson('foo')],
361
'code*': [self.makePerson('newguy')],
362
'ui': [self.makePerson('beuno')],
363
'ui*': [self.makePerson('bac')]})
364
self.assertEqual('[r=foo,newguy][ui=bac,beuno]', clause)
366
def test_code_reviewer_counts(self):
367
# Some people explicitly specify the 'code' type when they do code
368
# reviews, these are treated in the same way as reviewers without any
370
clause = self.get_reviewer_clause({'code': [self.makePerson('foo')]})
371
self.assertEqual('[r=foo][ui=none]', clause)
373
def test_release_critical(self):
374
# Reviews that are marked as release-critical are included in a
376
clause = self.get_reviewer_clause(
377
{'code': [self.makePerson('foo')],
378
'release-critical': [self.makePerson('bar')]})
379
self.assertEqual('[release-critical=bar][r=foo][ui=none]', clause)
381
def test_db_reviewer_counts(self):
382
# There's no special way of annotating database reviews in Launchpad
383
# commit messages, so they are included with the code reviews.
384
clause = self.get_reviewer_clause({'db': [self.makePerson('foo')]})
385
self.assertEqual('[r=foo][ui=none]', clause)
387
def test_ui_reviewers(self):
388
# If someone has done a UI review, then that appears in the clause
389
# separately from the code reviews.
390
clause = self.get_reviewer_clause(
391
{'code': [self.makePerson('foo')],
392
'ui': [self.makePerson('bar')],
394
self.assertEqual('[r=foo][ui=bar]', clause)
396
def test_no_reviewers(self):
397
# If the merge proposal hasn't been approved by anyone, we cannot
398
# generate a valid clause.
399
self.assertRaises(MissingReviewError, self.get_reviewer_clause, {})