~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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
Answer Tracker Karma
====================

To promote community contributions in the Launchpad Answer Tracker, it's
very important that we acknowledge their work and give them some karma
points.

These karma points are assigned to a user when he performs one of the
actions we consider to be a reasonable contribution.

    >>> from lp.registry.interfaces.person import IPersonSet
    >>> from lp.registry.interfaces.product import IProductSet
    >>> from lp.registry.model.karma import KarmaCategory
    >>> answers_category = KarmaCategory.byName('answers')
    >>> answers_karma_actions = answers_category.karmaactions
    >>> sorted([action.title for action in answers_karma_actions])
    [u'Answered question',
     u'Asked question',
     u'Comment made on a question',
     u'FAQ created',
     u'FAQ edited',
     u'Gave answer on a question',
     u'Gave more information on a question',
     u'Question description changed',
     u'Question linked to a bug',
     u'Question owner accepted answer',
     u'Question title changed',
     u'Rejected question',
     u'Reopened question',
     u'Requested for information on a question',
     u'Solved own question']

    >>> person_set = getUtility(IPersonSet)
    >>> sample_person = person_set.getByEmail('test@canonical.com')
    >>> foo_bar = person_set.getByEmail('foo.bar@canonical.com')

Setup an event listener to help ensure karma is assigned when it should.

    >>> from lp.testing.karma import KarmaAssignedEventListener
    >>> karma_helper = KarmaAssignedEventListener(show_person=True)
    >>> karma_helper.register_listener()

Define a generator that always give a date higher than the previous one
to order our messages.

    >>> from datetime import datetime, timedelta
    >>> from pytz import UTC
    >>> def timegenerator(origin):
    ...     now = origin
    ...     while True:
    ...         now += timedelta(seconds=5)
    ...         yield now
    >>> now = timegenerator(datetime.now(UTC))


Karma Actions
-------------


Creating a question
...................

    >>> login('test@canonical.com')
    >>> from zope.event import notify
    >>> firefox = getUtility(IProductSet)['firefox']
    >>> firefox_question = firefox.newQuestion(
    ...     title='New question', description='Question description.',
    ...     owner=sample_person, datecreated=now.next())
    Karma added: action=questionasked, product=firefox, person=name12


Expiring a question
...................

The expireQuestion() workflow method doesn't grant any karma because it
will usually be called by an automated script.

    >>> msg = firefox_question.expireQuestion(
    ...     foo_bar, 'Expiring because of inactivity. Reopen if you are '
    ...     'still having the problem and provide additional information.',
    ...     datecreated=now.next())


Reopening a question
....................

    >>> msg = firefox_question.reopen(
    ...     "Firefox doesn't have any 'Quick Searches' in its bookmarks.",
    ...     datecreated=now.next())
    Karma added: action=questionreopened, product=firefox, person=name12


Requesting for more information
...............................

    >>> msg = firefox_question.requestInfo(
    ...     foo_bar, 'What "Quick Searches" do you want?',
    ...     datecreated=now.next())
    Karma added: action=questionrequestedinfo, product=firefox, person=name16


Giving back more information
............................

    >>> msg = firefox_question.giveInfo(
    ...     'The same one than shipped upstreams.',
    ...     datecreated=now.next())
    Karma added: action=questiongaveinfo, product=firefox, person=name12


Giving an answer to a question
..............................

    >>> msg = firefox_question.giveAnswer(
    ...     foo_bar, "Ok, I see what you mean. You need to install them "
    ...     "manually for now.", datecreated=now.next())
    Karma added: action=questiongaveanswer, product=firefox, person=name16


Adding a comment
................

    >>> msg = firefox_question.addComment(
    ...     foo_bar, 'You could also fill a bug about that, if you like.',
    ...     datecreated=now.next())
    Karma added: action=questioncommentadded, product=firefox, person=name16


Confirming that the problem is solved
.....................................

When the user confirms that his problem is solved, karma will be given
for accepting an answer. The person whose answer was accepted will also
receives karma.

    >>> msg = firefox_question.confirmAnswer(
    ...     "Ok, thanks. I'll open a bug about this then.",
    ...     answer=msg, datecreated=now.next())
    Karma added: action=questionansweraccepted, product=firefox, person=name12
    Karma added: action=questionanswered, product=firefox, person=name16


Rejecting a question
....................

    >>> msg = firefox_question.reject(
    ...     foo_bar, 'This should really be a bug report.')
    Karma added: action=questionrejected, product=firefox, person=name16


Changing the status
...................

We do not grant karma for status change made outside of workflow:

    >>> login('foo.bar@canonical.com')
    >>> from lp.answers.enums import QuestionStatus
    >>> msg = firefox_question.setStatus(
    ...     foo_bar, QuestionStatus.OPEN, 'That rejection was an error.',
    ...     datecreated=now.next())


Changing the title of a question
................................

    >>> from zope.interface import providedBy
    >>> from lazr.lifecycle.event import ObjectModifiedEvent
    >>> from lazr.lifecycle.snapshot import Snapshot
    >>> old_question = Snapshot(
    ...     firefox_question, providing=providedBy(firefox_question))
    >>> login('test@canonical.com')
    >>> firefox_question.title = ('Firefox 1.5.0.5 does not have any '
    ...                         '"Quick Searches" installed by default')
    >>> notify(ObjectModifiedEvent(firefox_question, old_question, ['title']))
    Karma added: action=questiontitlechanged, product=firefox, person=name12


Changing the description of a question
......................................

    >>> old_question = Snapshot(
    ...     firefox_question, providing=providedBy(firefox_question))
    >>> firefox_question.description = (
    ...     'Firefox 1.5.0.5 does not have any "Quick Searches" installed '
    ...     'in the bookmarks by default, like the official ones do.')
    >>> notify(ObjectModifiedEvent(
    ...     firefox_question, old_question, ['description']))
    Karma added: action=questiondescriptionchanged, product=firefox,
        person=name12


Linking to a bug
................

    >>> from lp.bugs.model.bug import Bug
    >>> questionbug = firefox_question.linkBug(Bug.get(5))
    Karma added: action=questionlinkedtobug, product=firefox, person=name12


Solving own problem
...................

There is a special karma action to cover the case when the question
owner comes back to provide an answer to his own problem. We no longer
award karma for the questionownersolved action. It remains among the
answers karma actions so that we can continue to calculate karma for
persons who were awarded it in the past.

    # This test must have no output

    >>> msg = firefox_question.giveAnswer(
    ...     sample_person, "I was able to import some by following the "
    ...     "instructions on http://tinyurl.com/cyus4",
    ...     datecreated=now.next())


Creating a FAQ
..............

    >>> firefox_faq = firefox.newFAQ(
    ...     sample_person, 'A FAQ', 'About something important')
    Karma added: action=faqcreated, product=firefox, person=name12


Modifying a FAQ
...............

    >>> old_faq = Snapshot(firefox_faq, providing=providedBy(firefox_faq))
    >>> firefox_faq.title = 'How can I make the Fnord appears?'
    >>> firefox_faq.content = 'Install the Fnords highlighter extensions.'
    >>> notify(ObjectModifiedEvent(
    ...     firefox_faq, old_faq, ['title', 'content']))
    Karma added: action=faqedited, product=firefox, person=name12


Final check and tear down
-------------------------

Now we do a check to make sure all current Answer Tracker related karma
actions have been tested. Only the obsolete methods remain.

    >>> added_karma_actions = karma_helper.added_karma_actions
    >>> obsolete_actions = set(answers_karma_actions) - added_karma_actions
    >>> [action.title for action in obsolete_actions]
    [u'Solved own question']

    # Unregister the event listener to make sure we won't interfere in
    # other tests.

    >>> karma_helper.unregister_listener()