Merge lp:~jcsackett/launchpad/invalid-product-names into lp:launchpad

Proposed by j.c.sackett on 2012-10-31
Status: Merged
Approved by: Curtis Hovey on 2012-10-31
Approved revision: no longer in the source branch.
Merged at revision: 16224
Proposed branch: lp:~jcsackett/launchpad/invalid-product-names
Merge into: lp:launchpad
Diff against target: 132 lines (+24/-7)
8 files modified
lib/lp/code/model/tests/test_branchlookup.py (+1/-1)
lib/lp/code/xmlrpc/branch.py (+1/-1)
lib/lp/code/xmlrpc/codehosting.py (+6/-1)
lib/lp/code/xmlrpc/tests/test_codehosting.py (+10/-0)
lib/lp/codehosting/inmemory.py (+2/-0)
lib/lp/codehosting/vfs/branchfs.py (+1/-1)
lib/lp/xmlrpc/configure.zcml (+1/-1)
lib/lp/xmlrpc/faults.py (+2/-2)
To merge this branch: bzr merge lp:~jcsackett/launchpad/invalid-product-names
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code 2012-10-31 Approve on 2012-10-31
Review via email: mp+132405@code.launchpad.net

Commit Message

Updates handling of InvalidProductName on bzr push to return an error message to the user rather than OOPSing.

Description of the Change

Summary
=======
When someone pushes to an invalid product name (i.e. one that doesn't satisfy
our name validation), an unexpected error is triggered.

We should just handle it as we do non-existant products and products you don't
have permission to post to, rather than OOPSing.

Preimp
======
Spoke with Curtis Hovey.

Implementation
==============
The InvalidProductName exception is now caught in a block that handles all the
other expected errors when getting branch information from the path. In its
place, an xmlrpc fault.InvalidProductName is returned.

This is trapped and and returned as a PermissionDenied fault, as that is the
only fault that we return in order to avoid the bzr client being "clever" by
suggesting --create-prrefix or other solutions be tried.

Also: updated InvalidProductIdentifier to be InvalidProductName--there's no
reason to have two separate names for the same error.

Tests were written, which required adding a clause to check if the product
name is valid an if not raise the expected error in the InMemory backend. I
confess I can't figure out the purpose of the inmemory backend, as it seems to
be a mock of some sort but we test everything directly against the db.

Tests
=====
bin/test -vvct test_createBranch_invalid_product

QA
==
Attempt to push a branch to fiz:bar/trunk on qastaging. You should get back a
permission denied error about the branch being an invalid name, rather than an
unexpected error dump.

LoC
===
I have ~300 LoC of credit.

Lint
====

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/xmlrpc/faults.py
  lib/lp/code/xmlrpc/codehosting.py
  lib/lp/code/xmlrpc/tests/test_codehosting.py
  lib/lp/xmlrpc/configure.zcml
  lib/lp/codehosting/vfs/branchfs.py
  lib/lp/codehosting/inmemory.py
  lib/lp/code/model/tests/test_branchlookup.py
  lib/lp/code/xmlrpc/branch.py

To post a comment you must log in.
Curtis Hovey (sinzui) wrote :

Thank you.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/model/tests/test_branchlookup.py'
2--- lib/lp/code/model/tests/test_branchlookup.py 2012-09-18 18:36:09 +0000
3+++ lib/lp/code/model/tests/test_branchlookup.py 2012-11-01 15:14:20 +0000
4@@ -446,7 +446,7 @@
5 self.assertRaises(NoSuchProduct, self.traverser.traverse, 'bb')
6
7 def test_invalid_product(self):
8- # `traverse` raises `InvalidProductIdentifier` when resolving an lp
9+ # `traverse` raises `InvalidProductName` when resolving an lp
10 # path for a completely invalid product development focus branch.
11 self.assertRaises(
12 InvalidProductName, self.traverser.traverse, 'b')
13
14=== modified file 'lib/lp/code/xmlrpc/branch.py'
15--- lib/lp/code/xmlrpc/branch.py 2012-07-04 18:06:32 +0000
16+++ lib/lp/code/xmlrpc/branch.py 2012-11-01 15:14:20 +0000
17@@ -304,7 +304,7 @@
18 # the model code(blech) or some automated way of reraising as faults
19 # or using a narrower range of faults (e.g. only one "NoSuch" fault).
20 except InvalidProductName as e:
21- raise faults.InvalidProductIdentifier(urlutils.escape(e.name))
22+ raise faults.InvalidProductName(urlutils.escape(e.name))
23 except NoSuchProductSeries as e:
24 raise faults.NoSuchProductSeries(
25 urlutils.escape(e.name), e.product)
26
27=== modified file 'lib/lp/code/xmlrpc/codehosting.py'
28--- lib/lp/code/xmlrpc/codehosting.py 2012-07-24 06:39:54 +0000
29+++ lib/lp/code/xmlrpc/codehosting.py 2012-11-01 15:14:20 +0000
30@@ -65,7 +65,10 @@
31 IPersonSet,
32 NoSuchPerson,
33 )
34-from lp.registry.interfaces.product import NoSuchProduct
35+from lp.registry.interfaces.product import (
36+ NoSuchProduct,
37+ InvalidProductName,
38+ )
39 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
40 from lp.services.scripts.interfaces.scriptactivity import IScriptActivitySet
41 from lp.services.webapp import LaunchpadXMLRPCView
42@@ -219,6 +222,8 @@
43 except NoSuchProduct as e:
44 return faults.NotFound(
45 "Project '%s' does not exist." % e.name)
46+ except InvalidProductName as e:
47+ return faults.InvalidProductName(escape(e.name))
48 except NoSuchSourcePackageName as e:
49 try:
50 getUtility(ISourcePackageNameSet).new(e.name)
51
52=== modified file 'lib/lp/code/xmlrpc/tests/test_codehosting.py'
53--- lib/lp/code/xmlrpc/tests/test_codehosting.py 2012-09-18 19:41:02 +0000
54+++ lib/lp/code/xmlrpc/tests/test_codehosting.py 2012-11-01 15:14:20 +0000
55@@ -297,6 +297,16 @@
56 owner.id, escape('/~%s/no-such-product/%s' % (owner.name, name)))
57 self.assertEqual(faults.NotFound(message), fault)
58
59+ def test_createBranch_invalid_product(self):
60+ # Creating a branch with an invalid product name fails.
61+ owner = self.factory.makePerson()
62+ name = self.factory.getUniqueString()
63+ from lp.code.interfaces.codehosting import BRANCH_ALIAS_PREFIX
64+ branch_name = "/%s/fiz:buzz/%s" % (BRANCH_ALIAS_PREFIX, name)
65+ fault = self.codehosting_api.createBranch(
66+ owner.id, branch_name)
67+ self.assertEqual(faults.InvalidProductName(escape('fiz:buzz')), fault)
68+
69 def test_createBranch_other_user(self):
70 # Creating a branch under another user's directory fails.
71 creator = self.factory.makePerson()
72
73=== modified file 'lib/lp/codehosting/inmemory.py'
74--- lib/lp/codehosting/inmemory.py 2012-09-19 01:19:35 +0000
75+++ lib/lp/codehosting/inmemory.py 2012-11-01 15:14:20 +0000
76@@ -651,6 +651,8 @@
77 if data['product'] == '+junk':
78 product = None
79 elif data['product'] is not None:
80+ if not valid_name(data['product']):
81+ raise faults.InvalidProductName(escape(data['product']))
82 product = self._product_set.getByName(data['product'])
83 if product is None:
84 raise faults.NotFound(
85
86=== modified file 'lib/lp/codehosting/vfs/branchfs.py'
87--- lib/lp/codehosting/vfs/branchfs.py 2012-07-05 14:53:47 +0000
88+++ lib/lp/codehosting/vfs/branchfs.py 2012-11-01 15:14:20 +0000
89@@ -607,7 +607,7 @@
90 # parent directories", which is just misleading.
91 fault = trap_fault(
92 fail, faults.NotFound, faults.PermissionDenied,
93- faults.InvalidSourcePackageName)
94+ faults.InvalidSourcePackageName, faults.InvalidProductName)
95 faultString = fault.faultString
96 if isinstance(faultString, unicode):
97 faultString = faultString.encode('utf-8')
98
99=== modified file 'lib/lp/xmlrpc/configure.zcml'
100--- lib/lp/xmlrpc/configure.zcml 2012-01-20 06:58:13 +0000
101+++ lib/lp/xmlrpc/configure.zcml 2012-11-01 15:14:20 +0000
102@@ -150,7 +150,7 @@
103 <require like_class="xmlrpclib.Fault" />
104 </class>
105
106- <class class="lp.xmlrpc.faults.InvalidProductIdentifier">
107+ <class class="lp.xmlrpc.faults.InvalidProductName">
108 <require like_class="xmlrpclib.Fault" />
109 </class>
110
111
112=== modified file 'lib/lp/xmlrpc/faults.py'
113--- lib/lp/xmlrpc/faults.py 2012-01-20 06:58:13 +0000
114+++ lib/lp/xmlrpc/faults.py 2012-11-01 15:14:20 +0000
115@@ -20,7 +20,7 @@
116 'InvalidBranchIdentifier',
117 'InvalidBranchName',
118 'InvalidBranchUniqueName',
119- 'InvalidProductIdentifier',
120+ 'InvalidProductName',
121 'InvalidBranchUrl',
122 'InvalidSourcePackageName',
123 'OopsOccurred',
124@@ -294,7 +294,7 @@
125 component_type=component_type)
126
127
128-class InvalidProductIdentifier(LaunchpadFault):
129+class InvalidProductName(LaunchpadFault):
130 """Raised when we are passed an invalid name for a product.
131
132 This is for when users try to specify a product using a silly name