~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
ExternalBugTracker: Issuezilla and other Freaks
===============================================

Bugzilla has a few variants out there in the wild, and we work hard to
support them all.

Issuezilla
----------

We support Issuezilla-style trackers. These trackers are essentially
modified (ancient) versions of Bugzilla; their XML elements have
slightly different names, and they lack the severity field. We pretend
Mozilla's Bugzilla is an Issuezilla instance here:

    >>> from lp.bugs.interfaces.bugtracker import IBugTrackerSet

    >>> from lp.testing.layers import LaunchpadZopelessLayer
    >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster
    >>> from lp.bugs.tests.externalbugtracker import TestIssuezilla
    >>> txn = LaunchpadZopelessLayer.txn
    >>> mozilla_bugzilla = getUtility(IBugTrackerSet).getByName('mozilla.org')
    >>> issuezilla = TestIssuezilla(mozilla_bugzilla.baseurl)
    >>> issuezilla._probe_version()
    (2, 11)
    >>> for bug_watch in mozilla_bugzilla.watches:
    ...     print "%s: %s %s" % (bug_watch.remotebug,
    ...         bug_watch.remotestatus, bug_watch.remote_importance)
    2000:
    123543:
    42: FUBAR BAZBAZ
    42: FUBAR BAZBAZ
    >>> transaction.commit()
    >>> bug_watch_updater = CheckwatchesMaster(txn)
    >>> bug_watch_updater.updateBugWatches(
    ...     issuezilla, mozilla_bugzilla.watches)
    INFO:...:Updating 4 watches for 3 bugs on https://bugzilla.mozilla.org
    INFO:...:Didn't find bug u'42' on https://bugzilla.mozilla.org
    (local bugs: 1, 2).

    >>> for bug_watch in mozilla_bugzilla.watches:
    ...     print "%s: %s %s" % (bug_watch.remotebug,
    ...         bug_watch.remotestatus, bug_watch.remote_importance)
    2000: RESOLVED FIXED LOW
    123543: ASSIGNED HIGH
    42: FUBAR BAZBAZ
    42: FUBAR BAZBAZ


Bugzilla prior to 2.11
----------------------

Old-style Bugzillas are quite similar to Issuezilla. Again we pretend
Mozilla.org's using this old version. Here's the scoop:

    >>> from lp.bugs.tests.externalbugtracker import TestOldBugzilla
    >>> old_bugzilla = TestOldBugzilla(mozilla_bugzilla.baseurl)

  a) The version is way old:

    >>> old_bugzilla._probe_version()
    (2, 10)

  b) The tags are not prefixed with the bz: namespace:

    >>> bug_item_file = old_bugzilla._readBugItemFile()
    >>> "<bug_status>" in bug_item_file
    True
    >>> "<bug_id>" in bug_item_file
    True

We support them just fine:

    >>> remote_bugs = ['42', '123543']
    >>> old_bugzilla.initializeRemoteBugDB(remote_bugs)
    >>> for remote_bug in remote_bugs:
    ...     print "%s: %s %s" % (
    ...         remote_bug,
    ...         old_bugzilla.getRemoteStatus(remote_bug),
    ...         old_bugzilla.getRemoteImportance(remote_bug))
    42: RESOLVED FIXED LOW BLOCKER
    123543: ASSIGNED HIGH BLOCKER


Bugzilla oddities
-----------------

Some Bugzillas have some weird properties that we need to cater for:

    >>> from lp.bugs.tests.externalbugtracker import (
    ...     TestWeirdBugzilla)
    >>> weird_bugzilla = TestWeirdBugzilla(mozilla_bugzilla.baseurl)
    >>> weird_bugzilla._probe_version()
    (2, 20)

  a) The bug status tag is <bz:status> and not <bz:bug_status>

    >>> bug_item_file = weird_bugzilla._readBugItemFile()
    >>> "<bz:status>" in bug_item_file
    True

  b) The content is non-ascii:

    >>> bug_item_file.decode("ascii")
    Traceback (most recent call last):
    ...
    UnicodeDecodeError: 'ascii' codec can't decode byte...

Yet everything still works as expected:

    >>> remote_bugs = ['2000', '123543']
    >>> weird_bugzilla.initializeRemoteBugDB(remote_bugs)
    >>> for remote_bug in remote_bugs:
    ...     print "%s: %s %s" % (
    ...         remote_bug,
    ...         weird_bugzilla.getRemoteStatus(remote_bug),
    ...         weird_bugzilla.getRemoteImportance(remote_bug))
    2000: ASSIGNED HIGH BLOCKER
    123543: RESOLVED FIXED HIGH BLOCKER


Broken Bugzillas
----------------

What does /not/ work as expected is parsing Bugzillas which produce
invalid XML:

    >>> from lp.bugs.tests.externalbugtracker import (
    ...     TestBrokenBugzilla)
    >>> broken_bugzilla = TestBrokenBugzilla(mozilla_bugzilla.baseurl)
    >>> broken_bugzilla._probe_version()
    (2, 20)
    >>> "</foobar>" in broken_bugzilla._readBugItemFile()
    True

    >>> remote_bugs = ['42', '2000']
    >>> broken_bugzilla.initializeRemoteBugDB(remote_bugs)
    Traceback (most recent call last):
    ...
    UnparsableBugData: Failed to parse XML description...

However, embedded control characters do not generate errors.

    >>> from lp.bugs.tests.externalbugtracker import (
    ...     AnotherBrokenBugzilla)
    >>> broken_bugzilla = AnotherBrokenBugzilla(mozilla_bugzilla.baseurl)
    >>> r"NOT\x01USED" in repr(broken_bugzilla._readBugItemFile())
    True

    >>> remote_bugs = ['42', '2000']
    >>> broken_bugzilla.initializeRemoteBugDB(remote_bugs) # no exception