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