8687.15.11
by Karl Fogel
Add the copyright header block to files under lib/lp/answers/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
3 |
|
3691.398.12
by Francis J. Lacoste
Rename test files. |
4 |
"""Test the question workflow methods.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
5 |
|
3691.398.12
by Francis J. Lacoste
Rename test files. |
6 |
Comprehensive tests for the question workflow methods. A narrative kind of
|
7 |
documentation is done in the ../../doc/answer-tracker-workflow.txt Doctest,
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
8 |
but testing all the possible transitions makes the documentation more heavy
|
9 |
than necessary. This is tested here.
|
|
10 |
"""
|
|
11 |
||
12 |
__metaclass__ = type |
|
13 |
||
14 |
__all__ = [] |
|
15 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
16 |
from datetime import ( |
17 |
datetime, |
|
18 |
timedelta, |
|
19 |
)
|
|
20 |
import traceback |
|
21 |
import unittest |
|
22 |
||
23 |
from lazr.lifecycle.interfaces import ( |
|
24 |
IObjectCreatedEvent, |
|
25 |
IObjectModifiedEvent, |
|
26 |
)
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
27 |
from pytz import UTC |
28 |
from zope.component import getUtility |
|
29 |
from zope.interface.verify import verifyObject |
|
30 |
from zope.security.interfaces import Unauthorized |
|
4319.2.62
by Francis J. Lacoste
Work-around to the fact it's not posisble to call linkFAQ() multiple time with the same FAQ. |
31 |
from zope.security.proxy import removeSecurityProxy |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
32 |
|
12915.5.1
by Curtis Hovey
Rename questionenums.py to the new standard or enums.py |
33 |
from lp.answers.enums import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
34 |
QuestionAction, |
35 |
QuestionStatus, |
|
36 |
)
|
|
13099.1.7
by Curtis Hovey
Moved InvalidQuestionStateError to the errors module. |
37 |
from lp.answers.errors import ( |
38 |
InvalidQuestionStateError, |
|
39 |
NotQuestionOwnerError, |
|
40 |
)
|
|
14550.1.1
by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad |
41 |
from lp.answers.interfaces.question import IQuestion |
10409.5.55
by Curtis Hovey
Removed glob imports from answers. |
42 |
from lp.answers.interfaces.questionmessage import IQuestionMessage |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
43 |
from lp.registry.interfaces.distribution import IDistributionSet |
44 |
from lp.registry.interfaces.person import ( |
|
45 |
IPerson, |
|
46 |
IPersonSet, |
|
47 |
)
|
|
14606.4.7
by William Grant
canonical.lazr.testing.event -> lp.testing.event. |
48 |
from lp.services.webapp.authorization import clear_cache |
49 |
from lp.services.webapp.interfaces import ILaunchBag |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
50 |
from lp.services.worlddata.interfaces.language import ILanguageSet |
14606.4.7
by William Grant
canonical.lazr.testing.event -> lp.testing.event. |
51 |
from lp.testing import ( |
52 |
ANONYMOUS, |
|
53 |
login, |
|
54 |
login_person, |
|
55 |
)
|
|
56 |
from lp.testing.event import TestEventListener |
|
57 |
from lp.testing.layers import DatabaseFunctionalLayer |
|
3691.197.17
by Francis J. Lacoste
Use layer instead of inheriting from LaunchpadFunctionalTestCase |
58 |
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
59 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
60 |
class BaseAnswerTrackerWorkflowTestCase(unittest.TestCase): |
61 |
"""Base class for test cases related to the Answer Tracker workflow.
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
62 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
63 |
It provides the common fixture and test helper methods.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
64 |
"""
|
65 |
||
7944.3.10
by Francis J. Lacoste
Use DatabaseFunctionalLayer |
66 |
layer = DatabaseFunctionalLayer |
3691.197.17
by Francis J. Lacoste
Use layer instead of inheriting from LaunchpadFunctionalTestCase |
67 |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
68 |
def setUp(self): |
69 |
self.now = datetime.now(UTC) |
|
70 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
71 |
# Login as the question owner.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
72 |
login('no-priv@canonical.com') |
73 |
||
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
74 |
# Set up actors.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
75 |
personset = getUtility(IPersonSet) |
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
76 |
# User who submits request.
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
77 |
self.owner = personset.getByEmail('no-priv@canonical.com') |
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
78 |
# User who answers request.
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
79 |
self.answerer = personset.getByEmail('test@canonical.com') |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
80 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
81 |
# Admin user which can change question status.
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
82 |
self.admin = personset.getByEmail('foo.bar@canonical.com') |
3691.197.16
by Francis J. Lacoste
- Add setStatus() and addComment() methods. |
83 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
84 |
# Simple ubuntu question.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
85 |
self.ubuntu = getUtility(IDistributionSet).getByName('ubuntu') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
86 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
87 |
self.question = self.ubuntu.newQuestion( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
88 |
self.owner, 'Help!', 'I need help with Ubuntu', |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
89 |
datecreated=self.now) |
90 |
||
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
91 |
def tearDown(self): |
92 |
if hasattr(self, 'created_event_listener'): |
|
93 |
self.created_event_listener.unregister() |
|
94 |
self.modified_event_listener.unregister() |
|
95 |
||
7161.1.13
by Gary Poster
make lint happier, if not happy. |
96 |
def setQuestionStatus(self, question, new_status, |
97 |
comment="Status change."): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
98 |
"""Utility metho to change a question status.
|
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
99 |
|
100 |
This logs in as admin, change the status and log back as
|
|
101 |
the previous user.
|
|
102 |
"""
|
|
103 |
old_user = getUtility(ILaunchBag).user |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
104 |
login_person(self.admin) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
105 |
question.setStatus(self.admin, new_status, comment) |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
106 |
login_person(old_user) |
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
107 |
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
108 |
def setUpEventListeners(self): |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
109 |
"""Install a listener for events emitted during the test."""
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
110 |
self.collected_events = [] |
111 |
if hasattr(self, 'modified_event_listener'): |
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
112 |
# Event listeners is already registered.
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
113 |
return
|
114 |
self.modified_event_listener = TestEventListener( |
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
115 |
IQuestion, IObjectModifiedEvent, self.collectEvent) |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
116 |
self.created_event_listener = TestEventListener( |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
117 |
IQuestionMessage, IObjectCreatedEvent, self.collectEvent) |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
118 |
|
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
119 |
def collectEvent(self, object, event): |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
120 |
"""Collect events"""
|
121 |
self.collected_events.append(event) |
|
122 |
||
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
123 |
def nowPlus(self, n_hours): |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
124 |
"""Return a DateTime a number of hours in the future."""
|
125 |
return self.now + timedelta(hours=n_hours) |
|
126 |
||
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
127 |
def _testTransitionGuard(self, guard_name, statuses_expected_true): |
128 |
"""Helper for transition guard tests.
|
|
129 |
||
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
130 |
Helper that verifies that the Question guard_name attribute
|
10409.5.55
by Curtis Hovey
Removed glob imports from answers. |
131 |
is True when the question status is one listed in
|
132 |
statuses_expected_true and False otherwise.
|
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
133 |
"""
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
134 |
for status in QuestionStatus.items: |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
135 |
if status != self.question.status: |
136 |
self.setQuestionStatus(self.question, status) |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
137 |
expected = status.name in statuses_expected_true |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
138 |
allowed = getattr(self.question, guard_name) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
139 |
self.failUnless( |
140 |
expected == allowed, "%s != %s when status = %s" % ( |
|
141 |
guard_name, expected, status.name)) |
|
142 |
||
143 |
def _testValidTransition(self, statuses, transition_method, |
|
144 |
expected_owner, expected_action, expected_status, |
|
145 |
extra_message_check=None, |
|
146 |
transition_method_args=(), |
|
147 |
transition_method_kwargs=None, |
|
148 |
edited_fields=None): |
|
149 |
"""Helper for testing valid state transitions.
|
|
150 |
||
151 |
Helper that verifies that transition_method can be called when
|
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
152 |
the question status is one listed in statuses. It will validate the
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
153 |
returned message using checkTransitionMessage(). The transition_method
|
154 |
is called with the transition_method_args as positional parameters
|
|
155 |
and transition_method_kwargs as keyword parameters.
|
|
156 |
||
157 |
If extra_message_check is passed a function, it will be called with
|
|
158 |
the returned message for extra checks.
|
|
159 |
||
160 |
The datecreated parameter to the transition_method is set
|
|
161 |
automatically to a value that will make the message sort last.
|
|
162 |
||
163 |
The edited_fields parameter contain the list of field that
|
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
164 |
are expected to be present in IObjectModifiedEvent that should
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
165 |
be triggered.
|
166 |
"""
|
|
167 |
self.setUpEventListeners() |
|
7161.1.13
by Gary Poster
make lint happier, if not happy. |
168 |
count = 0 |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
169 |
if transition_method_kwargs is None: |
170 |
transition_method_kwargs = {} |
|
171 |
if 'datecreated' not in transition_method_kwargs: |
|
172 |
transition_method_kwargs['datecreated'] = self.nowPlus(0) |
|
173 |
for status in statuses: |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
174 |
if status != self.question.status: |
175 |
self.setQuestionStatus(self.question, status) |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
176 |
|
177 |
self.collected_events = [] |
|
178 |
||
4319.2.62
by Francis J. Lacoste
Work-around to the fact it's not posisble to call linkFAQ() multiple time with the same FAQ. |
179 |
# Make sure that there are no FAQ linked.
|
180 |
removeSecurityProxy(self.question).faq = None |
|
181 |
||
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
182 |
# Ensure ordering of the message.
|
183 |
transition_method_kwargs['datecreated'] = ( |
|
184 |
transition_method_kwargs['datecreated'] + timedelta(hours=1)) |
|
185 |
message = transition_method(*transition_method_args, |
|
186 |
**transition_method_kwargs) |
|
187 |
try: |
|
188 |
self.checkTransitionMessage( |
|
189 |
message, expected_owner=expected_owner, |
|
190 |
expected_action=expected_action, |
|
191 |
expected_status=expected_status) |
|
192 |
if extra_message_check: |
|
193 |
extra_message_check(message) |
|
194 |
except AssertionError: |
|
195 |
# We capture and re-raise the error here to display a nice
|
|
196 |
# message explaining in which state the transition failed.
|
|
197 |
raise AssertionError( |
|
198 |
"Failure in validating message when status=%s:\n%s" % ( |
|
199 |
status.name, traceback.format_exc(1))) |
|
200 |
self.checkTransitionEvents( |
|
201 |
message, edited_fields, status_name=status.name) |
|
202 |
count += 1 |
|
203 |
||
204 |
def _testInvalidTransition(self, valid_statuses, transition_method, |
|
205 |
*args, **kwargs): |
|
206 |
"""Helper for testing invalid transitions.
|
|
207 |
||
208 |
Helper that verifies that transition_method method cannot be
|
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
209 |
called when the question status is different than the ones in
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
210 |
valid_statuses.
|
211 |
||
212 |
args and kwargs contains the parameters that should be passed to the
|
|
213 |
transition method.
|
|
214 |
"""
|
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
215 |
for status in QuestionStatus.items: |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
216 |
if status.name in valid_statuses: |
217 |
continue
|
|
218 |
exceptionRaised = False |
|
219 |
try: |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
220 |
if status != self.question.status: |
221 |
self.setQuestionStatus(self.question, status) |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
222 |
transition_method(*args, **kwargs) |
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
223 |
except InvalidQuestionStateError: |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
224 |
exceptionRaised = True |
225 |
self.failUnless(exceptionRaised, |
|
226 |
"%s() when status = %s should raise an error" % ( |
|
227 |
transition_method.__name__, status.name)) |
|
228 |
||
229 |
def checkTransitionMessage(self, message, expected_owner, |
|
230 |
expected_action, expected_status): |
|
231 |
"""Helper method to check the message created by a transition.
|
|
232 |
||
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
233 |
It make sure that the message provides IQuestionMessage and that it
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
234 |
was appended to the question messages attribute. It also checks that
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
235 |
the subject was computed correctly and that the new_status, action
|
236 |
and owner attributes were set correctly.
|
|
237 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
238 |
It also verifies that the question status, datelastquery (or
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
239 |
datelastresponse) were updated to reflect the time of the message.
|
240 |
"""
|
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
241 |
self.failUnless(verifyObject(IQuestionMessage, message)) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
242 |
|
243 |
self.assertEquals("Re: Help!", message.subject) |
|
244 |
self.assertEquals(expected_owner, message.owner) |
|
245 |
self.assertEquals(expected_action, message.action) |
|
246 |
self.assertEquals(expected_status, message.new_status) |
|
247 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
248 |
self.assertEquals(message, self.question.messages[-1]) |
249 |
self.assertEquals(expected_status, self.question.status) |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
250 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
251 |
if expected_owner == self.question.owner: |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
252 |
self.assertEquals(message.datecreated, |
253 |
self.question.datelastquery) |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
254 |
else: |
255 |
self.assertEquals( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
256 |
message.datecreated, self.question.datelastresponse) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
257 |
|
258 |
def checkTransitionEvents(self, message, edited_fields, status_name): |
|
259 |
"""Helper method to validate the events triggered from the transition.
|
|
260 |
||
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
261 |
Check that an IObjectCreatedEvent event was sent when the message
|
262 |
was created and that an IObjectModifiedEvent was also sent.
|
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
263 |
The event object and edited_fields attribute are checked.
|
264 |
"""
|
|
11235.5.4
by Curtis Hovey
hush lint. |
265 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
266 |
def failure_msg(msg): |
267 |
return "From status %s: %s" % (status_name, msg) |
|
11235.5.4
by Curtis Hovey
hush lint. |
268 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
269 |
self.failUnless( |
270 |
len(self.collected_events) >= 1, |
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
271 |
failure_msg('failed to trigger an IObjectCreatedEvent')) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
272 |
created_event = self.collected_events[0] |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
273 |
created_event_user = IPerson(created_event.user) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
274 |
self.failUnless( |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
275 |
IObjectCreatedEvent.providedBy(created_event), |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
276 |
failure_msg( |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
277 |
"%s doesn't provide IObjectCreatedEvent" % created_event)) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
278 |
self.failUnless( |
279 |
created_event.object == message, |
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
280 |
failure_msg("IObjectCreatedEvent contains wrong message")) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
281 |
self.failUnless( |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
282 |
created_event_user == message.owner, |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
283 |
failure_msg("%s != %s" % ( |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
284 |
created_event_user.displayname, message.owner.displayname))) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
285 |
|
286 |
self.failUnless( |
|
287 |
len(self.collected_events) == 2, |
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
288 |
failure_msg('failed to trigger an IObjectModifiedEvent')) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
289 |
modified_event = self.collected_events[1] |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
290 |
modified_event_user = IPerson(modified_event.user) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
291 |
self.failUnless( |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
292 |
IObjectModifiedEvent.providedBy(modified_event), |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
293 |
failure_msg( |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
294 |
"%s doesn't provide IObjectModifiedEvent" |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
295 |
% modified_event)) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
296 |
self.failUnless( |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
297 |
modified_event.object == self.question, |
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
298 |
failure_msg("IObjectModifiedEvent contains wrong question")) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
299 |
self.failUnless( |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
300 |
modified_event_user == message.owner, |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
301 |
failure_msg("%s != %s" % ( |
7876.3.12
by Francis J. Lacoste
Event.user is a principal, so we need an IPerson case. |
302 |
modified_event_user.displayname, message.owner.displayname))) |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
303 |
if edited_fields: |
304 |
self.failUnless( |
|
305 |
set(modified_event.edited_fields) == set(edited_fields), |
|
306 |
failure_msg("%s != %s" % ( |
|
307 |
set(modified_event.edited_fields), set(edited_fields)))) |
|
308 |
||
309 |
||
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
310 |
class MiscAnswerTrackerWorkflowTestCase(BaseAnswerTrackerWorkflowTestCase): |
311 |
"""Various other test cases for the Answer Tracker workflow."""
|
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
312 |
|
313 |
def testDisallowNoOpSetStatus(self): |
|
314 |
"""Test that calling setStatus to change to the same status
|
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
315 |
raises an InvalidQuestionStateError.
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
316 |
"""
|
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
317 |
login('foo.bar@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
318 |
self.assertRaises(InvalidQuestionStateError, self.question.setStatus, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
319 |
self.admin, QuestionStatus.OPEN, 'Status Change') |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
320 |
|
321 |
||
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
322 |
class RequestInfoTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
323 |
"""Test cases for the requestInfo() workflow action method."""
|
324 |
||
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
325 |
def test_can_request_info(self): |
326 |
"""Test the can_request_info attribute in all the possible states."""
|
|
327 |
self._testTransitionGuard( |
|
328 |
'can_request_info', ['OPEN', 'NEEDSINFO', 'ANSWERED']) |
|
329 |
||
330 |
def test_requestInfo(self): |
|
331 |
"""Test that requestInfo() can be called in the OPEN, NEEDSINFO,
|
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
332 |
and ANSWERED state and that it returns a valid IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
333 |
"""
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
334 |
# Do no check the edited_fields attribute since it varies depending
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
335 |
# on the departure state.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
336 |
self._testValidTransition( |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
337 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO], |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
338 |
expected_owner=self.answerer, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
339 |
expected_action=QuestionAction.REQUESTINFO, |
340 |
expected_status=QuestionStatus.NEEDSINFO, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
341 |
transition_method=self.question.requestInfo, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
342 |
transition_method_args=( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
343 |
self.answerer, "What's your problem?"), |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
344 |
edited_fields=None) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
345 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
346 |
# Even if the question is answered, a user can request more
|
347 |
# information, but that leave the question in the ANSWERED state.
|
|
348 |
self.setQuestionStatus(self.question, QuestionStatus.ANSWERED) |
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
349 |
self.collected_events = [] |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
350 |
message = self.question.requestInfo( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
351 |
self.answerer, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
352 |
"The previous answer is bad. What is the problem again?", |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
353 |
datecreated=self.nowPlus(3)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
354 |
self.checkTransitionMessage( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
355 |
message, expected_owner=self.answerer, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
356 |
expected_action=QuestionAction.REQUESTINFO, |
357 |
expected_status=QuestionStatus.ANSWERED) |
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
358 |
self.checkTransitionEvents( |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
359 |
message, ['messages', 'datelastresponse'], |
360 |
QuestionStatus.OPEN.title) |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
361 |
|
362 |
def test_requestInfoFromOwnerIsInvalid(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
363 |
"""Test that the question owner cannot use requestInfo."""
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
364 |
self.assertRaises( |
13099.1.3
by Curtis Hovey
Updated Question to use new error types. |
365 |
NotQuestionOwnerError, self.question.requestInfo, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
366 |
self.owner, 'Why should I care?', datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
367 |
|
368 |
def test_requestInfoFromInvalidStates(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
369 |
"""Test that requestInfo cannot be called when the question status is
|
3691.197.52
by Francis J. Lacoste
Typos, grammar and other cleanup |
370 |
not OPEN, NEEDSINFO, or ANSWERED.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
371 |
"""
|
372 |
self._testInvalidTransition( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
373 |
['OPEN', 'NEEDSINFO', 'ANSWERED'], self.question.requestInfo, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
374 |
self.answerer, "What's up?", datecreated=self.nowPlus(3)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
375 |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
376 |
def test_requestInfoPermission(self): |
377 |
"""Test that only a logged in user can access requestInfo()."""
|
|
378 |
login(ANONYMOUS) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
379 |
self.assertRaises(Unauthorized, getattr, self.question, 'requestInfo') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
380 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
381 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
382 |
getattr(self.question, 'requestInfo') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
383 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
384 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
385 |
class GiveInfoTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
386 |
"""Test cases for the giveInfo() workflow action method."""
|
387 |
||
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
388 |
def test_can_give_info(self): |
389 |
"""Test the can_give_info attribute in all the possible states."""
|
|
390 |
self._testTransitionGuard('can_give_info', ['OPEN', 'NEEDSINFO']) |
|
391 |
||
392 |
def test_giveInfoFromInvalidStates(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
393 |
"""Test that giveInfo cannot be called when the question status is
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
394 |
not OPEN or NEEDSINFO.
|
395 |
"""
|
|
396 |
self._testInvalidTransition( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
397 |
['OPEN', 'NEEDSINFO'], self.question.giveInfo, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
398 |
"That's that.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
399 |
|
400 |
def test_giveInfo(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
401 |
"""Test that giveInfo() can be called when the question status is
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
402 |
OPEN or NEEDSINFO and that it returns a valid IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
403 |
"""
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
404 |
# Do not check the edited_fields attributes since it
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
405 |
# changes based on departure state.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
406 |
self._testValidTransition( |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
407 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO], |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
408 |
expected_owner=self.owner, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
409 |
expected_action=QuestionAction.GIVEINFO, |
410 |
expected_status=QuestionStatus.OPEN, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
411 |
transition_method=self.question.giveInfo, |
11235.5.4
by Curtis Hovey
hush lint. |
412 |
transition_method_args=("That's that.", ), |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
413 |
edited_fields=None) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
414 |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
415 |
def test_giveInfoPermission(self): |
416 |
"""Test that only the owner can access giveInfo()."""
|
|
417 |
login(ANONYMOUS) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
418 |
self.assertRaises(Unauthorized, getattr, self.question, 'giveInfo') |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
419 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
420 |
self.assertRaises(Unauthorized, getattr, self.question, 'giveInfo') |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
421 |
login_person(self.admin) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
422 |
self.assertRaises(Unauthorized, getattr, self.question, 'giveInfo') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
423 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
424 |
login_person(self.owner) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
425 |
getattr(self.question, 'giveInfo') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
426 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
427 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
428 |
class GiveAnswerTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
429 |
"""Test cases for the giveAnswer() workflow action method."""
|
430 |
||
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
431 |
def test_can_give_answer(self): |
432 |
"""Test the can_give_answer attribute in all the possible states."""
|
|
433 |
self._testTransitionGuard( |
|
434 |
'can_give_answer', ['OPEN', 'NEEDSINFO', 'ANSWERED']) |
|
435 |
||
436 |
def test_giveAnswerFromInvalidStates(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
437 |
"""Test that giveAnswer cannot be called when the question status is
|
3691.197.52
by Francis J. Lacoste
Typos, grammar and other cleanup |
438 |
not OPEN, NEEDSINFO, or ANSWERED.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
439 |
"""
|
440 |
self._testInvalidTransition( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
441 |
['OPEN', 'NEEDSINFO', 'ANSWERED'], self.question.giveAnswer, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
442 |
self.answerer, "The answer is this.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
443 |
|
4471.5.12
by Curtis Hovey
Renamed method. |
444 |
def test_giveAnswerByAnswerer(self): |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
445 |
"""Test that giveAnswer can be called when the question status is
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
446 |
one of OPEN, NEEDSINFO or ANSWERED and check that it returns a
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
447 |
valid IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
448 |
"""
|
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
449 |
# Do not check the edited_fields attributes since it
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
450 |
# changes based on departure state.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
451 |
self._testValidTransition( |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
452 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
453 |
QuestionStatus.ANSWERED], |
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
454 |
expected_owner=self.answerer, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
455 |
expected_action=QuestionAction.ANSWER, |
456 |
expected_status=QuestionStatus.ANSWERED, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
457 |
transition_method=self.question.giveAnswer, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
458 |
transition_method_args=( |
11235.5.4
by Curtis Hovey
hush lint. |
459 |
self.answerer, "It looks like a real problem.", ), |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
460 |
edited_fields=None) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
461 |
|
4471.5.10
by Curtis Hovey
Added a separate test for giveAnswerByOwner. Everything works, but a review is still needed. |
462 |
def test_giveAnswerByOwner(self): |
463 |
"""Test giveAnswerByOwner().
|
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
464 |
|
4471.5.10
by Curtis Hovey
Added a separate test for giveAnswerByOwner. Everything works, but a review is still needed. |
465 |
Test that giveAnswer can be called by the questions owner when the
|
466 |
question status is one of OPEN, NEEDSINFO or ANSWERED and check
|
|
467 |
that it returns a valid IQuestionMessage.
|
|
468 |
"""
|
|
469 |
# Do not check the edited_fields attributes since it
|
|
470 |
# changes based on departure state.
|
|
471 |
self._testValidTransition( |
|
472 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
|
473 |
QuestionStatus.ANSWERED], |
|
474 |
expected_owner=self.answerer, |
|
475 |
expected_action=QuestionAction.ANSWER, |
|
476 |
expected_status=QuestionStatus.ANSWERED, |
|
477 |
transition_method=self.question.giveAnswer, |
|
478 |
transition_method_args=( |
|
11235.5.4
by Curtis Hovey
hush lint. |
479 |
self.answerer, "It looks like a real problem.", ), |
4471.5.10
by Curtis Hovey
Added a separate test for giveAnswerByOwner. Everything works, but a review is still needed. |
480 |
edited_fields=None) |
481 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
482 |
# When the owner gives the answer, the question moves straight to
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
483 |
# SOLVED.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
484 |
def checkAnswerMessage(message): |
3691.197.52
by Francis J. Lacoste
Typos, grammar and other cleanup |
485 |
"""Check additional attributes set when the owner gives the
|
486 |
answers.
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
487 |
"""
|
4471.5.10
by Curtis Hovey
Added a separate test for giveAnswerByOwner. Everything works, but a review is still needed. |
488 |
self.assertEquals(None, self.question.answer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
489 |
self.assertEquals(self.owner, self.question.answerer) |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
490 |
self.assertEquals(message.datecreated, self.question.date_solved) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
491 |
|
492 |
self._testValidTransition( |
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
493 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
494 |
QuestionStatus.ANSWERED], |
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
495 |
expected_owner=self.owner, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
496 |
expected_action=QuestionAction.CONFIRM, |
497 |
expected_status=QuestionStatus.SOLVED, |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
498 |
extra_message_check=checkAnswerMessage, |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
499 |
transition_method=self.question.giveAnswer, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
500 |
transition_method_args=( |
11235.5.4
by Curtis Hovey
hush lint. |
501 |
self.owner, "I found the solution.", ), |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
502 |
transition_method_kwargs={'datecreated': self.nowPlus(3)}, |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
503 |
edited_fields=['status', 'messages', 'date_solved', 'answerer', |
4471.5.8
by Curtis Hovey
Revision per review. More work is needed in test_question_workflow.py. |
504 |
'datelastquery']) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
505 |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
506 |
def test_giveAnswerPermission(self): |
507 |
"""Test that only a logged in user can access giveAnswer()."""
|
|
508 |
login(ANONYMOUS) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
509 |
self.assertRaises(Unauthorized, getattr, self.question, 'giveAnswer') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
510 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
511 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
512 |
getattr(self.question, 'giveAnswer') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
513 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
514 |
|
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
515 |
class LinkFAQTestCase(BaseAnswerTrackerWorkflowTestCase): |
516 |
"""Test cases for the giveAnswer() workflow action method."""
|
|
517 |
||
518 |
def setUp(self): |
|
519 |
"""Create an additional FAQ."""
|
|
520 |
BaseAnswerTrackerWorkflowTestCase.setUp(self) |
|
521 |
||
522 |
# Only admin can create FAQ on ubuntu.
|
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
523 |
login_person(self.admin) |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
524 |
self.faq = self.ubuntu.newFAQ( |
4319.3.6
by Francis J. Lacoste
Merge faqbase-db: remove url and summary field. |
525 |
self.admin, 'Generic HowTo', 'Describe how to do anything.') |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
526 |
|
4319.3.3
by Francis J. Lacoste
Fixes spelling mistakes and other clarifications. |
527 |
# Logs in as owner.
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
528 |
login_person(self.owner) |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
529 |
|
530 |
def test_linkFAQ(self): |
|
531 |
"""Test that linkFAQ can be called when the question status is
|
|
532 |
one of OPEN, NEEDSINFO or ANSWERED and check that it returns a
|
|
533 |
valid IQuestionMessage.
|
|
534 |
"""
|
|
535 |
# Do not check the edited_fields attributes since it
|
|
536 |
# changes based on departure state.
|
|
537 |
def checkFAQ(message): |
|
538 |
"""Check that the FAQ attribute was set correctly."""
|
|
539 |
self.assertEquals(self.question.faq, self.faq) |
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
540 |
|
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
541 |
self._testValidTransition( |
542 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
|
543 |
QuestionStatus.ANSWERED], |
|
544 |
expected_owner=self.answerer, |
|
545 |
expected_action=QuestionAction.ANSWER, |
|
546 |
expected_status=QuestionStatus.ANSWERED, |
|
547 |
extra_message_check=checkFAQ, |
|
548 |
transition_method=self.question.linkFAQ, |
|
549 |
transition_method_args=( |
|
11235.5.4
by Curtis Hovey
hush lint. |
550 |
self.answerer, self.faq, "Check the FAQ!", ), |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
551 |
edited_fields=None) |
552 |
||
553 |
# When the owner links the FAQ, the question moves straight to
|
|
554 |
# SOLVED.
|
|
555 |
def checkAnswerMessage(message): |
|
556 |
"""Check additional attributes set when the owner gives the
|
|
557 |
answers.
|
|
558 |
"""
|
|
559 |
checkFAQ(message) |
|
560 |
self.assertEquals(self.owner, self.question.answerer) |
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
561 |
self.assertEquals(message.datecreated, self.question.date_solved) |
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
562 |
|
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
563 |
self._testValidTransition( |
564 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
|
565 |
QuestionStatus.ANSWERED], |
|
566 |
expected_owner=self.owner, |
|
567 |
expected_action=QuestionAction.CONFIRM, |
|
568 |
expected_status=QuestionStatus.SOLVED, |
|
569 |
extra_message_check=checkAnswerMessage, |
|
570 |
transition_method=self.question.linkFAQ, |
|
571 |
transition_method_args=( |
|
11235.5.4
by Curtis Hovey
hush lint. |
572 |
self.owner, self.faq, "I found the solution in that FAQ.", ), |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
573 |
transition_method_kwargs={'datecreated': self.nowPlus(3)}, |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
574 |
edited_fields=['status', 'messages', 'date_solved', 'answerer', |
4319.3.28
by Francis J. Lacoste
linkFAQ by owner doesn't set answer anymore. |
575 |
'datelastquery']) |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
576 |
|
577 |
def test_linkFAQPermission(self): |
|
578 |
"""Test that only a logged in user can access linkFAQ()."""
|
|
579 |
login(ANONYMOUS) |
|
580 |
self.assertRaises(Unauthorized, getattr, self.question, 'linkFAQ') |
|
581 |
||
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
582 |
login_person(self.answerer) |
4319.2.9
by Francis J. Lacoste
Add linkFAQ() method to IQuestion and other related attributes. |
583 |
getattr(self.question, 'linkFAQ') |
584 |
||
585 |
||
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
586 |
class ConfirmAnswerTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
587 |
"""Test cases for the confirmAnswer() workflow action method."""
|
588 |
||
3691.197.67
by Francis J. Lacoste
Split two tests. |
589 |
def test_can_confirm_answer_without_answer(self): |
590 |
"""Test the can_confirm_answer attribute when no answer was posted.
|
|
591 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
592 |
When the question didn't receive an answer, it should always be
|
3691.197.67
by Francis J. Lacoste
Split two tests. |
593 |
false.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
594 |
"""
|
595 |
self._testTransitionGuard('can_confirm_answer', []) |
|
596 |
||
3691.197.67
by Francis J. Lacoste
Split two tests. |
597 |
def test_can_confirm_answer_with_answer(self): |
598 |
"""Test that can_confirm_answer when there is an answer present.
|
|
599 |
||
600 |
Once one answer was given, it becomes possible in some states.
|
|
601 |
"""
|
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
602 |
self.question.giveAnswer( |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
603 |
self.answerer, 'Do something about it.', self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
604 |
self._testTransitionGuard( |
4471.5.1
by Curtis Hovey
Revised workflow to allow the question own to set the question status to Solved without selecting an answser first. An Answer can be confirmed while in the solved state. |
605 |
'can_confirm_answer', |
606 |
['OPEN', 'NEEDSINFO', 'ANSWERED', 'GIVEINFO', 'SOLVED']) |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
607 |
|
3691.197.67
by Francis J. Lacoste
Split two tests. |
608 |
def test_confirmAnswerFromInvalidStates_without_answer(self): |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
609 |
"""Test calling confirmAnswer from invalid states.
|
610 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
611 |
confirmAnswer() cannot be called when the question has no message with
|
3691.197.67
by Francis J. Lacoste
Split two tests. |
612 |
action ANSWER.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
613 |
"""
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
614 |
self._testInvalidTransition([], self.question.confirmAnswer, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
615 |
"That answer worked!.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
616 |
|
3691.197.67
by Francis J. Lacoste
Split two tests. |
617 |
def test_confirmAnswerFromInvalidStates_with_answer(self): |
618 |
""" Test calling confirmAnswer from invalid states with an answer.
|
|
619 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
620 |
When the question has a message with action ANSWER, confirmAnswer()
|
3691.197.67
by Francis J. Lacoste
Split two tests. |
621 |
can only be called when it is in the OPEN, NEEDSINFO, or ANSWERED
|
622 |
state.
|
|
623 |
"""
|
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
624 |
answer_message = self.question.giveAnswer( |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
625 |
self.answerer, 'Do something about it.', self.nowPlus(1)) |
4471.5.9
by Curtis Hovey
Minor dafe changes. giveAnswer is not right. |
626 |
self._testInvalidTransition( |
627 |
['OPEN', 'NEEDSINFO', 'ANSWERED', 'SOLVED'], |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
628 |
self.question.confirmAnswer, "That answer worked!.", |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
629 |
answer=answer_message, datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
630 |
|
4471.5.13
by Curtis Hovey
renamed test_giveAnswer -> test_giveAnswerByOwner |
631 |
def test_confirmAnswerBeforeSOLVED(self): |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
632 |
"""Test confirmAnswer().
|
633 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
634 |
Test that confirmAnswer() can be called when the question status
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
635 |
is one of OPEN, NEEDSINFO, ANSWERED and that it has at least one
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
636 |
ANSWER message and check that it returns a valid IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
637 |
"""
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
638 |
answer_message = self.question.giveAnswer( |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
639 |
self.answerer, "Get a grip!", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
640 |
|
641 |
def checkAnswerMessage(message): |
|
3691.197.21
by Francis J. Lacoste
Include real location of the error. Fix problem with unordered message in confirmAnswer |
642 |
# Check the attributes that are set when an answer is confirmed.
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
643 |
self.assertEquals(answer_message, self.question.answer) |
644 |
self.assertEquals(self.answerer, self.question.answerer) |
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
645 |
self.assertEquals(message.datecreated, self.question.date_solved) |
3691.197.21
by Francis J. Lacoste
Include real location of the error. Fix problem with unordered message in confirmAnswer |
646 |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
647 |
self._testValidTransition( |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
648 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
649 |
QuestionStatus.ANSWERED], |
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
650 |
expected_owner=self.owner, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
651 |
expected_action=QuestionAction.CONFIRM, |
652 |
expected_status=QuestionStatus.SOLVED, |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
653 |
extra_message_check=checkAnswerMessage, |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
654 |
transition_method=self.question.confirmAnswer, |
11235.5.4
by Curtis Hovey
hush lint. |
655 |
transition_method_args=("That was very useful.", ), |
3691.197.21
by Francis J. Lacoste
Include real location of the error. Fix problem with unordered message in confirmAnswer |
656 |
transition_method_kwargs={'answer': answer_message, |
11235.5.4
by Curtis Hovey
hush lint. |
657 |
'datecreated': self.nowPlus(2)}, |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
658 |
edited_fields=['status', 'messages', 'date_solved', 'answerer', |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
659 |
'answer', 'datelastquery']) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
660 |
|
4471.5.13
by Curtis Hovey
renamed test_giveAnswer -> test_giveAnswerByOwner |
661 |
def test_confirmAnswerAfterSOLVED(self): |
662 |
"""Test confirmAnswer().
|
|
663 |
||
664 |
Test that confirmAnswer() can be called when the question status
|
|
665 |
is SOLVED, and that it has at least one ANSWER message and check
|
|
666 |
that it returns a valid IQuestionMessage.
|
|
667 |
"""
|
|
668 |
answer_message = self.question.giveAnswer( |
|
669 |
self.answerer, "Press the any key.", datecreated=self.nowPlus(1)) |
|
670 |
self.question.giveAnswer( |
|
671 |
self.owner, 'I solved my own problem.', |
|
672 |
datecreated=self.nowPlus(2)) |
|
673 |
self.assertEquals(self.question.status, QuestionStatus.SOLVED) |
|
674 |
||
675 |
def checkAnswerMessage(message): |
|
676 |
# Check the attributes that are set when an answer is confirmed.
|
|
677 |
self.assertEquals(answer_message, self.question.answer) |
|
678 |
self.assertEquals(self.answerer, self.question.answerer) |
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
679 |
self.assertEquals(message.datecreated, self.question.date_solved) |
4471.5.13
by Curtis Hovey
renamed test_giveAnswer -> test_giveAnswerByOwner |
680 |
|
681 |
self._testValidTransition( |
|
682 |
[QuestionStatus.SOLVED], |
|
683 |
expected_owner=self.owner, |
|
684 |
expected_action=QuestionAction.CONFIRM, |
|
685 |
expected_status=QuestionStatus.SOLVED, |
|
686 |
extra_message_check=checkAnswerMessage, |
|
687 |
transition_method=self.question.confirmAnswer, |
|
11235.5.4
by Curtis Hovey
hush lint. |
688 |
transition_method_args=("The space bar also works.", ), |
4471.5.13
by Curtis Hovey
renamed test_giveAnswer -> test_giveAnswerByOwner |
689 |
transition_method_kwargs={'answer': answer_message, |
11235.5.4
by Curtis Hovey
hush lint. |
690 |
'datecreated': self.nowPlus(2)}, |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
691 |
edited_fields=['messages', 'date_solved', 'answerer', |
4471.5.13
by Curtis Hovey
renamed test_giveAnswer -> test_giveAnswerByOwner |
692 |
'answer', 'datelastquery']) |
693 |
||
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
694 |
def testCannotConfirmAnAnswerFromAnotherQuestion(self): |
4471.5.9
by Curtis Hovey
Minor dafe changes. giveAnswer is not right. |
695 |
"""Test that you can't confirm an answer from a different question."""
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
696 |
question1_answer = self.question.giveAnswer( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
697 |
self.answerer, 'Really, just do it!') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
698 |
question2 = self.ubuntu.newQuestion(self.owner, 'Help 2', 'Help me!') |
12887.1.1
by Curtis Hovey
Ensure distribution answer contacts are also checked for dsp question targets. |
699 |
question2.giveAnswer(self.answerer, 'Do that!') |
3691.197.16
by Francis J. Lacoste
- Add setStatus() and addComment() methods. |
700 |
answerRefused = False |
701 |
try: |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
702 |
question2.confirmAnswer('That worked!', answer=question1_answer) |
3691.197.16
by Francis J. Lacoste
- Add setStatus() and addComment() methods. |
703 |
except AssertionError: |
704 |
answerRefused = True |
|
705 |
self.failUnless( |
|
706 |
answerRefused, 'confirmAnswer accepted a message from a different' |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
707 |
'question') |
3691.197.16
by Francis J. Lacoste
- Add setStatus() and addComment() methods. |
708 |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
709 |
def test_confirmAnswerPermission(self): |
710 |
"""Test that only the owner can access confirmAnswer()."""
|
|
711 |
login(ANONYMOUS) |
|
7161.1.13
by Gary Poster
make lint happier, if not happy. |
712 |
self.assertRaises( |
713 |
Unauthorized, getattr, self.question, 'confirmAnswer') |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
714 |
login_person(self.answerer) |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
715 |
self.assertRaises( |
716 |
Unauthorized, getattr, self.question, 'confirmAnswer') |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
717 |
login_person(self.admin) |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
718 |
self.assertRaises( |
719 |
Unauthorized, getattr, self.question, 'confirmAnswer') |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
720 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
721 |
login_person(self.owner) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
722 |
getattr(self.question, 'confirmAnswer') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
723 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
724 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
725 |
class ReopenTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
726 |
"""Test cases for the reopen() workflow action method."""
|
727 |
||
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
728 |
def test_can_reopen(self): |
729 |
"""Test the can_reopen attribute in all the possible states."""
|
|
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
730 |
self._testTransitionGuard( |
731 |
'can_reopen', ['ANSWERED', 'EXPIRED', 'SOLVED']) |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
732 |
|
733 |
def test_reopenFromInvalidStates(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
734 |
"""Test that reopen cannot be called when the question status is
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
735 |
not one of OPEN, NEEDSINFO, or ANSWERED.
|
736 |
"""
|
|
737 |
self._testInvalidTransition( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
738 |
['ANSWERED', 'EXPIRED', 'SOLVED'], self.question.reopen, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
739 |
"I still have a problem.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
740 |
|
741 |
def test_reopen(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
742 |
"""Test that reopen() can be called when the question is in the
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
743 |
ANSWERED and EXPIRED state and that it returns a valid
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
744 |
IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
745 |
"""
|
746 |
self._testValidTransition( |
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
747 |
[QuestionStatus.ANSWERED, QuestionStatus.EXPIRED], |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
748 |
expected_owner=self.owner, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
749 |
expected_action=QuestionAction.REOPEN, |
750 |
expected_status=QuestionStatus.OPEN, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
751 |
transition_method=self.question.reopen, |
11235.5.4
by Curtis Hovey
hush lint. |
752 |
transition_method_args=('I still have this problem.', ), |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
753 |
edited_fields=['status', 'messages', 'datelastquery']) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
754 |
|
4471.5.11
by Curtis Hovey
Renamed reopenFromSOLVED -> reopenFromSOLVEDByOwner, added reopenFromSOLVEDByAnswerer. |
755 |
def test_reopenFromSOLVEDByOwner(self): |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
756 |
"""Test that reopen() can be called when the question is in the
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
757 |
SOLVED state (by the question owner) and that it returns an
|
4471.5.11
by Curtis Hovey
Renamed reopenFromSOLVED -> reopenFromSOLVEDByOwner, added reopenFromSOLVEDByAnswerer. |
758 |
appropriate IQuestionMessage. This transition should also clear
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
759 |
the date_solved, answered and answerer attributes.
|
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
760 |
"""
|
761 |
self.setUpEventListeners() |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
762 |
# Mark the question as solved by the user.
|
763 |
self.question.giveAnswer( |
|
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
764 |
self.owner, 'I solved my own problem.', |
765 |
datecreated=self.nowPlus(0)) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
766 |
self.assertEquals(self.question.status, QuestionStatus.SOLVED) |
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
767 |
|
3691.197.65
by Francis J. Lacoste
Turn comments into sentence. |
768 |
# Clear previous events.
|
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
769 |
self.collected_events = [] |
770 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
771 |
message = self.question.reopen( |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
772 |
"My solution doesn't work.", datecreated=self.nowPlus(1)) |
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
773 |
self.checkTransitionMessage( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
774 |
message, expected_owner=self.owner, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
775 |
expected_action=QuestionAction.REOPEN, |
776 |
expected_status=QuestionStatus.OPEN) |
|
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
777 |
self.checkTransitionEvents( |
4471.5.8
by Curtis Hovey
Revision per review. More work is needed in test_question_workflow.py. |
778 |
message, ['status', 'messages', 'answerer', |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
779 |
'date_solved', 'datelastquery'], |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
780 |
QuestionStatus.OPEN.title) |
3691.197.32
by Francis J. Lacoste
Allow reopening a SOLVED ticket. |
781 |
|
4471.5.11
by Curtis Hovey
Renamed reopenFromSOLVED -> reopenFromSOLVEDByOwner, added reopenFromSOLVEDByAnswerer. |
782 |
def test_reopenFromSOLVEDByAnswerer(self): |
783 |
"""Test that reopen() can be called when the question is in the
|
|
784 |
SOLVED state (answer confirmed by the question owner) and that it
|
|
785 |
returns an appropriate IQuestionMessage. This transition should
|
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
786 |
also clear the date_solved, answered and answerer attributes.
|
4471.5.11
by Curtis Hovey
Renamed reopenFromSOLVED -> reopenFromSOLVEDByOwner, added reopenFromSOLVEDByAnswerer. |
787 |
"""
|
788 |
self.setUpEventListeners() |
|
789 |
# Mark the question as solved by the user.
|
|
790 |
answer_message = self.question.giveAnswer( |
|
791 |
self.answerer, 'Press the any key.', datecreated=self.nowPlus(0)) |
|
792 |
self.question.confirmAnswer("That answer worked!.", |
|
793 |
answer=answer_message, datecreated=self.nowPlus(1)) |
|
794 |
self.assertEquals(self.question.status, QuestionStatus.SOLVED) |
|
795 |
||
796 |
# Clear previous events.
|
|
797 |
self.collected_events = [] |
|
798 |
||
799 |
message = self.question.reopen( |
|
800 |
"Where is the any key?", datecreated=self.nowPlus(1)) |
|
801 |
self.checkTransitionMessage( |
|
802 |
message, expected_owner=self.owner, |
|
803 |
expected_action=QuestionAction.REOPEN, |
|
804 |
expected_status=QuestionStatus.OPEN) |
|
805 |
self.checkTransitionEvents( |
|
806 |
message, ['status', 'messages', 'answerer', 'answer', |
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
807 |
'date_solved'], |
4471.5.11
by Curtis Hovey
Renamed reopenFromSOLVED -> reopenFromSOLVEDByOwner, added reopenFromSOLVEDByAnswerer. |
808 |
QuestionStatus.OPEN.title) |
809 |
||
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
810 |
def test_reopenPermission(self): |
811 |
"""Test that only the owner can access reopen()."""
|
|
812 |
login(ANONYMOUS) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
813 |
self.assertRaises(Unauthorized, getattr, self.question, 'reopen') |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
814 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
815 |
self.assertRaises(Unauthorized, getattr, self.question, 'reopen') |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
816 |
login_person(self.admin) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
817 |
self.assertRaises(Unauthorized, getattr, self.question, 'reopen') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
818 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
819 |
login_person(self.owner) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
820 |
getattr(self.question, 'reopen') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
821 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
822 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
823 |
class ExpireQuestionTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.398.20
by Francis J. Lacoste
Rename all methods. |
824 |
"""Test cases for the expireQuestion() workflow action method."""
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
825 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
826 |
def test_expireQuestionFromInvalidStates(self): |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
827 |
"""Test that expireQuestion cannot be called when the question status
|
828 |
is not one of OPEN or NEEDSINFO.
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
829 |
"""
|
830 |
self._testInvalidTransition( |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
831 |
['OPEN', 'NEEDSINFO'], self.question.expireQuestion, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
832 |
self.answerer, "Too late.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
833 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
834 |
def test_expireQuestion(self): |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
835 |
"""Test that expireQuestion() can be called when the question status
|
836 |
is OPEN or NEEDSINFO and that it returns a valid IQuestionMessage.
|
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
837 |
"""
|
838 |
self._testValidTransition( |
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
839 |
[QuestionStatus.OPEN, QuestionStatus.NEEDSINFO], |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
840 |
expected_owner=self.answerer, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
841 |
expected_action=QuestionAction.EXPIRE, |
842 |
expected_status=QuestionStatus.EXPIRED, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
843 |
transition_method=self.question.expireQuestion, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
844 |
transition_method_args=( |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
845 |
self.answerer, 'This question is expired.'), |
3691.197.31
by Francis J. Lacoste
All workflow methods now triggers an ISQLObjectModifiedEvent. |
846 |
edited_fields=['status', 'messages', 'datelastresponse']) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
847 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
848 |
def test_expireQuestionPermission(self): |
849 |
"""Test that only a logged in user can access expireQuestion()."""
|
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
850 |
login(ANONYMOUS) |
7161.1.13
by Gary Poster
make lint happier, if not happy. |
851 |
self.assertRaises( |
852 |
Unauthorized, getattr, self.question, 'expireQuestion') |
|
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
853 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
854 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
855 |
getattr(self.question, 'expireQuestion') |
3691.197.109
by Francis J. Lacoste
- Add launchpad.Owner permission. |
856 |
|
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
857 |
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
858 |
class RejectTestCase(BaseAnswerTrackerWorkflowTestCase): |
3691.197.97
by Francis J. Lacoste
Splitted tests by workflow methods. |
859 |
"""Test cases for the reject() workflow action method."""
|
860 |
||
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
861 |
def test_rejectFromInvalidStates(self): |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
862 |
"""Test that reject() cannot be called when the question status is
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
863 |
not one of OPEN or NEEDSINFO.
|
864 |
"""
|
|
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
865 |
valid_statuses = [status.name for status in QuestionStatus.items |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
866 |
if status.name != 'INVALID'] |
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
867 |
# Reject user must be an answer contact, (or admin, or product owner).
|
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
868 |
# Answer contacts must speak a language
|
869 |
self.answerer.addLanguage(getUtility(ILanguageSet)['en']) |
|
12959.4.23
by Curtis Hovey
Always pass the subscribed_by argument to addAnswerContact. |
870 |
self.ubuntu.addAnswerContact(self.answerer, self.answerer) |
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
871 |
login_person(self.answerer) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
872 |
self._testInvalidTransition( |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
873 |
valid_statuses, self.question.reject, |
3691.197.66
by Francis J. Lacoste
PEP-8 cleanup. |
874 |
self.answerer, "This is lame.", datecreated=self.nowPlus(1)) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
875 |
|
876 |
def test_reject(self): |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
877 |
"""Test that reject() can be called when the question status is
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
878 |
OPEN or NEEDSINFO and that it returns a valid IQuestionMessage.
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
879 |
"""
|
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
880 |
# Reject user must be an answer contact, (or admin, or product owner).
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
881 |
login_person(self.answerer) |
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
882 |
# Answer contacts must speak a language
|
883 |
self.answerer.addLanguage(getUtility(ILanguageSet)['en']) |
|
12959.4.23
by Curtis Hovey
Always pass the subscribed_by argument to addAnswerContact. |
884 |
self.ubuntu.addAnswerContact(self.answerer, self.answerer) |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
885 |
valid_statuses = [status for status in QuestionStatus.items |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
886 |
if status.name != 'INVALID'] |
3691.197.33
by Francis J. Lacoste
Consider a rejection message as answering the ticket. |
887 |
|
888 |
def checkRejectMessageIsAnAnswer(message): |
|
889 |
# Check that the rejection message was considered answering
|
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
890 |
# the question.
|
891 |
self.assertEquals(message, self.question.answer) |
|
892 |
self.assertEquals(self.answerer, self.question.answerer) |
|
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
893 |
self.assertEquals(message.datecreated, self.question.date_solved) |
3691.197.33
by Francis J. Lacoste
Consider a rejection message as answering the ticket. |
894 |
|
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
895 |
self._testValidTransition( |
896 |
valid_statuses, |
|
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
897 |
expected_owner=self.answerer, |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
898 |
expected_action=QuestionAction.REJECT, |
899 |
expected_status=QuestionStatus.INVALID, |
|
3691.197.33
by Francis J. Lacoste
Consider a rejection message as answering the ticket. |
900 |
extra_message_check=checkRejectMessageIsAnAnswer, |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
901 |
transition_method=self.question.reject, |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
902 |
transition_method_args=( |
3691.197.64
by Francis J. Lacoste
Rename actor variable according to role instead of name |
903 |
self.answerer, 'This is lame.'), |
4664.2.4
by Curtis Hovey
Renamed attribute from datesolved to date_solved. Doh. This was |
904 |
edited_fields=['status', 'messages', 'answerer', 'date_solved', |
3691.197.33
by Francis J. Lacoste
Consider a rejection message as answering the ticket. |
905 |
'answer', 'datelastresponse']) |
3691.197.15
by Francis J. Lacoste
* Made all workflow transitions checks the ticket state to ensure only |
906 |
|
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
907 |
def testRejectPermission(self): |
908 |
"""Test the reject() access control.
|
|
909 |
||
3691.398.22
by Francis J. Lacoste
Rename support facet to answers. |
910 |
Only an answer contacts and administrator can reject a question.
|
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
911 |
"""
|
912 |
login(ANONYMOUS) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
913 |
self.assertRaises(Unauthorized, getattr, self.question, 'reject') |
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
914 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
915 |
login_person(self.owner) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
916 |
self.assertRaises(Unauthorized, getattr, self.question, 'reject') |
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
917 |
|
6596.1.6
by Guilherme Salgado
Replace a bunch of login() calls with login_person() to workaround the new restriction on EmailAddress.email |
918 |
login_person(self.answerer) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
919 |
self.assertRaises(Unauthorized, getattr, self.question, 'reject') |
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
920 |
|
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
921 |
# Answer contacts must speak a language
|
922 |
self.answerer.addLanguage(getUtility(ILanguageSet)['en']) |
|
12959.4.23
by Curtis Hovey
Always pass the subscribed_by argument to addAnswerContact. |
923 |
self.question.target.addAnswerContact(self.answerer, self.answerer) |
12887.1.1
by Curtis Hovey
Ensure distribution answer contacts are also checked for dsp question targets. |
924 |
# clear authorization cache for check_permission
|
925 |
clear_cache() |
|
926 |
self.assertTrue( |
|
927 |
getattr(self.question, 'reject'), |
|
928 |
"Answer contact cannot reject question.") |
|
929 |
login_person(self.admin) |
|
930 |
self.assertTrue( |
|
931 |
getattr(self.question, 'reject'), |
|
932 |
"Admin cannot reject question.") |
|
933 |
||
934 |
def testRejectPermission_indirect_answer_contact(self): |
|
935 |
# Indirect answer contacts (for a distribution) can reject
|
|
936 |
# distribuiton source package questions.
|
|
937 |
login_person(self.admin) |
|
938 |
dsp = self.ubuntu.getSourcePackage('mozilla-firefox') |
|
939 |
self.question.target = dsp |
|
940 |
login_person(self.answerer) |
|
941 |
self.answerer.addLanguage(getUtility(ILanguageSet)['en']) |
|
12959.4.23
by Curtis Hovey
Always pass the subscribed_by argument to addAnswerContact. |
942 |
self.ubuntu.addAnswerContact(self.answerer, self.answerer) |
12887.1.1
by Curtis Hovey
Ensure distribution answer contacts are also checked for dsp question targets. |
943 |
self.assertTrue( |
944 |
getattr(self.question, 'reject'), |
|
945 |
"Answer contact cannot reject question.") |