Merge lp:~abentley/launchpad/user-blueprints-tests into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Merged at revision: 16157
Proposed branch: lp:~abentley/launchpad/user-blueprints-tests
Merge into: lp:launchpad
Diff against target: 241 lines (+215/-1)
2 files modified
lib/lp/registry/tests/test_person.py (+213/-0)
lib/lp/testing/factory.py (+2/-1)
To merge this branch: bzr merge lp:~abentley/launchpad/user-blueprints-tests
Reviewer Review Type Date Requested Status
Richard Harding (community) Approve
Review via email: mp+129944@code.launchpad.net

Commit message

Add tests for Person.specifications.

Description of the change

= Summary =
Add tests for Person.specifications.

== Pre-implementation notes ==
None

== LOC Rationale ==
Part of private projects

== Implementation details ==
This branch adds tests for Person.specifications, so that a follow-on branch can re-write it to use Storm expressions. Many of these tests were copied from the tests for Sprint.specifications.

== Tests ==
bin/test -t TestSpecifications test_person

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/testing/factory.py
  lib/lp/registry/tests/test_person.py

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/tests/test_person.py'
2--- lib/lp/registry/tests/test_person.py 2012-09-28 06:15:58 +0000
3+++ lib/lp/registry/tests/test_person.py 2012-10-16 16:52:26 +0000
4@@ -24,6 +24,14 @@
5 from lp.answers.model.answercontact import AnswerContact
6 from lp.app.enums import InformationType
7 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
8+from lp.blueprints.enums import (
9+ NewSpecificationDefinitionStatus,
10+ SpecificationDefinitionStatus,
11+ SpecificationImplementationStatus,
12+ SpecificationPriority,
13+ SpecificationFilter,
14+ SpecificationSort,
15+ )
16 from lp.blueprints.model.specification import Specification
17 from lp.bugs.interfaces.bugtasksearch import (
18 get_person_bugtasks_search_params,
19@@ -1550,3 +1558,208 @@
20 # 10. One to get all distroseries of a bug's distro. (See comment on
21 # getAssignedBugTasksDueBefore() to understand why it's needed)
22 self.assertThat(recorder, HasQueryCount(Equals(12)))
23+
24+
25+def list_result(sprint, filter=None, user=None):
26+ result = sprint.specifications(user, SpecificationSort.DATE, filter=filter)
27+ return list(result)
28+
29+
30+class TestSpecifications(TestCaseWithFactory):
31+
32+ layer = DatabaseFunctionalLayer
33+
34+ def setUp(self):
35+ super(TestSpecifications, self).setUp()
36+ self.date_created = datetime.now(pytz.utc)
37+
38+ def makeSpec(self, owner=None, date_created=0, title=None,
39+ status=NewSpecificationDefinitionStatus.NEW,
40+ name=None, priority=None, information_type=None):
41+ blueprint = self.factory.makeSpecification(
42+ title=title, status=status, name=name, priority=priority,
43+ information_type=information_type, owner=owner,
44+ )
45+ removeSecurityProxy(blueprint).datecreated = (
46+ self.date_created + timedelta(date_created))
47+ return blueprint
48+
49+ def test_specifications_quantity(self):
50+ # Ensure the quantity controls the maximum number of entries.
51+ owner = self.factory.makePerson()
52+ for count in range(10):
53+ self.factory.makeSpecification(owner=owner)
54+ self.assertEqual(10, owner.specifications(None).count())
55+ result = owner.specifications(None, quantity=None).count()
56+ self.assertEqual(10, result)
57+ self.assertEqual(8, owner.specifications(None, quantity=8).count())
58+ self.assertEqual(10, owner.specifications(None, quantity=11).count())
59+
60+ def test_date_sort(self):
61+ # Sort on date_created.
62+ owner = self.factory.makePerson()
63+ blueprint1 = self.makeSpec(owner, date_created=0)
64+ blueprint2 = self.makeSpec(owner, date_created=-1)
65+ blueprint3 = self.makeSpec(owner, date_created=1)
66+ result = list_result(owner)
67+ self.assertEqual([blueprint3, blueprint1, blueprint2], result)
68+
69+ def test_date_sort_id(self):
70+ # date-sorting when no date varies uses object id.
71+ owner = self.factory.makePerson()
72+ blueprint1 = self.makeSpec(owner)
73+ blueprint2 = self.makeSpec(owner)
74+ blueprint3 = self.makeSpec(owner)
75+ result = list_result(owner)
76+ self.assertEqual([blueprint1, blueprint2, blueprint3], result)
77+
78+ def test_priority_sort(self):
79+ # Sorting by priority works and is the default.
80+ # When priority is supplied, status is ignored.
81+ blueprint1 = self.makeSpec(priority=SpecificationPriority.UNDEFINED,
82+ status=SpecificationDefinitionStatus.NEW)
83+ owner = blueprint1.owner
84+ blueprint2 = self.makeSpec(
85+ owner, priority=SpecificationPriority.NOTFORUS,
86+ status=SpecificationDefinitionStatus.APPROVED)
87+ blueprint3 = self.makeSpec(
88+ owner, priority=SpecificationPriority.LOW,
89+ status=SpecificationDefinitionStatus.NEW)
90+ result = owner.specifications(None)
91+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
92+ result = owner.specifications(None, sort=SpecificationSort.PRIORITY)
93+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
94+
95+ def test_priority_sort_fallback_status(self):
96+ # Sorting by priority falls back to defintion_status.
97+ # When status is supplied, name is ignored.
98+ blueprint1 = self.makeSpec(
99+ status=SpecificationDefinitionStatus.NEW, name='a')
100+ owner = blueprint1.owner
101+ blueprint2 = self.makeSpec(
102+ owner, status=SpecificationDefinitionStatus.APPROVED, name='c')
103+ blueprint3 = self.makeSpec(
104+ owner, status=SpecificationDefinitionStatus.DISCUSSION, name='b')
105+ result = owner.specifications(None)
106+ self.assertEqual([blueprint2, blueprint3, blueprint1], list(result))
107+ result = owner.specifications(None, sort=SpecificationSort.PRIORITY)
108+ self.assertEqual([blueprint2, blueprint3, blueprint1], list(result))
109+
110+ def test_priority_sort_fallback_name(self):
111+ # Sorting by priority falls back to name
112+ blueprint1 = self.makeSpec(name='b')
113+ owner = blueprint1.owner
114+ blueprint2 = self.makeSpec(owner, name='c')
115+ blueprint3 = self.makeSpec(owner, name='a')
116+ result = owner.specifications(None)
117+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
118+ result = owner.specifications(None, sort=SpecificationSort.PRIORITY)
119+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
120+
121+ def test_ignore_inactive(self):
122+ # Specs for inactive products are skipped.
123+ product = self.factory.makeProduct()
124+ with celebrity_logged_in('admin'):
125+ product.active = False
126+ spec = self.factory.makeSpecification(product=product)
127+ self.assertNotIn(spec, spec.owner.specifications(None))
128+
129+ def test_include_distro(self):
130+ # Specs for distributions are included.
131+ distribution = self.factory.makeDistribution()
132+ spec = self.factory.makeSpecification(distribution=distribution)
133+ self.assertIn(spec, spec.owner.specifications(None))
134+
135+ def test_informational(self):
136+ # INFORMATIONAL causes only informational specs to be shown.
137+ enum = SpecificationImplementationStatus
138+ informational = self.factory.makeSpecification(
139+ implementation_status=enum.INFORMATIONAL)
140+ owner = informational.owner
141+ plain = self.factory.makeSpecification(owner=owner)
142+ result = owner.specifications(None)
143+ self.assertIn(informational, result)
144+ self.assertIn(plain, result)
145+ result = owner.specifications(
146+ None, filter=[SpecificationFilter.INFORMATIONAL])
147+ self.assertIn(informational, result)
148+ self.assertNotIn(plain, result)
149+
150+ def test_completeness(self):
151+ # If COMPLETE is specified, completed specs are listed. If INCOMPLETE
152+ # is specified or neither is specified, only incomplete specs are
153+ # listed.
154+ enum = SpecificationImplementationStatus
155+ implemented = self.factory.makeSpecification(
156+ implementation_status=enum.IMPLEMENTED)
157+ owner = implemented.owner
158+ non_implemented = self.factory.makeSpecification(owner=owner)
159+ result = owner.specifications(
160+ None, filter=[SpecificationFilter.COMPLETE])
161+ self.assertIn(implemented, result)
162+ self.assertNotIn(non_implemented, result)
163+
164+ result = owner.specifications(
165+ None, filter=[SpecificationFilter.INCOMPLETE])
166+ self.assertNotIn(implemented, result)
167+ self.assertIn(non_implemented, result)
168+ result = owner.specifications(
169+ None)
170+ self.assertNotIn(implemented, result)
171+ self.assertIn(non_implemented, result)
172+
173+ def test_all(self):
174+ # ALL causes both complete and incomplete to be listed.
175+ enum = SpecificationImplementationStatus
176+ implemented = self.factory.makeSpecification(
177+ implementation_status=enum.IMPLEMENTED)
178+ owner = implemented.owner
179+ non_implemented = self.factory.makeSpecification(owner=owner)
180+ result = owner.specifications(None, filter=[SpecificationFilter.ALL])
181+ self.assertContentEqual([implemented, non_implemented], result)
182+
183+ def test_valid(self):
184+ # VALID adjusts COMPLETE to exclude OBSOLETE and SUPERSEDED specs.
185+ # (INCOMPLETE already excludes OBSOLETE and SUPERSEDED.)
186+ i_enum = SpecificationImplementationStatus
187+ d_enum = SpecificationDefinitionStatus
188+ implemented = self.factory.makeSpecification(
189+ implementation_status=i_enum.IMPLEMENTED)
190+ owner = implemented.owner
191+ self.factory.makeSpecification(owner=owner, status=d_enum.SUPERSEDED)
192+ self.factory.makeSpecification(owner=owner, status=d_enum.OBSOLETE)
193+ filter = [SpecificationFilter.VALID, SpecificationFilter.COMPLETE]
194+ results = owner.specifications(None, filter=filter)
195+ self.assertContentEqual([implemented], results)
196+
197+ def test_roles(self):
198+ # If roles are specified, they control which specifications are shown.
199+ # If no roles are specified, all roles are used.
200+ created = self.factory.makeSpecification()
201+ person = created.owner
202+
203+ def rlist(filter=None):
204+ return list(person.specifications(None, filter=filter))
205+ assigned = self.factory.makeSpecification(assignee=person)
206+ drafting = self.factory.makeSpecification(drafter=person)
207+ approving = self.factory.makeSpecification(approver=person)
208+ subscribed = self.factory.makeSpecification()
209+ subscribed.subscribe(person)
210+ self.assertEqual([created, assigned, drafting, approving, subscribed],
211+ rlist([]))
212+ self.assertEqual([created], rlist([SpecificationFilter.CREATOR]))
213+ self.assertEqual([assigned], rlist([SpecificationFilter.ASSIGNEE]))
214+ self.assertEqual([drafting], rlist([SpecificationFilter.DRAFTER]))
215+ self.assertEqual([approving], rlist([SpecificationFilter.APPROVER]))
216+ self.assertEqual([subscribed],
217+ rlist([SpecificationFilter.SUBSCRIBER]))
218+
219+ def test_text_search(self):
220+ # Text searches work.
221+ blueprint1 = self.makeSpec(title='abc')
222+ owner = blueprint1.owner
223+ blueprint2 = self.makeSpec(owner, title='def')
224+ result = list_result(owner, ['abc'])
225+ self.assertEqual([blueprint1], result)
226+ result = list_result(owner, ['def'])
227+ self.assertEqual([blueprint2], result)
228
229=== modified file 'lib/lp/testing/factory.py'
230--- lib/lp/testing/factory.py 2012-10-15 23:20:25 +0000
231+++ lib/lp/testing/factory.py 2012-10-16 16:52:26 +0000
232@@ -2129,7 +2129,8 @@
233 if status.name not in status_names:
234 # Set the closed status after the status has a sane initial state.
235 naked_spec.definition_status = status
236- if status == SpecificationDefinitionStatus.OBSOLETE:
237+ if status in (SpecificationDefinitionStatus.OBSOLETE,
238+ SpecificationDefinitionStatus.SUPERSEDED):
239 # This is to satisfy a DB constraint of obsolete specs.
240 naked_spec.completer = owner
241 naked_spec.date_completed = datetime.now(pytz.UTC)