1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
from modernrpc.core import rpc_method, REQUEST_KEY |
3
|
|
|
|
4
|
|
|
from tcms.core.utils import form_errors_to_list |
5
|
|
|
from tcms.management.models import Tag |
6
|
|
|
from tcms.testcases.models import TestCase |
7
|
|
|
from tcms.testruns.models import TestExecution |
8
|
|
|
from tcms.testruns.models import TestRun |
9
|
|
|
from tcms.xmlrpc.decorators import permissions_required |
10
|
|
|
from tcms.testruns.forms import XMLRPCUpdateRunForm, XMLRPCNewRunForm |
11
|
|
|
|
12
|
|
|
|
13
|
|
|
__all__ = ( |
14
|
|
|
'create', |
15
|
|
|
'update', |
16
|
|
|
'filter', |
17
|
|
|
|
18
|
|
|
'add_case', |
19
|
|
|
'get_cases', |
20
|
|
|
'remove_case', |
21
|
|
|
|
22
|
|
|
'add_tag', |
23
|
|
|
'remove_tag', |
24
|
|
|
) |
25
|
|
|
|
26
|
|
|
|
27
|
|
|
@permissions_required('testruns.add_testexecution') |
28
|
|
|
@rpc_method(name='TestRun.add_case') |
29
|
|
|
def add_case(run_id, case_id): |
30
|
|
|
""" |
31
|
|
|
.. function:: XML-RPC TestRun.add_case(run_id, case_id) |
32
|
|
|
|
33
|
|
|
Add a TestCase to the selected test run. |
34
|
|
|
|
35
|
|
|
:param run_id: PK of TestRun to modify |
36
|
|
|
:type run_id: int |
37
|
|
|
:param case_id: PK of TestCase to be added |
38
|
|
|
:type case_id: int |
39
|
|
|
:return: Serialized :class:`tcms.testruns.models.TestExecution` object |
40
|
|
|
:raises: DoesNotExist if objects specified by the PKs don't exist |
41
|
|
|
:raises: PermissionDenied if missing *testruns.add_testexecution* permission |
42
|
|
|
""" |
43
|
|
|
test_case_run = TestRun.objects.get(pk=run_id).add_case_run( |
44
|
|
|
case=TestCase.objects.get(pk=case_id) |
45
|
|
|
) |
46
|
|
|
return test_case_run.serialize() |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
@permissions_required('testruns.delete_testexecution') |
50
|
|
|
@rpc_method(name='TestRun.remove_case') |
51
|
|
|
def remove_case(run_id, case_id): |
52
|
|
|
""" |
53
|
|
|
.. function:: XML-RPC TestRun.remove_case(run_id, case_id) |
54
|
|
|
|
55
|
|
|
Remove a TestCase from the selected test run. |
56
|
|
|
|
57
|
|
|
:param run_id: PK of TestRun to modify |
58
|
|
|
:type run_id: int |
59
|
|
|
:param case_id: PK of TestCase to be removed |
60
|
|
|
:type case_id: int |
61
|
|
|
:return: None |
62
|
|
|
:raises: PermissionDenied if missing *testruns.delete_testexecution* permission |
63
|
|
|
""" |
64
|
|
|
TestExecution.objects.filter(run=run_id, case=case_id).delete() |
65
|
|
|
|
66
|
|
|
|
67
|
|
|
@rpc_method(name='TestRun.get_cases') |
68
|
|
|
def get_cases(run_id): |
69
|
|
|
""" |
70
|
|
|
.. function:: XML-RPC TestRun.get_cases(run_id) |
71
|
|
|
|
72
|
|
|
Get the list of test cases that are attached to a test run. |
73
|
|
|
|
74
|
|
|
:param run_id: PK of TestRun to inspect |
75
|
|
|
:type run_id: int |
76
|
|
|
:return: Serialized list of :class:`tcms.testcases.models.TestCase` objects |
77
|
|
|
augmented with ``case_run_id`` and ``status`` information. |
78
|
|
|
:rtype: list(dict) |
79
|
|
|
""" |
80
|
|
|
tcs_serializer = TestCase.to_xmlrpc(query={'case_run__run_id': run_id}) |
81
|
|
|
|
82
|
|
|
qs = TestExecution.objects.filter(run_id=run_id).values( |
83
|
|
|
'case', 'pk', 'status__name') |
84
|
|
|
extra_info = dict(((row['case'], row) for row in qs.iterator())) |
|
|
|
|
85
|
|
|
|
86
|
|
|
for case in tcs_serializer: |
87
|
|
|
info = extra_info[case['case_id']] |
88
|
|
|
case['case_run_id'] = info['pk'] |
89
|
|
|
case['status'] = info['status__name'] |
90
|
|
|
|
91
|
|
|
return tcs_serializer |
92
|
|
|
|
93
|
|
|
|
94
|
|
|
@permissions_required('testruns.add_testruntag') |
95
|
|
|
@rpc_method(name='TestRun.add_tag') |
96
|
|
|
def add_tag(run_id, tag_name, **kwargs): |
97
|
|
|
""" |
98
|
|
|
.. function:: XML-RPC TestRun.add_tag(run_id, tag) |
99
|
|
|
|
100
|
|
|
Add one tag to the specified test run. |
101
|
|
|
|
102
|
|
|
:param run_id: PK of TestRun to modify |
103
|
|
|
:type run_id: int |
104
|
|
|
:param tag_name: Tag name to add |
105
|
|
|
:type tag_name: str |
106
|
|
|
:return: Serialized list of :class:`tcms.management.models.Tag` objects |
107
|
|
|
:raises: PermissionDenied if missing *testruns.add_testruntag* permission |
108
|
|
|
:raises: TestRun.DoesNotExist if object specified by PK doesn't exist |
109
|
|
|
:raises: Tag.DoesNotExist if missing *management.add_tag* permission and *tag_name* |
110
|
|
|
doesn't exist in the database! |
111
|
|
|
""" |
112
|
|
|
request = kwargs.get(REQUEST_KEY) |
113
|
|
|
tag, _ = Tag.get_or_create(request.user, tag_name) |
114
|
|
|
test_run = TestRun.objects.get(pk=run_id) |
115
|
|
|
test_run.add_tag(tag) |
116
|
|
|
return Tag.to_xmlrpc({'pk__in': test_run.tag.all()}) |
117
|
|
|
|
118
|
|
|
|
119
|
|
|
@permissions_required('testruns.delete_testruntag') |
120
|
|
|
@rpc_method(name='TestRun.remove_tag') |
121
|
|
|
def remove_tag(run_id, tag_name): |
122
|
|
|
""" |
123
|
|
|
.. function:: XML-RPC TestRun.remove_tag(run_id, tag) |
124
|
|
|
|
125
|
|
|
Remove a tag from the specified test run. |
126
|
|
|
|
127
|
|
|
:param run_id: PK of TestRun to modify |
128
|
|
|
:type run_id: int |
129
|
|
|
:param tag_name: Tag name to add |
130
|
|
|
:type tag_name: str |
131
|
|
|
:return: Serialized list of :class:`tcms.management.models.Tag` objects |
132
|
|
|
:raises: PermissionDenied if missing *testruns.delete_testruntag* permission |
133
|
|
|
:raises: DoesNotExist if objects specified don't exist |
134
|
|
|
""" |
135
|
|
|
tag = Tag.objects.get(name=tag_name) |
136
|
|
|
test_run = TestRun.objects.get(pk=run_id) |
137
|
|
|
test_run.remove_tag(tag) |
138
|
|
|
return Tag.to_xmlrpc({'pk__in': test_run.tag.all()}) |
139
|
|
|
|
140
|
|
|
|
141
|
|
|
@permissions_required('testruns.add_testrun') |
142
|
|
|
@rpc_method(name='TestRun.create') |
143
|
|
|
def create(values): |
144
|
|
|
""" |
145
|
|
|
.. function:: XML-RPC TestRun.create(values) |
146
|
|
|
|
147
|
|
|
Create new TestRun object and store it in the database. |
148
|
|
|
|
149
|
|
|
:param values: Field values for :class:`tcms.testruns.models.TestRun` |
150
|
|
|
:type values: dict |
151
|
|
|
:return: Serialized :class:`tcms.testruns.models.TestRun` object |
152
|
|
|
:raises: PermissionDenied if missing *testruns.add_testrun* permission |
153
|
|
|
:raises: ValueError if data validations fail |
154
|
|
|
|
155
|
|
|
Example:: |
156
|
|
|
|
157
|
|
|
>>> values = {'build': 384, |
158
|
|
|
'manager': 137, |
159
|
|
|
'plan': 137, |
160
|
|
|
'summary': 'Testing XML-RPC for TCMS', |
161
|
|
|
} |
162
|
|
|
>>> TestRun.create(values) |
163
|
|
|
""" |
164
|
|
|
form = XMLRPCNewRunForm(values) |
165
|
|
|
form.assign_plan(values.get('plan')) |
166
|
|
|
|
167
|
|
|
if form.is_valid(): |
168
|
|
|
test_run = TestRun.objects.create( |
169
|
|
|
product_version=form.cleaned_data['plan'].product_version, |
170
|
|
|
summary=form.cleaned_data['summary'], |
171
|
|
|
notes=form.cleaned_data['notes'], |
172
|
|
|
plan=form.cleaned_data['plan'], |
173
|
|
|
build=form.cleaned_data['build'], |
174
|
|
|
manager=form.cleaned_data['manager'], |
175
|
|
|
default_tester=form.cleaned_data['default_tester'], |
176
|
|
|
) |
177
|
|
|
else: |
178
|
|
|
raise ValueError(form_errors_to_list(form)) |
179
|
|
|
|
180
|
|
|
return test_run.serialize() |
181
|
|
|
|
182
|
|
|
|
183
|
|
|
@rpc_method(name='TestRun.filter') |
184
|
|
|
def filter(query=None): # pylint: disable=redefined-builtin |
185
|
|
|
""" |
186
|
|
|
.. function:: XML-RPC TestRun.filter(query) |
187
|
|
|
|
188
|
|
|
Perform a search and return the resulting list of test runs. |
189
|
|
|
|
190
|
|
|
:param query: Field lookups for :class:`tcms.testruns.models.TestRun` |
191
|
|
|
:type query: dict |
192
|
|
|
:return: List of serialized :class:`tcms.testruns.models.TestRun` objects |
193
|
|
|
:rtype: list(dict) |
194
|
|
|
""" |
195
|
|
|
|
196
|
|
|
if query is None: |
197
|
|
|
query = {} |
198
|
|
|
|
199
|
|
|
return TestRun.to_xmlrpc(query) |
200
|
|
|
|
201
|
|
|
|
202
|
|
|
@permissions_required('testruns.change_testrun') |
203
|
|
|
@rpc_method(name='TestRun.update') |
204
|
|
|
def update(run_id, values): |
205
|
|
|
""" |
206
|
|
|
.. function:: XML-RPC TestRun.update(run_id, values) |
207
|
|
|
|
208
|
|
|
Update the selected TestRun |
209
|
|
|
|
210
|
|
|
:param run_id: PK of TestRun to modify |
211
|
|
|
:type run_id: int |
212
|
|
|
:param values: Field values for :class:`tcms.testruns.models.TestRun` |
213
|
|
|
:type values: dict |
214
|
|
|
:return: Serialized :class:`tcms.testruns.models.TestRun` object |
215
|
|
|
:raises: PermissionDenied if missing *testruns.change_testrun* permission |
216
|
|
|
:raises: ValueError if data validations fail |
217
|
|
|
""" |
218
|
|
|
if values.get('product_version') and not values.get('product'): |
219
|
|
|
raise ValueError('Field "product" is required by product_version') |
220
|
|
|
|
221
|
|
|
form = XMLRPCUpdateRunForm(values) |
222
|
|
|
if values.get('product_version'): |
223
|
|
|
form.populate(product_id=values['product']) |
224
|
|
|
|
225
|
|
|
if not form.is_valid(): |
226
|
|
|
raise ValueError(form_errors_to_list(form)) |
227
|
|
|
|
228
|
|
|
test_run = TestRun.objects.get(pk=run_id) |
229
|
|
|
if form.cleaned_data['plan']: |
230
|
|
|
test_run.plan = form.cleaned_data['plan'] |
231
|
|
|
|
232
|
|
|
if form.cleaned_data['build']: |
233
|
|
|
test_run.build = form.cleaned_data['build'] |
234
|
|
|
|
235
|
|
|
if form.cleaned_data['manager']: |
236
|
|
|
test_run.manager = form.cleaned_data['manager'] |
237
|
|
|
|
238
|
|
|
test_run.default_tester = None |
239
|
|
|
|
240
|
|
|
if form.cleaned_data['default_tester']: |
241
|
|
|
test_run.default_tester = form.cleaned_data['default_tester'] |
242
|
|
|
|
243
|
|
|
if form.cleaned_data['summary']: |
244
|
|
|
test_run.summary = form.cleaned_data['summary'] |
245
|
|
|
|
246
|
|
|
if form.cleaned_data['product_version']: |
247
|
|
|
test_run.product_version = form.cleaned_data['product_version'] |
248
|
|
|
|
249
|
|
|
if 'notes' in values: |
250
|
|
|
if values['notes'] in (None, ''): |
251
|
|
|
test_run.notes = values['notes'] |
252
|
|
|
if form.cleaned_data['notes']: |
253
|
|
|
test_run.notes = form.cleaned_data['notes'] |
254
|
|
|
|
255
|
|
|
if form.cleaned_data['stop_date']: |
256
|
|
|
test_run.stop_date = form.cleaned_data['stop_date'] |
257
|
|
|
|
258
|
|
|
test_run.save() |
259
|
|
|
return test_run.serialize() |
260
|
|
|
|