Merge lp:~salgado/offspring/make-piston-handlers-privacy-aware into lp:~linaro-automation/offspring/private-builds

Proposed by Guilherme Salgado
Status: Merged
Approved by: James Tunnicliffe
Approved revision: no longer in the source branch.
Merged at revision: 61
Proposed branch: lp:~salgado/offspring/make-piston-handlers-privacy-aware
Merge into: lp:~linaro-automation/offspring/private-builds
Diff against target: 322 lines (+233/-9)
4 files modified
lib/offspring/web/queuemanager/handlers.py (+15/-7)
lib/offspring/web/queuemanager/tests/__init__.py (+1/-0)
lib/offspring/web/queuemanager/tests/factory.py (+4/-2)
lib/offspring/web/queuemanager/tests/test_handlers.py (+213/-0)
To merge this branch: bzr merge lp:~salgado/offspring/make-piston-handlers-privacy-aware
Reviewer Review Type Date Requested Status
James Tunnicliffe (community) Approve
Review via email: mp+79350@code.launchpad.net

Description of the change

Update most of the piston handlers to include private objects the user is allowed to see. There are two handlers that still need to be updated but those will be done in another branch as this one is already of a reasonable size.

To post a comment you must log in.
Revision history for this message
James Tunnicliffe (dooferlad) wrote :

Good stuff.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/offspring/web/queuemanager/handlers.py'
2--- lib/offspring/web/queuemanager/handlers.py 2011-08-13 07:24:06 +0000
3+++ lib/offspring/web/queuemanager/handlers.py 2011-10-13 23:27:26 +0000
4@@ -43,9 +43,11 @@
5 allowed_methods = ('GET')
6
7 def read(self, request, projectName, buildName):
8+ projects = Project.all_objects.accessible_by_user(request.user)
9 try:
10- project = Project.objects.get(pk=projectName)
11- build = BuildResult.objects.get(project=project, name=buildName)
12+ project = projects.get(pk=projectName)
13+ build = BuildResult.all_objects.accessible_by_user(
14+ request.user).get(project=project, name=buildName)
15 except:
16 return rc.NOT_FOUND
17 manifestPath = glob.glob(build.result_directory + '/images/*/*.manifest')[0]
18@@ -56,14 +58,17 @@
19 allowed_methods = ('GET')
20
21 def read(self, request, projectName, buildName):
22+ projects = Project.all_objects.accessible_by_user(request.user)
23+ builds = BuildResult.all_objects.accessible_by_user(request.user)
24 try:
25- project = Project.objects.get(pk=projectName)
26- base_build = BuildResult.objects.get(project=project, name=buildName)
27+ project = projects.get(pk=projectName)
28+ base_build = builds.get(project=project, name=buildName)
29 except:
30 return rc.NOT_FOUND
31 if request.GET.has_key('build'):
32 try:
33- target_build = BuildResult.objects.get(project=project, name=request.GET['build'])
34+ target_build = builds.get(
35+ project=project, name=request.GET['build'])
36 except:
37 return rc.NOT_FOUND
38 else:
39@@ -81,6 +86,7 @@
40 return output
41
42
43+# TODO: Must be made privacy-aware.
44 class ProjectNotificationSubscriptionHandler(BaseHandler):
45 allowed_methods = ('GET', 'POST', 'DELETE')
46 model = ProjectNotificationSubscription
47@@ -138,7 +144,7 @@
48 'reason', 'result', 'notes', 'is_released')
49
50 def read(self, request, projectName=None, buildName=None, builderName=None):
51- results = BuildResult.objects.all()
52+ results = BuildResult.all_objects.accessible_by_user(request.user)
53 if projectName is not None:
54 results = results.filter(project__name=projectName)
55 if buildName is not None:
56@@ -148,6 +154,7 @@
57 return results
58
59
60+# TODO: Must be made privacy-aware.
61 class BuildRequestHandler(BaseHandler):
62 allowed_methods = ('GET', 'POST', 'DELETE')
63 model = BuildRequest
64@@ -217,8 +224,9 @@
65 'created_at', 'published_at', 'status', 'checklist_url', 'notes')
66
67 def read(self, request, projectName):
68+ objects = Release.all_objects.accessible_by_user(request.user)
69 try:
70- releases = Release.objects.filter(build__project__name=projectName)
71+ releases = objects.filter(build__project__name=projectName)
72 except:
73 return rc.NOT_FOUND
74 return releases
75
76=== modified file 'lib/offspring/web/queuemanager/tests/__init__.py'
77--- lib/offspring/web/queuemanager/tests/__init__.py 2011-09-29 19:19:09 +0000
78+++ lib/offspring/web/queuemanager/tests/__init__.py 2011-10-13 23:27:26 +0000
79@@ -1,2 +1,3 @@
80+from .test_handlers import *
81 from .test_models import *
82 from .test_views import *
83
84=== modified file 'lib/offspring/web/queuemanager/tests/factory.py'
85--- lib/offspring/web/queuemanager/tests/factory.py 2011-10-10 14:11:38 +0000
86+++ lib/offspring/web/queuemanager/tests/factory.py 2011-10-13 23:27:26 +0000
87@@ -66,13 +66,15 @@
88 group.save()
89 return group
90
91- def makeBuildResult(self, project=None, name=None, result=None):
92+ def makeBuildResult(self, project=None, name=None, result=None,
93+ builder=None):
94 if name is None:
95 name = self.getUniqueString()
96 if project is None:
97 project = self.makeProject()
98 project.save()
99- result = BuildResult(name=name, project=project, result=result)
100+ result = BuildResult(name=name, project=project, result=result,
101+ builder=builder)
102 result.save()
103 return result
104
105
106=== added file 'lib/offspring/web/queuemanager/tests/test_handlers.py'
107--- lib/offspring/web/queuemanager/tests/test_handlers.py 1970-01-01 00:00:00 +0000
108+++ lib/offspring/web/queuemanager/tests/test_handlers.py 2011-10-13 23:27:26 +0000
109@@ -0,0 +1,213 @@
110+import errno
111+import os
112+
113+from django.contrib.auth import authenticate, login
114+from django.http import HttpRequest, HttpResponse
115+from django.test import TestCase
116+from django.contrib.sessions.middleware import SessionMiddleware
117+
118+from offspring.web.queuemanager.handlers import (
119+ BuildManifestComparisonHandler,
120+ BuildManifestHandler,
121+ BuildResultHandler,
122+ ReleaseHandler,
123+ )
124+from offspring.web.queuemanager.tests.factory import factory
125+
126+
127+class BaseHandlerTestCase(TestCase):
128+
129+ def setUp(self):
130+ super(BaseHandlerTestCase, self).setUp()
131+ self.request = HttpRequest()
132+ self.request.method = 'GET'
133+ # Set request.user and process the request manually using
134+ # SessionMiddleware so that we can use login(request, user) in tests.
135+ self.request.user = None
136+ SessionMiddleware().process_request(self.request)
137+
138+ def _login(self, user):
139+ user = authenticate(username=user.username, password=user.username)
140+ login(self.request, user)
141+ return user
142+
143+
144+class BuildResultHandlerTests(BaseHandlerTestCase):
145+
146+ def test_builds_for_inexistent_project(self):
147+ results = BuildResultHandler().read(
148+ self.request, projectName='not-existent')
149+ self.assertEqual(0, results.count())
150+
151+ def test_inexistent_build(self):
152+ results = BuildResultHandler().read(
153+ self.request, buildName='not-existent')
154+ self.assertEqual(0, results.count())
155+
156+ def test_public_project_builds(self):
157+ # The builds of public projects are visible to anyone.
158+ build = make_build(is_private=False)
159+ self.assertBuildIsVisibleToUser(build, factory.makeUser())
160+
161+ def test_private_project_build_is_visible_to_project_owner(self):
162+ build = make_build(is_private=True)
163+ self.assertBuildIsVisibleToUser(build, build.project.owner)
164+
165+ def test_private_project_builds_invisible_to_user(self):
166+ # If the user has no rights to see a given project, they'll get an
167+ # empty list of builds, just like if the project didn't exist.
168+ build = make_build(is_private=True)
169+ self.assertBuildIsNotVisibleToUser(build, factory.makeUser())
170+
171+ def assertBuildIsVisibleToUser(self, build, user):
172+ """Assert that the given build is visible to the given user."""
173+ user = self._login(user)
174+ handler = BuildResultHandler()
175+
176+ # It is visible when looking at all project builds...
177+ results = handler.read(self.request, projectName=build.project.name)
178+ self.assertEqual(1, results.count())
179+ self.assertEqual([build], list(results))
180+
181+ # when looking at one specific build ...
182+ results = handler.read(self.request, buildName=build.name)
183+ self.assertEqual(1, results.count())
184+ self.assertEqual([build], list(results))
185+
186+ # and when looking at all builds of a builder.
187+ results = handler.read(self.request, builderName=build.builder.name)
188+ self.assertEqual(1, results.count())
189+ self.assertEqual([build], list(results))
190+
191+ def assertBuildIsNotVisibleToUser(self, build, user):
192+ """Assert that the given build is not visible to the given user."""
193+ user = self._login(user)
194+ handler = BuildResultHandler()
195+
196+ # It is *not* visible when looking at all project builds...
197+ results = handler.read(self.request, projectName=build.project.name)
198+ self.assertEqual(0, results.count())
199+
200+ # when looking at one specific build ...
201+ results = handler.read(self.request, buildName=build.name)
202+ self.assertEqual(0, results.count())
203+
204+ # and when looking at all builds of a builder.
205+ results = handler.read(self.request, builderName=build.builder.name)
206+ self.assertEqual(0, results.count())
207+
208+
209+class ReleaseHandlerTests(BaseHandlerTestCase):
210+
211+ def test_public_project_release(self):
212+ release = factory.makeRelease(make_build(is_private=False))
213+ results = ReleaseHandler().read(
214+ self.request, projectName=release.build.project.name)
215+ self.assertEqual(1, results.count())
216+ self.assertEqual([release], list(results))
217+
218+ def test_private_project_release_is_visible_to_owner(self):
219+ release = factory.makeRelease(make_build(is_private=True))
220+ user = self._login(release.build.project.owner)
221+ results = ReleaseHandler().read(
222+ self.request, projectName=release.build.project.name)
223+ self.assertEqual(1, results.count())
224+ self.assertEqual([release], list(results))
225+
226+ def test_private_project_release_is_not_visible_to_others(self):
227+ release = factory.makeRelease(make_build(is_private=True))
228+ user = self._login(factory.makeUser())
229+ results = ReleaseHandler().read(
230+ self.request, projectName=release.build.project.name)
231+ self.assertEqual(0, results.count())
232+
233+
234+class BuildManifestHandlerTests(BaseHandlerTestCase):
235+
236+ def test_public_project_build_manifest(self):
237+ build = make_build(is_private=False)
238+ make_build_manifest_file(build)
239+ results = BuildManifestHandler().read(
240+ self.request, build.project.name, build.name)
241+ self.assertEqual([{'package': 'foo', 'version': '1.2'}], results)
242+
243+ def test_private_project_build_manifest_is_visible_to_owner(self):
244+ build = make_build(is_private=True)
245+ make_build_manifest_file(build)
246+ user = self._login(build.project.owner)
247+ results = BuildManifestHandler().read(
248+ self.request, build.project.name, build.name)
249+ self.assertEqual([{'package': 'foo', 'version': '1.2'}], results)
250+
251+ def test_private_project_build_manifest_returns_404_for_others(self):
252+ build = make_build(is_private=True)
253+ make_build_manifest_file(build)
254+ user = self._login(factory.makeUser())
255+ results = BuildManifestHandler().read(
256+ self.request, build.project.name, build.name)
257+ self.assertTrue(isinstance(results, HttpResponse))
258+ self.assertEqual(404, results.status_code)
259+
260+
261+class BuildManifestComparisonHandlerTests(BaseHandlerTestCase):
262+
263+ def test_public_projects_build_manifest_comparison(self):
264+ build = make_build(is_private=False)
265+ build2 = factory.makeBuildResult(
266+ project=build.project, builder=factory.makeLexbuilder())
267+ make_build_manifest_file(build)
268+ make_build_manifest_file(build2)
269+ self.request.GET['build'] = build2.name
270+ results = BuildManifestComparisonHandler().read(
271+ self.request, build.project.name, build.name)
272+ self.assertEqual(
273+ [{'changeType': 'no_change', 'target_version': '1.2',
274+ 'base_version': '1.2', 'package': 'foo'}],
275+ results)
276+
277+ def test_private_build_manifest_comparison_is_visible_to_owner(self):
278+ build = make_build(is_private=True)
279+ build2 = factory.makeBuildResult(
280+ project=build.project, builder=factory.makeLexbuilder())
281+ make_build_manifest_file(build)
282+ make_build_manifest_file(build2)
283+ user = self._login(build.project.owner)
284+ self.request.GET['build'] = build2.name
285+ results = BuildManifestComparisonHandler().read(
286+ self.request, build.project.name, build.name)
287+ self.assertEqual(
288+ [{'changeType': 'no_change', 'target_version': '1.2',
289+ 'base_version': '1.2', 'package': 'foo'}],
290+ results)
291+
292+ def test_private_build_manifest_comparison_returns_404_for_others(self):
293+ build = make_build(is_private=True)
294+ build2 = factory.makeBuildResult(
295+ project=build.project, builder=factory.makeLexbuilder())
296+ make_build_manifest_file(build)
297+ make_build_manifest_file(build2)
298+ user = self._login(factory.makeUser())
299+ self.request.GET['build'] = build2.name
300+ results = BuildManifestComparisonHandler().read(
301+ self.request, build.project.name, build.name)
302+ self.assertTrue(isinstance(results, HttpResponse))
303+ self.assertEqual(404, results.status_code)
304+
305+
306+def make_build(is_private):
307+ return factory.makeBuildResult(
308+ project=factory.makeProject(is_private=is_private),
309+ builder=factory.makeLexbuilder())
310+
311+
312+def make_build_manifest_file(build):
313+ """Create a manifest file where BuildManifestHandler expects to find it."""
314+ manifest_dir = os.path.join(build.result_directory, 'images', 'build')
315+ try:
316+ os.makedirs(manifest_dir)
317+ except OSError, exc:
318+ if exc.errno != errno.EEXIST:
319+ raise
320+ path = os.path.join(manifest_dir, 'build.manifest')
321+ with open(path, 'w') as fd:
322+ fd.write('foo 1.2')

Subscribers

People subscribed via source and target branches