-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathclient.py
More file actions
391 lines (309 loc) · 11.3 KB
/
client.py
File metadata and controls
391 lines (309 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
import re
import sys
from testrail.api import API
from testrail.case import Case
from testrail.configuration import Config, ConfigContainer
from testrail.helper import methdispatch, singleresult, TestRailError
from testrail.milestone import Milestone
from testrail.plan import Plan, PlanContainer
from testrail.project import Project, ProjectContainer
from testrail.result import Result, ResultContainer
from testrail.run import Run, RunContainer
from testrail.status import Status
from testrail.suite import Suite
from testrail.section import Section
from testrail.test import Test
from testrail.user import User
if sys.version_info >= (3,0):
unicode = str
class TestRail(object):
def __init__(self, project_id=0, email=None, key=None, url=None, verify_ssl=True, proxies=None):
self.api = API(email=email, key=key, url=url, verify_ssl=verify_ssl, proxies=proxies)
self.api.set_project_id(project_id)
self._project_id = project_id
def set_project_id(self, project_id):
self._project_id = project_id
self.api.set_project_id(project_id)
# Post generics
@methdispatch
def add(self, obj):
raise NotImplementedError
@methdispatch
def update(self, obj):
raise NotImplementedError
@methdispatch
def close(self, obj):
raise NotImplementedError
@methdispatch
def delete(self, obj):
raise NotImplementedError
# Project Methods
def projects(self):
return ProjectContainer(list(map(Project, self.api.projects())))
@methdispatch
def project(self):
return Project()
@project.register(str)
@project.register(unicode)
@singleresult
def _project_by_name(self, name):
return filter(lambda p: p.name == name, self.projects())
@project.register(int)
@singleresult
def _project_by_id(self, project_id):
return filter(lambda p: p.id == project_id, self.projects())
# User Methods
def users(self):
return list(map(User, self.api.users()))
@methdispatch
def user(self):
return User()
@user.register(int)
@singleresult
def _user_by_id(self, identifier):
return filter(lambda u: u.id == identifier, self.users())
@user.register(str)
@user.register(unicode)
@singleresult
def _user_by_email_name(self, identifier):
by_email = lambda u: u.email == identifier
by_name = lambda u: u.name == identifier
f = by_email if re.match('[^@]+@[^@]+\.[^@]+', identifier) else by_name
return filter(f, self.users())
def active_users(self):
return list(filter(lambda u: u.is_active is True, self.users()))
def inactive_users(self):
return list(filter(lambda u: u.is_active is False, self.users()))
# Suite Methods
def suites(self):
return list(map(Suite, self.api.suites(self._project_id)))
@methdispatch
def suite(self):
return Suite()
@suite.register(str)
@suite.register(unicode)
@singleresult
def _suite_by_name(self, name):
return filter(lambda s: s.name.lower() == name.lower(), self.suites())
@suite.register(int)
@singleresult
def _suite_by_id(self, suite_id):
return filter(lambda s: s.id == suite_id, self.suites())
def active_suites(self):
return filter(lambda s: s.is_completed is False, self.suites())
def completed_suites(self):
return filter(lambda s: s.is_completed is True, self.suites())
@add.register(Suite)
def _add_suite(self, obj):
obj.project = obj.project or self.project(self._project_id)
return Suite(self.api.add_suite(obj.raw_data()))
@update.register(Suite)
def _update_suite(self, obj):
return Suite(self.api.update_suite(obj.raw_data()))
@delete.register(Suite)
def _delete_suite(self, obj):
return self.api.delete_suite(obj.id)
# Milestone Methods
def milestones(self):
return list(map(Milestone, self.api.milestones(self._project_id)))
@methdispatch
def milestone(self):
return Milestone()
@milestone.register(str)
@milestone.register(unicode)
@singleresult
def _milestone_by_name(self, name):
return filter(
lambda m: m.name.lower() == name.lower(), self.milestones())
@milestone.register(int)
@singleresult
def _milestone_by_id(self, milestone_id):
return filter(lambda s: s.id == milestone_id, self.milestones())
@add.register(Milestone)
def _add_milestone(self, obj):
obj.project = obj.project or self.project(self._project_id)
return Milestone(self.api.add_milestone(obj.raw_data()))
@update.register(Milestone)
def _update_milestone(self, obj):
return Milestone(self.api.update_milestone(obj.raw_data()))
@delete.register(Milestone)
def _delete_milestone(self, obj):
return self.api.delete_milestone(obj.id)
# Plan Methods
@methdispatch
def plans(self):
return PlanContainer(list(map(Plan, self.api.plans(self._project_id))))
@plans.register(Milestone)
def _plans_for_milestone(self, obj):
plans = filter(lambda p: p.milestone is not None, self.plans())
return PlanContainer(filter(lambda p: p.milestone.id == obj.id, plans))
@methdispatch
def plan(self):
return Plan()
@plan.register(str)
@plan.register(unicode)
@singleresult
def _plan_by_name(self, name):
return filter(lambda p: p.name.lower() == name.lower(), self.plans())
@plan.register(int)
@singleresult
def _plan_by_id(self, plan_id):
return filter(lambda p: p.id == plan_id, self.plans())
def completed_plans(self):
return filter(lambda p: p.is_completed is True, self.plans())
def active_plans(self):
return filter(lambda p: p.is_completed is False, self.plans())
@add.register(Plan)
def _add_plan(self, obj, milestone=None):
obj.project = obj.project or self.project(self._project_id)
obj.milestone = milestone or obj.milestone
return Plan(self.api.add_plan(obj.raw_data()))
@update.register(Plan)
def _update_plan(self, obj):
return Plan(self.api.update_plan(obj.raw_data()))
@close.register(Plan)
def _close_plan(self, obj):
return Plan(self.api.close_plan(obj.id))
@delete.register(Plan)
def _delete_plan(self, obj):
return self.api.delete_plan(obj.id)
# Run Methods
@methdispatch
def runs(self):
return RunContainer(list(map(Run, self.api.runs(self._project_id))))
@runs.register(Milestone)
def _runs_for_milestone(self, obj):
return RunContainer(filter(
lambda r: r.milestone.id == obj.id, self.runs()))
@runs.register(str)
@runs.register(unicode)
def _runs_by_name(self, name):
# Returns all Runs that match :name, in descending order by ID
runs = list(filter(lambda r: r.name.lower() == name.lower(), self.runs()))
return sorted(runs, key=lambda r: r.id)
@methdispatch
def run(self):
return Run()
@run.register(str)
@run.register(unicode)
@singleresult
def _run_by_name(self, name):
# Returns the most recently created Run that matches :name
runs = list(filter(lambda r: r.name.lower() == name.lower(), self.runs()))
return sorted(runs, key=lambda r: r.id)[:1]
@run.register(int)
@singleresult
def _run_by_id(self, run_id):
return filter(lambda p: p.id == run_id, self.runs())
@add.register(Run)
def _add_run(self, obj):
obj.project = obj.project or self.project(self._project_id)
return Run(self.api.add_run(obj.raw_data()))
@update.register(Run)
def _update_run(self, obj):
return Run(self.api.update_run(obj.raw_data()))
@close.register(Run)
def _close_run(self, obj):
return Run(self.api.close_run(obj.id))
@delete.register(Run)
def _delete_run(self, obj):
return self.api.delete_run(obj.id)
# Case Methods
def cases(self, suite):
return list(map(Case, self.api.cases(self._project_id, suite.id)))
@methdispatch
def case(self):
return Case()
@case.register(str)
@case.register(unicode)
@singleresult
def _case_by_title(self, title, suite):
return filter(
lambda c: c.title.lower() == title.lower(), self.cases(suite))
@case.register(int)
@singleresult
def _case_by_id(self, case_id, suite=None):
if suite is None:
pass
else:
return filter(lambda c: c.id == case_id, self.cases(suite))
@add.register(Case)
def _add_case(self, obj):
return Case(self.api.add_case(obj.raw_data()))
@update.register(Case)
def _update_case(self, obj):
return Case(self.api.update_case(obj.raw_data()))
# Test Methods
def tests(self, run):
return list(map(Test, self.api.tests(run.id)))
@methdispatch
def test(self):
return Test()
@test.register(str)
@test.register(unicode)
@singleresult
def _test_by_name(self, name, run):
return filter(lambda t: t.title.lower() == name.lower(), self.tests(run))
@test.register(int)
@singleresult
def _test_by_id(self, test_id, run):
return filter(
lambda t: t.raw_data()['id'] == test_id, self.tests(run))
# Result Methods
@methdispatch
def results(self):
raise TestRailError("Must request results by Run or Test")
@results.register(Run)
def _results_for_run(self, run):
return ResultContainer(list(map(Result, self.api.results_by_run(run.id))))
@results.register(Test)
def _results_for_test(self, test):
return ResultContainer(list(map(Result, self.api.results_by_test(test.id))))
@methdispatch
def result(self):
return Result()
@result.register(dict)
def _result_for_dict(self, content):
return Result(content)
@add.register(Result)
def _add_result(self, obj):
self.api.add_result(obj.raw_data())
@add.register(tuple)
def _add_results(self, results):
obj, value = results
if isinstance(obj, Run):
self.api.add_results(list(map(lambda x: x.raw_data(), value)), obj.id)
# Section Methods
def sections(self, suite=None):
return list(map(Section, self.api.sections(suite_id=suite.id)))
@methdispatch
def section(self):
return Section()
@section.register(int)
def _section_by_id(self, section_id):
return Section(self.api.section_with_id(section_id))
@section.register(unicode)
@section.register(str)
@singleresult
def _section_by_name(self, name, suite=None):
return filter(lambda s: s.name == name, self.sections(suite))
@add.register(Section)
def _add_section(self, section):
return Section(self.api.add_section(section.raw_data()))
# Status Methods
def statuses(self):
return list(map(Status, self.api.statuses()))
@methdispatch
def status(self):
return Status()
@status.register(str)
@status.register(unicode)
@singleresult
def _status_by_name(self, name):
return filter(lambda s: s.name == name.lower(), self.statuses())
@status.register(int)
@singleresult
def _status_by_id(self, status_id):
return filter(lambda s: s.id == status_id, self.statuses())
def configs(self):
return ConfigContainer(list(map(Config, self.api.configs())))