1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
import time |
3
|
|
|
|
4
|
|
|
from modernrpc.core import rpc_method, REQUEST_KEY |
5
|
|
|
|
6
|
|
|
from tcms.core.utils import form_errors_to_list |
7
|
|
|
from tcms.core.contrib.comments.forms import SimpleForm |
8
|
|
|
from tcms.core.contrib.comments import utils as comment_utils |
9
|
|
|
from tcms.core.contrib.linkreference.views import create_link |
10
|
|
|
from tcms.core.contrib.linkreference.models import LinkReference |
11
|
|
|
from tcms.xmlrpc.serializer import XMLRPCSerializer |
12
|
|
|
from tcms.testruns.models import TestExecution |
13
|
|
|
from tcms.xmlrpc.decorators import permissions_required |
14
|
|
|
|
15
|
|
|
__all__ = ( |
16
|
|
|
'create', |
17
|
|
|
'update', |
18
|
|
|
'filter', |
19
|
|
|
|
20
|
|
|
'add_comment', |
21
|
|
|
|
22
|
|
|
'add_link', |
23
|
|
|
'get_links', |
24
|
|
|
'remove_link', |
25
|
|
|
) |
26
|
|
|
|
27
|
|
|
|
28
|
|
|
@rpc_method(name='TestCaseRun.add_comment') |
29
|
|
|
def add_comment(case_run_id, comment, **kwargs): |
30
|
|
|
""" |
31
|
|
|
.. function:: XML-RPC TestCaseRun.add_comment(case_run_id, comment) |
32
|
|
|
|
33
|
|
|
Add comment to selected test case run. |
34
|
|
|
|
35
|
|
|
:param case_run_id: PK of a TestCaseRun object |
36
|
|
|
:param case_run_id: int |
37
|
|
|
:param comment: The text to add as a comment |
38
|
|
|
:param comment: str |
39
|
|
|
:return: None or JSON string in case of errors |
40
|
|
|
""" |
41
|
|
|
case_run = TestExecution.objects.get(pk=case_run_id) |
42
|
|
|
|
43
|
|
|
data = { |
44
|
|
|
'content_type': 'testruns.testexecution', |
45
|
|
|
'object_pk': str(case_run_id), |
46
|
|
|
'timestamp': str(time.time()).split('.')[0], |
47
|
|
|
} |
48
|
|
|
data['security_hash'] = SimpleForm(case_run).generate_security_hash(**data) |
49
|
|
|
data['comment'] = comment |
50
|
|
|
|
51
|
|
|
form, _ = comment_utils.add_comment(kwargs.get(REQUEST_KEY), data) |
52
|
|
|
|
53
|
|
|
if not form.is_valid(): |
54
|
|
|
return form.errors.as_json() |
55
|
|
|
|
56
|
|
|
return None |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
# todo: this is very similar, if not duplicate to TestRun.add_case IMO |
60
|
|
|
# should we schedule it for removal ?!? |
61
|
|
|
@permissions_required('testruns.add_testexecution') |
62
|
|
|
@rpc_method(name='TestCaseRun.create') |
63
|
|
|
def create(values): |
64
|
|
|
""" |
65
|
|
|
.. function:: XML-RPC TestCaseRun.create(values) |
66
|
|
|
|
67
|
|
|
Create new TestCaseRun object and store it in the database. |
68
|
|
|
|
69
|
|
|
:param values: Field values for :class:`tcms.testruns.models.TestCaseRun` |
70
|
|
|
:type values: dict |
71
|
|
|
:return: Serialized :class:`tcms.testruns.models.TestCaseRun` object |
72
|
|
|
:raises: PermissionDenied if missing *testruns.add_testexecution* permission |
73
|
|
|
|
74
|
|
|
Minimal parameters:: |
75
|
|
|
|
76
|
|
|
>>> values = { |
77
|
|
|
'run': 1990, |
78
|
|
|
'case': 12345, |
79
|
|
|
'build': 123, |
80
|
|
|
} |
81
|
|
|
>>> TestExecution.create(values) |
82
|
|
|
""" |
83
|
|
|
from tcms.testruns.forms import XMLRPCNewCaseRunForm |
84
|
|
|
|
85
|
|
|
form = XMLRPCNewCaseRunForm(values) |
86
|
|
|
|
87
|
|
|
if not isinstance(values, dict): |
88
|
|
|
raise TypeError('Argument values must be in dict type.') |
89
|
|
|
if not values: |
90
|
|
|
raise ValueError('Argument values is empty.') |
91
|
|
|
|
92
|
|
|
if form.is_valid(): |
93
|
|
|
run = form.cleaned_data['run'] |
94
|
|
|
|
95
|
|
|
testcase_run = run.add_case_run( |
96
|
|
|
case=form.cleaned_data['case'], |
97
|
|
|
build=form.cleaned_data['build'], |
98
|
|
|
assignee=form.cleaned_data['assignee'], |
99
|
|
|
status=form.cleaned_data['status'], |
100
|
|
|
case_text_version=form.cleaned_data['case_text_version'], |
101
|
|
|
sortkey=form.cleaned_data['sortkey'] |
102
|
|
|
) |
103
|
|
|
else: |
104
|
|
|
raise ValueError(form_errors_to_list(form)) |
105
|
|
|
|
106
|
|
|
return testcase_run.serialize() |
107
|
|
|
|
108
|
|
|
|
109
|
|
|
@rpc_method(name='TestCaseRun.filter') |
110
|
|
|
def filter(values): # pylint: disable=redefined-builtin |
111
|
|
|
""" |
112
|
|
|
.. function:: XML-RPC TestCaseRun.filter(values) |
113
|
|
|
|
114
|
|
|
Perform a search and return the resulting list of test case executions. |
115
|
|
|
|
116
|
|
|
:param values: Field lookups for :class:`tcms.testruns.models.TestCaseRun` |
117
|
|
|
:type values: dict |
118
|
|
|
:return: List of serialized :class:`tcms.testruns.models.TestCaseRun` objects |
119
|
|
|
:rtype: list(dict) |
120
|
|
|
""" |
121
|
|
|
return TestExecution.to_xmlrpc(values) |
122
|
|
|
|
123
|
|
|
|
124
|
|
|
@permissions_required('testruns.change_testexecution') |
125
|
|
|
@rpc_method(name='TestCaseRun.update') |
126
|
|
|
def update(case_run_id, values, **kwargs): |
127
|
|
|
""" |
128
|
|
|
.. function:: XML-RPC TestCaseRun.update(case_run_id, values) |
129
|
|
|
|
130
|
|
|
Update the selected TestCaseRun |
131
|
|
|
|
132
|
|
|
:param case_run_id: PK of TestCaseRun to modify |
133
|
|
|
:type case_run_id: int |
134
|
|
|
:param values: Field values for :class:`tcms.testruns.models.TestCaseRun` |
135
|
|
|
:type values: dict |
136
|
|
|
:return: Serialized :class:`tcms.testruns.models.TestCaseRun` object |
137
|
|
|
:raises: PermissionDenied if missing *testruns.change_testexecution* permission |
138
|
|
|
""" |
139
|
|
|
from tcms.testruns.forms import XMLRPCUpdateCaseRunForm |
140
|
|
|
|
141
|
|
|
tcr = TestExecution.objects.get(pk=case_run_id) |
142
|
|
|
form = XMLRPCUpdateCaseRunForm(values) |
143
|
|
|
|
144
|
|
|
if form.is_valid(): |
145
|
|
|
if form.cleaned_data['build']: |
146
|
|
|
tcr.build = form.cleaned_data['build'] |
147
|
|
|
|
148
|
|
|
if form.cleaned_data['assignee']: |
149
|
|
|
tcr.assignee = form.cleaned_data['assignee'] |
150
|
|
|
|
151
|
|
|
if form.cleaned_data['status']: |
152
|
|
|
tcr.status = form.cleaned_data['status'] |
153
|
|
|
request = kwargs.get(REQUEST_KEY) |
154
|
|
|
tcr.tested_by = request.user |
155
|
|
|
|
156
|
|
|
if form.cleaned_data['sortkey'] is not None: |
157
|
|
|
tcr.sortkey = form.cleaned_data['sortkey'] |
158
|
|
|
|
159
|
|
|
tcr.save() |
160
|
|
|
|
161
|
|
|
else: |
162
|
|
|
raise ValueError(form_errors_to_list(form)) |
163
|
|
|
|
164
|
|
|
return tcr.serialize() |
165
|
|
|
|
166
|
|
|
|
167
|
|
|
@rpc_method(name='TestCaseRun.add_link') |
168
|
|
|
def add_link(case_run_id, name, url): |
169
|
|
|
""" |
170
|
|
|
.. function:: XML-RPC TestCaseRun.add_link(case_run_id, name, url) |
171
|
|
|
|
172
|
|
|
Add new URL link to a TestCaseRun |
173
|
|
|
|
174
|
|
|
:param case_run_id: PK of a TestCaseRun object |
175
|
|
|
:type case_run_id: int |
176
|
|
|
:param name: Name/description of the link |
177
|
|
|
:type name: str |
178
|
|
|
:param url: URL address |
179
|
|
|
:type url: str |
180
|
|
|
:return: ID of created link |
181
|
|
|
:rtype: int |
182
|
|
|
:raises: RuntimeError if operation not successfull |
183
|
|
|
""" |
184
|
|
|
result = create_link({ |
185
|
|
|
'name': name, |
186
|
|
|
'url': url, |
187
|
|
|
'target': 'TestExecution', |
188
|
|
|
'target_id': case_run_id |
189
|
|
|
}) |
190
|
|
|
if result['rc'] != 0: |
191
|
|
|
raise RuntimeError(result['response']) |
192
|
|
|
return result['data']['pk'] |
193
|
|
|
|
194
|
|
|
|
195
|
|
|
@rpc_method(name='TestCaseRun.remove_link') |
196
|
|
|
def remove_link(case_run_id, link_id): |
197
|
|
|
""" |
198
|
|
|
.. function:: XML-RPC TestCaseRun.remove_link(case_run_id, link_id) |
199
|
|
|
|
200
|
|
|
Remove URL link from TestCaseRun |
201
|
|
|
|
202
|
|
|
:param case_run_id: PK of TestCaseRun to modify |
203
|
|
|
:type case_run_id: int |
204
|
|
|
:param link_id: PK of link to remove |
205
|
|
|
:type link_id: int |
206
|
|
|
:return: None |
207
|
|
|
""" |
208
|
|
|
LinkReference.objects.filter(pk=link_id, test_case_run=case_run_id).delete() |
209
|
|
|
|
210
|
|
|
|
211
|
|
|
@rpc_method(name='TestCaseRun.get_links') |
212
|
|
|
def get_links(case_run_id): |
213
|
|
|
""" |
214
|
|
|
.. function:: XML-RPC TestCaseRun.get_links(case_run_id) |
215
|
|
|
|
216
|
|
|
Get URL links for the specified TestCaseRun |
217
|
|
|
|
218
|
|
|
:param case_run_id: PK of TestCaseRun object |
219
|
|
|
:type case_run_id: int |
220
|
|
|
:return: Serialized list of :class:`tcms.core.contrib.linkreference.models.LinkReference` |
221
|
|
|
objects |
222
|
|
|
""" |
223
|
|
|
links = LinkReference.objects.filter(test_case_run=case_run_id) |
224
|
|
|
serialier = XMLRPCSerializer(links) |
225
|
|
|
return serialier.serialize_queryset() |
226
|
|
|
|
227
|
|
|
|
228
|
|
|
# workaround for keeping backward-compatibility with users of the API calling TestCaseRun.* |
229
|
|
|
@rpc_method(name='TestExecution.add_comment') |
230
|
|
|
def test_execution_add_comment(case_run_id, comment, **kwargs): |
231
|
|
|
return add_comment(case_run_id, comment, **kwargs) |
232
|
|
|
|
233
|
|
|
|
234
|
|
|
@permissions_required('testruns.add_testexecution') |
235
|
|
|
@rpc_method(name='TestExecution.create') |
236
|
|
|
def test_execution_create(values): |
237
|
|
|
return create(values) |
238
|
|
|
|
239
|
|
|
|
240
|
|
|
@rpc_method(name='TestExecution.filter') |
241
|
|
|
def test_execution_filter(values): |
242
|
|
|
return filter(values) |
243
|
|
|
|
244
|
|
|
|
245
|
|
|
@rpc_method(name='TestExecution.get_links') |
246
|
|
|
def test_execution_get_links(case_run_id): |
247
|
|
|
return get_links(case_run_id) |
248
|
|
|
|
249
|
|
|
|
250
|
|
|
@rpc_method(name='TestExecution.remove_link') |
251
|
|
|
def test_execution_remove_link(case_run_id, link_id): |
252
|
|
|
return remove_link(case_run_id, link_id) |
253
|
|
|
|
254
|
|
|
|
255
|
|
|
@permissions_required('testruns.change_testexecution') |
256
|
|
|
@rpc_method(name='TestExecution.update') |
257
|
|
|
def test_execution_update(case_run_id, values, **kwargs): |
258
|
|
|
return update(case_run_id, values, **kwargs) |
259
|
|
|
|
260
|
|
|
|
261
|
|
|
@rpc_method(name='TestExecution.add_link') |
262
|
|
|
def test_execution_add_link(case_run_id, name, url): |
263
|
|
|
return add_link(case_run_id, name, url) |
264
|
|
|
|