Merge lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop into lp:linaro-ci-dashboard
- add_ci_job_loop
- Merge into trunk
Proposed by
James Tunnicliffe
Status: | Merged |
---|---|
Merged at revision: | 70 |
Proposed branch: | lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop |
Merge into: | lp:linaro-ci-dashboard |
Diff against target: |
562 lines (+349/-17) 18 files modified
HACKING (+12/-0) Makefile (+2/-0) README (+1/-0) config_template/config.xml (+2/-2) dashboard/frontend/api/api.py (+19/-2) dashboard/frontend/api/urls.py (+1/-0) dashboard/frontend/ci_job/migrations/0001_initial.py (+60/-0) dashboard/frontend/ci_job/models/__init__.py (+1/-0) dashboard/frontend/ci_job/models/ci_job.py (+107/-0) dashboard/frontend/ci_job/urls.py (+31/-0) dashboard/frontend/ci_job/views/ci_job_build_view.py (+25/-0) dashboard/frontend/ci_job/views/ci_job_detail_view.py (+24/-0) dashboard/frontend/models/loop_reference.py (+1/-0) dashboard/frontend/tests/test_api.py (+58/-13) dashboard/frontend/views/index_view.py (+2/-0) dashboard/settings.py (+1/-0) dashboard/urls.py (+1/-0) requirements.txt (+1/-0) |
To merge this branch: | bzr merge lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Linaro Infrastructure | Pending | ||
Review via email: mp+147694@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
James Tunnicliffe (dooferlad) wrote : | # |
- 75. By James Tunnicliffe
-
Removed invalid tests
- 76. By James Tunnicliffe
-
Removed commented out code
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'HACKING' |
2 | --- HACKING 2012-09-21 09:24:01 +0000 |
3 | +++ HACKING 2013-02-11 15:46:21 +0000 |
4 | @@ -49,6 +49,18 @@ |
5 | |
6 | Tests should be written and defined inside each sub-application. |
7 | |
8 | +When defining a new application, make sure the model app_label matches what is |
9 | +listed in settings.py: |
10 | + |
11 | +class CIJob(Loop): |
12 | + """Defines the base class for a CI Job.""" |
13 | + class Meta: |
14 | + app_label = 'ci_job' |
15 | + |
16 | +INSTALLED_APPS = ( |
17 | +... |
18 | + 'frontend.ci_job', |
19 | + |
20 | == Class Hierarchy == |
21 | |
22 | === Templates & Views === |
23 | |
24 | === modified file 'Makefile' |
25 | --- Makefile 2012-09-24 13:18:02 +0000 |
26 | +++ Makefile 2013-02-11 15:46:21 +0000 |
27 | @@ -24,6 +24,8 @@ |
28 | echo "No changes to android_textfield_loop models." |
29 | python dashboard/manage.py schemamigration hwpack_loop --auto || \ |
30 | echo "No changes to hwpack_loop models." |
31 | + python dashboard/manage.py schemamigration ci_job --auto || \ |
32 | + echo "No changes to ci_job models." |
33 | python dashboard/manage.py migrate |
34 | |
35 | migrate: syncdb |
36 | |
37 | === modified file 'README' |
38 | --- README 2013-02-01 11:49:24 +0000 |
39 | +++ README 2013-02-11 15:46:21 +0000 |
40 | @@ -17,6 +17,7 @@ |
41 | build-essential |
42 | openjdk-6-jre-headless |
43 | python-tastypie |
44 | + python-simplejson |
45 | |
46 | To unit test the API that tastypie provides you need Django version of at least |
47 | 1.4. If you have Django 1.3 the API will still work, but not be unit tested. |
48 | |
49 | === modified file 'config_template/config.xml' |
50 | --- config_template/config.xml 2012-09-20 08:46:37 +0000 |
51 | +++ config_template/config.xml 2013-02-11 15:46:21 +0000 |
52 | @@ -50,7 +50,7 @@ |
53 | </views> |
54 | <primaryView>All</primaryView> |
55 | <slaveAgentPort>0</slaveAgentPort> |
56 | - <label>IntegrationLoop AndroidLoop KernelLoop AndroidTextFieldLoop HwpackLoop</label> |
57 | + <label>IntegrationLoop AndroidLoop KernelLoop AndroidTextFieldLoop HwpackLoop CIJob</label> |
58 | <nodeProperties/> |
59 | <globalNodeProperties/> |
60 | -</hudson> |
61 | \ No newline at end of file |
62 | +</hudson> |
63 | |
64 | === modified file 'dashboard/frontend/api/api.py' |
65 | --- dashboard/frontend/api/api.py 2013-02-04 10:59:49 +0000 |
66 | +++ dashboard/frontend/api/api.py 2013-02-11 15:46:21 +0000 |
67 | @@ -16,9 +16,10 @@ |
68 | # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
69 | |
70 | from tastypie.resources import ModelResource |
71 | -from tastypie.authorization import DjangoAuthorization |
72 | -from tastypie.authentication import ApiKeyAuthentication |
73 | +from tastypie.authorization import DjangoAuthorization, Authorization |
74 | +from tastypie.authentication import ApiKeyAuthentication, Authentication |
75 | from dashboard.frontend.models.loop import Loop |
76 | +from frontend.ci_job.models.ci_job import CIJob |
77 | |
78 | """ |
79 | Add API endpoint logic here. The documentation to do this can be found here: |
80 | @@ -54,3 +55,19 @@ |
81 | resource_name = 'loops' |
82 | authorization = DjangoAuthorization() |
83 | authentication = ApiKeyAuthentication() |
84 | + |
85 | +class CIJobResource(ModelResource): |
86 | + class Meta: |
87 | + """Returns a list of all loops.""" |
88 | + queryset = CIJob.objects.all() |
89 | + resource_name = 'jobs' |
90 | + list_allowed_methods = ['get', 'post'] |
91 | + detail_allowed_methods = ['get', 'post', 'put', 'delete'] |
92 | + |
93 | + #http://django-tastypie.readthedocs.org/en/latest/authorization.html |
94 | + # Currently everyone who has an API key is equal. Suggest we tie this |
95 | + # down using a custom Authorization class (see above link) so anyone |
96 | + # can create and modify their own jobs, but only some users have |
97 | + # the ability to delete and modify other users' jobs. |
98 | + authorization = Authorization() #DjangoAuthorization() |
99 | + authentication = ApiKeyAuthentication() |
100 | |
101 | === modified file 'dashboard/frontend/api/urls.py' |
102 | --- dashboard/frontend/api/urls.py 2013-02-04 17:55:49 +0000 |
103 | +++ dashboard/frontend/api/urls.py 2013-02-11 15:46:21 +0000 |
104 | @@ -7,6 +7,7 @@ |
105 | # Register new resources here (probably defined in api.py) |
106 | v1_api.register(LoginTestResource()) |
107 | v1_api.register(LoopsResource()) |
108 | +v1_api.register(CIJobResource()) |
109 | |
110 | urlpatterns = patterns('', |
111 | (r'^api/', include(v1_api.urls)), |
112 | |
113 | === added directory 'dashboard/frontend/ci_job' |
114 | === added file 'dashboard/frontend/ci_job/__init__.py' |
115 | === added directory 'dashboard/frontend/ci_job/migrations' |
116 | === added file 'dashboard/frontend/ci_job/migrations/0001_initial.py' |
117 | --- dashboard/frontend/ci_job/migrations/0001_initial.py 1970-01-01 00:00:00 +0000 |
118 | +++ dashboard/frontend/ci_job/migrations/0001_initial.py 2013-02-11 15:46:21 +0000 |
119 | @@ -0,0 +1,60 @@ |
120 | +# -*- coding: utf-8 -*- |
121 | +import datetime |
122 | +from south.db import db |
123 | +from south.v2 import SchemaMigration |
124 | +from django.db import models |
125 | + |
126 | + |
127 | +class Migration(SchemaMigration): |
128 | + |
129 | + def forwards(self, orm): |
130 | + # Adding model 'CIJob' |
131 | + db.create_table('ci_job_cijob', ( |
132 | + ('loop_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['frontend.Loop'], unique=True, primary_key=True)), |
133 | + ('vcs_url', self.gf('django.db.models.fields.CharField')(max_length=255)), |
134 | + ('vcs_branch', self.gf('django.db.models.fields.CharField')(default='', max_length=255)), |
135 | + ('vcs_tag', self.gf('django.db.models.fields.CharField')(default='', max_length=255)), |
136 | + ('file_name', self.gf('django.db.models.fields.CharField')(max_length=255)), |
137 | + ('class_name', self.gf('django.db.models.fields.CharField')(max_length=255)), |
138 | + ('run_when_ready', self.gf('django.db.models.fields.BooleanField')(default=False)), |
139 | + )) |
140 | + db.send_create_signal('ci_job', ['CIJob']) |
141 | + |
142 | + |
143 | + def backwards(self, orm): |
144 | + # Deleting model 'CIJob' |
145 | + db.delete_table('ci_job_cijob') |
146 | + |
147 | + |
148 | + models = { |
149 | + 'ci_job.cijob': { |
150 | + 'Meta': {'object_name': 'CIJob', '_ormbases': ['frontend.Loop']}, |
151 | + 'class_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
152 | + 'file_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
153 | + 'loop_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['frontend.Loop']", 'unique': 'True', 'primary_key': 'True'}), |
154 | + 'run_when_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
155 | + 'vcs_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), |
156 | + 'vcs_tag': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), |
157 | + 'vcs_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}) |
158 | + }, |
159 | + 'frontend.loop': { |
160 | + 'Meta': {'object_name': 'Loop'}, |
161 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
162 | + 'is_official': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
163 | + 'is_restricted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
164 | + 'lava_tests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
165 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}), |
166 | + 'next_loop': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'previous_loop'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['frontend.Loop']", 'blank': 'True', 'unique': 'True'}), |
167 | + 'server': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['jenkinsserver.JenkinsServer']", 'null': 'True', 'on_delete': 'models.SET_NULL'}), |
168 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}) |
169 | + }, |
170 | + 'jenkinsserver.jenkinsserver': { |
171 | + 'Meta': {'object_name': 'JenkinsServer'}, |
172 | + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
173 | + 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
174 | + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
175 | + 'username': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
176 | + } |
177 | + } |
178 | + |
179 | + complete_apps = ['ci_job'] |
180 | \ No newline at end of file |
181 | |
182 | === added file 'dashboard/frontend/ci_job/migrations/__init__.py' |
183 | === added directory 'dashboard/frontend/ci_job/models' |
184 | === added file 'dashboard/frontend/ci_job/models/__init__.py' |
185 | --- dashboard/frontend/ci_job/models/__init__.py 1970-01-01 00:00:00 +0000 |
186 | +++ dashboard/frontend/ci_job/models/__init__.py 2013-02-11 15:46:21 +0000 |
187 | @@ -0,0 +1,1 @@ |
188 | +from frontend.ci_job.models.ci_job import * |
189 | |
190 | === added file 'dashboard/frontend/ci_job/models/ci_job.py' |
191 | --- dashboard/frontend/ci_job/models/ci_job.py 1970-01-01 00:00:00 +0000 |
192 | +++ dashboard/frontend/ci_job/models/ci_job.py 2013-02-11 15:46:21 +0000 |
193 | @@ -0,0 +1,107 @@ |
194 | +# Copyright (C) 2012 Linaro |
195 | +# |
196 | +# This file is part of linaro-ci-dashboard. |
197 | +# |
198 | +# linaro-ci-dashboard is free software: you can redistribute it and/or modify |
199 | +# it under the terms of the GNU Affero General Public License as published by |
200 | +# the Free Software Foundation, either version 3 of the License, or |
201 | +# (at your option) any later version. |
202 | +# |
203 | +# linaro-ci-dashboard is distributed in the hope that it will be useful, |
204 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
205 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
206 | +# GNU Affero General Public License for more details. |
207 | +# |
208 | +# You should have received a copy of the GNU Affero General Public License |
209 | +# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
210 | + |
211 | +from django.db import models |
212 | +from frontend.models.loop import Loop |
213 | +from jenkinsserver.models.jenkins_server import JenkinsServer |
214 | +#from django.contrib.auth.models import User |
215 | + |
216 | + |
217 | +class CIJob(Loop): |
218 | + """Defines the base class for a CI Job.""" |
219 | + class Meta: |
220 | + app_label = 'ci_job' |
221 | + |
222 | + vcs_url = models.CharField(max_length=255, |
223 | + verbose_name='Configuration repository') |
224 | + vcs_branch = models.CharField(max_length=255, |
225 | + verbose_name='Configuration branch', |
226 | + default='') |
227 | + vcs_tag = models.CharField(max_length=255, |
228 | + verbose_name='Configuration tag', |
229 | + default='') |
230 | + file_name = models.CharField(max_length=255, |
231 | + verbose_name='Configuration file name') |
232 | + class_name = models.CharField(max_length=255, |
233 | + verbose_name='Configuration class name') |
234 | + run_when_ready = models.BooleanField(default=False) |
235 | + |
236 | + #job_owner = models.ForeignKey(User, editable=False, |
237 | + # verbose_name='Job Owner') |
238 | + |
239 | + def save(self, *args, **kwargs): |
240 | + self.server = JenkinsServer.objects.get(id=1) |
241 | + self.type = self.__class__.__name__ |
242 | + super(self.__class__, self).save(*args, **kwargs) |
243 | + # We do not want a failure in remote server to affect the |
244 | + # CI Loop flow. |
245 | + try: |
246 | + self.server.create_or_update_loop(self) |
247 | + except: |
248 | + # TODO: Log error. |
249 | + pass |
250 | + |
251 | + def schedule_build(self, parameters=None): |
252 | + parameters = {'parameter': [{'delay': '0'}]} |
253 | + return super(self.__class__, self).schedule_build(parameters) |
254 | + |
255 | + def base64_config(self, |
256 | + include=None, |
257 | + exclude=None, |
258 | + capitalize=False, |
259 | + upper=False): |
260 | + exclude = ['id', 'server', 'loop_ptr', 'next_loop', 'name', 'type'] |
261 | + return super(CIJob, self).base64_config(include=include, |
262 | + exclude=exclude, |
263 | + capitalize=capitalize, |
264 | + upper=True) |
265 | + |
266 | + def preconfigure(self, configuration=None): |
267 | + """Makes a build parameter dict from build result configuration. |
268 | + |
269 | + This method should be overridden by subclasses. |
270 | + """ |
271 | + if isinstance(configuration, dict): |
272 | + # The name is the name of the loop that is calling the chained one, |
273 | + # not the one we want to actually configure, we drop it. |
274 | + configuration.pop('name') |
275 | + unmatched_values = u'' |
276 | + for key, value in configuration.iteritems(): |
277 | + if hasattr(self, key.lower()): |
278 | + setattr(self, key.lower(), value) |
279 | + else: |
280 | + # If the attr cannot be found, we throw everything in |
281 | + # user_defined_values since the text field is free form. |
282 | + unmatched_values = u'%s=%s\n' % (key.upper(), str(value)) |
283 | + |
284 | + self.user_defined_values = unmatched_values |
285 | + self.save() |
286 | + else: |
287 | + self.log.error("Parameter was not a 'dict' instance.") |
288 | + return {} |
289 | + |
290 | + @models.permalink |
291 | + def get_detail_url(self): |
292 | + return 'CIJobDetail', (), {'slug': self.name} |
293 | + |
294 | + @models.permalink |
295 | + def get_build_url(self): |
296 | + return 'CIJobBuild', (), {'slug': self.name} |
297 | + |
298 | + @models.permalink |
299 | + def get_update_url(self): |
300 | + return 'CIJobUpdate', (), {'slug': self.name} |
301 | |
302 | === added file 'dashboard/frontend/ci_job/urls.py' |
303 | --- dashboard/frontend/ci_job/urls.py 1970-01-01 00:00:00 +0000 |
304 | +++ dashboard/frontend/ci_job/urls.py 2013-02-11 15:46:21 +0000 |
305 | @@ -0,0 +1,31 @@ |
306 | +# Copyright (C) 2012 Linaro |
307 | +# |
308 | +# This file is part of linaro-ci-dashboard. |
309 | +# |
310 | +# linaro-ci-dashboard is free software: you can redistribute it and/or modify |
311 | +# it under the terms of the GNU Affero General Public License as published by |
312 | +# the Free Software Foundation, either version 3 of the License, or |
313 | +# (at your option) any later version. |
314 | +# |
315 | +# linaro-ci-dashboard is distributed in the hope that it will be useful, |
316 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
317 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
318 | +# GNU Affero General Public License for more details. |
319 | +# |
320 | +# You should have received a copy of the GNU Affero General Public License |
321 | +# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
322 | + |
323 | +from django.conf.urls.defaults import patterns, url |
324 | + |
325 | +from frontend.ci_job.views.ci_job_detail_view \ |
326 | + import CIJobDetailView |
327 | +from frontend.ci_job.views.ci_job_build_view \ |
328 | + import CIJobBuildView |
329 | + |
330 | + |
331 | +urlpatterns = patterns('', |
332 | + url(r'^ci_job/detail/(?P<slug>[\w|\W]+)/$', |
333 | + CIJobDetailView.as_view(), name='CIJobDetail'), |
334 | + url(r'^ci_job/build/(?P<slug>[\w|\W]+)/$', |
335 | + CIJobBuildView.as_view(), name='CIJobBuild'), |
336 | +) |
337 | |
338 | === added directory 'dashboard/frontend/ci_job/views' |
339 | === added file 'dashboard/frontend/ci_job/views/__init__.py' |
340 | === added file 'dashboard/frontend/ci_job/views/ci_job_build_view.py' |
341 | --- dashboard/frontend/ci_job/views/ci_job_build_view.py 1970-01-01 00:00:00 +0000 |
342 | +++ dashboard/frontend/ci_job/views/ci_job_build_view.py 2013-02-11 15:46:21 +0000 |
343 | @@ -0,0 +1,25 @@ |
344 | +#!/usr/bin/env python |
345 | +# Copyright (C) 2012 Linaro |
346 | +# |
347 | +# This file is part of linaro-ci-dashboard. |
348 | +# |
349 | +# linaro-ci-dashboard is free software: you can redistribute it and/or modify |
350 | +# it under the terms of the GNU Affero General Public License as published by |
351 | +# the Free Software Foundation, either version 3 of the License, or |
352 | +# (at your option) any later version. |
353 | +# |
354 | +# linaro-ci-dashboard is distributed in the hope that it will be useful, |
355 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
356 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
357 | +# GNU Affero General Public License for more details. |
358 | +# |
359 | +# You should have received a copy of the GNU Affero General Public License |
360 | +# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
361 | + |
362 | +from frontend.ci_job.models.ci_job import CIJob |
363 | +from frontend.views.loop_build_view import LoopBuildView |
364 | + |
365 | + |
366 | +class CIJobBuildView(LoopBuildView): |
367 | + |
368 | + model = CIJob |
369 | |
370 | === added file 'dashboard/frontend/ci_job/views/ci_job_detail_view.py' |
371 | --- dashboard/frontend/ci_job/views/ci_job_detail_view.py 1970-01-01 00:00:00 +0000 |
372 | +++ dashboard/frontend/ci_job/views/ci_job_detail_view.py 2013-02-11 15:46:21 +0000 |
373 | @@ -0,0 +1,24 @@ |
374 | +# Copyright (C) 2012 Linaro |
375 | +# |
376 | +# This file is part of linaro-ci-dashboard. |
377 | +# |
378 | +# linaro-ci-dashboard is free software: you can redistribute it and/or modify |
379 | +# it under the terms of the GNU Affero General Public License as published by |
380 | +# the Free Software Foundation, either version 3 of the License, or |
381 | +# (at your option) any later version. |
382 | +# |
383 | +# linaro-ci-dashboard is distributed in the hope that it will be useful, |
384 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
385 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
386 | +# GNU Affero General Public License for more details. |
387 | +# |
388 | +# You should have received a copy of the GNU Affero General Public License |
389 | +# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>. |
390 | + |
391 | +from frontend.ci_job.models.ci_job import CIJob |
392 | +from frontend.views.loop_detail_view import LoopDetailView |
393 | + |
394 | + |
395 | +class CIJobDetailView(LoopDetailView): |
396 | + |
397 | + model = CIJob |
398 | |
399 | === modified file 'dashboard/frontend/models/loop_reference.py' |
400 | --- dashboard/frontend/models/loop_reference.py 2012-09-18 12:16:59 +0000 |
401 | +++ dashboard/frontend/models/loop_reference.py 2013-02-11 15:46:21 +0000 |
402 | @@ -23,3 +23,4 @@ |
403 | INTEGRATION_LOOP = ('IntegrationLoop') |
404 | ANDROID_TEXTFIELD_LOOP = ('AndroidTextFieldLoop') |
405 | HWPACK_LOOP = ('HwpackLoop') |
406 | +CI_JOB = ('CIJob') |
407 | |
408 | === modified file 'dashboard/frontend/tests/test_api.py' |
409 | --- dashboard/frontend/tests/test_api.py 2013-02-04 17:55:49 +0000 |
410 | +++ dashboard/frontend/tests/test_api.py 2013-02-11 15:46:21 +0000 |
411 | @@ -20,8 +20,10 @@ |
412 | from tastypie.models import ApiKey |
413 | from dashboard.frontend.models.loop import Loop |
414 | from dashboard.frontend.android_build.models.android_loop import AndroidLoop |
415 | +from dashboard.frontend.ci_job.models.ci_job import CIJob |
416 | import requests |
417 | from urlparse import urljoin |
418 | +import simplejson |
419 | |
420 | |
421 | class ApiTests(LiveServerTestCase): |
422 | @@ -32,13 +34,18 @@ |
423 | def setUp(self): |
424 | super(ApiTests, self).setUp() |
425 | |
426 | + self.settings = {} |
427 | + self.settings["ci_server"] = "http://localhost:8081" |
428 | + self.settings["api_prefix"] = "/api/dev/" |
429 | + self.settings["username"] = 'daniel' |
430 | + self.settings["password"] = 'pass' |
431 | + self.settings["api_key"] = "0" |
432 | + |
433 | # Create a user. |
434 | - self.username = 'daniel' |
435 | - self.password = 'pass' |
436 | self.user = User.objects.create_user( |
437 | - self.username, 'daniel@example.com', self.password) |
438 | - |
439 | - self.api_key = "0" |
440 | + self.settings["username"], |
441 | + 'daniel@example.com', |
442 | + self.settings["password"]) |
443 | |
444 | # Add a couple of jobs to test against. |
445 | self.android_loop = AndroidLoop() |
446 | @@ -51,16 +58,35 @@ |
447 | self.loop.type = Loop.__class__.__name__ |
448 | self.loop.save() |
449 | |
450 | - def get(self, url): |
451 | - payload = {"username": self.username, |
452 | - "api_key": self.api_key, |
453 | - "format": "json"} |
454 | - url = urljoin("http://localhost:8081", "/api/dev/" + url) |
455 | - return requests.get(url, params=payload) |
456 | + def get(self, url, in_params=None): |
457 | + url, params = self._prep_request(url, in_params) |
458 | + return requests.get(url, params=params) |
459 | + |
460 | + def post(self, url, data, in_params=None): |
461 | + url, params = self._prep_request(url, in_params) |
462 | + return requests.post(url, data=data, params=params, |
463 | + headers={"content-type": "application/json"}) |
464 | + |
465 | + def _prep_request(self, url, in_params=None): |
466 | + params = {"username": self.settings["username"], |
467 | + "api_key": self.settings["api_key"], |
468 | + "format": "json"} |
469 | + |
470 | + url = urljoin(self.settings["ci_server"], |
471 | + self.settings["api_prefix"] + url) |
472 | + |
473 | + # If we don't have a trailing slash, we will just be redirected. Avoid |
474 | + # the extra call. |
475 | + if url[-1] != "/": |
476 | + url += "/" |
477 | + |
478 | + if in_params: |
479 | + params.update(in_params) |
480 | + |
481 | + return url, params |
482 | |
483 | def login(self): |
484 | - self.api_key = ApiKey.objects.create(user=self.user).key |
485 | - #self.create_apikey(self.username, self.api_key) |
486 | + self.settings["api_key"] = ApiKey.objects.create(user=self.user).key |
487 | |
488 | def test_login_test_unauthorzied(self): |
489 | r = self.get("login_test") |
490 | @@ -93,3 +119,22 @@ |
491 | api_test_names = {json[0]['name'], json[1]['name']} |
492 | test_names = {self.android_loop.name, self.loop.name} |
493 | self.assertEqual(api_test_names, test_names) |
494 | + |
495 | + def test_add_job(self): |
496 | + self.login() |
497 | + data = { |
498 | + "vcs_url": "vcsurl", |
499 | + "file_name": "filename", |
500 | + "class_name": "classname", |
501 | + "run": False, |
502 | + "name": "jobname" |
503 | + } |
504 | + json_data = simplejson.dumps(data) |
505 | + |
506 | + r = self.post("jobs", json_data, {}) |
507 | + self.assertEqual(r.status_code, requests.codes.created) |
508 | + |
509 | + jobs = CIJob.objects.all() |
510 | + |
511 | + self.assertEqual(len(jobs), 1) |
512 | + self.assertEqual(jobs[0].name, data["name"]) |
513 | |
514 | === modified file 'dashboard/frontend/views/index_view.py' |
515 | --- dashboard/frontend/views/index_view.py 2012-09-13 11:37:13 +0000 |
516 | +++ dashboard/frontend/views/index_view.py 2013-02-11 15:46:21 +0000 |
517 | @@ -25,6 +25,7 @@ |
518 | from frontend.android_textfield_loop.models.android_textfield_loop \ |
519 | import AndroidTextFieldLoop |
520 | from frontend.hwpack_loop.models.hwpack_loop import HwpackLoop |
521 | +from frontend.ci_job.models.ci_job import CIJob |
522 | |
523 | class IndexView(TemplateView): |
524 | |
525 | @@ -42,4 +43,5 @@ |
526 | context['kernel_loops'] = KernelLoop.objects.all() |
527 | context['android_textfield_loops'] = AndroidTextFieldLoop.objects.all() |
528 | context['hwpack_loops'] = HwpackLoop.objects.all() |
529 | + context['ci_jobs'] = CIJob.objects.all() |
530 | return context |
531 | |
532 | === modified file 'dashboard/settings.py' |
533 | --- dashboard/settings.py 2013-01-30 17:20:40 +0000 |
534 | +++ dashboard/settings.py 2013-02-11 15:46:21 +0000 |
535 | @@ -158,6 +158,7 @@ |
536 | 'frontend.android_textfield_loop', |
537 | 'frontend.hwpack_loop', |
538 | 'frontend.api', |
539 | + 'frontend.ci_job', |
540 | 'tastypie', |
541 | 'south', |
542 | # Uncomment the next line to enable admin documentation: |
543 | |
544 | === modified file 'dashboard/urls.py' |
545 | --- dashboard/urls.py 2013-01-21 16:16:03 +0000 |
546 | +++ dashboard/urls.py 2013-02-11 15:46:21 +0000 |
547 | @@ -40,4 +40,5 @@ |
548 | url(r'^', include('dashboard.frontend.android_textfield_loop.urls')), |
549 | url(r'^', include('dashboard.frontend.hwpack_loop.urls')), |
550 | url(r'^', include('dashboard.frontend.api.urls')), |
551 | + url(r'^', include('dashboard.frontend.ci_job.urls')), |
552 | ) |
553 | |
554 | === modified file 'requirements.txt' |
555 | --- requirements.txt 2013-02-01 11:39:17 +0000 |
556 | +++ requirements.txt 2013-02-11 15:46:21 +0000 |
557 | @@ -12,4 +12,5 @@ |
558 | python-jenkins==0.2 |
559 | python-openid==2.2.5 |
560 | requests==1.1.0 |
561 | +simplejson==3.0.7 |
562 | wsgiref==0.1.2 |
Crumbs. Got old tests in this. Will remove.