13597.1.1
by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint. |
1 |
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
|
8687.15.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
3 |
|
4 |
"""In-memory doubles of core codehosting objects."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
__all__ = [ |
|
7055.5.4
by Jonathan Lange
Eschew 'fake' and 'real' for 'inmemory' and 'db'. |
8 |
'InMemoryFrontend', |
10100.1.14
by Jonathan Lange
iter_split is in services. |
9 |
'XMLRPCWrapper', |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
10 |
]
|
11 |
||
8312.3.5
by Michael Hudson
mostly copy and pasted tests for the xml-rpc endpoint |
12 |
import operator |
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
13 |
from xmlrpclib import Fault |
14 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
15 |
from bzrlib.urlutils import ( |
16 |
escape, |
|
17 |
unescape, |
|
18 |
)
|
|
11583.3.15
by Jonathan Lange
Use the DeferredBlockingProxy in codehosting. |
19 |
from twisted.internet import defer |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
20 |
from zope.component import ( |
21 |
adapter, |
|
22 |
getSiteManager, |
|
23 |
)
|
|
8031.2.4
by Jonathan Lange
Use IBranchTarget() in the test, rather than directly getting the stacking |
24 |
from zope.interface import implementer |
25 |
||
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
26 |
from canonical.database.constants import UTC_NOW |
14593.1.1
by Curtis Hovey
Moved xmlrpc to lp. |
27 |
from lp.xmlrpc import faults |
14550.1.1
by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad |
28 |
from lp.app.validators import LaunchpadValidationError |
13662.5.3
by Aaron Bentley
Handle invalid source package names. |
29 |
from lp.app.validators.name import valid_name |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
30 |
from lp.code.bzr import ( |
31 |
BranchFormat, |
|
32 |
ControlFormat, |
|
33 |
RepositoryFormat, |
|
34 |
)
|
|
35 |
from lp.code.enums import BranchType |
|
10379.2.3
by Michael Hudson
acquireBranchToPull changes |
36 |
from lp.code.errors import UnknownBranchTypeError |
8555.2.2
by Tim Penhey
Move enum -> enums. |
37 |
from lp.code.interfaces.branch import IBranch |
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
38 |
from lp.code.interfaces.branchtarget import IBranchTarget |
39 |
from lp.code.interfaces.codehosting import ( |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
40 |
BRANCH_ALIAS_PREFIX, |
12707.7.6
by Tim Penhey
Created a function to do the basic alias assembly. |
41 |
branch_id_alias, |
12707.4.7
by Tim Penhey
Fix the inmemory xmlrpc mock. |
42 |
BRANCH_ID_ALIAS_PREFIX, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
43 |
BRANCH_TRANSPORT, |
44 |
CONTROL_TRANSPORT, |
|
45 |
LAUNCHPAD_ANONYMOUS, |
|
46 |
LAUNCHPAD_SERVICES, |
|
47 |
)
|
|
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
48 |
from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
49 |
from lp.code.model.branchnamespace import BranchNamespaceSet |
50 |
from lp.code.model.branchtarget import ( |
|
51 |
PackageBranchTarget, |
|
52 |
ProductBranchTarget, |
|
53 |
)
|
|
9590.3.3
by Michael Hudson
start addressing review comments |
54 |
from lp.code.xmlrpc.codehosting import datetime_from_tuple |
13662.5.3
by Aaron Bentley
Handle invalid source package names. |
55 |
from lp.registry.errors import InvalidName |
9113.7.4
by Jonathan Lange
Update many imports of pocket. |
56 |
from lp.registry.interfaces.pocket import PackagePublishingPocket |
10100.1.14
by Jonathan Lange
iter_split is in services. |
57 |
from lp.services.utils import iter_split |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
58 |
from lp.services.xmlrpc import LaunchpadFault |
8400.1.8
by Tim Penhey
Fix some imports. |
59 |
from lp.testing.factory import ObjectFactory |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
60 |
|
61 |
||
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
62 |
class FakeStore: |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
63 |
"""Fake store that implements find well enough to pass tests.
|
64 |
||
65 |
This is needed because some of the `test_codehosting` tests use
|
|
66 |
assertSqlAttributeEqualsDate, which relies on ORM behaviour. Here, we fake
|
|
67 |
enough of the ORM to pass the tests.
|
|
68 |
"""
|
|
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
69 |
|
70 |
def __init__(self, object_set): |
|
71 |
self._object_set = object_set |
|
72 |
||
73 |
def find(self, cls, **kwargs): |
|
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
74 |
"""Implement Store.find that takes two attributes: id and one other.
|
75 |
||
76 |
This is called by `assertSqlAttributeEqualsDate`, which relies on
|
|
77 |
`find` returning either a single match or None. Returning a match
|
|
78 |
implies that the given attribute has the expected value. Returning
|
|
79 |
None implies the opposite.
|
|
80 |
"""
|
|
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
81 |
branch_id = kwargs.pop('id') |
82 |
assert len(kwargs) == 1, ( |
|
83 |
'Expected only id and one other. Got %r' % kwargs) |
|
84 |
attribute = kwargs.keys()[0] |
|
85 |
expected_value = kwargs[attribute] |
|
86 |
branch = self._object_set.get(branch_id) |
|
87 |
if branch is None: |
|
8447.4.27
by Michael Hudson
fix remaining tests |
88 |
return FakeResult(None) |
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
89 |
if expected_value is getattr(branch, attribute): |
8447.4.27
by Michael Hudson
fix remaining tests |
90 |
return FakeResult(branch) |
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
91 |
return None |
92 |
||
93 |
||
8447.4.27
by Michael Hudson
fix remaining tests |
94 |
class FakeResult: |
95 |
"""As with FakeStore, just enough of a result to pass tests."""
|
|
96 |
||
97 |
def __init__(self, branch): |
|
98 |
self._branch = branch |
|
99 |
||
100 |
def one(self): |
|
101 |
return self._branch |
|
102 |
||
103 |
||
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
104 |
class FakeDatabaseObject: |
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
105 |
"""Base class for fake database objects."""
|
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
106 |
|
107 |
def _set_object_set(self, object_set): |
|
108 |
self.__storm_object_info__ = {'store': FakeStore(object_set)} |
|
109 |
||
110 |
||
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
111 |
class ObjectSet: |
112 |
"""Generic set of database objects."""
|
|
113 |
||
114 |
def __init__(self): |
|
7055.5.2
by Jonathan Lange
Make object sets use dicts internally so that ids are stable. |
115 |
self._objects = {} |
116 |
self._next_id = 1 |
|
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
117 |
|
118 |
def _add(self, db_object): |
|
7055.5.2
by Jonathan Lange
Make object sets use dicts internally so that ids are stable. |
119 |
self._objects[self._next_id] = db_object |
120 |
db_object.id = self._next_id |
|
121 |
self._next_id += 1 |
|
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
122 |
db_object._set_object_set(self) |
123 |
return db_object |
|
124 |
||
7055.5.2
by Jonathan Lange
Make object sets use dicts internally so that ids are stable. |
125 |
def _delete(self, db_object): |
126 |
del self._objects[db_object.id] |
|
127 |
||
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
128 |
def __iter__(self): |
7055.5.2
by Jonathan Lange
Make object sets use dicts internally so that ids are stable. |
129 |
return self._objects.itervalues() |
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
130 |
|
7055.10.11
by Jonathan Lange
Test write permissions thoroughly and simplify the inmemory version somewhat. |
131 |
def _find(self, **kwargs): |
132 |
[(key, value)] = kwargs.items() |
|
133 |
for obj in self: |
|
134 |
if getattr(obj, key) == value: |
|
135 |
return obj |
|
136 |
||
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
137 |
def get(self, id): |
7055.5.2
by Jonathan Lange
Make object sets use dicts internally so that ids are stable. |
138 |
return self._objects.get(id, None) |
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
139 |
|
140 |
def getByName(self, name): |
|
7055.10.11
by Jonathan Lange
Test write permissions thoroughly and simplify the inmemory version somewhat. |
141 |
return self._find(name=name) |
7055.4.13
by Jonathan Lange
Shuffle things around a bit so that the logic is clearer. |
142 |
|
143 |
||
11121.5.38
by Tim Penhey
Make sure that the branch doesn't exist after a link failure. |
144 |
class BranchSet(ObjectSet): |
145 |
"""Extra find methods for branches."""
|
|
146 |
||
147 |
def getByUniqueName(self, unique_name): |
|
148 |
return self._find(unique_name=unique_name) |
|
149 |
||
150 |
||
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
151 |
class FakeSourcePackage: |
152 |
"""Fake ISourcePackage."""
|
|
153 |
||
154 |
def __init__(self, sourcepackagename, distroseries): |
|
155 |
self.sourcepackagename = sourcepackagename |
|
156 |
self.distroseries = distroseries |
|
157 |
||
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
158 |
def __hash__(self): |
159 |
return hash((self.sourcepackagename.id, self.distroseries.id)) |
|
160 |
||
161 |
def __eq__(self, other): |
|
162 |
return (self.sourcepackagename.id == other.sourcepackagename.id |
|
163 |
and self.distroseries.id == other.distroseries.id) |
|
164 |
||
165 |
def __ne__(self, other): |
|
166 |
return not (self == other) |
|
167 |
||
7362.13.3
by Jonathan Lange
Use distribution property more effectively. |
168 |
@property
|
169 |
def distribution(self): |
|
7362.13.15
by Jonathan Lange
Guard against distroseries being None |
170 |
if self.distroseries is not None: |
171 |
return self.distroseries.distribution |
|
172 |
else: |
|
173 |
return None |
|
7362.13.3
by Jonathan Lange
Use distribution property more effectively. |
174 |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
175 |
@property
|
176 |
def development_version(self): |
|
177 |
name = '%s-devel' % self.distribution.name |
|
178 |
dev_series = self._distroseries_set.getByName(name) |
|
179 |
if dev_series is None: |
|
180 |
dev_series = FakeDistroSeries(name, self.distribution) |
|
181 |
self._distroseries_set._add(dev_series) |
|
182 |
return self.__class__(self.sourcepackagename, dev_series) |
|
183 |
||
184 |
@property
|
|
185 |
def path(self): |
|
186 |
return '%s/%s/%s' % ( |
|
187 |
self.distribution.name, |
|
188 |
self.distroseries.name, |
|
189 |
self.sourcepackagename.name) |
|
190 |
||
191 |
def getBranch(self, pocket): |
|
192 |
return self.distroseries._linked_branches.get( |
|
193 |
(self, pocket), None) |
|
194 |
||
195 |
def setBranch(self, pocket, branch, registrant): |
|
196 |
self.distroseries._linked_branches[self, pocket] = branch |
|
197 |
||
198 |
||
13662.5.1
by Aaron Bentley
Pushing to non-existant sourcepackagename creates. |
199 |
class SourcePackageNameSet(ObjectSet): |
200 |
||
201 |
def new(self, name_string): |
|
13662.5.3
by Aaron Bentley
Handle invalid source package names. |
202 |
if not valid_name(name_string): |
203 |
raise InvalidName(name_string) |
|
13662.5.1
by Aaron Bentley
Pushing to non-existant sourcepackagename creates. |
204 |
return self._add(FakeSourcePackageName(name_string)) |
205 |
||
206 |
||
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
207 |
@adapter(FakeSourcePackage) |
208 |
@implementer(IBranchTarget) |
|
209 |
def fake_source_package_to_branch_target(fake_package): |
|
210 |
return PackageBranchTarget(fake_package) |
|
211 |
||
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
212 |
|
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
213 |
class FakeBranch(FakeDatabaseObject): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
214 |
"""Fake branch object."""
|
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
215 |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
216 |
def __init__(self, branch_type, name, owner, url=None, product=None, |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
217 |
stacked_on=None, private=False, registrant=None, |
218 |
distroseries=None, sourcepackagename=None): |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
219 |
self.branch_type = branch_type |
220 |
self.last_mirror_attempt = None |
|
221 |
self.last_mirrored = None |
|
222 |
self.last_mirrored_id = None |
|
223 |
self.next_mirror_time = None |
|
224 |
self.url = url |
|
225 |
self.mirror_failures = 0 |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
226 |
self.name = name |
227 |
self.owner = owner |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
228 |
self.stacked_on = None |
229 |
self.mirror_status_message = None |
|
230 |
self.stacked_on = stacked_on |
|
231 |
self.private = private |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
232 |
self.product = product |
7055.4.18
by Jonathan Lange
Implement createBranch |
233 |
self.registrant = registrant |
7362.9.16
by Jonathan Lange
Merge lower thread |
234 |
self._mirrored = False |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
235 |
self.distroseries = distroseries |
236 |
self.sourcepackagename = sourcepackagename |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
237 |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
238 |
@property
|
239 |
def unique_name(self): |
|
240 |
if self.product is None: |
|
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
241 |
if self.distroseries is None: |
242 |
product = '+junk' |
|
243 |
else: |
|
244 |
product = '%s/%s/%s' % ( |
|
245 |
self.distroseries.distribution.name, |
|
246 |
self.distroseries.name, |
|
247 |
self.sourcepackagename.name) |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
248 |
else: |
249 |
product = self.product.name |
|
250 |
return '~%s/%s/%s' % (self.owner.name, product, self.name) |
|
251 |
||
7055.4.15
by Jonathan Lange
Make the tests pass again. |
252 |
def getPullURL(self): |
8312.3.8
by Michael Hudson
return the branch type from the xml-rpc method too |
253 |
return 'lp-fake:///' + self.unique_name |
254 |
||
255 |
@property
|
|
256 |
def target(self): |
|
257 |
if self.product is None: |
|
258 |
if self.distroseries is None: |
|
259 |
target = self.owner |
|
260 |
else: |
|
261 |
target = self.sourcepackage |
|
262 |
else: |
|
263 |
target = self.product |
|
264 |
return IBranchTarget(target) |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
265 |
|
266 |
def requestMirror(self): |
|
267 |
self.next_mirror_time = UTC_NOW |
|
268 |
||
269 |
||
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
270 |
class FakePerson(FakeDatabaseObject): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
271 |
"""Fake person object."""
|
14449.6.2
by Curtis Hovey
Updated templates to use is_team property. |
272 |
is_team = False |
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
273 |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
274 |
def __init__(self, name): |
275 |
self.name = self.displayname = name |
|
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
276 |
|
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
277 |
def inTeam(self, person_or_team): |
278 |
if self is person_or_team: |
|
279 |
return True |
|
14449.6.1
by Curtis Hovey
Remove isTeam(). Replace calls with .is_team. |
280 |
if not person_or_team.is_team: |
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
281 |
return False |
282 |
return self in person_or_team._members |
|
283 |
||
284 |
||
285 |
class FakeTeam(FakePerson): |
|
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
286 |
"""Fake team."""
|
14449.6.2
by Curtis Hovey
Updated templates to use is_team property. |
287 |
is_team = True |
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
288 |
|
289 |
def __init__(self, name, members=None): |
|
290 |
super(FakeTeam, self).__init__(name) |
|
291 |
if members is None: |
|
292 |
self._members = [] |
|
293 |
else: |
|
294 |
self._members = list(members) |
|
295 |
||
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
296 |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
297 |
class FakeProduct(FakeDatabaseObject): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
298 |
"""Fake product."""
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
299 |
|
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
300 |
def __init__(self, name, owner): |
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
301 |
self.name = name |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
302 |
self.owner = owner |
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
303 |
self.bzr_path = name |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
304 |
self.development_focus = FakeProductSeries(self, 'trunk') |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
305 |
self.series = { |
306 |
'trunk': self.development_focus, |
|
307 |
}
|
|
308 |
||
309 |
def getSeries(self, name): |
|
310 |
return self.series.get(name, None) |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
311 |
|
312 |
||
8031.2.4
by Jonathan Lange
Use IBranchTarget() in the test, rather than directly getting the stacking |
313 |
@adapter(FakeProduct) |
314 |
@implementer(IBranchTarget) |
|
315 |
def fake_product_to_branch_target(fake_product): |
|
8031.2.11
by Jonathan Lange
Apply review comments |
316 |
"""Adapt a `FakeProduct` to `IBranchTarget`."""
|
8031.2.4
by Jonathan Lange
Use IBranchTarget() in the test, rather than directly getting the stacking |
317 |
return ProductBranchTarget(fake_product) |
318 |
||
319 |
||
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
320 |
@adapter(FakeProduct) |
321 |
@implementer(ICanHasLinkedBranch) |
|
322 |
def fake_product_to_can_has_linked_branch(fake_product): |
|
323 |
"""Adapt a `FakeProduct` to `ICanHasLinkedBranch`."""
|
|
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
324 |
return fake_product.development_focus |
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
325 |
|
326 |
||
7055.4.15
by Jonathan Lange
Make the tests pass again. |
327 |
class FakeProductSeries(FakeDatabaseObject): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
328 |
"""Fake product series."""
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
329 |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
330 |
branch = None |
331 |
||
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
332 |
def __init__(self, product, name): |
333 |
self.product = product |
|
334 |
self.name = name |
|
335 |
||
11121.5.31
by Tim Penhey
More tests and tweaks to make the tests pass. |
336 |
@property
|
337 |
def bzr_path(self): |
|
338 |
if self.product.development_focus is self: |
|
339 |
return self.product.name |
|
340 |
else: |
|
341 |
return "%s/%s" % (self.product.name, self.name) |
|
342 |
||
7055.4.15
by Jonathan Lange
Make the tests pass again. |
343 |
|
11121.5.30
by Tim Penhey
W00t, all tests pass. |
344 |
@adapter(FakeProductSeries) |
345 |
@implementer(ICanHasLinkedBranch) |
|
346 |
def fake_productseries_to_can_has_linked_branch(fake_productseries): |
|
347 |
"""Adapt a `FakeProductSeries` to `ICanHasLinkedBranch`."""
|
|
348 |
return fake_productseries |
|
349 |
||
350 |
||
7055.4.12
by Jonathan Lange
Start to get a real fake structure. |
351 |
class FakeScriptActivity(FakeDatabaseObject): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
352 |
"""Fake script activity."""
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
353 |
|
354 |
def __init__(self, name, hostname, date_started, date_completed): |
|
7055.4.6
by Jonathan Lange
Factor out an object set -- I think this is a good idea. |
355 |
self.id = self.name = name |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
356 |
self.hostname = hostname |
357 |
self.date_started = datetime_from_tuple(date_started) |
|
358 |
self.date_completed = datetime_from_tuple(date_completed) |
|
359 |
||
360 |
||
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
361 |
class FakeDistribution(FakeDatabaseObject): |
362 |
||
363 |
def __init__(self, name): |
|
364 |
self.name = name |
|
365 |
||
366 |
||
367 |
class FakeDistroSeries(FakeDatabaseObject): |
|
368 |
"""Fake distroseries."""
|
|
369 |
||
370 |
def __init__(self, name, distribution): |
|
371 |
self.name = name |
|
372 |
self.distribution = distribution |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
373 |
self._linked_branches = {} |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
374 |
|
375 |
||
376 |
class FakeSourcePackageName(FakeDatabaseObject): |
|
377 |
"""Fake SourcePackageName."""
|
|
378 |
||
379 |
def __init__(self, name): |
|
380 |
self.name = name |
|
381 |
||
382 |
||
7055.4.19
by Jonathan Lange
Make getBranchInformation pass all the tests. We now have a fully fake |
383 |
DEFAULT_PRODUCT = object() |
384 |
||
385 |
||
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
386 |
class FakeObjectFactory(ObjectFactory): |
387 |
||
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
388 |
def __init__(self, branch_set, person_set, product_set, distribution_set, |
389 |
distroseries_set, sourcepackagename_set): |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
390 |
super(FakeObjectFactory, self).__init__() |
7055.4.11
by Jonathan Lange
Get rid of the last branch source references. |
391 |
self._branch_set = branch_set |
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
392 |
self._person_set = person_set |
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
393 |
self._product_set = product_set |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
394 |
self._distribution_set = distribution_set |
395 |
self._distroseries_set = distroseries_set |
|
396 |
self._sourcepackagename_set = sourcepackagename_set |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
397 |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
398 |
def makeBranch(self, branch_type=None, stacked_on=None, private=False, |
7055.4.19
by Jonathan Lange
Make getBranchInformation pass all the tests. We now have a fully fake |
399 |
product=DEFAULT_PRODUCT, owner=None, name=None, |
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
400 |
registrant=None, sourcepackage=None): |
8312.3.8
by Michael Hudson
return the branch type from the xml-rpc method too |
401 |
if branch_type is None: |
402 |
branch_type = BranchType.HOSTED |
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
403 |
if branch_type == BranchType.MIRRORED: |
404 |
url = self.getUniqueURL() |
|
405 |
else: |
|
406 |
url = None |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
407 |
if name is None: |
408 |
name = self.getUniqueString() |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
409 |
if owner is None: |
410 |
owner = self.makePerson() |
|
7055.4.19
by Jonathan Lange
Make getBranchInformation pass all the tests. We now have a fully fake |
411 |
if product is DEFAULT_PRODUCT: |
412 |
product = self.makeProduct() |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
413 |
if registrant is None: |
414 |
registrant = self.makePerson() |
|
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
415 |
if sourcepackage is None: |
416 |
sourcepackagename = None |
|
417 |
distroseries = None |
|
418 |
else: |
|
419 |
sourcepackagename = sourcepackage.sourcepackagename |
|
420 |
distroseries = sourcepackage.distroseries |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
421 |
IBranch['name'].validate(unicode(name)) |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
422 |
branch = FakeBranch( |
7055.4.18
by Jonathan Lange
Implement createBranch |
423 |
branch_type, name=name, owner=owner, url=url, |
424 |
stacked_on=stacked_on, product=product, private=private, |
|
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
425 |
registrant=registrant, distroseries=distroseries, |
426 |
sourcepackagename=sourcepackagename) |
|
7055.4.11
by Jonathan Lange
Get rid of the last branch source references. |
427 |
self._branch_set._add(branch) |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
428 |
return branch |
429 |
||
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
430 |
def makeAnyBranch(self, **kwargs): |
431 |
return self.makeProductBranch(**kwargs) |
|
432 |
||
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
433 |
def makePackageBranch(self, sourcepackage=None, **kwargs): |
434 |
if sourcepackage is None: |
|
435 |
sourcepackage = self.makeSourcePackage() |
|
436 |
return self.makeBranch( |
|
437 |
product=None, sourcepackage=sourcepackage, **kwargs) |
|
438 |
||
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
439 |
def makePersonalBranch(self, owner=None, **kwargs): |
440 |
if owner is None: |
|
441 |
owner = self.makePerson() |
|
442 |
return self.makeBranch( |
|
443 |
owner=owner, product=None, sourcepackage=None, **kwargs) |
|
444 |
||
445 |
def makeProductBranch(self, product=None, **kwargs): |
|
446 |
if product is None: |
|
447 |
product = self.makeProduct() |
|
448 |
return self.makeBranch(product=product, sourcepackage=None, **kwargs) |
|
449 |
||
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
450 |
def makeDistribution(self): |
451 |
distro = FakeDistribution(self.getUniqueString()) |
|
452 |
self._distribution_set._add(distro) |
|
453 |
return distro |
|
454 |
||
13597.1.1
by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint. |
455 |
def makeDistroSeries(self): |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
456 |
distro = self.makeDistribution() |
457 |
distroseries_name = self.getUniqueString() |
|
458 |
distroseries = FakeDistroSeries(distroseries_name, distro) |
|
459 |
self._distroseries_set._add(distroseries) |
|
460 |
return distroseries |
|
461 |
||
462 |
def makeSourcePackageName(self): |
|
13662.5.1
by Aaron Bentley
Pushing to non-existant sourcepackagename creates. |
463 |
return self._sourcepackagename_set.new(self.getUniqueString()) |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
464 |
|
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
465 |
def makeSourcePackage(self, distroseries=None, sourcepackagename=None): |
466 |
if distroseries is None: |
|
13597.1.1
by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint. |
467 |
distroseries = self.makeDistroSeries() |
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
468 |
if sourcepackagename is None: |
469 |
sourcepackagename = self.makeSourcePackageName() |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
470 |
package = FakeSourcePackage(sourcepackagename, distroseries) |
471 |
package._distroseries_set = self._distroseries_set |
|
472 |
return package |
|
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
473 |
|
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
474 |
def makeTeam(self, owner): |
475 |
team = FakeTeam(name=self.getUniqueString(), members=[owner]) |
|
476 |
self._person_set._add(team) |
|
477 |
return team |
|
478 |
||
11121.5.38
by Tim Penhey
Make sure that the branch doesn't exist after a link failure. |
479 |
def makePerson(self, name=None): |
480 |
if name is None: |
|
481 |
name = self.getUniqueString() |
|
482 |
person = FakePerson(name=name) |
|
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
483 |
self._person_set._add(person) |
484 |
return person |
|
485 |
||
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
486 |
def makeProduct(self, name=None, owner=None): |
487 |
if name is None: |
|
488 |
name = self.getUniqueString() |
|
489 |
if owner is None: |
|
490 |
owner = self.makePerson() |
|
491 |
product = FakeProduct(name, owner) |
|
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
492 |
self._product_set._add(product) |
493 |
return product |
|
7055.4.15
by Jonathan Lange
Make the tests pass again. |
494 |
|
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
495 |
def makeProductSeries(self, product, name=None): |
496 |
if name is None: |
|
497 |
name = self.getUniqueString() |
|
11121.5.30
by Tim Penhey
W00t, all tests pass. |
498 |
series = FakeProductSeries(product, name) |
499 |
product.series[name] = series |
|
500 |
return series |
|
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
501 |
|
7362.9.16
by Jonathan Lange
Merge lower thread |
502 |
def enableDefaultStackingForProduct(self, product, branch=None): |
503 |
"""Give 'product' a default stacked-on branch.
|
|
504 |
||
505 |
:param product: The product to give a default stacked-on branch to.
|
|
506 |
:param branch: The branch that should be the default stacked-on
|
|
507 |
branch. If not supplied, a fresh branch will be created.
|
|
508 |
"""
|
|
509 |
if branch is None: |
|
510 |
branch = self.makeBranch(product=product) |
|
8137.2.2
by Jonathan Lange
Fix last remaining use of user_branch |
511 |
product.development_focus.branch = branch |
9590.13.5
by Michael Hudson
fix test_codehosting tests |
512 |
branch.last_mirrored_id = 'rev1' |
7362.9.16
by Jonathan Lange
Merge lower thread |
513 |
return branch |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
514 |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
515 |
def enableDefaultStackingForPackage(self, package, branch): |
516 |
"""Give 'package' a default stacked-on branch.
|
|
517 |
||
518 |
:param package: The package to give a default stacked-on branch to.
|
|
519 |
:param branch: The branch that should be the default stacked-on
|
|
520 |
branch.
|
|
521 |
"""
|
|
522 |
package.development_version.setBranch( |
|
523 |
PackagePublishingPocket.RELEASE, branch, branch.owner) |
|
9590.13.5
by Michael Hudson
fix test_codehosting tests |
524 |
branch.last_mirrored_id = 'rev1' |
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
525 |
return branch |
526 |
||
8031.2.7
by Jonathan Lange
Remove default_stacked_on_branch from product, make all the tests use |
527 |
|
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
528 |
class FakeCodehosting: |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
529 |
|
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
530 |
def __init__(self, branch_set, person_set, product_set, distribution_set, |
531 |
distroseries_set, sourcepackagename_set, factory, |
|
532 |
script_activity_set): |
|
7055.4.7
by Jonathan Lange
Pass the branch set to the fake puller |
533 |
self._branch_set = branch_set |
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
534 |
self._person_set = person_set |
535 |
self._product_set = product_set |
|
536 |
self._distribution_set = distribution_set |
|
537 |
self._distroseries_set = distroseries_set |
|
538 |
self._sourcepackagename_set = sourcepackagename_set |
|
539 |
self._factory = factory |
|
7055.4.7
by Jonathan Lange
Pass the branch set to the fake puller |
540 |
self._script_activity_set = script_activity_set |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
541 |
|
10379.2.5
by Michael Hudson
integration test and implied fixes |
542 |
def acquireBranchToPull(self, branch_type_names): |
10379.2.3
by Michael Hudson
acquireBranchToPull changes |
543 |
if not branch_type_names: |
544 |
branch_type_names = 'HOSTED', 'MIRRORED', 'IMPORTED' |
|
545 |
branch_types = [] |
|
546 |
for branch_type_name in branch_type_names: |
|
547 |
try: |
|
548 |
branch_types.append(BranchType.items[branch_type_name]) |
|
549 |
except KeyError: |
|
550 |
raise UnknownBranchTypeError( |
|
551 |
'Unknown branch type: %r' % (branch_type_name,)) |
|
8312.3.5
by Michael Hudson
mostly copy and pasted tests for the xml-rpc endpoint |
552 |
branches = sorted( |
553 |
[branch for branch in self._branch_set |
|
9032.2.2
by Michael Hudson
test and fix |
554 |
if branch.next_mirror_time is not None |
10379.2.3
by Michael Hudson
acquireBranchToPull changes |
555 |
and branch.branch_type in branch_types], |
8312.3.5
by Michael Hudson
mostly copy and pasted tests for the xml-rpc endpoint |
556 |
key=operator.attrgetter('next_mirror_time')) |
557 |
if branches: |
|
558 |
branch = branches[-1] |
|
9590.1.79
by Michael Hudson
readability++ |
559 |
# Mark it as started mirroring.
|
560 |
branch.last_mirror_attempt = UTC_NOW |
|
561 |
branch.next_mirror_time = None |
|
8312.3.8
by Michael Hudson
return the branch type from the xml-rpc method too |
562 |
default_branch = branch.target.default_stacked_on_branch |
8811.1.1
by Michael Hudson
assorted tests and tweaks |
563 |
if default_branch is None: |
564 |
default_branch_name = '' |
|
565 |
elif (branch.branch_type == BranchType.MIRRORED |
|
566 |
and default_branch.private): |
|
567 |
default_branch_name = '' |
|
8312.3.8
by Michael Hudson
return the branch type from the xml-rpc method too |
568 |
else: |
8811.1.1
by Michael Hudson
assorted tests and tweaks |
569 |
default_branch_name = '/' + default_branch.unique_name |
8312.3.8
by Michael Hudson
return the branch type from the xml-rpc method too |
570 |
return (branch.id, branch.getPullURL(), branch.unique_name, |
571 |
default_branch_name, branch.branch_type.name) |
|
8312.3.5
by Michael Hudson
mostly copy and pasted tests for the xml-rpc endpoint |
572 |
else: |
573 |
return () |
|
574 |
||
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
575 |
def mirrorFailed(self, branch_id, reason): |
7055.4.7
by Jonathan Lange
Pass the branch set to the fake puller |
576 |
branch = self._branch_set.get(branch_id) |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
577 |
if branch is None: |
578 |
return faults.NoBranchWithID(branch_id) |
|
579 |
branch.mirror_failures += 1 |
|
580 |
branch.mirror_status_message = reason |
|
581 |
return True |
|
582 |
||
583 |
def recordSuccess(self, name, hostname, date_started, date_completed): |
|
7055.4.7
by Jonathan Lange
Pass the branch set to the fake puller |
584 |
self._script_activity_set._add( |
7055.4.6
by Jonathan Lange
Factor out an object set -- I think this is a good idea. |
585 |
FakeScriptActivity(name, hostname, date_started, date_completed)) |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
586 |
return True |
587 |
||
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
588 |
def _parseUniqueName(self, branch_path): |
589 |
"""Return a dict of the parsed information and the branch name."""
|
|
7213.4.4
by Jonathan Lange
createBranch now raises PermissionDenied when users try to create branches |
590 |
try: |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
591 |
namespace_path, branch_name = branch_path.rsplit('/', 1) |
7213.4.4
by Jonathan Lange
createBranch now raises PermissionDenied when users try to create branches |
592 |
except ValueError: |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
593 |
raise faults.PermissionDenied( |
11121.5.31
by Tim Penhey
More tests and tweaks to make the tests pass. |
594 |
"Cannot create branch at '/%s'" % branch_path) |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
595 |
data = BranchNamespaceSet().parse(namespace_path) |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
596 |
return data, branch_name |
597 |
||
598 |
def _createBranch(self, registrant, branch_path): |
|
599 |
"""The guts of the create branch method.
|
|
600 |
||
601 |
Raises exceptions on error conditions.
|
|
602 |
"""
|
|
603 |
to_link = None |
|
604 |
if branch_path.startswith(BRANCH_ALIAS_PREFIX + '/'): |
|
605 |
branch_path = branch_path[len(BRANCH_ALIAS_PREFIX) + 1:] |
|
606 |
if branch_path.startswith('~'): |
|
607 |
data, branch_name = self._parseUniqueName(branch_path) |
|
608 |
else: |
|
609 |
tokens = branch_path.split('/') |
|
610 |
data = { |
|
611 |
'person': registrant.name, |
|
612 |
'product': tokens[0], |
|
613 |
}
|
|
614 |
branch_name = 'trunk' |
|
615 |
# check the series
|
|
616 |
product = self._product_set.getByName(data['product']) |
|
617 |
if product is not None: |
|
11121.5.30
by Tim Penhey
W00t, all tests pass. |
618 |
if len(tokens) > 1: |
619 |
series = product.getSeries(tokens[1]) |
|
620 |
if series is None: |
|
621 |
raise faults.NotFound( |
|
622 |
"No such product series: '%s'." % tokens[1]) |
|
623 |
else: |
|
624 |
to_link = ICanHasLinkedBranch(series) |
|
625 |
else: |
|
626 |
to_link = ICanHasLinkedBranch(product) |
|
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
627 |
# don't forget the link.
|
628 |
else: |
|
629 |
data, branch_name = self._parseUniqueName(branch_path) |
|
630 |
||
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
631 |
owner = self._person_set.getByName(data['person']) |
7055.4.18
by Jonathan Lange
Implement createBranch |
632 |
if owner is None: |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
633 |
raise faults.NotFound( |
9738.1.11
by Michael Hudson
fix test failures |
634 |
"User/team '%s' does not exist." % (data['person'],)) |
7055.5.9
by Jonathan Lange
Improve comments on authorization checks |
635 |
# The real code consults the branch creation policy of the product. We
|
636 |
# don't need to do so here, since the tests above this layer never
|
|
637 |
# encounter that behaviour. If they *do* change to rely on the branch
|
|
638 |
# creation policy, the observed behaviour will be failure to raise
|
|
639 |
# exceptions.
|
|
640 |
if not registrant.inTeam(owner): |
|
11121.5.30
by Tim Penhey
W00t, all tests pass. |
641 |
raise faults.PermissionDenied( |
7055.4.18
by Jonathan Lange
Implement createBranch |
642 |
('%s cannot create branches owned by %s' |
643 |
% (registrant.displayname, owner.displayname))) |
|
7362.12.24
by Jonathan Lange
Restore change that somehow got lost. |
644 |
product = sourcepackage = None |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
645 |
if data['product'] == '+junk': |
7055.4.18
by Jonathan Lange
Implement createBranch |
646 |
product = None |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
647 |
elif data['product'] is not None: |
648 |
product = self._product_set.getByName(data['product']) |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
649 |
if product is None: |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
650 |
raise faults.NotFound( |
9738.1.11
by Michael Hudson
fix test failures |
651 |
"Project '%s' does not exist." % (data['product'],)) |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
652 |
elif data['distribution'] is not None: |
653 |
distro = self._distribution_set.getByName(data['distribution']) |
|
7362.9.14
by Jonathan Lange
Tests for all sorts of not found errors. |
654 |
if distro is None: |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
655 |
raise faults.NotFound( |
7362.9.27
by Jonathan Lange
Whole bunch of minor exception-related crap. |
656 |
"No such distribution: '%s'." % (data['distribution'],)) |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
657 |
distroseries = self._distroseries_set.getByName( |
658 |
data['distroseries']) |
|
7362.9.14
by Jonathan Lange
Tests for all sorts of not found errors. |
659 |
if distroseries is None: |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
660 |
raise faults.NotFound( |
7362.9.27
by Jonathan Lange
Whole bunch of minor exception-related crap. |
661 |
"No such distribution series: '%s'." |
7362.9.14
by Jonathan Lange
Tests for all sorts of not found errors. |
662 |
% (data['distroseries'],)) |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
663 |
sourcepackagename = self._sourcepackagename_set.getByName( |
664 |
data['sourcepackagename']) |
|
7362.9.14
by Jonathan Lange
Tests for all sorts of not found errors. |
665 |
if sourcepackagename is None: |
13662.5.3
by Aaron Bentley
Handle invalid source package names. |
666 |
try: |
667 |
sourcepackagename = self._sourcepackagename_set.new( |
|
668 |
data['sourcepackagename']) |
|
669 |
except InvalidName: |
|
670 |
raise faults.InvalidSourcePackageName( |
|
671 |
data['sourcepackagename']) |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
672 |
sourcepackage = self._factory.makeSourcePackage( |
673 |
distroseries, sourcepackagename) |
|
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
674 |
else: |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
675 |
raise faults.PermissionDenied( |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
676 |
"Cannot create branch at '%s'" % branch_path) |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
677 |
branch = self._factory.makeBranch( |
678 |
owner=owner, name=branch_name, product=product, |
|
679 |
sourcepackage=sourcepackage, registrant=registrant, |
|
680 |
branch_type=BranchType.HOSTED) |
|
681 |
if to_link is not None: |
|
682 |
if registrant.inTeam(to_link.product.owner): |
|
683 |
to_link.branch = branch |
|
684 |
else: |
|
11121.5.38
by Tim Penhey
Make sure that the branch doesn't exist after a link failure. |
685 |
self._branch_set._delete(branch) |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
686 |
raise faults.PermissionDenied( |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
687 |
"Cannot create linked branch at '%s'." % branch_path) |
688 |
return branch.id |
|
689 |
||
690 |
def createBranch(self, requester_id, branch_path): |
|
691 |
if not branch_path.startswith('/'): |
|
692 |
return faults.InvalidPath(branch_path) |
|
693 |
escaped_path = unescape(branch_path.strip('/')) |
|
694 |
registrant = self._person_set.get(requester_id) |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
695 |
try: |
11121.5.29
by Tim Penhey
5 out of 7 failing inmemory tests now passing. |
696 |
return self._createBranch(registrant, escaped_path) |
697 |
except LaunchpadFault, e: |
|
698 |
return e |
|
7055.4.18
by Jonathan Lange
Implement createBranch |
699 |
except LaunchpadValidationError, e: |
9738.1.9
by Michael Hudson
tests for internal xml-rpc changes and fixes to in-memory double of same |
700 |
msg = e.args[0] |
701 |
if isinstance(msg, unicode): |
|
702 |
msg = msg.encode('utf-8') |
|
703 |
return faults.PermissionDenied(msg) |
|
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
704 |
|
705 |
def requestMirror(self, requester_id, branch_id): |
|
706 |
self._branch_set.get(branch_id).requestMirror() |
|
707 |
||
9590.4.8
by Michael Hudson
don't use removeSecurityProxy to freely |
708 |
def branchChanged(self, login_id, branch_id, stacked_on_location, |
709 |
last_revision_id, control_string, branch_string, |
|
710 |
repository_string): |
|
9590.2.12
by Michael Hudson
inmemory implementation of reporting bogus stacking |
711 |
branch = self._branch_set._find(id=branch_id) |
712 |
if branch is None: |
|
713 |
return faults.NoBranchWithID(branch_id) |
|
9590.3.1
by Michael Hudson
clear the mirror_status_message if there is no error in branchChanged |
714 |
branch.mirror_status_message = None |
9590.2.8
by Michael Hudson
in memory implementaion of branchChanged, one more test |
715 |
if stacked_on_location == '': |
716 |
stacked_on_branch = None |
|
717 |
else: |
|
718 |
# We could log or something if the branch is not found here, but
|
|
719 |
# we just wait until the scanner fails and sets up an appropriate
|
|
720 |
# message.
|
|
721 |
stacked_on_branch = self._branch_set._find( |
|
722 |
unique_name=stacked_on_location.strip('/')) |
|
9590.2.12
by Michael Hudson
inmemory implementation of reporting bogus stacking |
723 |
if stacked_on_branch is None: |
724 |
branch.mirror_status_message = ( |
|
725 |
'Invalid stacked on location: ' + stacked_on_location) |
|
9590.2.8
by Michael Hudson
in memory implementaion of branchChanged, one more test |
726 |
branch.stacked_on = stacked_on_branch |
9590.3.3
by Michael Hudson
start addressing review comments |
727 |
branch.last_mirrored = UTC_NOW |
9590.2.8
by Michael Hudson
in memory implementaion of branchChanged, one more test |
728 |
if branch.last_mirrored_id != last_revision_id: |
729 |
branch.last_mirrored_id = last_revision_id |
|
9590.2.23
by Michael Hudson
unit tests for branchChange recording the format |
730 |
|
731 |
def match_title(enum, title, default): |
|
732 |
for value in enum.items: |
|
733 |
if value.title == title: |
|
734 |
return value |
|
735 |
else: |
|
736 |
return default |
|
737 |
||
738 |
branch.control_format = match_title( |
|
739 |
ControlFormat, control_string, ControlFormat.UNRECOGNIZED) |
|
740 |
branch.branch_format = match_title( |
|
741 |
BranchFormat, branch_string, BranchFormat.UNRECOGNIZED) |
|
742 |
branch.repository_format = match_title( |
|
743 |
RepositoryFormat, repository_string, |
|
744 |
RepositoryFormat.UNRECOGNIZED) |
|
745 |
||
9590.2.8
by Michael Hudson
in memory implementaion of branchChanged, one more test |
746 |
return True |
747 |
||
7055.5.10
by Jonathan Lange
Make canRead a little better. |
748 |
def _canRead(self, person_id, branch): |
749 |
"""Can the person 'person_id' see 'branch'?"""
|
|
750 |
# This is a substitute for an actual launchpad.View check on the
|
|
751 |
# branch. It doesn't have to match the behaviour exactly, as long as
|
|
752 |
# it's stricter than the real implementation (that way, mismatches in
|
|
753 |
# behaviour should generate explicit errors.)
|
|
754 |
if person_id == LAUNCHPAD_SERVICES: |
|
755 |
return True |
|
7551.3.7
by Michael Hudson
use a new, custom value rather than ftests.ANONYMOUS to indicate the anonymous user to translatePath |
756 |
if person_id == LAUNCHPAD_ANONYMOUS: |
7459.5.20
by Michael Hudson
let have us some tests for translatePath(ANONYMOUS, ...) |
757 |
return not branch.private |
7055.5.10
by Jonathan Lange
Make canRead a little better. |
758 |
if not branch.private: |
759 |
return True |
|
760 |
person = self._person_set.get(person_id) |
|
761 |
return person.inTeam(branch.owner) |
|
762 |
||
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
763 |
def _canWrite(self, person_id, branch): |
764 |
"""Can the person 'person_id' write to 'branch'?"""
|
|
7551.3.7
by Michael Hudson
use a new, custom value rather than ftests.ANONYMOUS to indicate the anonymous user to translatePath |
765 |
if person_id in [LAUNCHPAD_ANONYMOUS, LAUNCHPAD_SERVICES]: |
7055.5.3
by Jonathan Lange
Nail team ownership rules down. |
766 |
return False |
767 |
if branch.branch_type != BranchType.HOSTED: |
|
768 |
return False |
|
769 |
person = self._person_set.get(person_id) |
|
770 |
return person.inTeam(branch.owner) |
|
771 |
||
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
772 |
def _get_product_target(self, path): |
773 |
try: |
|
774 |
owner_name, product_name = path.split('/') |
|
775 |
except ValueError: |
|
776 |
# Wrong number of segments -- can't be a product.
|
|
777 |
return
|
|
778 |
product = self._product_set.getByName(product_name) |
|
779 |
return product |
|
780 |
||
781 |
def _get_package_target(self, path): |
|
782 |
try: |
|
783 |
owner_name, distro_name, series_name, package_name = ( |
|
784 |
path.split('/')) |
|
785 |
except ValueError: |
|
786 |
# Wrong number of segments -- can't be a package.
|
|
787 |
return
|
|
788 |
distro = self._distribution_set.getByName(distro_name) |
|
789 |
distroseries = self._distroseries_set.getByName(series_name) |
|
790 |
sourcepackagename = self._sourcepackagename_set.getByName( |
|
791 |
package_name) |
|
792 |
if None in (distro, distroseries, sourcepackagename): |
|
793 |
return
|
|
794 |
return self._factory.makeSourcePackage( |
|
795 |
distroseries, sourcepackagename) |
|
796 |
||
7213.4.8
by Jonathan Lange
_getProduct -> _serializeControlDirectory. |
797 |
def _serializeControlDirectory(self, requester, product_path, |
798 |
trailing_path): |
|
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
799 |
if not ('.bzr' == trailing_path or trailing_path.startswith('.bzr/')): |
800 |
return
|
|
801 |
target = self._get_product_target(product_path) |
|
802 |
if target is None: |
|
803 |
target = self._get_package_target(product_path) |
|
804 |
if target is None: |
|
805 |
return
|
|
806 |
default_branch = IBranchTarget(target).default_stacked_on_branch |
|
7055.10.22
by Jonathan Lange
Handle the case where there is no default stacked-on branch set. |
807 |
if default_branch is None: |
808 |
return
|
|
7055.10.24
by Jonathan Lange
Return a NotFound for product control directories where the stacked-on branch |
809 |
if not self._canRead(requester, default_branch): |
810 |
return
|
|
12707.7.6
by Tim Penhey
Created a function to do the basic alias assembly. |
811 |
path = branch_id_alias(default_branch) |
7213.4.11
by Jonathan Lange
Return escaped URLs for the stacked-on branch. |
812 |
return ( |
813 |
CONTROL_TRANSPORT, |
|
12707.7.5
by Tim Penhey
Update the tests and the in-memory mock. |
814 |
{'default_stack_on': escape(path)}, |
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
815 |
trailing_path) |
7055.10.16
by Jonathan Lange
Make the first control directory test pass in a fairly crappy way. |
816 |
|
12707.4.7
by Tim Penhey
Fix the inmemory xmlrpc mock. |
817 |
def _serializeBranch(self, requester_id, branch, trailing_path, |
818 |
force_readonly=False): |
|
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
819 |
if not self._canRead(requester_id, branch): |
7459.6.5
by Michael Hudson
kill PERMISSION_DENIED_FAULT_CODE, replace with faults.PermissionDenied |
820 |
return faults.PermissionDenied() |
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
821 |
elif branch.branch_type == BranchType.REMOTE: |
822 |
return None |
|
12707.4.7
by Tim Penhey
Fix the inmemory xmlrpc mock. |
823 |
if force_readonly: |
824 |
writable = False |
|
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
825 |
else: |
12707.4.7
by Tim Penhey
Fix the inmemory xmlrpc mock. |
826 |
writable = self._canWrite(requester_id, branch) |
827 |
return ( |
|
828 |
BRANCH_TRANSPORT, |
|
829 |
{'id': branch.id, 'writable': writable}, |
|
830 |
trailing_path) |
|
831 |
||
832 |
def _translateBranchIdAlias(self, requester, path): |
|
833 |
# If the path isn't a branch id alias, nothing more to do.
|
|
834 |
stripped_path = unescape(path.strip('/')) |
|
835 |
if not stripped_path.startswith(BRANCH_ID_ALIAS_PREFIX + '/'): |
|
836 |
return None |
|
837 |
try: |
|
838 |
parts = stripped_path.split('/', 2) |
|
839 |
branch_id = int(parts[1]) |
|
840 |
except (ValueError, IndexError): |
|
841 |
return faults.PathTranslationError(path) |
|
842 |
branch = self._branch_set.get(branch_id) |
|
843 |
if branch is None: |
|
844 |
return faults.PathTranslationError(path) |
|
845 |
try: |
|
846 |
trailing = parts[2] |
|
847 |
except IndexError: |
|
848 |
trailing = '' |
|
849 |
return self._serializeBranch(requester, branch, trailing, True) |
|
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
850 |
|
7055.10.1
by Jonathan Lange
Start work on translatePath. |
851 |
def translatePath(self, requester_id, path): |
7055.10.4
by Jonathan Lange
Make the preceding slash compulsory. |
852 |
if not path.startswith('/'): |
853 |
return faults.InvalidPath(path) |
|
12707.4.7
by Tim Penhey
Fix the inmemory xmlrpc mock. |
854 |
branch = self._translateBranchIdAlias(requester_id, path) |
855 |
if branch is not None: |
|
856 |
return branch |
|
7055.10.3
by Jonathan Lange
Start bringing in branch translation. |
857 |
stripped_path = path.strip('/') |
7055.10.5
by Jonathan Lange
Handle child paths within a branch. |
858 |
for first, second in iter_split(stripped_path, '/'): |
7055.10.6
by Jonathan Lange
translatePath should handle escaped paths. |
859 |
first = unescape(first).encode('utf-8') |
7055.10.16
by Jonathan Lange
Make the first control directory test pass in a fairly crappy way. |
860 |
# Is it a branch?
|
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
861 |
if first.startswith('+branch/'): |
11121.5.6
by Jonathan Lange
Fix the inmemory server |
862 |
component_name = first[len('+branch/'):] |
863 |
product = self._product_set.getByName(component_name) |
|
864 |
if product: |
|
865 |
branch = product.development_focus.branch |
|
866 |
else: |
|
13597.1.1
by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint. |
867 |
branch = self._branch_set._find( |
868 |
unique_name=component_name) |
|
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
869 |
else: |
870 |
branch = self._branch_set._find(unique_name=first) |
|
7055.10.16
by Jonathan Lange
Make the first control directory test pass in a fairly crappy way. |
871 |
if branch is not None: |
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
872 |
branch = self._serializeBranch(requester_id, branch, second) |
7459.6.2
by Michael Hudson
fix implementations |
873 |
if isinstance(branch, Fault): |
874 |
return branch |
|
875 |
elif branch is None: |
|
7213.4.7
by Jonathan Lange
extract serialize branch from inmemory translatePath. |
876 |
break
|
877 |
return branch |
|
7055.10.16
by Jonathan Lange
Make the first control directory test pass in a fairly crappy way. |
878 |
|
879 |
# Is it a product?
|
|
7213.4.8
by Jonathan Lange
_getProduct -> _serializeControlDirectory. |
880 |
product = self._serializeControlDirectory( |
881 |
requester_id, first, second) |
|
7055.10.16
by Jonathan Lange
Make the first control directory test pass in a fairly crappy way. |
882 |
if product: |
883 |
return product |
|
7055.10.1
by Jonathan Lange
Start work on translatePath. |
884 |
return faults.PathTranslationError(path) |
885 |
||
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
886 |
|
7055.5.4
by Jonathan Lange
Eschew 'fake' and 'real' for 'inmemory' and 'db'. |
887 |
class InMemoryFrontend: |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
888 |
"""A in-memory 'frontend' to Launchpad's branch services.
|
889 |
||
890 |
This is an in-memory version of `LaunchpadDatabaseFrontend`.
|
|
891 |
"""
|
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
892 |
|
893 |
def __init__(self): |
|
11121.5.38
by Tim Penhey
Make sure that the branch doesn't exist after a link failure. |
894 |
self._branch_set = BranchSet() |
7055.4.8
by Jonathan Lange
Make the set concept a little stronger. |
895 |
self._script_activity_set = ObjectSet() |
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
896 |
self._person_set = ObjectSet() |
7055.4.17
by Jonathan Lange
And now, getDefaultStackedOnBranch works. |
897 |
self._product_set = ObjectSet() |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
898 |
self._distribution_set = ObjectSet() |
899 |
self._distroseries_set = ObjectSet() |
|
13662.5.1
by Aaron Bentley
Pushing to non-existant sourcepackagename creates. |
900 |
self._sourcepackagename_set = SourcePackageNameSet() |
7055.4.18
by Jonathan Lange
Implement createBranch |
901 |
self._factory = FakeObjectFactory( |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
902 |
self._branch_set, self._person_set, self._product_set, |
903 |
self._distribution_set, self._distroseries_set, |
|
904 |
self._sourcepackagename_set) |
|
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
905 |
self._codehosting = FakeCodehosting( |
7055.4.18
by Jonathan Lange
Implement createBranch |
906 |
self._branch_set, self._person_set, self._product_set, |
7362.9.13
by Jonathan Lange
Add a test for creating a sourcepackage branch via createBranch. |
907 |
self._distribution_set, self._distroseries_set, |
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
908 |
self._sourcepackagename_set, self._factory, |
909 |
self._script_activity_set) |
|
8031.2.7
by Jonathan Lange
Remove default_stacked_on_branch from product, make all the tests use |
910 |
sm = getSiteManager() |
11121.5.1
by Jonathan Lange
Begin supporting +branch over codehosting. |
911 |
sm.registerAdapter(fake_product_to_can_has_linked_branch) |
8031.2.7
by Jonathan Lange
Remove default_stacked_on_branch from product, make all the tests use |
912 |
sm.registerAdapter(fake_product_to_branch_target) |
8031.4.9
by Jonathan Lange
Get the in memory versions passing. |
913 |
sm.registerAdapter(fake_source_package_to_branch_target) |
11121.5.30
by Tim Penhey
W00t, all tests pass. |
914 |
sm.registerAdapter(fake_productseries_to_can_has_linked_branch) |
7055.4.16
by Jonathan Lange
Start running the filesystem tests against a fake. They don't pass yet. |
915 |
|
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
916 |
def getCodehostingEndpoint(self): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
917 |
"""See `LaunchpadDatabaseFrontend`.
|
918 |
||
919 |
Return an in-memory implementation of IBranchFileSystem that passes
|
|
920 |
the tests in `test_codehosting`.
|
|
921 |
"""
|
|
9590.1.49
by Michael Hudson
more combining the puller and filesystem endpoints |
922 |
return self._codehosting |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
923 |
|
924 |
def getLaunchpadObjectFactory(self): |
|
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
925 |
"""See `LaunchpadDatabaseFrontend`.
|
926 |
||
927 |
Returns a partial, in-memory implementation of LaunchpadObjectFactory
|
|
928 |
-- enough to pass the tests.
|
|
929 |
"""
|
|
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
930 |
return self._factory |
931 |
||
7940.2.10
by Jonathan Lange
Get the codehosting xmlrpc tests passing. |
932 |
def getBranchLookup(self): |
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
933 |
"""See `LaunchpadDatabaseFrontend`.
|
934 |
||
7940.2.10
by Jonathan Lange
Get the codehosting xmlrpc tests passing. |
935 |
Returns a partial implementation of `IBranchLookup` -- enough to pass
|
936 |
the tests.
|
|
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
937 |
"""
|
7055.4.8
by Jonathan Lange
Make the set concept a little stronger. |
938 |
return self._branch_set |
7055.4.4
by Jonathan Lange
Move the fakes out of the test module. |
939 |
|
940 |
def getLastActivity(self, activity_name): |
|
7055.5.11
by Jonathan Lange
Add a bunch of docstrings. |
941 |
"""Get the last script activity with 'activity_name'."""
|
7055.4.8
by Jonathan Lange
Make the set concept a little stronger. |
942 |
return self._script_activity_set.getByName(activity_name) |
7055.4.29
by Jonathan Lange
Add an XMLRPCWrapper that deals with Zope's crazy fault handling. |
943 |
|
944 |
||
945 |
class XMLRPCWrapper: |
|
946 |
"""Wrapper around the endpoints that emulates an XMLRPC client."""
|
|
947 |
||
948 |
def __init__(self, endpoint): |
|
949 |
self.endpoint = endpoint |
|
950 |
||
11583.3.15
by Jonathan Lange
Use the DeferredBlockingProxy in codehosting. |
951 |
def _callRemote(self, method_name, *args): |
7055.4.29
by Jonathan Lange
Add an XMLRPCWrapper that deals with Zope's crazy fault handling. |
952 |
result = getattr(self.endpoint, method_name)(*args) |
953 |
if isinstance(result, Fault): |
|
954 |
raise result |
|
955 |
return result |
|
11583.3.15
by Jonathan Lange
Use the DeferredBlockingProxy in codehosting. |
956 |
|
957 |
def callRemote(self, method_name, *args): |
|
958 |
return defer.maybeDeferred(self._callRemote, method_name, *args) |