Merge lp:~milo/linaro-ci-dashboard/simple-mock into lp:linaro-ci-dashboard
- simple-mock
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Stevan Radaković |
Approved revision: | 50 |
Merged at revision: | 50 |
Proposed branch: | lp:~milo/linaro-ci-dashboard/simple-mock |
Merge into: | lp:linaro-ci-dashboard |
Diff against target: |
650 lines (+328/-152) 12 files modified
Makefile (+2/-2) dashboard/frontend/android_build/tests/test_android_build_views.py (+9/-15) dashboard/frontend/android_textfield_loop/tests/test_android_textfield_views.py (+9/-9) dashboard/frontend/integration_loop/tests/__init__.py (+27/-0) dashboard/frontend/integration_loop/tests/test_integration_loop_clientresponse.py (+75/-0) dashboard/frontend/integration_loop/tests/test_integration_loop_views.py (+56/-0) dashboard/frontend/kernel_build/tests/test_kernel_build_views.py (+9/-13) dashboard/frontend/tests/__init__.py (+0/-3) dashboard/frontend/tests/loop_mock.py (+125/-0) dashboard/frontend/tests/test_clientresponse.py (+0/-54) dashboard/frontend/tests/test_views.py (+15/-53) dashboard/frontend/views/loop_detail_view.py (+1/-3) |
To merge this branch: | bzr merge lp:~milo/linaro-ci-dashboard/simple-mock |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stevan Radaković | Approve | ||
Linaro Infrastructure | Pending | ||
Review via email:
|
Commit message
Description of the change
In this branch I worked out a little issue we had when running the tests. Basically, with the new refactoring of the views, we are looking for objects with the query 'Loop.objects.get' that accepts parameters (in our case the primary key). The problem is that during the test we mock the other objects present in the view, so the primary key during the test is not a valid primary key for the query set.
Here I introduced a couple of very simple mocks, Python classes that inherits from MagicMock, that mimicks a Loop instance, the 'Loop.objects' query, the '_meta' field and a generic 'field'.
I refactored the tests in order to use the new mocks, and also moved the integration_loop tests under the integration_loop sub-app (before they were under the frontend main app).
Preview Diff
1 | === modified file 'Makefile' | |||
2 | --- Makefile 2012-09-10 16:49:11 +0000 | |||
3 | +++ Makefile 2012-09-14 08:22:19 +0000 | |||
4 | @@ -33,7 +33,7 @@ | |||
5 | 33 | 33 | ||
6 | 34 | test: | 34 | test: |
7 | 35 | python dashboard/manage.py jenkins start | 35 | python dashboard/manage.py jenkins start |
10 | 36 | python dashboard/manage.py test frontend android_build kernel_build \ | 36 | python dashboard/manage.py test frontend android_build integration_loop \ |
11 | 37 | android_textfield_loop jenkinsserver | 37 | kernel_build android_textfield_loop jenkinsserver |
12 | 38 | 38 | ||
13 | 39 | .PHONY: help migration test | 39 | .PHONY: help migration test |
14 | 40 | 40 | ||
15 | === modified file 'dashboard/frontend/android_build/tests/test_android_build_views.py' | |||
16 | --- dashboard/frontend/android_build/tests/test_android_build_views.py 2012-09-12 14:31:41 +0000 | |||
17 | +++ dashboard/frontend/android_build/tests/test_android_build_views.py 2012-09-14 08:22:19 +0000 | |||
18 | @@ -14,8 +14,6 @@ | |||
19 | 14 | # | 14 | # |
20 | 15 | # You should have received a copy of the GNU Affero General Public License | 15 | # You should have received a copy of the GNU Affero General Public License |
21 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
22 | 17 | from django.test import TestCase | ||
23 | 18 | from mock import MagicMock | ||
24 | 19 | 17 | ||
25 | 20 | from frontend.android_build.views.android_loop_create_view \ | 18 | from frontend.android_build.views.android_loop_create_view \ |
26 | 21 | import AndroidLoopCreateView | 19 | import AndroidLoopCreateView |
27 | @@ -23,18 +21,13 @@ | |||
28 | 23 | import AndroidLoopDetailView | 21 | import AndroidLoopDetailView |
29 | 24 | from frontend.android_build.views.android_loop_update_view\ | 22 | from frontend.android_build.views.android_loop_update_view\ |
30 | 25 | import AndroidLoopUpdateView | 23 | import AndroidLoopUpdateView |
43 | 26 | 24 | from frontend.tests.test_views import ( | |
44 | 27 | 25 | ViewsTestsGeneral, | |
45 | 28 | class AndroidBuildViewsTest(TestCase): | 26 | LoopMock |
46 | 29 | 27 | ) | |
47 | 30 | def setUp(self): | 28 | |
48 | 31 | self.mock_loop = MagicMock() | 29 | |
49 | 32 | self.mock_loop.loop_ptr = MagicMock() | 30 | class AndroidBuildViewsTest(ViewsTestsGeneral): |
38 | 33 | self.mock_loop.loop_ptr.id = 0 | ||
39 | 34 | self.mock_loop.loop_ptr.loopbuild_set = MagicMock() | ||
40 | 35 | self.mock_loop.loop_ptr.loopbuild_set.all = MagicMock() | ||
41 | 36 | self.mock_loop.next_loop = MagicMock() | ||
42 | 37 | self.mock_loop.next_loop.id = 1 | ||
50 | 38 | 31 | ||
51 | 39 | def test_create_view_get_context_data(self): | 32 | def test_create_view_get_context_data(self): |
52 | 40 | android_loop_create_view = AndroidLoopCreateView() | 33 | android_loop_create_view = AndroidLoopCreateView() |
53 | @@ -51,7 +44,8 @@ | |||
54 | 51 | context = AndroidLoopDetailView.get_context_data( | 44 | context = AndroidLoopDetailView.get_context_data( |
55 | 52 | android_loop_detail_view) | 45 | android_loop_detail_view) |
56 | 53 | self.assertEqual(context['request'], "some request data") | 46 | self.assertEqual(context['request'], "some request data") |
58 | 54 | self.assertEqual(context['builds'].__class__.__name__, "MagicMock") | 47 | self.assertEqual(context['builds'].__class__.__name__, |
59 | 48 | LoopMock.__name__) | ||
60 | 55 | 49 | ||
61 | 56 | def test_update_view_get_context_data(self): | 50 | def test_update_view_get_context_data(self): |
62 | 57 | android_loop_update_view = AndroidLoopUpdateView() | 51 | android_loop_update_view = AndroidLoopUpdateView() |
63 | 58 | 52 | ||
64 | === modified file 'dashboard/frontend/android_textfield_loop/tests/test_android_textfield_views.py' | |||
65 | --- dashboard/frontend/android_textfield_loop/tests/test_android_textfield_views.py 2012-09-10 07:45:21 +0000 | |||
66 | +++ dashboard/frontend/android_textfield_loop/tests/test_android_textfield_views.py 2012-09-14 08:22:19 +0000 | |||
67 | @@ -14,8 +14,6 @@ | |||
68 | 14 | # | 14 | # |
69 | 15 | # You should have received a copy of the GNU Affero General Public License | 15 | # You should have received a copy of the GNU Affero General Public License |
70 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
71 | 17 | from django.test import TestCase | ||
72 | 18 | from mock import MagicMock | ||
73 | 19 | 17 | ||
74 | 20 | from frontend.android_textfield_loop.views.android_textfield_loop_create_view \ | 18 | from frontend.android_textfield_loop.views.android_textfield_loop_create_view \ |
75 | 21 | import AndroidTextFieldLoopCreateView | 19 | import AndroidTextFieldLoopCreateView |
76 | @@ -23,12 +21,13 @@ | |||
77 | 23 | import AndroidTextFieldLoopDetailView | 21 | import AndroidTextFieldLoopDetailView |
78 | 24 | from frontend.android_textfield_loop.views.android_textfield_loop_update_view \ | 22 | from frontend.android_textfield_loop.views.android_textfield_loop_update_view \ |
79 | 25 | import AndroidTextFieldLoopUpdateView | 23 | import AndroidTextFieldLoopUpdateView |
86 | 26 | 24 | from frontend.tests.test_views import ( | |
87 | 27 | 25 | ViewsTestsGeneral, | |
88 | 28 | class AndroidTextFieldViewsTest(TestCase): | 26 | LoopMock, |
89 | 29 | 27 | ) | |
90 | 30 | def setUp(self): | 28 | |
91 | 31 | self.mock_loop = MagicMock() | 29 | |
92 | 30 | class AndroidTextFieldViewsTest(ViewsTestsGeneral): | ||
93 | 32 | 31 | ||
94 | 33 | def test_create_view_get_context_data(self): | 32 | def test_create_view_get_context_data(self): |
95 | 34 | android_textfield_create_view = AndroidTextFieldLoopCreateView() | 33 | android_textfield_create_view = AndroidTextFieldLoopCreateView() |
96 | @@ -45,7 +44,8 @@ | |||
97 | 45 | context = AndroidTextFieldLoopDetailView.get_context_data( | 44 | context = AndroidTextFieldLoopDetailView.get_context_data( |
98 | 46 | android_textfield_detail_view) | 45 | android_textfield_detail_view) |
99 | 47 | self.assertEqual(context['request'], "some request data") | 46 | self.assertEqual(context['request'], "some request data") |
101 | 48 | self.assertEqual(context['builds'].__class__.__name__, "MagicMock") | 47 | self.assertEqual(context['builds'].__class__.__name__, |
102 | 48 | LoopMock.__name__) | ||
103 | 49 | 49 | ||
104 | 50 | def test_update_view_get_context_data(self): | 50 | def test_update_view_get_context_data(self): |
105 | 51 | android_textfield_update_view = AndroidTextFieldLoopUpdateView() | 51 | android_textfield_update_view = AndroidTextFieldLoopUpdateView() |
106 | 52 | 52 | ||
107 | === added directory 'dashboard/frontend/integration_loop/tests' | |||
108 | === added file 'dashboard/frontend/integration_loop/tests/__init__.py' | |||
109 | --- dashboard/frontend/integration_loop/tests/__init__.py 1970-01-01 00:00:00 +0000 | |||
110 | +++ dashboard/frontend/integration_loop/tests/__init__.py 2012-09-14 08:22:19 +0000 | |||
111 | @@ -0,0 +1,27 @@ | |||
112 | 1 | # Copyright (C) 2012 Linaro | ||
113 | 2 | # | ||
114 | 3 | # This file is part of linaro-ci-dashboard. | ||
115 | 4 | # | ||
116 | 5 | # linaro-ci-dashboard is free software: you can redistribute it and/or modify | ||
117 | 6 | # it under the terms of the GNU Affero General Public License as published by | ||
118 | 7 | # the Free Software Foundation, either version 3 of the License, or | ||
119 | 8 | # (at your option) any later version. | ||
120 | 9 | # | ||
121 | 10 | # linaro-ci-dashboard is distributed in the hope that it will be useful, | ||
122 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
123 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
124 | 13 | # GNU Affero General Public License for more details. | ||
125 | 14 | # | ||
126 | 15 | # You should have received a copy of the GNU Affero General Public License | ||
127 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | ||
128 | 17 | |||
129 | 18 | from dashboard.frontend.integration_loop.tests.test_integration_loop_views \ | ||
130 | 19 | import * | ||
131 | 20 | from dashboard.frontend.integration_loop.tests.\ | ||
132 | 21 | test_integration_loop_clientresponse import * | ||
133 | 22 | |||
134 | 23 | |||
135 | 24 | __test__ = { | ||
136 | 25 | 'IntegrationLoopViewsTest': IntegrationLoopViewsTest, | ||
137 | 26 | 'IntegrationLoopClientresponseTest': IntegrationLoopClientresponseTest, | ||
138 | 27 | } | ||
139 | 0 | \ No newline at end of file | 28 | \ No newline at end of file |
140 | 1 | 29 | ||
141 | === added file 'dashboard/frontend/integration_loop/tests/test_integration_loop_clientresponse.py' | |||
142 | --- dashboard/frontend/integration_loop/tests/test_integration_loop_clientresponse.py 1970-01-01 00:00:00 +0000 | |||
143 | +++ dashboard/frontend/integration_loop/tests/test_integration_loop_clientresponse.py 2012-09-14 08:22:19 +0000 | |||
144 | @@ -0,0 +1,75 @@ | |||
145 | 1 | # Copyright (C) 2012 Linaro | ||
146 | 2 | # | ||
147 | 3 | # This file is part of linaro-ci-dashboard. | ||
148 | 4 | # | ||
149 | 5 | # linaro-ci-dashboard is free software: you can redistribute it and/or modify | ||
150 | 6 | # it under the terms of the GNU Affero General Public License as published by | ||
151 | 7 | # the Free Software Foundation, either version 3 of the License, or | ||
152 | 8 | # (at your option) any later version. | ||
153 | 9 | # | ||
154 | 10 | # linaro-ci-dashboard is distributed in the hope that it will be useful, | ||
155 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
156 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
157 | 13 | # GNU Affero General Public License for more details. | ||
158 | 14 | # | ||
159 | 15 | # You should have received a copy of the GNU Affero General Public License | ||
160 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | ||
161 | 17 | |||
162 | 18 | import urllib | ||
163 | 19 | from frontend.tests.test_clientresponse import ClientResponseTestsGeneral | ||
164 | 20 | |||
165 | 21 | |||
166 | 22 | class IntegrationLoopClientresponseTest(ClientResponseTestsGeneral): | ||
167 | 23 | |||
168 | 24 | def setUp(self): | ||
169 | 25 | super(IntegrationLoopClientresponseTest, self).setUp() | ||
170 | 26 | self.integration_loop_data = {"name": "testjob", | ||
171 | 27 | "branch": "lp:linaro-ci-dashboard", | ||
172 | 28 | "precommand": "make migrate", | ||
173 | 29 | "command": "make test", | ||
174 | 30 | "next_loop_0": "", | ||
175 | 31 | } | ||
176 | 32 | |||
177 | 33 | def test_integration_loop_create_get(self): | ||
178 | 34 | self.client.login(username=self.user, password=self.passwd) | ||
179 | 35 | response = self.client.get("/integration_loop/create/") | ||
180 | 36 | self.assertIn("/integration_loop/create/", response.content) | ||
181 | 37 | template_names = [template.name for template in | ||
182 | 38 | response.templates] | ||
183 | 39 | self.assertEquals(template_names, ["integration_loop_create.html", | ||
184 | 40 | "loop_create.html", | ||
185 | 41 | "base.html", | ||
186 | 42 | "login.html", | ||
187 | 43 | ]) | ||
188 | 44 | |||
189 | 45 | def test_integration_loop_create_post_no_data(self): | ||
190 | 46 | self.client.login(username=self.user, password=self.passwd) | ||
191 | 47 | response = self.client.post("/integration_loop/create/", {}) | ||
192 | 48 | self.assertEquals(response.status_code, 200) | ||
193 | 49 | self.assertIn("This field is required", response.content) | ||
194 | 50 | |||
195 | 51 | def test_integration_loop_create_post(self): | ||
196 | 52 | self.client.login(username=self.user, password=self.passwd) | ||
197 | 53 | |||
198 | 54 | # Follow redirect after save. | ||
199 | 55 | response = self.client.post("/integration_loop/create/", | ||
200 | 56 | self.integration_loop_data, follow=True) | ||
201 | 57 | # Assert response code. | ||
202 | 58 | self.assertEquals(response.status_code, 200) | ||
203 | 59 | # Assert redirect chain. | ||
204 | 60 | self.assertEquals(response.redirect_chain[0][1], 302) | ||
205 | 61 | self.assertIn(urllib.quote(self.integration_loop_data["name"]), | ||
206 | 62 | response.redirect_chain[0][0]) | ||
207 | 63 | # Assert template names for detail page. | ||
208 | 64 | template_names = [template.name for template in | ||
209 | 65 | response.templates] | ||
210 | 66 | self.assertEquals(template_names, ["loop_detail.html", | ||
211 | 67 | "base.html", | ||
212 | 68 | "login.html", | ||
213 | 69 | ]) | ||
214 | 70 | # Assert if everything is present on detail page. | ||
215 | 71 | self.assertIn(self.integration_loop_data["name"], response.content) | ||
216 | 72 | self.assertIn(self.integration_loop_data["branch"], response.content) | ||
217 | 73 | self.assertIn(self.integration_loop_data["precommand"], | ||
218 | 74 | response.content) | ||
219 | 75 | self.assertIn(self.integration_loop_data["command"], response.content) | ||
220 | 0 | \ No newline at end of file | 76 | \ No newline at end of file |
221 | 1 | 77 | ||
222 | === added file 'dashboard/frontend/integration_loop/tests/test_integration_loop_views.py' | |||
223 | --- dashboard/frontend/integration_loop/tests/test_integration_loop_views.py 1970-01-01 00:00:00 +0000 | |||
224 | +++ dashboard/frontend/integration_loop/tests/test_integration_loop_views.py 2012-09-14 08:22:19 +0000 | |||
225 | @@ -0,0 +1,56 @@ | |||
226 | 1 | # Copyright (C) 2012 Linaro | ||
227 | 2 | # | ||
228 | 3 | # This file is part of linaro-ci-dashboard. | ||
229 | 4 | # | ||
230 | 5 | # linaro-ci-dashboard is free software: you can redistribute it and/or modify | ||
231 | 6 | # it under the terms of the GNU Affero General Public License as published by | ||
232 | 7 | # the Free Software Foundation, either version 3 of the License, or | ||
233 | 8 | # (at your option) any later version. | ||
234 | 9 | # | ||
235 | 10 | # linaro-ci-dashboard is distributed in the hope that it will be useful, | ||
236 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
237 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
238 | 13 | # GNU Affero General Public License for more details. | ||
239 | 14 | # | ||
240 | 15 | # You should have received a copy of the GNU Affero General Public License | ||
241 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | ||
242 | 17 | |||
243 | 18 | from frontend.integration_loop.views.integration_loop_create_view \ | ||
244 | 19 | import IntegrationLoopCreateView | ||
245 | 20 | from frontend.integration_loop.views.integration_loop_update_view \ | ||
246 | 21 | import IntegrationLoopUpdateView | ||
247 | 22 | from frontend.integration_loop.views.integration_loop_detail_view \ | ||
248 | 23 | import IntegrationLoopDetailView | ||
249 | 24 | from frontend.tests.test_views import ( | ||
250 | 25 | ViewsTestsGeneral, | ||
251 | 26 | LoopMock, | ||
252 | 27 | ) | ||
253 | 28 | |||
254 | 29 | |||
255 | 30 | class IntegrationLoopViewsTest(ViewsTestsGeneral): | ||
256 | 31 | |||
257 | 32 | def test_create_view_get_context_data(self): | ||
258 | 33 | integration_loop_create_view = IntegrationLoopCreateView() | ||
259 | 34 | integration_loop_create_view.request = "some request data" | ||
260 | 35 | integration_loop_create_view.object = self.mock_loop | ||
261 | 36 | context = IntegrationLoopCreateView.get_context_data( | ||
262 | 37 | integration_loop_create_view) | ||
263 | 38 | self.assertEqual(context['request'], "some request data") | ||
264 | 39 | |||
265 | 40 | def test_detail_view_get_context_data(self): | ||
266 | 41 | integration_loop_detail_view = IntegrationLoopDetailView() | ||
267 | 42 | integration_loop_detail_view.request = "some request data" | ||
268 | 43 | integration_loop_detail_view.object = self.mock_loop | ||
269 | 44 | context = IntegrationLoopDetailView.get_context_data( | ||
270 | 45 | integration_loop_detail_view) | ||
271 | 46 | self.assertEqual(context['request'], "some request data") | ||
272 | 47 | self.assertEqual(context['builds'].__class__.__name__, | ||
273 | 48 | LoopMock.__name__) | ||
274 | 49 | |||
275 | 50 | def test_update_view_get_context_data(self): | ||
276 | 51 | integration_loop_update_view = IntegrationLoopUpdateView() | ||
277 | 52 | integration_loop_update_view.request = "some request data" | ||
278 | 53 | integration_loop_update_view.object = self.mock_loop | ||
279 | 54 | context = IntegrationLoopUpdateView.get_context_data( | ||
280 | 55 | integration_loop_update_view) | ||
281 | 56 | self.assertEqual(context['request'], "some request data") | ||
282 | 0 | 57 | ||
283 | === modified file 'dashboard/frontend/kernel_build/tests/test_kernel_build_views.py' | |||
284 | --- dashboard/frontend/kernel_build/tests/test_kernel_build_views.py 2012-08-23 11:22:21 +0000 | |||
285 | +++ dashboard/frontend/kernel_build/tests/test_kernel_build_views.py 2012-09-14 08:22:19 +0000 | |||
286 | @@ -14,8 +14,6 @@ | |||
287 | 14 | # | 14 | # |
288 | 15 | # You should have received a copy of the GNU Affero General Public License | 15 | # You should have received a copy of the GNU Affero General Public License |
289 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
290 | 17 | from django.test import TestCase | ||
291 | 18 | from mock import MagicMock | ||
292 | 19 | 17 | ||
293 | 20 | from frontend.kernel_build.views.kernel_loop_create_view \ | 18 | from frontend.kernel_build.views.kernel_loop_create_view \ |
294 | 21 | import KernelLoopCreateView | 19 | import KernelLoopCreateView |
295 | @@ -23,16 +21,13 @@ | |||
296 | 23 | import KernelLoopDetailView | 21 | import KernelLoopDetailView |
297 | 24 | from frontend.kernel_build.views.kernel_loop_update_view\ | 22 | from frontend.kernel_build.views.kernel_loop_update_view\ |
298 | 25 | import KernelLoopUpdateView | 23 | import KernelLoopUpdateView |
309 | 26 | 24 | from frontend.tests.test_views import ( | |
310 | 27 | 25 | ViewsTestsGeneral, | |
311 | 28 | class KernelBuildViewsTest(TestCase): | 26 | LoopMock, |
312 | 29 | 27 | ) | |
313 | 30 | def setUp(self): | 28 | |
314 | 31 | self.mock_loop = MagicMock() | 29 | |
315 | 32 | self.mock_loop.loop_ptr = MagicMock() | 30 | class KernelBuildViewsTest(ViewsTestsGeneral): |
306 | 33 | self.mock_loop.loop_ptr.id = 0 | ||
307 | 34 | self.mock_loop.loop_ptr.loopbuild_set = MagicMock() | ||
308 | 35 | self.mock_loop.loop_ptr.loopbuild_set.all = MagicMock() | ||
316 | 36 | 31 | ||
317 | 37 | def test_create_view_get_context_data(self): | 32 | def test_create_view_get_context_data(self): |
318 | 38 | kernel_loop_create_view = KernelLoopCreateView() | 33 | kernel_loop_create_view = KernelLoopCreateView() |
319 | @@ -49,7 +44,8 @@ | |||
320 | 49 | context = KernelLoopDetailView.get_context_data( | 44 | context = KernelLoopDetailView.get_context_data( |
321 | 50 | kernel_loop_detail_view) | 45 | kernel_loop_detail_view) |
322 | 51 | self.assertEqual(context['request'], "some request data") | 46 | self.assertEqual(context['request'], "some request data") |
324 | 52 | self.assertEqual(context['builds'].__class__.__name__, "MagicMock") | 47 | self.assertEqual(context['builds'].__class__.__name__, |
325 | 48 | LoopMock.__name__) | ||
326 | 53 | 49 | ||
327 | 54 | def test_update_view_get_context_data(self): | 50 | def test_update_view_get_context_data(self): |
328 | 55 | kernel_loop_update_view = KernelLoopUpdateView() | 51 | kernel_loop_update_view = KernelLoopUpdateView() |
329 | 56 | 52 | ||
330 | === modified file 'dashboard/frontend/tests/__init__.py' | |||
331 | --- dashboard/frontend/tests/__init__.py 2012-09-05 17:32:44 +0000 | |||
332 | +++ dashboard/frontend/tests/__init__.py 2012-09-14 08:22:19 +0000 | |||
333 | @@ -9,9 +9,6 @@ | |||
334 | 9 | __test__ = { | 9 | __test__ = { |
335 | 10 | 'HomePageViewTests': HomePageViewTest, | 10 | 'HomePageViewTests': HomePageViewTest, |
336 | 11 | 'IndexViewTests': IndexViewTest, | 11 | 'IndexViewTests': IndexViewTest, |
337 | 12 | 'IntegrationLoopCreateViewTests': IntegrationLoopCreateViewTest, | ||
338 | 13 | 'IntegrationLoopDetailViewTests': IntegrationLoopDetailViewTest, | ||
339 | 14 | 'IntegrationLoopUpdateViewTests': IntegrationLoopUpdateViewTest, | ||
340 | 15 | 'LoopTests': LoopTest, | 12 | 'LoopTests': LoopTest, |
341 | 16 | 'ClientResponseTests': ClientResponseTests, | 13 | 'ClientResponseTests': ClientResponseTests, |
342 | 17 | 'JenkinsCommandTest': JenkinsCommandTest, | 14 | 'JenkinsCommandTest': JenkinsCommandTest, |
343 | 18 | 15 | ||
344 | === added file 'dashboard/frontend/tests/loop_mock.py' | |||
345 | --- dashboard/frontend/tests/loop_mock.py 1970-01-01 00:00:00 +0000 | |||
346 | +++ dashboard/frontend/tests/loop_mock.py 2012-09-14 08:22:19 +0000 | |||
347 | @@ -0,0 +1,125 @@ | |||
348 | 1 | # Copyright (C) 2012 Linaro | ||
349 | 2 | # | ||
350 | 3 | # This file is part of linaro-ci-dashboard. | ||
351 | 4 | # | ||
352 | 5 | # linaro-ci-dashboard is free software: you can redistribute it and/or modify | ||
353 | 6 | # it under the terms of the GNU Affero General Public License as published by | ||
354 | 7 | # the Free Software Foundation, either version 3 of the License, or | ||
355 | 8 | # (at your option) any later version. | ||
356 | 9 | # | ||
357 | 10 | # linaro-ci-dashboard is distributed in the hope that it will be useful, | ||
358 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
359 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
360 | 13 | # GNU Affero General Public License for more details. | ||
361 | 14 | # | ||
362 | 15 | # You should have received a copy of the GNU Affero General Public License | ||
363 | 16 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | ||
364 | 17 | |||
365 | 18 | from mock import MagicMock | ||
366 | 19 | |||
367 | 20 | |||
368 | 21 | class ObjectsMock(MagicMock): | ||
369 | 22 | """ | ||
370 | 23 | This mock represents the 'objects' queryset of a Django model. It is | ||
371 | 24 | basically used to mock access like 'MODEL.objects' when looking up | ||
372 | 25 | a specific model. | ||
373 | 26 | """ | ||
374 | 27 | def __init__(self, *args, **kwargs): | ||
375 | 28 | super(ObjectsMock, self).__init__(*args, **kwargs) | ||
376 | 29 | |||
377 | 30 | def get(self, *args, **kwargs): | ||
378 | 31 | return LoopMock() | ||
379 | 32 | |||
380 | 33 | def all(self): | ||
381 | 34 | return [LoopMock()] | ||
382 | 35 | |||
383 | 36 | |||
384 | 37 | class LoopMock(MagicMock): | ||
385 | 38 | """ | ||
386 | 39 | Class that mocks a generic Loop object. This class should be used when it | ||
387 | 40 | is necessary to pass an actual object. | ||
388 | 41 | """ | ||
389 | 42 | def __init__(self, *args, **kwargs): | ||
390 | 43 | super(LoopMock, self).__init__(*args, **kwargs) | ||
391 | 44 | |||
392 | 45 | @property | ||
393 | 46 | def name(self): | ||
394 | 47 | return self.__class__.__name__ | ||
395 | 48 | |||
396 | 49 | @property | ||
397 | 50 | def type(self): | ||
398 | 51 | return self.__class__.__name__ | ||
399 | 52 | |||
400 | 53 | @property | ||
401 | 54 | def is_restricted(self): | ||
402 | 55 | return False | ||
403 | 56 | |||
404 | 57 | @property | ||
405 | 58 | def is_protected(self): | ||
406 | 59 | return False | ||
407 | 60 | |||
408 | 61 | @property | ||
409 | 62 | def _meta(self): | ||
410 | 63 | return MetaMock() | ||
411 | 64 | |||
412 | 65 | |||
413 | 66 | class MetaMock(MagicMock): | ||
414 | 67 | """ | ||
415 | 68 | Mock class that represents the Meta class of a Django model, accessed via | ||
416 | 69 | the _meta attribute of a model instance. | ||
417 | 70 | """ | ||
418 | 71 | def __init__(self, *args, **kwargs): | ||
419 | 72 | super(MetaMock, self).__init__(*args, **kwargs) | ||
420 | 73 | |||
421 | 74 | @property | ||
422 | 75 | def app_label(self): | ||
423 | 76 | return "label" | ||
424 | 77 | |||
425 | 78 | def get_field(self, name=None): | ||
426 | 79 | """ | ||
427 | 80 | Mocks the get_field method of _meta. | ||
428 | 81 | |||
429 | 82 | :param name: The name of the field to get back. | ||
430 | 83 | :type name str | ||
431 | 84 | :return A FieldMock object mocking a field. | ||
432 | 85 | """ | ||
433 | 86 | return FieldMock(name=name) | ||
434 | 87 | |||
435 | 88 | |||
436 | 89 | class FieldMock(MagicMock): | ||
437 | 90 | """ | ||
438 | 91 | Mock class that represents a field in a class model. | ||
439 | 92 | """ | ||
440 | 93 | def __init__(self, name=None, verbose_name=None, *args, **kwargs): | ||
441 | 94 | """ | ||
442 | 95 | Initialized the field mock. By default, if passed with no arguments, | ||
443 | 96 | the field name and verbose name will be set to the class name. | ||
444 | 97 | |||
445 | 98 | :param name: The name associated with this field. | ||
446 | 99 | :type name str | ||
447 | 100 | :param verbose_name: The verbose name associated with this field. | ||
448 | 101 | :type verbose_name str | ||
449 | 102 | """ | ||
450 | 103 | super(FieldMock, self).__init__(*args, **kwargs) | ||
451 | 104 | if name is not None: | ||
452 | 105 | self._name = name | ||
453 | 106 | else: | ||
454 | 107 | self._name = self.__class__.__name__ | ||
455 | 108 | if verbose_name is not None: | ||
456 | 109 | self._verbose_name = verbose_name | ||
457 | 110 | else: | ||
458 | 111 | self._verbose_name = self.__class__.__name__ | ||
459 | 112 | |||
460 | 113 | @property | ||
461 | 114 | def name(self): | ||
462 | 115 | """ | ||
463 | 116 | :return The name of the field. | ||
464 | 117 | """ | ||
465 | 118 | return self._name | ||
466 | 119 | |||
467 | 120 | @property | ||
468 | 121 | def verbose_name(self): | ||
469 | 122 | """ | ||
470 | 123 | :return The verbose name associated with the field. | ||
471 | 124 | """ | ||
472 | 125 | return self._verbose_name | ||
473 | 0 | 126 | ||
474 | === modified file 'dashboard/frontend/tests/test_clientresponse.py' | |||
475 | --- dashboard/frontend/tests/test_clientresponse.py 2012-09-12 13:15:13 +0000 | |||
476 | +++ dashboard/frontend/tests/test_clientresponse.py 2012-09-14 08:22:19 +0000 | |||
477 | @@ -19,7 +19,6 @@ | |||
478 | 19 | from django.test import TestCase | 19 | from django.test import TestCase |
479 | 20 | from django.contrib.auth.models import User, Group | 20 | from django.contrib.auth.models import User, Group |
480 | 21 | from django.test.client import Client | 21 | from django.test.client import Client |
481 | 22 | import urllib | ||
482 | 23 | 22 | ||
483 | 24 | 23 | ||
484 | 25 | class ClientResponseTestsGeneral(TestCase): | 24 | class ClientResponseTestsGeneral(TestCase): |
485 | @@ -44,15 +43,6 @@ | |||
486 | 44 | 43 | ||
487 | 45 | class ClientResponseTests(ClientResponseTestsGeneral): | 44 | class ClientResponseTests(ClientResponseTestsGeneral): |
488 | 46 | 45 | ||
489 | 47 | def setUp(self): | ||
490 | 48 | super(ClientResponseTests, self).setUp() | ||
491 | 49 | self.integration_loop_data = {"name": "testjob", | ||
492 | 50 | "branch": "lp:linaro-ci-dashboard", | ||
493 | 51 | "precommand": "make migrate", | ||
494 | 52 | "command": "make test", | ||
495 | 53 | "next_loop_0": "", | ||
496 | 54 | } | ||
497 | 55 | |||
498 | 56 | # Test case should fail if the login_required decorator source code | 46 | # Test case should fail if the login_required decorator source code |
499 | 57 | # in index_view.py is removed. | 47 | # in index_view.py is removed. |
500 | 58 | def test_response_index_when_user_not_auth_by_login_required(self): | 48 | def test_response_index_when_user_not_auth_by_login_required(self): |
501 | @@ -74,47 +64,3 @@ | |||
502 | 74 | self.assertIn(str(self.user), response.content) | 64 | self.assertIn(str(self.user), response.content) |
503 | 75 | response = self.client.get('/home/') | 65 | response = self.client.get('/home/') |
504 | 76 | self.assertIn(str(self.user), response.content) | 66 | self.assertIn(str(self.user), response.content) |
505 | 77 | |||
506 | 78 | def test_integration_loop_create_get(self): | ||
507 | 79 | self.client.login(username=self.user, password=self.passwd) | ||
508 | 80 | response = self.client.get("/integration_loop/create/") | ||
509 | 81 | self.assertIn("/integration_loop/create/", response.content) | ||
510 | 82 | template_names = [template.name for template in | ||
511 | 83 | response.templates] | ||
512 | 84 | self.assertEquals(template_names, ["integration_loop_create.html", | ||
513 | 85 | "loop_create.html", | ||
514 | 86 | "base.html", | ||
515 | 87 | "login.html", | ||
516 | 88 | ]) | ||
517 | 89 | |||
518 | 90 | def test_integration_loop_create_post_no_data(self): | ||
519 | 91 | self.client.login(username=self.user, password=self.passwd) | ||
520 | 92 | response = self.client.post("/integration_loop/create/", {}) | ||
521 | 93 | self.assertEquals(response.status_code, 200) | ||
522 | 94 | self.assertIn("This field is required", response.content) | ||
523 | 95 | |||
524 | 96 | def test_integration_loop_create_post(self): | ||
525 | 97 | self.client.login(username=self.user, password=self.passwd) | ||
526 | 98 | |||
527 | 99 | # Follow redirect after save. | ||
528 | 100 | response = self.client.post("/integration_loop/create/", | ||
529 | 101 | self.integration_loop_data, follow=True) | ||
530 | 102 | # Assert response code. | ||
531 | 103 | self.assertEquals(response.status_code, 200) | ||
532 | 104 | # Assert redirect chain. | ||
533 | 105 | self.assertEquals(response.redirect_chain[0][1], 302) | ||
534 | 106 | self.assertIn(urllib.quote(self.integration_loop_data["name"]), | ||
535 | 107 | response.redirect_chain[0][0]) | ||
536 | 108 | # Assert template names for detail page. | ||
537 | 109 | template_names = [template.name for template in | ||
538 | 110 | response.templates] | ||
539 | 111 | self.assertEquals(template_names, ["loop_detail.html", | ||
540 | 112 | "base.html", | ||
541 | 113 | "login.html", | ||
542 | 114 | ]) | ||
543 | 115 | # Assert if everything is present on detail page. | ||
544 | 116 | self.assertIn(self.integration_loop_data["name"], response.content) | ||
545 | 117 | self.assertIn(self.integration_loop_data["branch"], response.content) | ||
546 | 118 | self.assertIn(self.integration_loop_data["precommand"], | ||
547 | 119 | response.content) | ||
548 | 120 | self.assertIn(self.integration_loop_data["command"], response.content) | ||
549 | 121 | 67 | ||
550 | === modified file 'dashboard/frontend/tests/test_views.py' | |||
551 | --- dashboard/frontend/tests/test_views.py 2012-08-16 15:38:48 +0000 | |||
552 | +++ dashboard/frontend/tests/test_views.py 2012-09-14 08:22:19 +0000 | |||
553 | @@ -15,17 +15,25 @@ | |||
554 | 15 | # | 15 | # |
555 | 16 | # You should have received a copy of the GNU Affero General Public License | 16 | # You should have received a copy of the GNU Affero General Public License |
556 | 17 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
557 | 18 | |||
558 | 18 | from django.test import TestCase | 19 | from django.test import TestCase |
559 | 19 | from mock import Mock, patch | ||
560 | 20 | 20 | ||
561 | 21 | from frontend.views.home_page_view import HomePageView | 21 | from frontend.views.home_page_view import HomePageView |
562 | 22 | from frontend.views.index_view import IndexView | 22 | from frontend.views.index_view import IndexView |
569 | 23 | from frontend.integration_loop.views.integration_loop_create_view \ | 23 | from frontend.tests.loop_mock import ( |
570 | 24 | import IntegrationLoopCreateView | 24 | ObjectsMock, |
571 | 25 | from frontend.integration_loop.views.integration_loop_update_view \ | 25 | LoopMock, |
572 | 26 | import IntegrationLoopUpdateView | 26 | ) |
573 | 27 | from frontend.integration_loop.views.integration_loop_detail_view \ | 27 | from frontend.models.loop import Loop |
574 | 28 | import IntegrationLoopDetailView | 28 | |
575 | 29 | |||
576 | 30 | class ViewsTestsGeneral(TestCase): | ||
577 | 31 | def setUp(self): | ||
578 | 32 | self.mock_loop = LoopMock() | ||
579 | 33 | Loop.objects = ObjectsMock() | ||
580 | 34 | |||
581 | 35 | def tearDown(self): | ||
582 | 36 | super(ViewsTestsGeneral, self).tearDown() | ||
583 | 29 | 37 | ||
584 | 30 | 38 | ||
585 | 31 | class HomePageViewTest(TestCase): | 39 | class HomePageViewTest(TestCase): |
586 | @@ -44,49 +52,3 @@ | |||
587 | 44 | index_view.request = "some request data" | 52 | index_view.request = "some request data" |
588 | 45 | context = IndexView.get_context_data(index_view) | 53 | context = IndexView.get_context_data(index_view) |
589 | 46 | self.assertEqual(context['request'], "some request data") | 54 | self.assertEqual(context['request'], "some request data") |
590 | 47 | |||
591 | 48 | |||
592 | 49 | class IntegrationLoopCreateViewTest(TestCase): | ||
593 | 50 | |||
594 | 51 | def setUp(self): | ||
595 | 52 | self.mock_loop = Mock() | ||
596 | 53 | |||
597 | 54 | def test_get_context_data(self): | ||
598 | 55 | integration_loop_create_view = IntegrationLoopCreateView() | ||
599 | 56 | integration_loop_create_view.request = "some request data" | ||
600 | 57 | integration_loop_create_view.object = self.mock_loop | ||
601 | 58 | context = IntegrationLoopCreateView.get_context_data( | ||
602 | 59 | integration_loop_create_view) | ||
603 | 60 | self.assertEqual(context['request'], "some request data") | ||
604 | 61 | |||
605 | 62 | |||
606 | 63 | class IntegrationLoopDetailViewTest(TestCase): | ||
607 | 64 | |||
608 | 65 | def setUp(self): | ||
609 | 66 | self.mock_loop = Mock() | ||
610 | 67 | self.mock_loop.loop_ptr = Mock() | ||
611 | 68 | self.mock_loop.loop_ptr.loopbuild_set = Mock() | ||
612 | 69 | self.mock_loop.loop_ptr.loopbuild_set.all = Mock() | ||
613 | 70 | |||
614 | 71 | def test_get_context_data(self): | ||
615 | 72 | integration_loop_detail_view = IntegrationLoopDetailView() | ||
616 | 73 | integration_loop_detail_view.request = "some request data" | ||
617 | 74 | integration_loop_detail_view.object = self.mock_loop | ||
618 | 75 | context = IntegrationLoopDetailView.get_context_data( | ||
619 | 76 | integration_loop_detail_view) | ||
620 | 77 | self.assertEqual(context['request'], "some request data") | ||
621 | 78 | self.assertEqual(context['builds'].__class__.__name__, "Mock") | ||
622 | 79 | |||
623 | 80 | |||
624 | 81 | class IntegrationLoopUpdateViewTest(TestCase): | ||
625 | 82 | |||
626 | 83 | def setUp(self): | ||
627 | 84 | self.mock_loop = Mock() | ||
628 | 85 | |||
629 | 86 | def test_get_context_data(self): | ||
630 | 87 | integration_loop_update_view = IntegrationLoopUpdateView() | ||
631 | 88 | integration_loop_update_view.request = "some request data" | ||
632 | 89 | integration_loop_update_view.object = self.mock_loop | ||
633 | 90 | context = IntegrationLoopUpdateView.get_context_data( | ||
634 | 91 | integration_loop_update_view) | ||
635 | 92 | self.assertEqual(context['request'], "some request data") | ||
636 | 93 | 55 | ||
637 | === modified file 'dashboard/frontend/views/loop_detail_view.py' | |||
638 | --- dashboard/frontend/views/loop_detail_view.py 2012-09-12 14:31:41 +0000 | |||
639 | +++ dashboard/frontend/views/loop_detail_view.py 2012-09-14 08:22:19 +0000 | |||
640 | @@ -55,9 +55,7 @@ | |||
641 | 55 | field = self.object._meta.get_field('next_loop') | 55 | field = self.object._meta.get_field('next_loop') |
642 | 56 | pk = self.object.next_loop_id | 56 | pk = self.object.next_loop_id |
643 | 57 | verbose_name = field.verbose_name.capitalize() | 57 | verbose_name = field.verbose_name.capitalize() |
647 | 58 | # XXX changed to isinstance, since tests were failing: we need to | 58 | if pk is not None: |
645 | 59 | # mock Loop, not the model variable, in a better way in our tests. | ||
646 | 60 | if isinstance(pk, int): | ||
648 | 61 | # Get the pointer to the object we want to retrieve, and retrieve | 59 | # Get the pointer to the object we want to retrieve, and retrieve |
649 | 62 | # the actual instance. We can do this since all our loops inherits | 60 | # the actual instance. We can do this since all our loops inherits |
650 | 63 | # from the same base class (Loop), and we have the information | 61 | # from the same base class (Loop), and we have the information |
Thanks Milo, it looks great!
Approve +1.