Merge lp:~cjohnston/ubuntu-ci-services-itself/ticket-artifact into lp:ubuntu-ci-services-itself

Proposed by Chris Johnston
Status: Merged
Approved by: Chris Johnston
Approved revision: 134
Merged at revision: 139
Proposed branch: lp:~cjohnston/ubuntu-ci-services-itself/ticket-artifact
Merge into: lp:ubuntu-ci-services-itself
Diff against target: 820 lines (+366/-138)
10 files modified
docs/components/ticket-system.rst (+13/-1)
ticket_system/ticket/admin.py (+11/-3)
ticket_system/ticket/api.py (+37/-16)
ticket_system/ticket/migrations/0001_initial.py (+40/-19)
ticket_system/ticket/models.py (+33/-9)
ticket_system/ticket/tests/test_full_read_api.py (+64/-40)
ticket_system/ticket/tests/test_models.py (+28/-10)
ticket_system/ticket/tests/test_read_api.py (+57/-15)
ticket_system/ticket/tests/test_write_api.py (+74/-20)
ticket_system/ticket_system/urls.py (+9/-5)
To merge this branch: bzr merge lp:~cjohnston/ubuntu-ci-services-itself/ticket-artifact
Reviewer Review Type Date Requested Status
Francis Ginther Approve
Chris Johnston (community) Needs Resubmitting
Review via email: mp+202701@code.launchpad.net

Commit message

Add the ability for an artifact to be attached to a ticket as well as a subticket. Also add 'image' as an available artifact type

To post a comment you must log in.
Revision history for this message
Chris Johnston (cjohnston) :
review: Needs Resubmitting
Revision history for this message
Francis Ginther (fginther) wrote :

Looks good.

review: Approve
Revision history for this message
Chris Johnston (cjohnston) wrote :
Download full text (6.6 KiB)

The attempt to merge lp:~cjohnston/ubuntu-ci-services-itself/ticket-artifact into lp:ubuntu-ci-services-itself failed. Below is the output from the failed tests.

New python executable in /tmp/tmp.d2pOSanjFp/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.
== Testing ci-utils ....
running develop
running egg_info
creating ci_utils.egg-info
writing requirements to ci_utils.egg-info/requires.txt
writing ci_utils.egg-info/PKG-INFO
writing top-level names to ci_utils.egg-info/top_level.txt
writing dependency_links to ci_utils.egg-info/dependency_links.txt
writing manifest file 'ci_utils.egg-info/SOURCES.txt'
reading manifest file 'ci_utils.egg-info/SOURCES.txt'
writing manifest file 'ci_utils.egg-info/SOURCES.txt'
running build_ext
Creating /tmp/tmp.d2pOSanjFp/lib/python2.7/site-packages/ci-utils.egg-link (link to .)
Adding ci-utils 0.1 to easy-install.pth file

Installed /tmp/tarmac/branch.wCS45R/ci-utils
Processing dependencies for ci-utils==0.1
Searching for testtools
Reading http://pypi.python.org/simple/testtools/
Best match: testtools 0.9.34
Downloading https://pypi.python.org/packages/source/t/testtools/testtools-0.9.34.tar.gz#md5=51d37e7376a70cee40cf17b44889fc88
Processing testtools-0.9.34.tar.gz
Running testtools-0.9.34/setup.py -q bdist_egg --dist-dir /tmp/easy_install-pWYY7D/testtools-0.9.34/egg-dist-tmp-93q4HA
Adding testtools 0.9.34 to easy-install.pth file

Installed /tmp/tmp.d2pOSanjFp/lib/python2.7/site-packages/testtools-0.9.34-py2.7.egg
Searching for restish==0.12.1
Reading http://pypi.python.org/simple/restish/
Best match: restish 0.12.1
Downloading https://pypi.python.org/packages/source/r/restish/restish-0.12.1.tar.gz#md5=c29e0b755c44c21659de8e463093ea47
Processing restish-0.12.1.tar.gz
Running restish-0.12.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-dReg03/restish-0.12.1/egg-dist-tmp-3VS1nY
Adding restish 0.12.1 to easy-install.pth file

Installed /tmp/tmp.d2pOSanjFp/lib/python2.7/site-packages/restish-0.12.1-py2.7.egg
Searching for python-subunit
Reading http://pypi.python.org/simple/python-subunit/
Reading http://launchpad.net/subunit
Best match: python-subunit 0.0.16
Downloading https://pypi.python.org/packages/source/p/python-subunit/python-subunit-0.0.16.tar.gz#md5=c0ec919f8a1051de4ad89000f95324aa
Processing python-subunit-0.0.16.tar.gz
Running python-subunit-0.0.16/setup.py -q bdist_egg --dist-dir /tmp/easy_install-HqidGs/python-subunit-0.0.16/egg-dist-tmp-QTgytN
Adding python-subunit 0.0.16 to easy-install.pth file
Installing subunit-filter script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit-2to1 script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit-ls script to /tmp/tmp.d2pOSanjFp/bin
Installing tap2subunit script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit-1to2 script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit2pyunit script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit2junitxml script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit-tags script to /tmp/tmp.d2pOSanjFp/bin
Installing subunit-notify...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'docs/components/ticket-system.rst'
2--- docs/components/ticket-system.rst 2014-01-21 19:36:04 +0000
3+++ docs/components/ticket-system.rst 2014-01-24 17:44:23 +0000
4@@ -277,11 +277,23 @@
5 Create artifact
6 ~~~~~~~~~~~~~~~
7
8+
9+*Ticket*
10+
11+Valid types are: "RESULTS", "LOGS", "IMAGE"
12+
13+::
14+
15+ curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "my_artifact", "ticket": "/api/v1/ticket/X/", "reference": "http://path.to/artifact/", "type": "IMAGE"}' http://localhost:8000/api/v1/ticketartifact/
16+
17+
18+*Subticket*
19+
20 Valid types are: "SPU", "RESULTS", "LOGS"
21
22 ::
23
24- curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "my_artifact", "subticket": "/api/v1/subticket/X/", "reference": "http://path.to/artifact/", "type": "SPU"}' http://localhost:8000/api/v1/artifact/
25+ curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "my_artifact", "subticket": "/api/v1/subticket/X/", "reference": "http://path.to/artifact/", "type": "SPU"}' http://localhost:8000/api/v1/subticketartifact/
26
27 Create subticket
28 ~~~~~~~~~~~~~~~~
29
30=== modified file 'ticket_system/ticket/admin.py'
31--- ticket_system/ticket/admin.py 2013-12-20 21:12:13 +0000
32+++ ticket_system/ticket/admin.py 2014-01-24 17:44:23 +0000
33@@ -14,7 +14,8 @@
34 # along with this program. If not, see <http://www.gnu.org/licenses/>.
35
36 from django.contrib import admin
37-from ticket.models import Ticket, SubTicket, SourcePackageUpload, Artifact
38+from ticket.models import (Ticket, SubTicket, SourcePackageUpload,
39+ TicketArtifact, SubTicketArtifact)
40
41
42 class TicketAdmin(admin.ModelAdmin):
43@@ -34,7 +35,13 @@
44 list_display = ('sourcepackage', 'version')
45
46
47-class ArtifactAdmin(admin.ModelAdmin):
48+class TicketArtifactAdmin(admin.ModelAdmin):
49+ list_filter = ['type']
50+ search_fields = ['name']
51+ list_display = ('name', 'ticket', 'type')
52+
53+
54+class SubTicketArtifactAdmin(admin.ModelAdmin):
55 list_filter = ['type']
56 search_fields = ['name']
57 list_display = ('name', 'subticket', 'type')
58@@ -42,4 +49,5 @@
59 admin.site.register(Ticket, TicketAdmin)
60 admin.site.register(SubTicket, SubTicketAdmin)
61 admin.site.register(SourcePackageUpload, SourcePackageUploadAdmin)
62-admin.site.register(Artifact, ArtifactAdmin)
63+admin.site.register(TicketArtifact, TicketArtifactAdmin)
64+admin.site.register(SubTicketArtifact, SubTicketArtifactAdmin)
65
66=== modified file 'ticket_system/ticket/api.py'
67--- ticket_system/ticket/api.py 2014-01-21 19:36:04 +0000
68+++ ticket_system/ticket/api.py 2014-01-24 17:44:23 +0000
69@@ -17,7 +17,8 @@
70 from tastypie.constants import ALL
71 from tastypie.authorization import Authorization
72 from tastypie.resources import ModelResource
73-from ticket.models import (Ticket, SubTicket, SourcePackageUpload, Artifact,
74+from ticket.models import (Ticket, SubTicket, SourcePackageUpload,
75+ TicketArtifact, SubTicketArtifact,
76 SubTicketWorkflowStep, SubTicketWorkflowStepStatus,
77 TicketWorkflowStep, TicketWorkflowStepStatus,
78 get_enum_title)
79@@ -91,19 +92,36 @@
80 authorization = Authorization()
81
82
83-class ArtifactResource(ModelResource):
84- subticket = fields.ToOneField(SubTicketResource, 'subticket', full=True)
85-
86- class Meta:
87- queryset = Artifact.objects.all()
88- allowed_methods = ['get', 'post']
89- authorization = Authorization()
90-
91-
92-class FullArtifactResource(ModelResource):
93-
94- class Meta:
95- queryset = Artifact.objects.all()
96+class TicketArtifactResource(ModelResource):
97+ ticket = fields.ToOneField(TicketResource, 'ticket', null=True, full=True)
98+
99+ class Meta:
100+ queryset = TicketArtifact.objects.all()
101+ allowed_methods = ['get', 'post']
102+ authorization = Authorization()
103+
104+
105+class SubTicketArtifactResource(ModelResource):
106+ subticket = fields.ToOneField(SubTicketResource, 'subticket', null=True,
107+ full=True)
108+
109+ class Meta:
110+ queryset = SubTicketArtifact.objects.all()
111+ allowed_methods = ['get', 'post']
112+ authorization = Authorization()
113+
114+
115+class FullTicketArtifactResource(ModelResource):
116+
117+ class Meta:
118+ queryset = TicketArtifact.objects.all()
119+ allowed_methods = ['get']
120+
121+
122+class FullSubTicketArtifactResource(ModelResource):
123+
124+ class Meta:
125+ queryset = SubTicketArtifact.objects.all()
126 allowed_methods = ['get']
127
128
129@@ -111,8 +129,8 @@
130 source_package_upload = fields.ToOneField(SourcePackageUploadResource,
131 'source_package_upload',
132 full=True)
133- artifact = fields.ToManyField(FullArtifactResource, 'artifact_set',
134- full=True)
135+ artifact = fields.ToManyField(FullSubTicketArtifactResource,
136+ 'subticketartifact_set', full=True)
137
138 class Meta:
139 queryset = SubTicket.objects.all()
140@@ -122,6 +140,9 @@
141 class FullTicketResource(TicketTranslatedResource):
142 subticket = fields.ToManyField(FullSubTicketResource, 'subticket_set',
143 full=True)
144+ artifact = fields.ToManyField(FullTicketArtifactResource,
145+ 'ticketartifact_set', null=True,
146+ full=True)
147
148 class Meta:
149 queryset = Ticket.objects.all()
150
151=== modified file 'ticket_system/ticket/migrations/0001_initial.py'
152--- ticket_system/ticket/migrations/0001_initial.py 2013-12-20 21:12:13 +0000
153+++ ticket_system/ticket/migrations/0001_initial.py 2014-01-24 17:44:23 +0000
154@@ -44,15 +44,25 @@
155 ))
156 db.send_create_signal(u'ticket', ['SubTicket'])
157
158- # Adding model 'Artifact'
159- db.create_table('artifact', (
160- (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
161- ('type', self.gf('django.db.models.fields.CharField')(max_length=4096)),
162- ('subticket', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ticket.SubTicket'])),
163- ('reference', self.gf('django.db.models.fields.CharField')(max_length=4096)),
164- ('name', self.gf('django.db.models.fields.CharField')(max_length=4096)),
165- ))
166- db.send_create_signal(u'ticket', ['Artifact'])
167+ # Adding model 'SubTicketArtifact'
168+ db.create_table('subticket_artifact', (
169+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
170+ ('reference', self.gf('django.db.models.fields.CharField')(max_length=4096)),
171+ ('name', self.gf('django.db.models.fields.CharField')(max_length=4096)),
172+ ('type', self.gf('django.db.models.fields.CharField')(max_length=4096)),
173+ ('subticket', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ticket.SubTicket'], null=True)),
174+ ))
175+ db.send_create_signal(u'ticket', ['SubTicketArtifact'])
176+
177+ # Adding model 'TicketArtifact'
178+ db.create_table('ticket_artifact', (
179+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
180+ ('reference', self.gf('django.db.models.fields.CharField')(max_length=4096)),
181+ ('name', self.gf('django.db.models.fields.CharField')(max_length=4096)),
182+ ('type', self.gf('django.db.models.fields.CharField')(max_length=4096)),
183+ ('ticket', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ticket.Ticket'], null=True)),
184+ ))
185+ db.send_create_signal(u'ticket', ['TicketArtifact'])
186
187
188 def backwards(self, orm):
189@@ -65,8 +75,11 @@
190 # Deleting model 'SubTicket'
191 db.delete_table('subticket')
192
193- # Deleting model 'Artifact'
194- db.delete_table('artifact')
195+ # Deleting model 'SubTicketArtifact'
196+ db.delete_table('subticket_artifact')
197+
198+ # Deleting model 'TicketArtifact'
199+ db.delete_table('ticket_artifact')
200
201
202 models = {
203@@ -75,14 +88,6 @@
204 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
205 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
206 },
207- u'ticket.artifact': {
208- 'Meta': {'object_name': 'Artifact', 'db_table': "'artifact'"},
209- u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
210- 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
211- 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
212- 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']"}),
213- 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
214- },
215 u'ticket.sourcepackageupload': {
216 'Meta': {'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"},
217 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
218@@ -98,6 +103,14 @@
219 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
220 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"})
221 },
222+ u'ticket.subticketartifact': {
223+ 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"},
224+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
225+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
226+ 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
227+ 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']", 'null': 'True'}),
228+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
229+ },
230 u'ticket.ticket': {
231 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket'"},
232 'added_binaries': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True', 'blank': 'True'}),
233@@ -112,6 +125,14 @@
234 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
235 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
236 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
237+ },
238+ u'ticket.ticketartifact': {
239+ 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"},
240+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
241+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
242+ 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
243+ 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']", 'null': 'True'}),
244+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
245 }
246 }
247
248
249=== modified file 'ticket_system/ticket/models.py'
250--- ticket_system/ticket/models.py 2014-01-16 16:02:10 +0000
251+++ ticket_system/ticket/models.py 2014-01-24 17:44:23 +0000
252@@ -157,20 +157,44 @@
253 return "{} {}".format(self.ticket, self.source_package_upload)
254
255
256-class Artifact(models.Model):
257+class ArtifactBase(models.Model):
258 class Meta:
259- db_table = 'artifact'
260+ abstract = True
261
262- ARTIFACT_TYPE = (
263- ('RESULTS', 'Test Results'),
264- ('SPU', 'Source Package Upload'),
265- ('LOGS', 'Logs'),
266- )
267- type = models.CharField(choices=ARTIFACT_TYPE, max_length=4096)
268- subticket = models.ForeignKey(SubTicket)
269 # 'reference' provided by the artifact manager
270 reference = models.CharField(max_length=4096)
271 name = models.CharField(max_length=4096)
272
273+
274+class SubTicketArtifact(ArtifactBase):
275+ SUBTICKET_ARTIFACT_TYPE = (
276+ ('RESULTS', 'Test Results'),
277+ ('SPU', 'Source Package Upload'),
278+ ('LOGS', 'Logs'),
279+ )
280+
281+ class Meta:
282+ db_table = 'subticket_artifact'
283+
284+ type = models.CharField(choices=SUBTICKET_ARTIFACT_TYPE, max_length=4096)
285+ subticket = models.ForeignKey(SubTicket, null=True)
286+
287+ def __unicode__(self):
288+ return "{} {}".format(self.name, self.type)
289+
290+
291+class TicketArtifact(ArtifactBase):
292+ TICKET_ARTIFACT_TYPE = (
293+ ('RESULTS', 'Test Results'),
294+ ('LOGS', 'Logs'),
295+ ('IMAGE', 'Image'),
296+ )
297+
298+ class Meta:
299+ db_table = 'ticket_artifact'
300+
301+ type = models.CharField(choices=TICKET_ARTIFACT_TYPE, max_length=4096)
302+ ticket = models.ForeignKey(Ticket, null=True)
303+
304 def __unicode__(self):
305 return "{} {}".format(self.name, self.type)
306
307=== modified file 'ticket_system/ticket/tests/test_full_read_api.py'
308--- ticket_system/ticket/tests/test_full_read_api.py 2014-01-22 17:14:18 +0000
309+++ ticket_system/ticket/tests/test_full_read_api.py 2014-01-24 17:44:23 +0000
310@@ -34,31 +34,41 @@
311 sourcepackage=self.sourcepackage)
312 self.subticket = mommy.make('SubTicket', ticket=self.ticket,
313 source_package_upload=self.spu)
314- self.artifact = mommy.make('Artifact', subticket=self.subticket)
315- self.maxDiff = None
316+ self.artifact_1 = mommy.make('TicketArtifact', ticket=self.ticket)
317+ self.artifact_2 = mommy.make('SubTicketArtifact',
318+ subticket=self.subticket)
319
320 def test_get_fullticket_api(self):
321 obj = self.getResource('fullticket/')
322 self.assertEqual(obj['objects'][0], {
323- u'status': get_enum_title(self.ticket.status,
324- TicketWorkflowStepStatus),
325- u'current_workflow_step': get_enum_title(
326- self.ticket.current_workflow_step, TicketWorkflowStep),
327+ u'added_binaries': self.ticket.added_binaries,
328+ u'artifact': [{
329+ u'resource_uri': u'/api/v1/fullticketartifact/{0}/'.format(
330+ self.artifact_1.pk),
331+ u'type': unicode(self.artifact_1.type),
332+ u'id': self.artifact_1.pk,
333+ u'reference': unicode(self.artifact_1.reference),
334+ u'name': unicode(self.artifact_1.name)}],
335+ u'status': unicode(get_enum_title(self.ticket.status,
336+ TicketWorkflowStepStatus)),
337+ u'current_workflow_step': unicode(get_enum_title(
338+ self.ticket.current_workflow_step, TicketWorkflowStep)),
339 u'description': unicode(self.ticket.description),
340 u'title': unicode(self.ticket.title),
341 u'subticket': [{
342- u'status': get_enum_title(self.subticket.status,
343- SubTicketWorkflowStepStatus),
344- u'current_workflow_step': get_enum_title(
345+ u'status': unicode(get_enum_title(self.subticket.status,
346+ SubTicketWorkflowStepStatus)),
347+ u'current_workflow_step': unicode(get_enum_title(
348 self.subticket.current_workflow_step,
349- SubTicketWorkflowStep),
350+ SubTicketWorkflowStep)),
351 u'artifact': [{
352- u'resource_uri': u'/api/v1/fullartifact/{0}/'.format(
353- self.artifact.pk),
354- u'type': unicode(self.artifact.type),
355- u'id': self.artifact.pk,
356- u'reference': unicode(self.artifact.reference),
357- u'name': unicode(self.artifact.name)}],
358+ u'resource_uri':
359+ u'/api/v1/fullsubticketartifact/{0}/'.format(
360+ self.artifact_2.pk),
361+ u'type': unicode(self.artifact_2.type),
362+ u'id': self.artifact_2.pk,
363+ u'reference': unicode(self.artifact_2.reference),
364+ u'name': unicode(self.artifact_2.name)}],
365 u'assignee': unicode(self.subticket.assignee),
366 u'source_package_upload': {
367 u'version': unicode(self.spu.version),
368@@ -82,36 +92,46 @@
369 u'resource_uri': u'/api/v1/fullticket/{0}/'.format(self.ticket.pk),
370 u'updated': unicode(self.ticket.updated.strftime(
371 "%Y-%m-%dT%H:%M:%S.%f")),
372- u'added_binaries': self.ticket.added_binaries,
373 u'removed_binaries': self.ticket.removed_binaries,
374 })
375
376- def test_get_fullartifact_api(self):
377- obj = self.getResource('fullartifact/')
378- self.assertEqual(obj['objects'][0], {
379- u'resource_uri': u'/api/v1/fullartifact/{0}/'.format(
380- self.artifact.pk),
381- u'type': unicode(self.artifact.type),
382- u'id': self.artifact.pk,
383- u'reference': unicode(self.artifact.reference),
384- u'name': unicode(self.artifact.name),
385+ def test_get_fullticketartifact_api(self):
386+ obj = self.getResource('fullticketartifact/')
387+ self.assertEqual(obj['objects'][0], {
388+ u'resource_uri': u'/api/v1/fullticketartifact/{0}/'.format(
389+ self.artifact_1.pk),
390+ u'type': unicode(self.artifact_1.type),
391+ u'id': self.artifact_1.pk,
392+ u'reference': unicode(self.artifact_1.reference),
393+ u'name': unicode(self.artifact_1.name),
394+ })
395+
396+ def test_get_fullsubticketartifact_api(self):
397+ obj = self.getResource('fullsubticketartifact/')
398+ self.assertEqual(obj['objects'][0], {
399+ u'resource_uri': u'/api/v1/fullsubticketartifact/{0}/'.format(
400+ self.artifact_2.pk),
401+ u'type': unicode(self.artifact_2.type),
402+ u'id': self.artifact_2.pk,
403+ u'reference': unicode(self.artifact_2.reference),
404+ u'name': unicode(self.artifact_2.name),
405 })
406
407 def test_get_fullsubticket_api(self):
408 obj = self.getResource('fullsubticket/')
409 self.assertEqual(obj['objects'][0], {
410- u'status': get_enum_title(self.subticket.status,
411- SubTicketWorkflowStepStatus),
412- u'current_workflow_step': get_enum_title(
413+ u'status': unicode(get_enum_title(self.subticket.status,
414+ SubTicketWorkflowStepStatus)),
415+ u'current_workflow_step': unicode(get_enum_title(
416 self.subticket.current_workflow_step,
417- SubTicketWorkflowStep),
418+ SubTicketWorkflowStep)),
419 u'artifact': [{
420- u'resource_uri': u'/api/v1/fullartifact/{0}/'.format(
421- self.artifact.pk),
422- u'type': unicode(self.artifact.type),
423- u'id': self.artifact.pk,
424- u'reference': unicode(self.artifact.reference),
425- u'name': unicode(self.artifact.name)}],
426+ u'resource_uri': u'/api/v1/fullsubticketartifact/{0}/'.format(
427+ self.artifact_2.pk),
428+ u'type': unicode(self.artifact_2.type),
429+ u'id': self.artifact_2.pk,
430+ u'reference': unicode(self.artifact_2.reference),
431+ u'name': unicode(self.artifact_2.name)}],
432 u'assignee': unicode(self.subticket.assignee),
433 u'source_package_upload': {
434 u'version': unicode(self.spu.version),
435@@ -149,16 +169,20 @@
436 sourcepackage=self.sourcepackage)
437 self.subticket_1 = mommy.make('SubTicket', ticket=self.ticket_1,
438 source_package_upload=self.spu)
439- self.artifact_1 = mommy.make('Artifact', subticket=self.subticket_1)
440+ self.artifact_1 = mommy.make('SubTicketArtifact',
441+ subticket=self.subticket_1)
442 self.subticket_2 = mommy.make('SubTicket', ticket=self.ticket_2,
443 source_package_upload=self.spu)
444- self.artifact_2 = mommy.make('Artifact', subticket=self.subticket_2)
445+ self.artifact_2 = mommy.make('SubTicketArtifact',
446+ subticket=self.subticket_2)
447 self.subticket_3 = mommy.make('SubTicket', ticket=self.ticket_3,
448 source_package_upload=self.spu)
449- self.artifact_3 = mommy.make('Artifact', subticket=self.subticket_3)
450+ self.artifact_3 = mommy.make('SubTicketArtifact',
451+ subticket=self.subticket_3)
452 self.subticket_4 = mommy.make('SubTicket', ticket=self.ticket_4,
453 source_package_upload=self.spu)
454- self.artifact_4 = mommy.make('Artifact', subticket=self.subticket_4)
455+ self.artifact_4 = mommy.make('SubTicketArtifact',
456+ subticket=self.subticket_4)
457
458 def test_queued_ticket_next(self):
459 obj = self.getResource('next/')
460
461=== modified file 'ticket_system/ticket/tests/test_models.py'
462--- ticket_system/ticket/tests/test_models.py 2014-01-09 21:08:05 +0000
463+++ ticket_system/ticket/tests/test_models.py 2014-01-24 17:44:23 +0000
464@@ -16,10 +16,10 @@
465 from django.db import IntegrityError
466 from django.test import TestCase
467 from project.models import SourcePackage
468-from ticket.models import (Artifact, SourcePackageUpload, SubTicket,
469- SubTicketWorkflowStep, SubTicketWorkflowStepStatus,
470- Ticket, TicketWorkflowStep,
471- TicketWorkflowStepStatus)
472+from ticket.models import (TicketArtifact, SubTicketArtifact, SubTicket,
473+ SourcePackageUpload, SubTicketWorkflowStep,
474+ SubTicketWorkflowStepStatus, Ticket,
475+ TicketWorkflowStep, TicketWorkflowStepStatus)
476
477
478 def create_sourcepackage(name='my-package'):
479@@ -72,9 +72,18 @@
480 return subticket
481
482
483-def create_artifact(name="test.log", subticket=None,
484- reference='123abc'):
485- artifact = Artifact()
486+def create_ticketartifact(name="test.log", ticket=None, reference='123abc'):
487+ artifact = TicketArtifact()
488+ artifact.name = name
489+ artifact.ticket = ticket
490+ artifact.reference = reference
491+ artifact.save()
492+ return artifact
493+
494+
495+def create_subticketartifact(name="test.log", subticket=None,
496+ reference='123abc'):
497+ artifact = SubTicketArtifact()
498 artifact.name = name
499 artifact.subticket = subticket
500 artifact.reference = reference
501@@ -91,10 +100,10 @@
502 self.subticket = create_subticket(ticket=self.ticket,
503 assignee='test@example.com',
504 source_package_upload=self.spu)
505- self.artifact_1 = create_artifact(subticket=self.subticket)
506
507- def test_creating_an_artifact(self):
508- artifact_in_database = Artifact.objects.exclude(
509+ def test_creating_an_artifact_subticket(self):
510+ self.artifact_1 = create_subticketartifact(subticket=self.subticket)
511+ artifact_in_database = SubTicketArtifact.objects.exclude(
512 subticket=None)
513 self.assertEquals(len(artifact_in_database), 1)
514 only_artifact_in_database = artifact_in_database[0]
515@@ -102,6 +111,15 @@
516
517 self.assertEquals(only_artifact_in_database.name, "test.log")
518
519+ def test_creating_an_artifact_ticket(self):
520+ self.artifact_2 = create_ticketartifact(ticket=self.ticket)
521+ artifact_in_database = TicketArtifact.objects.exclude(ticket=None)
522+ self.assertEquals(len(artifact_in_database), 1)
523+ only_artifact_in_database = artifact_in_database[0]
524+ self.assertEquals(only_artifact_in_database, self.artifact_2)
525+
526+ self.assertEquals(only_artifact_in_database.name, "test.log")
527+
528 def test_creating_a_ticket(self):
529 ticket_in_database = Ticket.objects.all()
530 self.assertEquals(len(ticket_in_database), 1)
531
532=== modified file 'ticket_system/ticket/tests/test_read_api.py'
533--- ticket_system/ticket/tests/test_read_api.py 2014-01-22 17:14:18 +0000
534+++ ticket_system/ticket/tests/test_read_api.py 2014-01-24 17:44:23 +0000
535@@ -34,13 +34,16 @@
536 sourcepackage=self.sourcepackage)
537 self.subticket = mommy.make('SubTicket', ticket=self.ticket,
538 source_package_upload=self.spu)
539- self.artifact = mommy.make('Artifact', subticket=self.subticket)
540+ self.artifact_1 = mommy.make('SubTicketArtifact',
541+ subticket=self.subticket)
542+ self.artifact_2 = mommy.make('TicketArtifact', ticket=self.ticket)
543+ self.maxDiff = None
544
545- def test_get_artifact_api(self):
546- obj = self.getResource('artifact/')
547+ def test_get_artifact_api_subticket(self):
548+ obj = self.getResource('subticketartifact/')
549 self.assertEqual(obj['objects'][0], {
550- u'name': unicode(self.artifact.name),
551- u'reference': unicode(self.artifact.reference),
552+ u'name': unicode(self.artifact_1.name),
553+ u'reference': unicode(self.artifact_1.reference),
554 u'subticket': {
555 u'status': unicode(get_enum_title(self.subticket.status,
556 SubTicketWorkflowStepStatus)),
557@@ -81,9 +84,41 @@
558 u'id': self.subticket.pk,
559 u'resource_uri': u'/api/v1/subticket/{0}/'.format(
560 self.subticket.pk)},
561- u'type': unicode(self.artifact.type),
562- u'id': self.artifact.pk,
563- u'resource_uri': u'/api/v1/artifact/{0}/'.format(self.artifact.pk),
564+ u'type': unicode(self.artifact_1.type),
565+ u'id': self.artifact_1.pk,
566+ u'resource_uri': u'/api/v1/subticketartifact/{0}/'.format(
567+ self.artifact_1.pk),
568+ })
569+
570+ def test_get_artifact_api_ticket(self):
571+ obj = self.getResource('ticketartifact/')
572+ self.assertEqual(obj['objects'][0], {
573+ u'name': unicode(self.artifact_2.name),
574+ u'reference': unicode(self.artifact_2.reference),
575+ u'ticket': {
576+ u'added_binaries': self.ticket.added_binaries,
577+ u'status': unicode(get_enum_title(self.ticket.status,
578+ TicketWorkflowStepStatus)),
579+ u'created': unicode(self.ticket.created.strftime(
580+ "%Y-%m-%dT%H:%M:%S.%f")),
581+ u'current_workflow_step': unicode(get_enum_title(
582+ self.ticket.current_workflow_step,
583+ TicketWorkflowStep)),
584+ u'description': unicode(self.ticket.description),
585+ u'title': unicode(self.ticket.title),
586+ u'bug_id': self.ticket.bug_id,
587+ u'owner': unicode(self.ticket.owner),
588+ u'removed_binaries': self.ticket.removed_binaries,
589+ u'base_image': unicode(self.ticket.base_image),
590+ u'id': self.ticket.pk,
591+ u'resource_uri': u'/api/v1/ticket/{0}/'.format(
592+ self.ticket.pk),
593+ u'updated': unicode(self.ticket.updated.strftime(
594+ "%Y-%m-%dT%H:%M:%S.%f"))},
595+ u'type': unicode(self.artifact_2.type),
596+ u'id': self.artifact_2.pk,
597+ u'resource_uri': u'/api/v1/ticketartifact/{0}/'.format(
598+ self.artifact_2.pk),
599 })
600
601 def test_get_subticket_api(self):
602@@ -284,25 +319,32 @@
603 sourcepackage=self.sourcepackage)
604 self.subticket_1 = mommy.make('SubTicket', ticket=self.ticket_1,
605 source_package_upload=self.spu)
606- self.artifact_1 = mommy.make('Artifact', subticket=self.subticket_1)
607+ self.artifact_1 = mommy.make('SubTicketArtifact',
608+ subticket=self.subticket_1)
609 self.subticket_2 = mommy.make('SubTicket', ticket=self.ticket_2,
610 source_package_upload=self.spu)
611- self.artifact_2 = mommy.make('Artifact', subticket=self.subticket_2)
612+ self.artifact_2 = mommy.make('SubTicketArtifact',
613+ subticket=self.subticket_2)
614 self.subticket_3 = mommy.make('SubTicket', ticket=self.ticket_3,
615 source_package_upload=self.spu)
616- self.artifact_3 = mommy.make('Artifact', subticket=self.subticket_3)
617+ self.artifact_3 = mommy.make('SubTicketArtifact',
618+ subticket=self.subticket_3)
619 self.subticket_4 = mommy.make('SubTicket', ticket=self.ticket_4,
620 source_package_upload=self.spu)
621- self.artifact_4 = mommy.make('Artifact', subticket=self.subticket_4)
622+ self.artifact_4 = mommy.make('SubTicketArtifact',
623+ subticket=self.subticket_4)
624 self.subticket_5 = mommy.make('SubTicket', ticket=self.ticket_5,
625 source_package_upload=self.spu)
626- self.artifact_5 = mommy.make('Artifact', subticket=self.subticket_5)
627+ self.artifact_5 = mommy.make('SubTicketArtifact',
628+ subticket=self.subticket_5)
629 self.subticket_6 = mommy.make('SubTicket', ticket=self.ticket_6,
630 source_package_upload=self.spu)
631- self.artifact_6 = mommy.make('Artifact', subticket=self.subticket_6)
632+ self.artifact_6 = mommy.make('SubTicketArtifact',
633+ subticket=self.subticket_6)
634 self.subticket_7 = mommy.make('SubTicket', ticket=self.ticket_7,
635 source_package_upload=self.spu)
636- self.artifact_7 = mommy.make('Artifact', subticket=self.subticket_7)
637+ self.artifact_7 = mommy.make('SubTicketArtifact',
638+ subticket=self.subticket_7)
639
640 def test_total_open_tickets(self):
641 obj = self.getResource('opentickets/')
642
643=== modified file 'ticket_system/ticket/tests/test_write_api.py'
644--- ticket_system/ticket/tests/test_write_api.py 2014-01-24 15:10:17 +0000
645+++ ticket_system/ticket/tests/test_write_api.py 2014-01-24 17:44:23 +0000
646@@ -17,9 +17,9 @@
647 from model_mommy.recipe import Recipe, seq
648 from ci_utils.tastypie.test import TastypieTestCase
649 from project.models import SourcePackage
650-from ticket.models import (Artifact, SourcePackageUpload, SubTicket,
651+from ticket.models import (TicketArtifact, SourcePackageUpload, SubTicket,
652 SubTicketWorkflowStep, SubTicketWorkflowStepStatus,
653- Ticket, TicketWorkflowStep,
654+ Ticket, TicketWorkflowStep, SubTicketArtifact,
655 TicketWorkflowStepStatus)
656
657
658@@ -132,7 +132,7 @@
659 'assignee': 'test@example.com',
660 }
661
662- def test_post_subticket(self):
663+ def test_post_subticket_subticket(self):
664 # Check how many are there first.
665 self.assertEqual(SubTicket.objects.count(), 1)
666 self.post(resource=self.resource, params=self.post_subticket_data)
667@@ -159,32 +159,86 @@
668 self.assertHttpMethodNotAllowed(resp)
669
670
671-class APICreateArtifactResourceTest(TastypieTestCase):
672-
673- def setUp(self):
674- super(APICreateArtifactResourceTest, self).setUp('/api/v1')
675+class APICreateTicketArtifactResourceTest(TastypieTestCase):
676+
677+ def setUp(self):
678+ super(APICreateTicketArtifactResourceTest, self).setUp('/api/v1')
679+ self.ticket = mommy.make('Ticket')
680+ self.artifact = mommy.make('TicketArtifact',
681+ ticket=self.ticket)
682+ self.resource = 'ticketartifact/'
683+ self.detail_url = self.resource + '{0}/'.format(self.artifact.pk)
684+ self.ticket_uri = '/api/v1/ticket/{0}/'.format(self.ticket.pk)
685+ self.post_artifact_data_ticket = {
686+ 'type': 'LOGS',
687+ 'name': 'my_artifact',
688+ 'ticket': self.ticket_uri,
689+ 'reference': 'http://www.example.com/m1CTLg5FHY',
690+ }
691+
692+ def test_post_artifact_ticket(self):
693+ """
694+ Test creating an artifact for a ticket via the API
695+ """
696+ # Check how many are there first.
697+ self.assertEqual(TicketArtifact.objects.count(), 1)
698+ self.post(resource=self.resource,
699+ params=self.post_artifact_data_ticket)
700+ # Verify a new one has been added.
701+ self.assertEqual(TicketArtifact.objects.count(), 2)
702+
703+ def test_patch_detail(self):
704+ # Grab the current data & modify it slightly.
705+ original_data = self.getResource(self.detail_url)
706+ new_data = original_data.copy()
707+ new_data['name'] = 'my_upload'
708+
709+ self.assertEqual(TicketArtifact.objects.count(), 1)
710+ resp = self.client.patch('/api/v1/' + self.detail_url, data=new_data)
711+ self.assertHttpMethodNotAllowed(resp)
712+ # Make sure the count hasn't changed & we did an update.
713+ self.assertEqual(TicketArtifact.objects.count(), 1)
714+ # Check for updated data.
715+ self.assertEqual(TicketArtifact.objects.get(
716+ pk=self.artifact.pk).name, self.artifact.name)
717+
718+ def test_delete_artifact_not_allowed(self):
719+ resp = self.delete(resource=self.detail_url)
720+ self.assertHttpMethodNotAllowed(resp)
721+
722+
723+class APICreateSubTicketArtifactResourceTest(TastypieTestCase):
724+
725+ def setUp(self):
726+ super(APICreateSubTicketArtifactResourceTest, self).setUp('/api/v1')
727 self.sourcepackage = sourcepackage_recipe.make()
728 self.spu = mommy.make('SourcePackageUpload',
729 sourcepackage=self.sourcepackage)
730- self.subticket = mommy.make('SubTicket',
731+ self.ticket = mommy.make('Ticket')
732+ self.subticket = mommy.make('SubTicket', ticket=self.ticket,
733 source_package_upload=self.spu)
734- self.artifact = mommy.make('Artifact', subticket=self.subticket)
735- self.resource = 'artifact/'
736+ self.artifact = mommy.make('SubTicketArtifact',
737+ subticket=self.subticket)
738+ self.resource = 'subticketartifact/'
739 self.detail_url = self.resource + '{0}/'.format(self.artifact.pk)
740 self.subticket_uri = '/api/v1/subticket/{0}/'.format(self.subticket.pk)
741- self.post_artifact_data = {
742+ self.post_artifact_data_subticket = {
743 'type': 'SPU',
744 'name': 'my_artifact',
745 'subticket': self.subticket_uri,
746- 'reference': 'm1CTLg5FHY',
747+ 'reference': 'http://www.example.com/m1CTLg5FHY',
748 }
749
750- def test_post_artifact(self):
751+ def test_post_artifact_subticket(self):
752+ """
753+ Test creating an artifact for a subticket via the API
754+ """
755 # Check how many are there first.
756- self.assertEqual(Artifact.objects.count(), 1)
757- self.post(resource=self.resource, params=self.post_artifact_data)
758+ self.assertEqual(SubTicketArtifact.objects.count(), 1)
759+ self.post(resource=self.resource,
760+ params=self.post_artifact_data_subticket)
761 # Verify a new one has been added.
762- self.assertEqual(Artifact.objects.count(), 2)
763+ self.assertEqual(SubTicketArtifact.objects.count(), 2)
764
765 def test_patch_detail(self):
766 # Grab the current data & modify it slightly.
767@@ -192,14 +246,14 @@
768 new_data = original_data.copy()
769 new_data['name'] = 'my_upload'
770
771- self.assertEqual(Artifact.objects.count(), 1)
772+ self.assertEqual(SubTicketArtifact.objects.count(), 1)
773 resp = self.client.patch('/api/v1/' + self.detail_url, data=new_data)
774 self.assertHttpMethodNotAllowed(resp)
775 # Make sure the count hasn't changed & we did an update.
776- self.assertEqual(Artifact.objects.count(), 1)
777+ self.assertEqual(SubTicketArtifact.objects.count(), 1)
778 # Check for updated data.
779- self.assertEqual(Artifact.objects.get(pk=self.artifact.pk).name,
780- self.artifact.name)
781+ self.assertEqual(SubTicketArtifact.objects.get(
782+ pk=self.artifact.pk).name, self.artifact.name)
783
784 def test_delete_artifact_not_allowed(self):
785 resp = self.delete(resource=self.detail_url)
786
787=== modified file 'ticket_system/ticket_system/urls.py'
788--- ticket_system/ticket_system/urls.py 2014-01-20 16:41:12 +0000
789+++ ticket_system/ticket_system/urls.py 2014-01-24 17:44:23 +0000
790@@ -18,12 +18,14 @@
791 from tastypie.api import Api
792 from people.api import PersonResource
793 from project.api import SourcePackageResource, BinaryPackageResource
794-from ticket.api import (TicketResource, SubTicketResource, ArtifactResource,
795+from ticket.api import (TicketResource, SubTicketResource,
796+ TicketArtifactResource, SubTicketArtifactResource,
797 SourcePackageUploadResource, FullSubTicketResource,
798- FullTicketResource, FullArtifactResource,
799+ FullTicketResource, FullTicketArtifactResource,
800 TicketStatusResource, TicketUpdateStatusResource,
801 SubTicketUpdateStatusResource, NextTicketResource,
802- SubTicketStatusResource, OpenTicketResource)
803+ SubTicketStatusResource, OpenTicketResource,
804+ FullSubTicketArtifactResource)
805
806 admin.autodiscover()
807 v1_api = Api(api_name='v1')
808@@ -33,8 +35,10 @@
809 v1_api.register(TicketResource())
810 v1_api.register(SubTicketResource())
811 v1_api.register(SourcePackageUploadResource())
812-v1_api.register(ArtifactResource())
813-v1_api.register(FullArtifactResource())
814+v1_api.register(TicketArtifactResource())
815+v1_api.register(SubTicketArtifactResource())
816+v1_api.register(FullTicketArtifactResource())
817+v1_api.register(FullSubTicketArtifactResource())
818 v1_api.register(FullSubTicketResource())
819 v1_api.register(FullTicketResource())
820 v1_api.register(SubTicketUpdateStatusResource())

Subscribers

People subscribed via source and target branches