~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
151
152
153
154
155
156
157
158
159
160
161
= Bug Links =

Questions can be linked to bugs. A user should do that when the problem
exposed in the question is related to a bug report.

== Adding Links ==

Question #2 in firefox is about a user which has trouble displaying the
SVG demo on the W3C site. There is an existing Launchpad bug report (#1)
which describes that problem. A user that wants to document that
relationship goes to the question and click the 'Link Existing Bug'.

This link is only available to registered user:

    >>> anon_browser.open(
    ...     'http://launchpad.dev/firefox/+question/2')
    >>> anon_browser.getLink(url='+linkbug').click()
    Traceback (most recent call last):
      ...
    Unauthorized: ...

    >>> user_browser.open(
    ...     'http://launchpad.dev/firefox/+question/2')
    >>> user_browser.getLink('Link existing bug').click()

To link the bug, the user enters the bug ID and clicks the 'Add'
button.

    >>> user_browser.getControl('Bug ID').value = '111'
    >>> user_browser.getControl('Link').click()

When the user makes a mistake and uses an invalid bug number, an error
message is displayed:

    >>> soup = find_main_content(user_browser.contents)
    >>> soup.first('div', 'message')
    <div class="message">Not a valid bug number or nickname.</div>

The user is offered a link to search for bug in case he doesn't know the
bug number.

    >>> user_browser.getLink('Bug listing').click()
    >>> user_browser.url
    '.../firefox/+bugs'

    >>> user_browser.goBack(1)

The user now enters the correct bug number and after clicking the
'Link' button, the bug will now be listed under the 'Related bugs'
portlet:

    >>> user_browser.getControl('Bug ID').value = '1'
    >>> user_browser.getControl('Link').click()
    >>> print extract_text(
    ...     find_tag_by_id(user_browser.contents, 'related-bugs'))
    Related bugs
    Bug #1: Firefox does not support SVG

A notification is also displayed.

    >>> for message in get_feedback_messages(user_browser.contents):
    ...     print message
    Added link to bug #1: ...Firefox does not support SVG...


== Removing Links ==

To remove bug links, the user uses the 'Remove Bug Link' action.

    >>> user_browser.getLink('Remove bug link').click()
    >>> print user_browser.title
    Remove links to bug reports : Question #...

The list of linked bugs is displayed. The user selects the link to
remove and clicks the 'Remove' button.

    >>> user_browser.getControl('#1: Firefox').selected = True
    >>> user_browser.getControl('Remove').click()

The user is redirected to the question page and a confirmation
message is displayed:

    >>> user_browser.url
    '.../firefox/+question/2'
    >>> soup = find_main_content(user_browser.contents)
    >>> soup.first('div', 'informational message')
    <div class="informational message">Removed link to bug #...</div>
    >>> print extract_text(
    ...     find_tag_by_id(user_browser.contents, 'related-bugs'))
    Related bugs


== Link to Private Bugs ==

    # Let's mark bug #6 as private and only accessible by an
    # administrator.
    # XXX flacoste 2006-08-22 bug=57307:
    # This should use a private bug in our sample data.
    >>> from zope.component import getUtility
    >>> from lp.testing import login, logout
    >>> from lp.services.database.sqlbase import flush_database_updates
    >>> from lp.services.webapp.interfaces import ILaunchBag
    >>> from lp.bugs.interfaces.bug import IBugSet
    >>> login('foo.bar@canonical.com')
    >>> private_bug = getUtility(IBugSet).get(6)
    >>> private_bug.setPrivate(True, getUtility(ILaunchBag).user)
    True
    >>> flush_database_updates()
    >>> logout()

A regular user shouldn't be able to link to a private bug he doesn't
have access to:

    # We use the no-priv user here because sample person is subscribed
    # and thus has access to the private bug.
    >>> browser.addHeader('Authorization', 'Basic no-priv@canonical.com:test')
    >>> browser.open('http://launchpad.dev/firefox/+question/2')
    >>> browser.getLink('Link existing bug').click()
    >>> browser.getControl('Bug ID').value = '6'
    >>> browser.getControl('Link').click()
    >>> for tag in find_tags_by_class(browser.contents, 'message'):
    ...     print tag.renderContents()
    There is 1 error.
    You are not allowed to link to private bug #6.

An administrator (or another user having access to the bug) should be
able to link to that bug.

    >>> admin_browser.open(
    ...     'http://launchpad.dev/firefox/+question/2')
    >>> admin_browser.getLink('Link existing bug').click()
    >>> admin_browser.getControl('Bug ID').value = '6'
    >>> admin_browser.getControl('Link').click()
    >>> print extract_text(
    ...     find_tag_by_id(admin_browser.contents, 'related-bugs'))
    Related bugs
    Bug #6: Firefox crashes when Save As dialog for a nonexistent window
    is closed

An anonymous visitor (or a user that doesn't have access to the bug) sees
nothing.

    >>> anon_browser.open(
    ...     'http://launchpad.dev/firefox/+question/2')
    >>> print extract_text(
    ...     find_tag_by_id(anon_browser.contents, 'related-bugs'))
    Related bugs

Only the administrator will be able to unlink the bug.

    >>> browser.open('http://launchpad.dev/firefox/+question/2')
    >>> browser.getLink('Remove bug link').click()
    >>> soup = find_main_content(browser.contents)
    >>> for message in get_feedback_messages(browser.contents):
    ...     print message
    There are no links that you are allowed to remove.

    >>> admin_browser.getLink('Remove bug link').click()
    >>> admin_browser.getControl('#6: Firefox').selected = True
    >>> admin_browser.getControl('Remove').click()