~launchpad-pqm/launchpad/devel

4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
1
= ExternalBugTracker: Roundup =
2
4767.5.32 by Graham Binns
Typo fix.
3
This covers the implementation of the ExternalBugTracker class for Roundup
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
4
bugwatches.
5
6
7
== Basics ==
8
9
The ExternalBugTracker descendant class which implements methods for updating
4767.5.28 by Graham Binns
It's called Roundup, not Trac, fool.
10
bug watches on Roundup bug trackers is externalbugtracker.Roundup, which
11
implements IExternalBugTracker.
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
12
8523.3.10 by Gavin Panella
Fix up some externalbugtracker imports.
13
    >>> from lp.bugs.externalbugtracker import Roundup
11716.1.6 by Curtis Hovey
Converted glob imports in doctests to import for the true module.
14
    >>> from lp.bugs.interfaces.bugtracker import BugTrackerType
15
    >>> from lp.bugs.interfaces.externalbugtracker import IExternalBugTracker
8523.3.1 by Gavin Panella
Bugs tree reorg after automated migration.
16
    >>> from lp.bugs.tests.externalbugtracker import (
4953.4.2 by Bjorn Tillenius
make ExternalBugTracker accept a 'bugtracker' argument instead of 'baseurl'.
17
    ...     new_bugtracker)
4767.5.34 by Graham Binns
Some review fixes for Kiko.
18
    >>> from canonical.launchpad.webapp.testing import verifyObject
4953.4.2 by Bjorn Tillenius
make ExternalBugTracker accept a 'bugtracker' argument instead of 'baseurl'.
19
    >>> verifyObject(
5228.1.5 by Christian Robottom Reis
Rename IExternalBugtracker to IExternalBugTracker
20
    ...     IExternalBugTracker,
5816.1.1 by Bjorn Tillenius
Make ExternalBugTracker accept a URL instead of a transaction and bug tracker.
21
    ...     Roundup('http://example.com'))
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
22
    True
23
24
25
== Status Conversion ==
26
7403.5.8 by Gavin Panella
Convert remote statuses more generally. In other words, don't use the isPython() method.
27
The basic Roundup bug statuses (i.e. those available by default in new
28
Roundup instances) map to Launchpad bug statuses.
29
30
Roundup.convertRemoteStatus() handles the conversion.
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
31
5816.1.1 by Bjorn Tillenius
Make ExternalBugTracker accept a URL instead of a transaction and bug tracker.
32
    >>> roundup = Roundup('http://example.com/')
6326.8.15 by Gavin Panella
Convert roundup.
33
    >>> roundup.convertRemoteStatus('1').title
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
34
    'New'
6326.8.15 by Gavin Panella
Convert roundup.
35
    >>> roundup.convertRemoteStatus('2').title
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
36
    'Confirmed'
6326.8.15 by Gavin Panella
Convert roundup.
37
    >>> roundup.convertRemoteStatus('3').title
38
    'Incomplete'
39
    >>> roundup.convertRemoteStatus('4').title
40
    'Incomplete'
41
    >>> roundup.convertRemoteStatus('5').title
42
    'In Progress'
43
    >>> roundup.convertRemoteStatus('6').title
44
    'In Progress'
45
    >>> roundup.convertRemoteStatus('7').title
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
46
    'Fix Committed'
6326.8.15 by Gavin Panella
Convert roundup.
47
    >>> roundup.convertRemoteStatus('8').title
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
48
    'Fix Released'
49
7403.5.8 by Gavin Panella
Convert remote statuses more generally. In other words, don't use the isPython() method.
50
Some Roundup trackers are set up to use multiple fields (columns in
51
Roundup terminology) to represent bug statuses. We store multiple
52
values by joining them with colons. The Roundup class knows how many
53
fields are expected for a particular remote host (for those that we
54
support), and will generate an error when we have more or less field
55
values compared to the expected number of fields.
56
57
    >>> roundup.convertRemoteStatus('1:2')
58
    Traceback (most recent call last):
59
      ...
60
    UnknownRemoteStatusError: 1 field(s) expected, got 2: 1:2
61
4767.5.26 by Graham Binns
Paragraphing in doctests.
62
If the status isn't something that our Roundup ExternalBugTracker can
5863.4.11 by Graham Binns
Fixed all tests, finally. Whoop de do.
63
understand an UnknownRemoteStatusError will be raised.
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
64
65
    >>> roundup.convertRemoteStatus('eggs').title
5863.4.11 by Graham Binns
Fixed all tests, finally. Whoop de do.
66
    Traceback (most recent call last):
67
      ...
7403.5.8 by Gavin Panella
Convert remote statuses more generally. In other words, don't use the isPython() method.
68
    UnknownRemoteStatusError: Unrecognized value for field 1 (status): eggs
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
69
70
71
== Initialization ==
72
4767.5.27 by Graham Binns
It's called Roundup, not Trac, fool
73
Calling initializeRemoteBugDB() on our Roundup instance and passing it a set
74
of remote bug IDs will fetch those bug IDs from the server and file them in a
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
75
local variable for later use.
76
6253.2.3 by Gavin Panella
Update tests.
77
We use a test-oriented implementation for the purposes of these tests, which
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
78
overrides ExternalBugTracker.urlopen() so that we don't have to rely on a
79
working network connection.
80
8523.3.1 by Gavin Panella
Bugs tree reorg after automated migration.
81
    >>> from lp.bugs.tests.externalbugtracker import (
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
82
    ...     TestRoundup, print_bugwatches)
5816.1.1 by Bjorn Tillenius
Make ExternalBugTracker accept a URL instead of a transaction and bug tracker.
83
    >>> roundup = TestRoundup(u'http://test.roundup/')
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
84
    >>> roundup.initializeRemoteBugDB([1])
85
    >>> sorted(roundup.bugs.keys())
86
    [1]
87
88
89
== Export Methods ==
90
91
There are two means by which we can export Roundup bug statuses: on a
92
bug-by-bug basis and as a batch. When the number of bugs that need updating is
93
less than a given bug roundupker's batch_query_threshold the bugs will be
94
fetched one-at-a-time:
95
96
    >>> roundup.batch_query_threshold
97
    10
98
99
    >>> roundup.trace_calls = True
100
    >>> roundup.initializeRemoteBugDB([6, 7, 8, 9, 10])
4953.4.2 by Bjorn Tillenius
make ExternalBugTracker accept a 'bugtracker' argument instead of 'baseurl'.
101
    CALLED urlopen(u'http://test.roundup/issue?...&id=6')
102
    CALLED urlopen(u'http://test.roundup/issue?...&id=7')
103
    CALLED urlopen(u'http://test.roundup/issue?...&id=8')
104
    CALLED urlopen(u'http://test.roundup/issue?...&id=9')
105
    CALLED urlopen(u'http://test.roundup/issue?...&id=10')
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
106
107
If there are more than batch_query_threshold bugs to update then they are
108
fetched as a batch:
109
110
    >>> roundup.batch_query_threshold = 4
111
    >>> roundup.initializeRemoteBugDB([6, 7, 8, 9, 10])
4953.4.2 by Bjorn Tillenius
make ExternalBugTracker accept a 'bugtracker' argument instead of 'baseurl'.
112
    CALLED urlopen(u'http://test.roundup/issue?...@startwith=0')
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
113
114
115
== Updating Bug Watches ==
116
117
First, we create some bug watches to test with:
118
11692.6.4 by Curtis Hovey
Fixed tests with multiple imports on the line.
119
    >>> from lp.bugs.interfaces.bug import IBugSet
120
    >>> from lp.registry.interfaces.person import IPersonSet
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
121
    >>> sample_person = getUtility(IPersonSet).getByEmail('test@canonical.com')
122
4945.2.3 by Bjorn Tillenius
make the rest of the externalbugtracker-* tests run using the checkwatches db user.
123
    >>> example_bug_tracker = new_bugtracker(BugTrackerType.ROUNDUP)
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
124
11692.6.2 by Curtis Hovey
Use deglober to fixing simple glob imports in doctests.
125
    >>> from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
126
    >>> example_bug = getUtility(IBugSet).get(10)
127
    >>> example_bugwatch = example_bug.addWatch(
7982.1.15 by Bjorn Tillenius
Fix test failures.
128
    ...     example_bug_tracker, '1',
129
    ...     getUtility(ILaunchpadCelebrities).janitor)
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
130
131
132
Collect the Example.com watches:
133
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
134
    >>> print_bugwatches(example_bug_tracker.watches)
135
    Remote bug 1: None
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
136
137
And have a Roundup instance process them:
138
10512.4.24 by Gavin Panella
Get all the externalbugtracker*.txt doctests passing.
139
    >>> transaction.commit()
140
11716.1.12 by Curtis Hovey
Sorted imports in doctests.
141
    >>> from canonical.testing.layers import LaunchpadZopelessLayer
10694.2.25 by Graham Binns
Renamed BugWatchUpdater -> CheckwatchesMaster. This is the wrong name for it, but I did it to avoid bikeshedding.
142
    >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster
5816.1.1 by Bjorn Tillenius
Make ExternalBugTracker accept a URL instead of a transaction and bug tracker.
143
    >>> txn = LaunchpadZopelessLayer.txn
10694.2.25 by Graham Binns
Renamed BugWatchUpdater -> CheckwatchesMaster. This is the wrong name for it, but I did it to avoid bikeshedding.
144
    >>> bug_watch_updater = CheckwatchesMaster(txn)
5816.1.1 by Bjorn Tillenius
Make ExternalBugTracker accept a URL instead of a transaction and bug tracker.
145
    >>> roundup = TestRoundup(example_bug_tracker.baseurl)
5626.5.2 by Bjorn Tillenius
move ExternalBugtracker.updateBugWatches() to BugWatchUpdater.updateBugWatches(). Debbugs.importBugComments() is now broken, though.
146
    >>> bug_watch_updater.updateBugWatches(
147
    ...     roundup, example_bug_tracker.watches)
7910.2.7 by Graham Binns
Updated checkwatches tests to deal with logging output changes.
148
    INFO:...:Updating 1 watches for 1 bugs on http://bugs.some.where
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
149
    >>> print_bugwatches(example_bug_tracker.watches)
150
    Remote bug 1: 1
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
151
152
We'll add some more watches now.
153
11692.6.2 by Curtis Hovey
Use deglober to fixing simple glob imports in doctests.
154
    >>> from lp.bugs.interfaces.bugwatch import IBugWatchSet
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
155
    >>> print_bugwatches(example_bug_tracker.watches,
156
    ...     roundup.convertRemoteStatus)
157
    Remote bug 1: New
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
158
159
    >>> remote_bugs = [
4767.5.21 by Graham Binns
Roundup.getRemoteStatus() now returns a string rather than an int so that updateBugWatches() doesn't get confused and think that a watch was updated when it wasn't.
160
    ...     (2, 'Confirmed'),
161
    ...     (3, 'Incomplete'),
162
    ...     (4, 'Incomplete'),
163
    ...     (5, 'In Progress'),
164
    ...     (9, 'In Progress'),
165
    ...     (10, 'Fix Committed'),
166
    ...     (11, 'Fix Released'),
167
    ...     (12, 'Incomplete'),
168
    ...     (13, 'Incomplete'),
169
    ...     (14, 'In Progress')
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
170
    ... ]
171
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
172
    >>> bug_watch_set = getUtility(IBugWatchSet)
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
173
    >>> for remote_bug_id, remote_status in remote_bugs:
174
    ...     bug_watch = bug_watch_set.createBugWatch(
175
    ...         bug=example_bug, owner=sample_person,
176
    ...         bugtracker=example_bug_tracker,
177
    ...         remotebug=str(remote_bug_id))
178
179
    >>> roundup.trace_calls = True
5626.5.2 by Bjorn Tillenius
move ExternalBugtracker.updateBugWatches() to BugWatchUpdater.updateBugWatches(). Debbugs.importBugComments() is now broken, though.
180
    >>> bug_watch_updater.updateBugWatches(
181
    ...     roundup, example_bug_tracker.watches)
7910.2.7 by Graham Binns
Updated checkwatches tests to deal with logging output changes.
182
    INFO:...:Updating 11 watches for 11 bugs on http://bugs.some.where
4945.2.3 by Bjorn Tillenius
make the rest of the externalbugtracker-* tests run using the checkwatches db user.
183
    CALLED urlopen(u'http://.../issue?...@startwith=0')
4767.5.21 by Graham Binns
Roundup.getRemoteStatus() now returns a string rather than an int so that updateBugWatches() doesn't get confused and think that a watch was updated when it wasn't.
184
4767.5.39 by Graham Binns
Added a print_bugwatches() helper function to ftests.externalbugtracker.
185
    >>> print_bugwatches(example_bug_tracker.watches,
186
    ...     roundup.convertRemoteStatus)
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
187
    Remote bug 1: New
4767.5.21 by Graham Binns
Roundup.getRemoteStatus() now returns a string rather than an int so that updateBugWatches() doesn't get confused and think that a watch was updated when it wasn't.
188
    Remote bug 2: Confirmed
189
    Remote bug 3: Incomplete
190
    Remote bug 4: Incomplete
191
    Remote bug 5: In Progress
192
    Remote bug 9: In Progress
193
    Remote bug 10: Fix Committed
194
    Remote bug 11: Fix Released
195
    Remote bug 12: Incomplete
196
    Remote bug 13: Incomplete
197
    Remote bug 14: In Progress
4767.5.20 by Graham Binns
Added tests, etc., that I stupidly forgot to commit.
198