Merge lp:~tsimonq2/ubuntu-qa-website/python-library-merge into lp:ubuntu-qa-website
- python-library-merge
- Merge into drupal7-rewrite
Proposed by
Simon Quigley
Status: | Merged |
---|---|
Merged at revision: | 427 |
Proposed branch: | lp:~tsimonq2/ubuntu-qa-website/python-library-merge |
Merge into: | lp:ubuntu-qa-website |
Diff against target: |
1271 lines (+1210/-0) 12 files modified
python-library/qatracker.py (+535/-0) python-library/tests/run (+35/-0) python-library/tests/setup.sql (+4/-0) python-library/tests/test_bug.py (+17/-0) python-library/tests/test_build.py (+98/-0) python-library/tests/test_milestone.py (+56/-0) python-library/tests/test_product.py (+51/-0) python-library/tests/test_rebuilds.py (+69/-0) python-library/tests/test_result.py (+173/-0) python-library/tests/test_rpc.py (+27/-0) python-library/tests/test_series.py (+77/-0) python-library/tests/test_testcase.py (+68/-0) |
To merge this branch: | bzr merge lp:~tsimonq2/ubuntu-qa-website/python-library-merge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nicholas Skaggs | Pending | ||
Review via email: mp+287711@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'python-library' | |||
2 | === added file 'python-library/qatracker.py' | |||
3 | --- python-library/qatracker.py 1970-01-01 00:00:00 +0000 | |||
4 | +++ python-library/qatracker.py 2016-03-01 21:32:25 +0000 | |||
5 | @@ -0,0 +1,535 @@ | |||
6 | 1 | #!/usr/bin/python3 | ||
7 | 2 | # -*- coding: utf-8 -*- | ||
8 | 3 | |||
9 | 4 | # Copyright (C) 2011, 2012 Canonical Ltd. | ||
10 | 5 | # Author: Stéphane Graber <stgraber@ubuntu.com> | ||
11 | 6 | |||
12 | 7 | # This library is free software; you can redistribute it and/or | ||
13 | 8 | # modify it under the terms of the GNU Lesser General Public | ||
14 | 9 | # License as published by the Free Software Foundation; either | ||
15 | 10 | # version 2.1 of the License, or (at your option) any later version. | ||
16 | 11 | |||
17 | 12 | # This library is distributed in the hope that it will be useful, | ||
18 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | 15 | # Lesser General Public License for more details. | ||
21 | 16 | |||
22 | 17 | # You should have received a copy of the GNU Lesser General Public | ||
23 | 18 | # License along with this library; if not, write to the Free Software | ||
24 | 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | ||
25 | 20 | # USA | ||
26 | 21 | |||
27 | 22 | try: | ||
28 | 23 | import xmlrpc.client as xmlrpclib | ||
29 | 24 | except ImportError: | ||
30 | 25 | import xmlrpclib | ||
31 | 26 | |||
32 | 27 | import base64 | ||
33 | 28 | from datetime import datetime | ||
34 | 29 | |||
35 | 30 | # Taken from qatracker/qatracker.modules (PHP code) | ||
36 | 31 | # cat qatracker.module | grep " = array" | sed -e 's/^\$//g' \ | ||
37 | 32 | # -e 's/array(/[/g' -e 's/);/]/g' -e "s/t('/\"/g" -e "s/')/\"/g" | ||
38 | 33 | ### AUTO-GENERATED -> | ||
39 | 34 | qatracker_build_milestone_status = ["Active", "Re-building", "Disabled", | ||
40 | 35 | "Superseded", "Ready"] | ||
41 | 36 | qatracker_milestone_notify = ["No", "Yes"] | ||
42 | 37 | qatracker_milestone_autofill = ["No", "Yes"] | ||
43 | 38 | qatracker_milestone_status = ["Testing", "Released", "Archived"] | ||
44 | 39 | qatracker_milestone_series_status = ["Active", "Disabled"] | ||
45 | 40 | qatracker_milestone_series_manifest_status = ["Active", "Disabled"] | ||
46 | 41 | qatracker_product_status = ["Active", "Disabled"] | ||
47 | 42 | qatracker_product_type = ["iso", "package", "hardware"] | ||
48 | 43 | qatracker_product_download_type = ["HTTP", "RSYNC", "ZSYNC", | ||
49 | 44 | "GPG signature", "MD5 checksum", "Comment", | ||
50 | 45 | "Torrent"] | ||
51 | 46 | qatracker_testsuite_testcase_status = ["Mandatory", "Disabled", "Run-once", | ||
52 | 47 | "Optional"] | ||
53 | 48 | qatracker_result_result = ["Failed", "Passed", "In progress"] | ||
54 | 49 | qatracker_result_status = ["Active", "Disabled"] | ||
55 | 50 | qatracker_rebuild_status = ["Requested", "Queued", "Building", "Built", | ||
56 | 51 | "Published", "Canceled"] | ||
57 | 52 | ### <- AUTO-GENERATED | ||
58 | 53 | |||
59 | 54 | |||
60 | 55 | class QATrackerRPCObject(): | ||
61 | 56 | """Base class for objects received over XML-RPC""" | ||
62 | 57 | |||
63 | 58 | CONVERT_BOOL = [] | ||
64 | 59 | CONVERT_DATE = [] | ||
65 | 60 | CONVERT_INT = [] | ||
66 | 61 | |||
67 | 62 | def __init__(self, tracker, rpc_dict): | ||
68 | 63 | # Convert the dict we get from the API into an object | ||
69 | 64 | |||
70 | 65 | for key in rpc_dict: | ||
71 | 66 | if key in self.CONVERT_INT: | ||
72 | 67 | try: | ||
73 | 68 | setattr(self, key, int(rpc_dict[key])) | ||
74 | 69 | except ValueError: | ||
75 | 70 | setattr(self, key, None) | ||
76 | 71 | elif key in self.CONVERT_BOOL: | ||
77 | 72 | setattr(self, key, rpc_dict[key] == "true") | ||
78 | 73 | elif key in self.CONVERT_DATE: | ||
79 | 74 | try: | ||
80 | 75 | setattr(self, key, datetime.strptime(rpc_dict[key], | ||
81 | 76 | '%Y-%m-%d %H:%M:%S')) | ||
82 | 77 | except ValueError: | ||
83 | 78 | setattr(self, key, None) | ||
84 | 79 | else: | ||
85 | 80 | setattr(self, key, str(rpc_dict[key])) | ||
86 | 81 | |||
87 | 82 | self.tracker = tracker | ||
88 | 83 | |||
89 | 84 | def __repr__(self): | ||
90 | 85 | return "%s: %s" % (self.__class__.__name__, self.title) | ||
91 | 86 | |||
92 | 87 | |||
93 | 88 | class QATrackerBug(QATrackerRPCObject): | ||
94 | 89 | """A bug entry""" | ||
95 | 90 | |||
96 | 91 | CONVERT_INT = ['bugnumber', 'count'] | ||
97 | 92 | CONVERT_DATE = ['earliest_report', 'latest_report'] | ||
98 | 93 | |||
99 | 94 | def __repr__(self): | ||
100 | 95 | return "%s: %s" % (self.__class__.__name__, self.bugnumber) | ||
101 | 96 | |||
102 | 97 | |||
103 | 98 | class QATrackerBuild(QATrackerRPCObject): | ||
104 | 99 | """A build entry""" | ||
105 | 100 | |||
106 | 101 | CONVERT_INT = ['id', 'productid', 'userid', 'status'] | ||
107 | 102 | CONVERT_DATE = ['date'] | ||
108 | 103 | |||
109 | 104 | def __repr__(self): | ||
110 | 105 | return "%s: %s" % (self.__class__.__name__, self.id) | ||
111 | 106 | |||
112 | 107 | def add_result(self, testcase, result, comment='', hardware='', bugs={}): | ||
113 | 108 | """Add a result to the build""" | ||
114 | 109 | |||
115 | 110 | if (self.tracker.access not in ("user", "admin") and | ||
116 | 111 | self.tracker.access is not None): | ||
117 | 112 | raise Exception("Access denied, you need 'user' but are '%s'" % | ||
118 | 113 | self.tracker.access) | ||
119 | 114 | |||
120 | 115 | build_testcase = None | ||
121 | 116 | |||
122 | 117 | # FIXME: Supporting 'str' containing the testcase name would be nice | ||
123 | 118 | if isinstance(testcase, QATrackerTestcase): | ||
124 | 119 | build_testcase = testcase.id | ||
125 | 120 | elif isinstance(testcase, int): | ||
126 | 121 | build_testcase = testcase | ||
127 | 122 | |||
128 | 123 | if not build_testcase: | ||
129 | 124 | raise IndexError("Couldn't find testcase: %s" % (testcase,)) | ||
130 | 125 | |||
131 | 126 | if isinstance(result, list): | ||
132 | 127 | raise TypeError("result must be a string or an integer") | ||
133 | 128 | |||
134 | 129 | build_result = self.tracker._get_valid_id_list(qatracker_result_result, | ||
135 | 130 | result) | ||
136 | 131 | |||
137 | 132 | if not isinstance(bugs, dict): | ||
138 | 133 | raise TypeError("bugs must be a dict") | ||
139 | 134 | |||
140 | 135 | for bug in bugs: | ||
141 | 136 | if not isinstance(bug, int) or bug <= 0: | ||
142 | 137 | raise ValueError("A bugnumber must be a number >= 0") | ||
143 | 138 | |||
144 | 139 | if not isinstance(bugs[bug], int) or bugs[bug] not in (0, 1): | ||
145 | 140 | raise ValueError("A bugimportance must be in (0,1)") | ||
146 | 141 | |||
147 | 142 | resultid = int(self.tracker.tracker.results.add(self.id, | ||
148 | 143 | build_testcase, | ||
149 | 144 | build_result[0], | ||
150 | 145 | str(comment), | ||
151 | 146 | str(hardware), | ||
152 | 147 | bugs)) | ||
153 | 148 | if resultid == -1: | ||
154 | 149 | raise Exception("Couldn't post your result.") | ||
155 | 150 | |||
156 | 151 | new_result = None | ||
157 | 152 | for entry in self.get_results(build_testcase, 0): | ||
158 | 153 | if entry.id == resultid: | ||
159 | 154 | new_result = entry | ||
160 | 155 | break | ||
161 | 156 | |||
162 | 157 | return new_result | ||
163 | 158 | |||
164 | 159 | def get_results(self, testcase, status=qatracker_result_status): | ||
165 | 160 | """Get a list of results for the given build and testcase""" | ||
166 | 161 | |||
167 | 162 | build_testcase = None | ||
168 | 163 | |||
169 | 164 | # FIXME: Supporting 'str' containing the testcase name would be nice | ||
170 | 165 | if isinstance(testcase, QATrackerTestcase): | ||
171 | 166 | build_testcase = testcase.id | ||
172 | 167 | elif isinstance(testcase, int): | ||
173 | 168 | build_testcase = testcase | ||
174 | 169 | |||
175 | 170 | if not build_testcase: | ||
176 | 171 | raise IndexError("Couldn't find testcase: %s" % (testcase,)) | ||
177 | 172 | |||
178 | 173 | record_filter = self.tracker._get_valid_id_list( | ||
179 | 174 | qatracker_result_status, | ||
180 | 175 | status) | ||
181 | 176 | |||
182 | 177 | if len(record_filter) == 0: | ||
183 | 178 | return [] | ||
184 | 179 | |||
185 | 180 | results = [] | ||
186 | 181 | for entry in self.tracker.tracker.results.get_list( | ||
187 | 182 | self.id, build_testcase, list(record_filter)): | ||
188 | 183 | results.append(QATrackerResult(self.tracker, entry)) | ||
189 | 184 | |||
190 | 185 | return results | ||
191 | 186 | |||
192 | 187 | |||
193 | 188 | class QATrackerMilestone(QATrackerRPCObject): | ||
194 | 189 | """A milestone entry""" | ||
195 | 190 | |||
196 | 191 | CONVERT_INT = ['id', 'status', 'series'] | ||
197 | 192 | CONVERT_BOOL = ['notify'] | ||
198 | 193 | |||
199 | 194 | def get_bugs(self): | ||
200 | 195 | """Returns a list of all bugs linked to this milestone""" | ||
201 | 196 | |||
202 | 197 | bugs = [] | ||
203 | 198 | for entry in self.tracker.tracker.bugs.get_list(self.id): | ||
204 | 199 | bugs.append(QATrackerBug(self.tracker, entry)) | ||
205 | 200 | |||
206 | 201 | return bugs | ||
207 | 202 | |||
208 | 203 | def add_build(self, product, version, note="", notify=True): | ||
209 | 204 | """Add a build to the milestone""" | ||
210 | 205 | |||
211 | 206 | if self.status != 0: | ||
212 | 207 | raise TypeError("Only active milestones are accepted") | ||
213 | 208 | |||
214 | 209 | if self.tracker.access != "admin" and self.tracker.access is not None: | ||
215 | 210 | raise Exception("Access denied, you need 'admin' but are '%s'" % | ||
216 | 211 | self.tracker.access) | ||
217 | 212 | |||
218 | 213 | if not isinstance(notify, bool): | ||
219 | 214 | raise TypeError("notify must be a boolean") | ||
220 | 215 | |||
221 | 216 | build_product = None | ||
222 | 217 | |||
223 | 218 | if isinstance(product, QATrackerProduct): | ||
224 | 219 | build_product = product | ||
225 | 220 | else: | ||
226 | 221 | valid_products = self.tracker.get_products(0) | ||
227 | 222 | |||
228 | 223 | for entry in valid_products: | ||
229 | 224 | if (entry.title.lower() == str(product).lower() or | ||
230 | 225 | entry.id == product): | ||
231 | 226 | build_product = entry | ||
232 | 227 | break | ||
233 | 228 | |||
234 | 229 | if not build_product: | ||
235 | 230 | raise IndexError("Couldn't find product: %s" % product) | ||
236 | 231 | |||
237 | 232 | if build_product.status != 0: | ||
238 | 233 | raise TypeError("Only active products are accepted") | ||
239 | 234 | |||
240 | 235 | self.tracker.tracker.builds.add(build_product.id, self.id, | ||
241 | 236 | str(version), str(note), notify) | ||
242 | 237 | |||
243 | 238 | new_build = None | ||
244 | 239 | for entry in self.get_builds(0): | ||
245 | 240 | if (entry.productid == build_product.id | ||
246 | 241 | and entry.version == str(version)): | ||
247 | 242 | new_build = entry | ||
248 | 243 | break | ||
249 | 244 | |||
250 | 245 | return new_build | ||
251 | 246 | |||
252 | 247 | def get_builds(self, status=qatracker_build_milestone_status): | ||
253 | 248 | """Get a list of builds for the milestone""" | ||
254 | 249 | |||
255 | 250 | record_filter = self.tracker._get_valid_id_list( | ||
256 | 251 | qatracker_build_milestone_status, status) | ||
257 | 252 | |||
258 | 253 | if len(record_filter) == 0: | ||
259 | 254 | return [] | ||
260 | 255 | |||
261 | 256 | builds = [] | ||
262 | 257 | for entry in self.tracker.tracker.builds.get_list(self.id, | ||
263 | 258 | list(record_filter)): | ||
264 | 259 | builds.append(QATrackerBuild(self.tracker, entry)) | ||
265 | 260 | |||
266 | 261 | return builds | ||
267 | 262 | |||
268 | 263 | |||
269 | 264 | class QATrackerProduct(QATrackerRPCObject): | ||
270 | 265 | CONVERT_INT = ['id', 'type', 'status'] | ||
271 | 266 | |||
272 | 267 | def get_testcases(self, series, | ||
273 | 268 | status=qatracker_testsuite_testcase_status): | ||
274 | 269 | """Get a list of testcases associated with the product""" | ||
275 | 270 | |||
276 | 271 | record_filter = self.tracker._get_valid_id_list( | ||
277 | 272 | qatracker_testsuite_testcase_status, status) | ||
278 | 273 | |||
279 | 274 | if len(record_filter) == 0: | ||
280 | 275 | return [] | ||
281 | 276 | |||
282 | 277 | if isinstance(series, QATrackerMilestone): | ||
283 | 278 | seriesid = series.series | ||
284 | 279 | elif isinstance(series, int): | ||
285 | 280 | seriesid = series | ||
286 | 281 | else: | ||
287 | 282 | raise TypeError("series needs to be a valid QATrackerMilestone" | ||
288 | 283 | " instance or an integer") | ||
289 | 284 | |||
290 | 285 | testcases = [] | ||
291 | 286 | for entry in self.tracker.tracker.testcases.get_list( | ||
292 | 287 | self.id, seriesid, list(record_filter)): | ||
293 | 288 | testcases.append(QATrackerTestcase(self.tracker, entry)) | ||
294 | 289 | |||
295 | 290 | return testcases | ||
296 | 291 | |||
297 | 292 | |||
298 | 293 | class QATrackerRebuild(QATrackerRPCObject): | ||
299 | 294 | CONVERT_INT = ['id', 'seriesid', 'productid', 'milestoneid', 'requestedby', | ||
300 | 295 | 'changedby', 'status'] | ||
301 | 296 | CONVERT_DATE = ['requestedat', 'changedat'] | ||
302 | 297 | |||
303 | 298 | def __repr__(self): | ||
304 | 299 | return "%s: %s" % (self.__class__.__name__, self.id) | ||
305 | 300 | |||
306 | 301 | def save(self): | ||
307 | 302 | """Save any change that happened on this entry. | ||
308 | 303 | NOTE: At the moment only supports the status field.""" | ||
309 | 304 | |||
310 | 305 | if (self.tracker.access != "admin" and | ||
311 | 306 | self.tracker.access is not None): | ||
312 | 307 | raise Exception("Access denied, you need 'admin' but are '%s'" % | ||
313 | 308 | self.tracker.access) | ||
314 | 309 | |||
315 | 310 | retval = self.tracker.tracker.rebuilds.update_status(self.id, | ||
316 | 311 | self.status) | ||
317 | 312 | if retval is not True: | ||
318 | 313 | raise Exception("Failed to update rebuild") | ||
319 | 314 | |||
320 | 315 | return retval | ||
321 | 316 | |||
322 | 317 | |||
323 | 318 | class QATrackerResult(QATrackerRPCObject): | ||
324 | 319 | CONVERT_INT = ['id', 'reporterid', 'revisionid', 'result', 'changedby', | ||
325 | 320 | 'status'] | ||
326 | 321 | CONVERT_DATE = ['date', 'lastchange'] | ||
327 | 322 | __deleted = False | ||
328 | 323 | |||
329 | 324 | def __repr__(self): | ||
330 | 325 | return "%s: %s" % (self.__class__.__name__, self.id) | ||
331 | 326 | |||
332 | 327 | def delete(self): | ||
333 | 328 | """Remove the result from the tracker""" | ||
334 | 329 | |||
335 | 330 | if (self.tracker.access not in ("user", "admin") and | ||
336 | 331 | self.tracker.access is not None): | ||
337 | 332 | raise Exception("Access denied, you need 'user' but are '%s'" % | ||
338 | 333 | self.tracker.access) | ||
339 | 334 | |||
340 | 335 | if self.__deleted: | ||
341 | 336 | raise IndexError("Result has already been removed") | ||
342 | 337 | |||
343 | 338 | retval = self.tracker.tracker.results.delete(self.id) | ||
344 | 339 | if retval is not True: | ||
345 | 340 | raise Exception("Failed to remove result") | ||
346 | 341 | |||
347 | 342 | self.status = 1 | ||
348 | 343 | self.__deleted = True | ||
349 | 344 | |||
350 | 345 | def save(self): | ||
351 | 346 | """Save any change that happened on this entry""" | ||
352 | 347 | |||
353 | 348 | if (self.tracker.access not in ("user", "admin") and | ||
354 | 349 | self.tracker.access is not None): | ||
355 | 350 | raise Exception("Access denied, you need 'user' but are '%s'" % | ||
356 | 351 | self.tracker.access) | ||
357 | 352 | |||
358 | 353 | if self.__deleted: | ||
359 | 354 | raise IndexError("Result no longer exists") | ||
360 | 355 | |||
361 | 356 | retval = self.tracker.tracker.results.update(self.id, self.result, | ||
362 | 357 | self.comment, | ||
363 | 358 | self.hardware, | ||
364 | 359 | self.bugs) | ||
365 | 360 | if retval is not True: | ||
366 | 361 | raise Exception("Failed to update result") | ||
367 | 362 | |||
368 | 363 | return retval | ||
369 | 364 | |||
370 | 365 | |||
371 | 366 | class QATrackerSeries(QATrackerRPCObject): | ||
372 | 367 | CONVERT_INT = ['id', 'status'] | ||
373 | 368 | |||
374 | 369 | def get_manifest(self, status=qatracker_milestone_series_manifest_status): | ||
375 | 370 | """Get a list of products in the series' manifest""" | ||
376 | 371 | |||
377 | 372 | record_filter = self.tracker._get_valid_id_list( | ||
378 | 373 | qatracker_milestone_series_manifest_status, status) | ||
379 | 374 | |||
380 | 375 | if len(record_filter) == 0: | ||
381 | 376 | return [] | ||
382 | 377 | |||
383 | 378 | manifest_entries = [] | ||
384 | 379 | for entry in self.tracker.tracker.series.get_manifest( | ||
385 | 380 | self.id, list(record_filter)): | ||
386 | 381 | manifest_entries.append(QATrackerSeriesManifest( | ||
387 | 382 | self.tracker, entry)) | ||
388 | 383 | |||
389 | 384 | return manifest_entries | ||
390 | 385 | |||
391 | 386 | |||
392 | 387 | class QATrackerSeriesManifest(QATrackerRPCObject): | ||
393 | 388 | CONVERT_INT = ['id', 'productid', 'status'] | ||
394 | 389 | |||
395 | 390 | def __repr__(self): | ||
396 | 391 | return "%s: %s" % (self.__class__.__name__, self.product_title) | ||
397 | 392 | |||
398 | 393 | |||
399 | 394 | class QATrackerTestcase(QATrackerRPCObject): | ||
400 | 395 | CONVERT_INT = ['id', 'status', 'weight', 'suite'] | ||
401 | 396 | |||
402 | 397 | |||
403 | 398 | class QATracker(): | ||
404 | 399 | def __init__(self, url, username=None, password=None): | ||
405 | 400 | class AuthTransport(xmlrpclib.Transport): | ||
406 | 401 | def set_auth(self, auth): | ||
407 | 402 | self.auth = auth | ||
408 | 403 | |||
409 | 404 | def get_host_info(self, host): | ||
410 | 405 | host, extra_headers, x509 = \ | ||
411 | 406 | xmlrpclib.Transport.get_host_info(self, host) | ||
412 | 407 | if extra_headers is None: | ||
413 | 408 | extra_headers = [] | ||
414 | 409 | extra_headers.append(('Authorization', 'Basic %s' % auth)) | ||
415 | 410 | return host, extra_headers, x509 | ||
416 | 411 | |||
417 | 412 | if username and password: | ||
418 | 413 | try: | ||
419 | 414 | auth = str(base64.b64encode( | ||
420 | 415 | bytes('%s:%s' % (username, password), 'utf-8')), | ||
421 | 416 | 'utf-8') | ||
422 | 417 | except TypeError: | ||
423 | 418 | auth = base64.b64encode('%s:%s' % (username, password)) | ||
424 | 419 | |||
425 | 420 | transport = AuthTransport() | ||
426 | 421 | transport.set_auth(auth) | ||
427 | 422 | drupal = xmlrpclib.ServerProxy(url, transport=transport) | ||
428 | 423 | else: | ||
429 | 424 | drupal = xmlrpclib.ServerProxy(url) | ||
430 | 425 | |||
431 | 426 | # Call listMethods() so if something is wrong we know it immediately | ||
432 | 427 | drupal.system.listMethods() | ||
433 | 428 | |||
434 | 429 | # Get our current access | ||
435 | 430 | self.access = drupal.qatracker.get_access() | ||
436 | 431 | |||
437 | 432 | self.tracker = drupal.qatracker | ||
438 | 433 | |||
439 | 434 | def _get_valid_id_list(self, status_list, status): | ||
440 | 435 | """ Get a list of valid keys and a list or just a single | ||
441 | 436 | entry of input to check against the list of valid keys. | ||
442 | 437 | The function looks for valid indexes and content, doing | ||
443 | 438 | case insensitive checking for strings and returns a list | ||
444 | 439 | of indexes for the list of valid keys. """ | ||
445 | 440 | |||
446 | 441 | def process(status_list, status): | ||
447 | 442 | valid_status = [entry.lower() for entry in status_list] | ||
448 | 443 | |||
449 | 444 | if isinstance(status, int): | ||
450 | 445 | if status < 0 or status >= len(valid_status): | ||
451 | 446 | raise IndexError("Invalid status: %s" % status) | ||
452 | 447 | return int(status) | ||
453 | 448 | |||
454 | 449 | if isinstance(status, str): | ||
455 | 450 | status = status.lower() | ||
456 | 451 | if status not in valid_status: | ||
457 | 452 | raise IndexError("Invalid status: %s" % status) | ||
458 | 453 | return valid_status.index(status) | ||
459 | 454 | |||
460 | 455 | raise TypeError("Invalid status type: %s (expected str or int)" % | ||
461 | 456 | type(status)) | ||
462 | 457 | |||
463 | 458 | record_filter = set() | ||
464 | 459 | |||
465 | 460 | if isinstance(status, list): | ||
466 | 461 | for entry in status: | ||
467 | 462 | record_filter.add(process(status_list, entry)) | ||
468 | 463 | else: | ||
469 | 464 | record_filter.add(process(status_list, status)) | ||
470 | 465 | |||
471 | 466 | return list(record_filter) | ||
472 | 467 | |||
473 | 468 | def get_bugs(self): | ||
474 | 469 | """Get a list of all bugs reported on the site""" | ||
475 | 470 | |||
476 | 471 | bugs = [] | ||
477 | 472 | for entry in self.tracker.bugs.get_list(0): | ||
478 | 473 | bugs.append(QATrackerBug(self, entry)) | ||
479 | 474 | |||
480 | 475 | return bugs | ||
481 | 476 | |||
482 | 477 | def get_milestones(self, status=qatracker_milestone_status): | ||
483 | 478 | """Get a list of all milestones""" | ||
484 | 479 | |||
485 | 480 | record_filter = self._get_valid_id_list(qatracker_milestone_status, | ||
486 | 481 | status) | ||
487 | 482 | |||
488 | 483 | if len(record_filter) == 0: | ||
489 | 484 | return [] | ||
490 | 485 | |||
491 | 486 | milestones = [] | ||
492 | 487 | for entry in self.tracker.milestones.get_list(list(record_filter)): | ||
493 | 488 | milestones.append(QATrackerMilestone(self, entry)) | ||
494 | 489 | |||
495 | 490 | return milestones | ||
496 | 491 | |||
497 | 492 | def get_products(self, status=qatracker_product_status): | ||
498 | 493 | """Get a list of all products""" | ||
499 | 494 | |||
500 | 495 | record_filter = self._get_valid_id_list(qatracker_product_status, | ||
501 | 496 | status) | ||
502 | 497 | |||
503 | 498 | if len(record_filter) == 0: | ||
504 | 499 | return [] | ||
505 | 500 | |||
506 | 501 | products = [] | ||
507 | 502 | for entry in self.tracker.products.get_list(list(record_filter)): | ||
508 | 503 | products.append(QATrackerProduct(self, entry)) | ||
509 | 504 | |||
510 | 505 | return products | ||
511 | 506 | |||
512 | 507 | def get_rebuilds(self, status=qatracker_rebuild_status): | ||
513 | 508 | """Get a list of all rebuilds""" | ||
514 | 509 | |||
515 | 510 | record_filter = self._get_valid_id_list( | ||
516 | 511 | qatracker_rebuild_status, status) | ||
517 | 512 | |||
518 | 513 | if len(record_filter) == 0: | ||
519 | 514 | return [] | ||
520 | 515 | |||
521 | 516 | rebuilds = [] | ||
522 | 517 | for entry in self.tracker.rebuilds.get_list(list(record_filter)): | ||
523 | 518 | rebuilds.append(QATrackerRebuild(self, entry)) | ||
524 | 519 | |||
525 | 520 | return rebuilds | ||
526 | 521 | |||
527 | 522 | def get_series(self, status=qatracker_milestone_series_status): | ||
528 | 523 | """Get a list of all series""" | ||
529 | 524 | |||
530 | 525 | record_filter = self._get_valid_id_list( | ||
531 | 526 | qatracker_milestone_series_status, status) | ||
532 | 527 | |||
533 | 528 | if len(record_filter) == 0: | ||
534 | 529 | return [] | ||
535 | 530 | |||
536 | 531 | series = [] | ||
537 | 532 | for entry in self.tracker.series.get_list(list(record_filter)): | ||
538 | 533 | series.append(QATrackerSeries(self, entry)) | ||
539 | 534 | |||
540 | 535 | return series | ||
541 | 0 | 536 | ||
542 | === added directory 'python-library/tests' | |||
543 | === added file 'python-library/tests/run' | |||
544 | --- python-library/tests/run 1970-01-01 00:00:00 +0000 | |||
545 | +++ python-library/tests/run 2016-03-01 21:32:25 +0000 | |||
546 | @@ -0,0 +1,35 @@ | |||
547 | 1 | #!/usr/bin/python3 | ||
548 | 2 | import unittest | ||
549 | 3 | import os | ||
550 | 4 | import re | ||
551 | 5 | import shutil | ||
552 | 6 | import sys | ||
553 | 7 | |||
554 | 8 | coverage = True | ||
555 | 9 | try: | ||
556 | 10 | from coverage import coverage | ||
557 | 11 | cov = coverage() | ||
558 | 12 | cov.start() | ||
559 | 13 | except ImportError: | ||
560 | 14 | print("No coverage report, make sure python-coverage is installed") | ||
561 | 15 | coverage = False | ||
562 | 16 | |||
563 | 17 | sys.path.insert(0, '.') | ||
564 | 18 | |||
565 | 19 | if len(sys.argv) > 1: | ||
566 | 20 | test_filter = sys.argv[1] | ||
567 | 21 | else: | ||
568 | 22 | test_filter = '' | ||
569 | 23 | |||
570 | 24 | tests = [t[:-3] for t in os.listdir('tests') | ||
571 | 25 | if t.startswith('test_') and t.endswith('.py') and | ||
572 | 26 | re.search(test_filter, t)] | ||
573 | 27 | tests.sort() | ||
574 | 28 | suite = unittest.TestLoader().loadTestsFromNames(tests) | ||
575 | 29 | res = unittest.TextTestRunner(verbosity=2).run(suite) | ||
576 | 30 | |||
577 | 31 | if coverage: | ||
578 | 32 | if os.path.exists('tests/coverage'): | ||
579 | 33 | shutil.rmtree('tests/coverage') | ||
580 | 34 | cov.stop() | ||
581 | 35 | cov.html_report(include=["qatracker.py"], directory='tests/coverage') | ||
582 | 0 | 36 | ||
583 | === added file 'python-library/tests/setup.sql' | |||
584 | --- python-library/tests/setup.sql 1970-01-01 00:00:00 +0000 | |||
585 | +++ python-library/tests/setup.sql 2016-03-01 21:32:25 +0000 | |||
586 | @@ -0,0 +1,4 @@ | |||
587 | 1 | INSERT INTO users (uid, name, data, status) VALUES (99999, 'user', 'a:1:{s:17:"qatracker_api_key";s:4:"user";}', 1); | ||
588 | 2 | INSERT INTO users (uid, name, data, status) VALUES (99998, 'admin', 'a:1:{s:17:"qatracker_api_key";s:5:"admin";}', 1); | ||
589 | 3 | INSERT INTO users_roles (uid, rid) VALUES (99999, 2); | ||
590 | 4 | INSERT INTO users_roles (uid, rid) VALUES (99998, 4); | ||
591 | 0 | 5 | ||
592 | === added file 'python-library/tests/test_bug.py' | |||
593 | --- python-library/tests/test_bug.py 1970-01-01 00:00:00 +0000 | |||
594 | +++ python-library/tests/test_bug.py 2016-03-01 21:32:25 +0000 | |||
595 | @@ -0,0 +1,17 @@ | |||
596 | 1 | import unittest | ||
597 | 2 | import qatracker | ||
598 | 3 | import datetime | ||
599 | 4 | |||
600 | 5 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
601 | 6 | |||
602 | 7 | |||
603 | 8 | class BugTests(unittest.TestCase): | ||
604 | 9 | def setUp(self): | ||
605 | 10 | self.instance = qatracker.QATracker(URL) | ||
606 | 11 | |||
607 | 12 | def test_all_bugs(self): | ||
608 | 13 | bugs = self.instance.get_bugs() | ||
609 | 14 | if bugs: | ||
610 | 15 | self.assertIsInstance(bugs[0].bugnumber, int) | ||
611 | 16 | self.assertIsInstance(bugs[0].earliest_report, datetime.datetime) | ||
612 | 17 | self.assertTrue(str(bugs[0]).startswith('QATrackerBug: ')) | ||
613 | 0 | 18 | ||
614 | === added file 'python-library/tests/test_build.py' | |||
615 | --- python-library/tests/test_build.py 1970-01-01 00:00:00 +0000 | |||
616 | +++ python-library/tests/test_build.py 2016-03-01 21:32:25 +0000 | |||
617 | @@ -0,0 +1,98 @@ | |||
618 | 1 | import unittest | ||
619 | 2 | import qatracker | ||
620 | 3 | |||
621 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
622 | 5 | |||
623 | 6 | |||
624 | 7 | class BuildTests(unittest.TestCase): | ||
625 | 8 | def setUp(self): | ||
626 | 9 | self.instance = qatracker.QATracker(URL, 'admin', 'admin') | ||
627 | 10 | self.milestone = self.instance.get_milestones('testing')[0] | ||
628 | 11 | |||
629 | 12 | def test_build_lower(self): | ||
630 | 13 | self.assertIsInstance(self.milestone.get_builds('active'), list) | ||
631 | 14 | |||
632 | 15 | def test_build_mixed(self): | ||
633 | 16 | self.assertIsInstance(self.milestone.get_builds('DisAblEd'), list) | ||
634 | 17 | |||
635 | 18 | def test_build_upper(self): | ||
636 | 19 | self.assertIsInstance(self.milestone.get_builds('RE-BUILDING'), list) | ||
637 | 20 | |||
638 | 21 | def test_build_id(self): | ||
639 | 22 | self.assertIsInstance(self.milestone.get_builds(3), list) | ||
640 | 23 | |||
641 | 24 | def test_build_list(self): | ||
642 | 25 | self.assertIsInstance(self.milestone.get_builds(['Re-Building', 0, | ||
643 | 26 | 'DISABLED', | ||
644 | 27 | 'SuperSeded']), list) | ||
645 | 28 | |||
646 | 29 | def test_build_empty_list(self): | ||
647 | 30 | self.assertEquals(self.milestone.get_builds([]), []) | ||
648 | 31 | |||
649 | 32 | def test_build_all(self): | ||
650 | 33 | self.assertIsInstance(self.milestone.get_builds(), list) | ||
651 | 34 | |||
652 | 35 | def test_build_type(self): | ||
653 | 36 | build = self.milestone.get_builds(0)[0] | ||
654 | 37 | self.assertIsInstance(build, qatracker.QATrackerBuild) | ||
655 | 38 | self.assertIsInstance(build.status, int) | ||
656 | 39 | self.assertIsInstance(build.version, str) | ||
657 | 40 | |||
658 | 41 | def test_build_repr(self): | ||
659 | 42 | build = self.milestone.get_builds(0)[0] | ||
660 | 43 | self.assertTrue(str(build).startswith('QATrackerBuild: ')) | ||
661 | 44 | |||
662 | 45 | def test_build_add_by_name(self): | ||
663 | 46 | product = self.instance.get_products(0)[0] | ||
664 | 47 | self.milestone.add_build(product.title, '1234', '', False) | ||
665 | 48 | |||
666 | 49 | def test_build_add_by_id(self): | ||
667 | 50 | product = self.instance.get_products(0)[0] | ||
668 | 51 | build = self.milestone.add_build(product.id, '1234', '', False) | ||
669 | 52 | self.assertEquals(build.productid, product.id) | ||
670 | 53 | self.assertEquals(build.version, '1234') | ||
671 | 54 | self.assertEquals(build.note, '') | ||
672 | 55 | |||
673 | 56 | def test_build_invalid_add_disabled_product_by_id(self): | ||
674 | 57 | product = self.instance.get_products(1)[0] | ||
675 | 58 | self.assertRaises(IndexError, self.milestone.add_build, | ||
676 | 59 | product=product.id, version='1234') | ||
677 | 60 | |||
678 | 61 | def test_build_invalid_add_disabled_product_by_object(self): | ||
679 | 62 | product = self.instance.get_products(1)[0] | ||
680 | 63 | self.assertRaises(TypeError, self.milestone.add_build, | ||
681 | 64 | product=product, version='1234') | ||
682 | 65 | |||
683 | 66 | def test_build_invalid_add_disabled_milestone_by_object(self): | ||
684 | 67 | milestone = self.instance.get_milestones('archived')[0] | ||
685 | 68 | product = self.instance.get_products(1)[0] | ||
686 | 69 | self.assertRaises(TypeError, milestone.add_build, | ||
687 | 70 | product=product, version='1234') | ||
688 | 71 | |||
689 | 72 | def test_build_invalid_add_invalid_by_name(self): | ||
690 | 73 | self.assertRaises(IndexError, self.milestone.add_build, | ||
691 | 74 | product='bmaifno', version='1234') | ||
692 | 75 | |||
693 | 76 | def test_build_invalid_add_invalid_by_id(self): | ||
694 | 77 | self.assertRaises(IndexError, self.milestone.add_build, | ||
695 | 78 | product=-1, version='1234') | ||
696 | 79 | |||
697 | 80 | def test_build_invalid_add_invalid_notify(self): | ||
698 | 81 | product = self.instance.get_products(0)[0] | ||
699 | 82 | self.assertRaises(TypeError, self.milestone.add_build, | ||
700 | 83 | product=product.id, version='1234', notify=object()) | ||
701 | 84 | |||
702 | 85 | def test_build_invalid_add_invalid_no_access(self): | ||
703 | 86 | instance = qatracker.QATracker(URL, 'user', 'user') | ||
704 | 87 | milestone = instance.get_milestones('testing')[0] | ||
705 | 88 | self.assertRaises(Exception, milestone.add_build, product=0, | ||
706 | 89 | version='1234') | ||
707 | 90 | |||
708 | 91 | def test_build_invalid_id(self): | ||
709 | 92 | self.assertRaises(IndexError, self.milestone.get_builds, (-1)) | ||
710 | 93 | |||
711 | 94 | def test_build_invalid_string(self): | ||
712 | 95 | self.assertRaises(IndexError, self.milestone.get_builds, ('bla')) | ||
713 | 96 | |||
714 | 97 | def test_build_invalid_type(self): | ||
715 | 98 | self.assertRaises(TypeError, self.milestone.get_builds, (object())) | ||
716 | 0 | 99 | ||
717 | === added file 'python-library/tests/test_milestone.py' | |||
718 | --- python-library/tests/test_milestone.py 1970-01-01 00:00:00 +0000 | |||
719 | +++ python-library/tests/test_milestone.py 2016-03-01 21:32:25 +0000 | |||
720 | @@ -0,0 +1,56 @@ | |||
721 | 1 | import unittest | ||
722 | 2 | import qatracker | ||
723 | 3 | |||
724 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
725 | 5 | |||
726 | 6 | |||
727 | 7 | class MilestoneTests(unittest.TestCase): | ||
728 | 8 | def setUp(self): | ||
729 | 9 | self.instance = qatracker.QATracker(URL) | ||
730 | 10 | |||
731 | 11 | def test_milestone_lower(self): | ||
732 | 12 | milestones = self.instance.get_milestones('testing') | ||
733 | 13 | self.assertIsInstance(milestones, list) | ||
734 | 14 | |||
735 | 15 | def test_milestone_mixed(self): | ||
736 | 16 | milestones = self.instance.get_milestones('RelEaSed') | ||
737 | 17 | self.assertIsInstance(milestones, list) | ||
738 | 18 | |||
739 | 19 | def test_milestone_upper(self): | ||
740 | 20 | milestones = self.instance.get_milestones('ARCHIVED') | ||
741 | 21 | self.assertIsInstance(milestones, list) | ||
742 | 22 | |||
743 | 23 | def test_milestone_id(self): | ||
744 | 24 | milestones = self.instance.get_milestones(2) | ||
745 | 25 | self.assertIsInstance(milestones, list) | ||
746 | 26 | |||
747 | 27 | def test_milestone_list(self): | ||
748 | 28 | milestones = self.instance.get_milestones(['testing', 2, 'archIved']) | ||
749 | 29 | self.assertIsInstance(milestones, list) | ||
750 | 30 | |||
751 | 31 | def test_milestone_empty_list(self): | ||
752 | 32 | self.assertEquals(self.instance.get_milestones([]), []) | ||
753 | 33 | |||
754 | 34 | def test_milestone_all(self): | ||
755 | 35 | self.assertIsInstance(self.instance.get_milestones(), list) | ||
756 | 36 | |||
757 | 37 | def test_milestone_type(self): | ||
758 | 38 | milestone = self.instance.get_milestones(2)[10] | ||
759 | 39 | self.assertIsInstance(milestone, qatracker.QATrackerMilestone) | ||
760 | 40 | self.assertIsInstance(milestone.notify, bool) | ||
761 | 41 | self.assertIsInstance(milestone.status, int) | ||
762 | 42 | self.assertIsInstance(milestone.title, str) | ||
763 | 43 | self.assertIsInstance(milestone.get_bugs(), list) | ||
764 | 44 | |||
765 | 45 | def test_milestone_repr(self): | ||
766 | 46 | milestone = self.instance.get_milestones(2)[0] | ||
767 | 47 | self.assertTrue(str(milestone).startswith('QATrackerMilestone: ')) | ||
768 | 48 | |||
769 | 49 | def test_milestone_invalid_id(self): | ||
770 | 50 | self.assertRaises(IndexError, self.instance.get_milestones, (-1)) | ||
771 | 51 | |||
772 | 52 | def test_milestone_invalid_string(self): | ||
773 | 53 | self.assertRaises(IndexError, self.instance.get_milestones, ('bla')) | ||
774 | 54 | |||
775 | 55 | def test_milestone_invalid_type(self): | ||
776 | 56 | self.assertRaises(TypeError, self.instance.get_milestones, (object())) | ||
777 | 0 | 57 | ||
778 | === added file 'python-library/tests/test_product.py' | |||
779 | --- python-library/tests/test_product.py 1970-01-01 00:00:00 +0000 | |||
780 | +++ python-library/tests/test_product.py 2016-03-01 21:32:25 +0000 | |||
781 | @@ -0,0 +1,51 @@ | |||
782 | 1 | import unittest | ||
783 | 2 | import qatracker | ||
784 | 3 | |||
785 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
786 | 5 | |||
787 | 6 | |||
788 | 7 | class ProductTests(unittest.TestCase): | ||
789 | 8 | def setUp(self): | ||
790 | 9 | self.instance = qatracker.QATracker(URL) | ||
791 | 10 | |||
792 | 11 | def test_product_lower(self): | ||
793 | 12 | self.assertIsInstance(self.instance.get_products('active'), list) | ||
794 | 13 | |||
795 | 14 | def test_product_mixed(self): | ||
796 | 15 | self.assertIsInstance(self.instance.get_products('DisAblEd'), list) | ||
797 | 16 | |||
798 | 17 | def test_product_upper(self): | ||
799 | 18 | self.assertIsInstance(self.instance.get_products('ACTIVE'), list) | ||
800 | 19 | |||
801 | 20 | def test_product_id(self): | ||
802 | 21 | self.assertIsInstance(self.instance.get_products(1), list) | ||
803 | 22 | |||
804 | 23 | def test_product_list(self): | ||
805 | 24 | self.assertIsInstance(self.instance.get_products(['ActivE', 1, | ||
806 | 25 | 'DISABLED', | ||
807 | 26 | 'disabled']), list) | ||
808 | 27 | |||
809 | 28 | def test_product_empty_list(self): | ||
810 | 29 | self.assertEquals(self.instance.get_products([]), []) | ||
811 | 30 | |||
812 | 31 | def test_product_all(self): | ||
813 | 32 | self.assertIsInstance(self.instance.get_products(), list) | ||
814 | 33 | |||
815 | 34 | def test_product_type(self): | ||
816 | 35 | product = self.instance.get_products(0)[0] | ||
817 | 36 | self.assertIsInstance(product, qatracker.QATrackerProduct) | ||
818 | 37 | self.assertIsInstance(product.status, int) | ||
819 | 38 | self.assertIsInstance(product.title, str) | ||
820 | 39 | |||
821 | 40 | def test_product_repr(self): | ||
822 | 41 | product = self.instance.get_products(0)[0] | ||
823 | 42 | self.assertTrue(str(product).startswith('QATrackerProduct: ')) | ||
824 | 43 | |||
825 | 44 | def test_product_invalid_id(self): | ||
826 | 45 | self.assertRaises(IndexError, self.instance.get_products, (-1)) | ||
827 | 46 | |||
828 | 47 | def test_product_invalid_string(self): | ||
829 | 48 | self.assertRaises(IndexError, self.instance.get_products, ('bla')) | ||
830 | 49 | |||
831 | 50 | def test_product_invalid_type(self): | ||
832 | 51 | self.assertRaises(TypeError, self.instance.get_products, (object())) | ||
833 | 0 | 52 | ||
834 | === added file 'python-library/tests/test_rebuilds.py' | |||
835 | --- python-library/tests/test_rebuilds.py 1970-01-01 00:00:00 +0000 | |||
836 | +++ python-library/tests/test_rebuilds.py 2016-03-01 21:32:25 +0000 | |||
837 | @@ -0,0 +1,69 @@ | |||
838 | 1 | import unittest | ||
839 | 2 | import qatracker | ||
840 | 3 | from datetime import datetime | ||
841 | 4 | |||
842 | 5 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
843 | 6 | |||
844 | 7 | |||
845 | 8 | class ProductTests(unittest.TestCase): | ||
846 | 9 | def setUp(self): | ||
847 | 10 | self.instance = qatracker.QATracker(URL, 'admin', 'admin') | ||
848 | 11 | |||
849 | 12 | def test_rebuilds_lower(self): | ||
850 | 13 | self.assertIsInstance(self.instance.get_rebuilds('requested'), list) | ||
851 | 14 | |||
852 | 15 | def test_rebuilds_mixed(self): | ||
853 | 16 | self.assertIsInstance(self.instance.get_rebuilds('BuIlDing'), list) | ||
854 | 17 | |||
855 | 18 | def test_rebuilds_upper(self): | ||
856 | 19 | self.assertIsInstance(self.instance.get_rebuilds('PUBLISHED'), list) | ||
857 | 20 | |||
858 | 21 | def test_rebuilds_id(self): | ||
859 | 22 | self.assertIsInstance(self.instance.get_rebuilds(3), list) | ||
860 | 23 | |||
861 | 24 | def test_rebuilds_list(self): | ||
862 | 25 | self.assertIsInstance(self.instance.get_rebuilds(['reQuested', 1, | ||
863 | 26 | 'PUBLISHED', | ||
864 | 27 | 'canceled']), list) | ||
865 | 28 | |||
866 | 29 | def test_rebuilds_empty_list(self): | ||
867 | 30 | self.assertEquals(self.instance.get_rebuilds([]), []) | ||
868 | 31 | |||
869 | 32 | def test_rebuilds_all(self): | ||
870 | 33 | self.assertIsInstance(self.instance.get_rebuilds(), list) | ||
871 | 34 | |||
872 | 35 | def test_rebuilds_type(self): | ||
873 | 36 | rebuild = self.instance.get_rebuilds()[0] | ||
874 | 37 | self.assertIsInstance(rebuild, qatracker.QATrackerRebuild) | ||
875 | 38 | self.assertIsInstance(rebuild.id, int) | ||
876 | 39 | self.assertIsInstance(rebuild.product_title, str) | ||
877 | 40 | self.assertIsInstance(rebuild.requestedat, datetime) | ||
878 | 41 | |||
879 | 42 | def test_rebuilds_repr(self): | ||
880 | 43 | rebuild = self.instance.get_rebuilds()[0] | ||
881 | 44 | self.assertTrue(str(rebuild).startswith('QATrackerRebuild: ')) | ||
882 | 45 | |||
883 | 46 | def test_rebuilds_invalid_id(self): | ||
884 | 47 | self.assertRaises(IndexError, self.instance.get_rebuilds, -1) | ||
885 | 48 | |||
886 | 49 | def test_rebuilds_invalid_string(self): | ||
887 | 50 | self.assertRaises(IndexError, self.instance.get_rebuilds, 'bla') | ||
888 | 51 | |||
889 | 52 | def test_rebuilds_invalid_type(self): | ||
890 | 53 | self.assertRaises(TypeError, self.instance.get_rebuilds, object()) | ||
891 | 54 | |||
892 | 55 | def test_rebuilds_invalid_save_no_access(self): | ||
893 | 56 | instance = qatracker.QATracker(URL) | ||
894 | 57 | rebuild = instance.get_rebuilds()[0] | ||
895 | 58 | rebuild.status = 2 | ||
896 | 59 | self.assertRaises(Exception, rebuild.save) | ||
897 | 60 | |||
898 | 61 | def test_rebuilds_valid_save(self): | ||
899 | 62 | rebuild = self.instance.get_rebuilds()[0] | ||
900 | 63 | rebuild.status = 2 | ||
901 | 64 | self.assertTrue(rebuild.save()) | ||
902 | 65 | |||
903 | 66 | def test_rebuilds_invalid_status_save(self): | ||
904 | 67 | rebuild = self.instance.get_rebuilds()[0] | ||
905 | 68 | rebuild.status = 99 | ||
906 | 69 | self.assertRaises(Exception, rebuild.save) | ||
907 | 0 | 70 | ||
908 | === added file 'python-library/tests/test_result.py' | |||
909 | --- python-library/tests/test_result.py 1970-01-01 00:00:00 +0000 | |||
910 | +++ python-library/tests/test_result.py 2016-03-01 21:32:25 +0000 | |||
911 | @@ -0,0 +1,173 @@ | |||
912 | 1 | import unittest | ||
913 | 2 | import qatracker | ||
914 | 3 | import datetime | ||
915 | 4 | |||
916 | 5 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
917 | 6 | |||
918 | 7 | |||
919 | 8 | class ResultTests(unittest.TestCase): | ||
920 | 9 | def setUp(self): | ||
921 | 10 | self.instance = qatracker.QATracker(URL, 'user', 'user') | ||
922 | 11 | self.milestone = self.instance.get_milestones('testing')[0] | ||
923 | 12 | self.builds = self.milestone.get_builds('active') | ||
924 | 13 | |||
925 | 14 | def test_result_by_object(self): | ||
926 | 15 | results = [] | ||
927 | 16 | for product in self.instance.get_products('active'): | ||
928 | 17 | builds = [build for build in self.builds | ||
929 | 18 | if build.productid == product.id] | ||
930 | 19 | if len(builds) == 0: | ||
931 | 20 | continue | ||
932 | 21 | |||
933 | 22 | for testcase in product.get_testcases(self.milestone, 'mandatory'): | ||
934 | 23 | build = builds[0] | ||
935 | 24 | results += build.get_results(testcase) | ||
936 | 25 | if len(results) > 0: | ||
937 | 26 | break | ||
938 | 27 | else: | ||
939 | 28 | continue | ||
940 | 29 | break | ||
941 | 30 | |||
942 | 31 | result = results[0] | ||
943 | 32 | self.assertIsInstance(result, qatracker.QATrackerResult) | ||
944 | 33 | self.assertIsInstance(result.id, int) | ||
945 | 34 | self.assertIsInstance(result.date, datetime.datetime) | ||
946 | 35 | self.assertIsInstance(result.comment, str) | ||
947 | 36 | self.assertTrue(str(result).startswith('QATrackerResult: ')) | ||
948 | 37 | |||
949 | 38 | def test_result_by_id(self): | ||
950 | 39 | results = [] | ||
951 | 40 | for product in self.instance.get_products('active'): | ||
952 | 41 | builds = [build for build in self.builds | ||
953 | 42 | if build.productid == product.id] | ||
954 | 43 | if len(builds) == 0: | ||
955 | 44 | continue | ||
956 | 45 | |||
957 | 46 | for testcase in product.get_testcases(self.milestone, 'mandatory'): | ||
958 | 47 | build = builds[0] | ||
959 | 48 | results += build.get_results(testcase.id) | ||
960 | 49 | if len(results) > 0: | ||
961 | 50 | break | ||
962 | 51 | else: | ||
963 | 52 | continue | ||
964 | 53 | break | ||
965 | 54 | |||
966 | 55 | result = results[0] | ||
967 | 56 | self.assertIsInstance(result, qatracker.QATrackerResult) | ||
968 | 57 | self.assertIsInstance(result.id, int) | ||
969 | 58 | self.assertIsInstance(result.date, datetime.datetime) | ||
970 | 59 | self.assertIsInstance(result.comment, str) | ||
971 | 60 | self.assertTrue(str(result).startswith('QATrackerResult: ')) | ||
972 | 61 | |||
973 | 62 | def test_result_add_by_object(self): | ||
974 | 63 | testcase = None | ||
975 | 64 | build = None | ||
976 | 65 | |||
977 | 66 | for product in self.instance.get_products('active'): | ||
978 | 67 | builds = [build for build in self.builds | ||
979 | 68 | if build.productid == product.id] | ||
980 | 69 | if len(builds) == 0: | ||
981 | 70 | continue | ||
982 | 71 | |||
983 | 72 | build = builds[0] | ||
984 | 73 | testcase = product.get_testcases(self.milestone, 'mandatory')[0] | ||
985 | 74 | break | ||
986 | 75 | |||
987 | 76 | result = build.add_result(testcase, 'failed') | ||
988 | 77 | self.assertIsInstance(result, qatracker.QATrackerResult) | ||
989 | 78 | self.assertIsInstance(result.id, int) | ||
990 | 79 | self.assertIsInstance(result.date, datetime.datetime) | ||
991 | 80 | self.assertIsInstance(result.comment, str) | ||
992 | 81 | self.assertEquals(result.result, 0) | ||
993 | 82 | self.assertTrue(str(result).startswith('QATrackerResult: ')) | ||
994 | 83 | |||
995 | 84 | result.comment = "edited" | ||
996 | 85 | result.save() | ||
997 | 86 | result.delete() | ||
998 | 87 | |||
999 | 88 | self.assertRaises(Exception, result.save) | ||
1000 | 89 | |||
1001 | 90 | def test_result_add_by_id(self): | ||
1002 | 91 | testcase = None | ||
1003 | 92 | build = None | ||
1004 | 93 | |||
1005 | 94 | for product in self.instance.get_products('active'): | ||
1006 | 95 | builds = [build for build in self.builds | ||
1007 | 96 | if build.productid == product.id] | ||
1008 | 97 | if len(builds) == 0: | ||
1009 | 98 | continue | ||
1010 | 99 | |||
1011 | 100 | build = builds[0] | ||
1012 | 101 | testcase = product.get_testcases(self.milestone, 'mandatory')[0] | ||
1013 | 102 | break | ||
1014 | 103 | |||
1015 | 104 | result = build.add_result(testcase.id, 2) | ||
1016 | 105 | self.assertIsInstance(result, qatracker.QATrackerResult) | ||
1017 | 106 | self.assertIsInstance(result.id, int) | ||
1018 | 107 | self.assertIsInstance(result.date, datetime.datetime) | ||
1019 | 108 | self.assertIsInstance(result.comment, str) | ||
1020 | 109 | self.assertEquals(result.result, 2) | ||
1021 | 110 | self.assertTrue(str(result).startswith('QATrackerResult: ')) | ||
1022 | 111 | |||
1023 | 112 | result.delete() | ||
1024 | 113 | |||
1025 | 114 | self.assertRaises(Exception, result.delete) | ||
1026 | 115 | |||
1027 | 116 | def test_result_invalid_remove(self): | ||
1028 | 117 | result = qatracker.QATrackerResult(self.instance, {'id': '0'}) | ||
1029 | 118 | self.assertRaises(Exception, result.delete) | ||
1030 | 119 | |||
1031 | 120 | def test_result_invalid_remove_no_access(self): | ||
1032 | 121 | instance = qatracker.QATracker(URL) | ||
1033 | 122 | result = qatracker.QATrackerResult(instance, {'id': '0'}) | ||
1034 | 123 | self.assertRaises(Exception, result.delete) | ||
1035 | 124 | |||
1036 | 125 | def test_result_invalid_save(self): | ||
1037 | 126 | result = qatracker.QATrackerResult(self.instance, {'id': '0', | ||
1038 | 127 | 'comment': '', | ||
1039 | 128 | 'result': '0', | ||
1040 | 129 | 'hardware': '', | ||
1041 | 130 | 'bugs': {}}) | ||
1042 | 131 | self.assertRaises(Exception, result.save) | ||
1043 | 132 | |||
1044 | 133 | def test_result_invalid_save_no_access(self): | ||
1045 | 134 | instance = qatracker.QATracker(URL) | ||
1046 | 135 | result = qatracker.QATrackerResult(instance, {'id': '0'}) | ||
1047 | 136 | self.assertRaises(Exception, result.save) | ||
1048 | 137 | |||
1049 | 138 | def test_result_invalid_add_invalid_testcase(self): | ||
1050 | 139 | self.assertRaises(IndexError, self.builds[0].add_result, | ||
1051 | 140 | testcase=object(), result='in progress') | ||
1052 | 141 | |||
1053 | 142 | def test_result_invalid_add_invalid_result(self): | ||
1054 | 143 | self.assertRaises(TypeError, self.builds[0].add_result, | ||
1055 | 144 | testcase=1, result=['in progress']) | ||
1056 | 145 | |||
1057 | 146 | def test_result_invalid_add_invalid_bugs(self): | ||
1058 | 147 | self.assertRaises(TypeError, self.builds[0].add_result, | ||
1059 | 148 | testcase=1, result='in progress', bugs="bla") | ||
1060 | 149 | |||
1061 | 150 | def test_result_invalid_add_invalid_bugnumber(self): | ||
1062 | 151 | self.assertRaises(ValueError, self.builds[0].add_result, | ||
1063 | 152 | testcase=1, result='in progress', bugs={-1: 0}) | ||
1064 | 153 | |||
1065 | 154 | def test_result_invalid_add_invalid_bugimportance(self): | ||
1066 | 155 | self.assertRaises(ValueError, self.builds[0].add_result, | ||
1067 | 156 | testcase=1, result='in progress', bugs={123: 'a'}) | ||
1068 | 157 | |||
1069 | 158 | def test_result_invalid_add_invalid_response(self): | ||
1070 | 159 | self.assertRaises(Exception, self.builds[0].add_result, | ||
1071 | 160 | testcase=-1, result='in progress') | ||
1072 | 161 | |||
1073 | 162 | def test_result_invalid_add_invalid_no_access(self): | ||
1074 | 163 | instance = qatracker.QATracker(URL) | ||
1075 | 164 | milestone = instance.get_milestones('testing')[0] | ||
1076 | 165 | builds = milestone.get_builds('active') | ||
1077 | 166 | self.assertRaises(Exception, builds[0].add_result, | ||
1078 | 167 | testcase=10, result='in progress') | ||
1079 | 168 | |||
1080 | 169 | def test_result_invalid_id(self): | ||
1081 | 170 | self.assertRaises(IndexError, self.builds[0].get_results, (object())) | ||
1082 | 171 | |||
1083 | 172 | def test_result_invalid_no_status(self): | ||
1084 | 173 | self.assertEquals(self.builds[0].get_results(1234, []), []) | ||
1085 | 0 | 174 | ||
1086 | === added file 'python-library/tests/test_rpc.py' | |||
1087 | --- python-library/tests/test_rpc.py 1970-01-01 00:00:00 +0000 | |||
1088 | +++ python-library/tests/test_rpc.py 2016-03-01 21:32:25 +0000 | |||
1089 | @@ -0,0 +1,27 @@ | |||
1090 | 1 | import unittest | ||
1091 | 2 | import qatracker | ||
1092 | 3 | |||
1093 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
1094 | 5 | |||
1095 | 6 | try: | ||
1096 | 7 | import xmlrpc.client as xmlrpclib | ||
1097 | 8 | except ImportError: | ||
1098 | 9 | import xmlrpclib | ||
1099 | 10 | |||
1100 | 11 | |||
1101 | 12 | class RPCTests(unittest.TestCase): | ||
1102 | 13 | def test_rpc_anonymous(self): | ||
1103 | 14 | tracker = qatracker.QATracker(URL) | ||
1104 | 15 | self.assertEquals(tracker.access, 'public') | ||
1105 | 16 | |||
1106 | 17 | def test_rpc_authenticated_user(self): | ||
1107 | 18 | tracker = qatracker.QATracker(URL, 'user', 'user') | ||
1108 | 19 | self.assertEquals(tracker.access, 'user') | ||
1109 | 20 | |||
1110 | 21 | def test_rpc_authenticated_admin(self): | ||
1111 | 22 | tracker = qatracker.QATracker(URL, 'admin', 'admin') | ||
1112 | 23 | self.assertEquals(tracker.access, 'admin') | ||
1113 | 24 | |||
1114 | 25 | def test_rpc_invalid_target(self): | ||
1115 | 26 | self.assertRaises(xmlrpclib.ProtocolError, qatracker.QATracker, | ||
1116 | 27 | ("%s.invalid" % URL)) | ||
1117 | 0 | 28 | ||
1118 | === added file 'python-library/tests/test_series.py' | |||
1119 | --- python-library/tests/test_series.py 1970-01-01 00:00:00 +0000 | |||
1120 | +++ python-library/tests/test_series.py 2016-03-01 21:32:25 +0000 | |||
1121 | @@ -0,0 +1,77 @@ | |||
1122 | 1 | import unittest | ||
1123 | 2 | import qatracker | ||
1124 | 3 | |||
1125 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
1126 | 5 | |||
1127 | 6 | |||
1128 | 7 | class ProductTests(unittest.TestCase): | ||
1129 | 8 | def setUp(self): | ||
1130 | 9 | self.instance = qatracker.QATracker(URL) | ||
1131 | 10 | |||
1132 | 11 | def test_series_lower(self): | ||
1133 | 12 | self.assertIsInstance(self.instance.get_series('active'), list) | ||
1134 | 13 | |||
1135 | 14 | def test_series_mixed(self): | ||
1136 | 15 | self.assertIsInstance(self.instance.get_series('DisAblEd'), list) | ||
1137 | 16 | |||
1138 | 17 | def test_series_upper(self): | ||
1139 | 18 | self.assertIsInstance(self.instance.get_series('ACTIVE'), list) | ||
1140 | 19 | |||
1141 | 20 | def test_series_id(self): | ||
1142 | 21 | self.assertIsInstance(self.instance.get_series(1), list) | ||
1143 | 22 | |||
1144 | 23 | def test_series_list(self): | ||
1145 | 24 | self.assertIsInstance(self.instance.get_series(['AcTiVe', 1, | ||
1146 | 25 | 'DISABLED', | ||
1147 | 26 | 'active']), list) | ||
1148 | 27 | |||
1149 | 28 | def test_series_empty_list(self): | ||
1150 | 29 | self.assertEquals(self.instance.get_series([]), []) | ||
1151 | 30 | |||
1152 | 31 | def test_series_all(self): | ||
1153 | 32 | self.assertIsInstance(self.instance.get_series(), list) | ||
1154 | 33 | |||
1155 | 34 | def test_series_type(self): | ||
1156 | 35 | series = self.instance.get_series()[0] | ||
1157 | 36 | self.assertIsInstance(series, qatracker.QATrackerSeries) | ||
1158 | 37 | self.assertIsInstance(series.id, int) | ||
1159 | 38 | self.assertIsInstance(series.title, str) | ||
1160 | 39 | |||
1161 | 40 | def test_series_repr(self): | ||
1162 | 41 | series = self.instance.get_series()[0] | ||
1163 | 42 | self.assertTrue(str(series).startswith('QATrackerSeries: ')) | ||
1164 | 43 | |||
1165 | 44 | def test_series_invalid_id(self): | ||
1166 | 45 | self.assertRaises(IndexError, self.instance.get_series, -1) | ||
1167 | 46 | |||
1168 | 47 | def test_series_invalid_string(self): | ||
1169 | 48 | self.assertRaises(IndexError, self.instance.get_series, 'bla') | ||
1170 | 49 | |||
1171 | 50 | def test_series_invalid_type(self): | ||
1172 | 51 | self.assertRaises(TypeError, self.instance.get_series, object()) | ||
1173 | 52 | |||
1174 | 53 | def test_series_manifest_all(self): | ||
1175 | 54 | self.assertIsInstance(self.instance.get_series()[0].get_manifest(), | ||
1176 | 55 | list) | ||
1177 | 56 | |||
1178 | 57 | def test_series_manifest_none(self): | ||
1179 | 58 | self.assertIsInstance(self.instance.get_series()[0].get_manifest([]), | ||
1180 | 59 | list) | ||
1181 | 60 | |||
1182 | 61 | def test_series_manifest_type(self): | ||
1183 | 62 | for series in self.instance.get_series(): | ||
1184 | 63 | manifest = series.get_manifest() | ||
1185 | 64 | if manifest: | ||
1186 | 65 | self.assertIsInstance(manifest[0], | ||
1187 | 66 | qatracker.QATrackerSeriesManifest) | ||
1188 | 67 | self.assertIsInstance(manifest[0].productid, int) | ||
1189 | 68 | self.assertIsInstance(manifest[0].product_title, str) | ||
1190 | 69 | break | ||
1191 | 70 | |||
1192 | 71 | def test_series_manifest_repr(self): | ||
1193 | 72 | for series in self.instance.get_series(): | ||
1194 | 73 | manifest = series.get_manifest() | ||
1195 | 74 | if manifest: | ||
1196 | 75 | self.assertTrue(str(manifest[0]).startswith( | ||
1197 | 76 | 'QATrackerSeriesManifest: ')) | ||
1198 | 77 | break | ||
1199 | 0 | 78 | ||
1200 | === added file 'python-library/tests/test_testcase.py' | |||
1201 | --- python-library/tests/test_testcase.py 1970-01-01 00:00:00 +0000 | |||
1202 | +++ python-library/tests/test_testcase.py 2016-03-01 21:32:25 +0000 | |||
1203 | @@ -0,0 +1,68 @@ | |||
1204 | 1 | import unittest | ||
1205 | 2 | import qatracker | ||
1206 | 3 | |||
1207 | 4 | URL = 'http://iso.qa.dev.stgraber.org/xmlrpc.php' | ||
1208 | 5 | |||
1209 | 6 | |||
1210 | 7 | class TestcaseTests(unittest.TestCase): | ||
1211 | 8 | def setUp(self): | ||
1212 | 9 | self.instance = qatracker.QATracker(URL) | ||
1213 | 10 | self.product = self.instance.get_products(0)[0] | ||
1214 | 11 | self.milestone = self.instance.get_milestones()[0] | ||
1215 | 12 | |||
1216 | 13 | def test_testcase_lower(self): | ||
1217 | 14 | self.assertIsInstance(self.product.get_testcases(self.milestone, | ||
1218 | 15 | 'mandatory'), list) | ||
1219 | 16 | |||
1220 | 17 | def test_testcase_mixed(self): | ||
1221 | 18 | self.assertIsInstance(self.product.get_testcases(self.milestone, | ||
1222 | 19 | 'DisAblEd'), list) | ||
1223 | 20 | |||
1224 | 21 | def test_testcase_upper(self): | ||
1225 | 22 | self.assertIsInstance(self.product.get_testcases(self.milestone, | ||
1226 | 23 | 'RUN-ONCE'), list) | ||
1227 | 24 | |||
1228 | 25 | def test_testcase_id(self): | ||
1229 | 26 | self.assertIsInstance(self.product.get_testcases(self.milestone, | ||
1230 | 27 | 3), list) | ||
1231 | 28 | |||
1232 | 29 | def test_testcase_seriesid(self): | ||
1233 | 30 | self.assertIsInstance(self.product.get_testcases(self.milestone.series, | ||
1234 | 31 | 3), list) | ||
1235 | 32 | |||
1236 | 33 | def test_testcase_list(self): | ||
1237 | 34 | self.assertIsInstance(self.product.get_testcases(self.milestone, | ||
1238 | 35 | ['Run-once', 0, | ||
1239 | 36 | 'DISABLED', | ||
1240 | 37 | 'optional']), list) | ||
1241 | 38 | |||
1242 | 39 | def test_testcase_empty_list(self): | ||
1243 | 40 | self.assertEquals(self.product.get_testcases(self.milestone, []), []) | ||
1244 | 41 | |||
1245 | 42 | def test_testcase_all(self): | ||
1246 | 43 | self.assertIsInstance(self.product.get_testcases(self.milestone), list) | ||
1247 | 44 | |||
1248 | 45 | def test_testcase_type(self): | ||
1249 | 46 | testcase = self.product.get_testcases(self.milestone, 0)[0] | ||
1250 | 47 | self.assertIsInstance(testcase, qatracker.QATrackerTestcase) | ||
1251 | 48 | self.assertIsInstance(testcase.status, int) | ||
1252 | 49 | self.assertIsInstance(testcase.title, str) | ||
1253 | 50 | |||
1254 | 51 | def test_testcase_repr(self): | ||
1255 | 52 | testcase = self.product.get_testcases(self.milestone, 0)[0] | ||
1256 | 53 | self.assertTrue(str(testcase).startswith('QATrackerTestcase: ')) | ||
1257 | 54 | |||
1258 | 55 | def test_testcase_invalid_id(self): | ||
1259 | 56 | self.assertRaises(IndexError, self.product.get_testcases, | ||
1260 | 57 | self.milestone, -1) | ||
1261 | 58 | |||
1262 | 59 | def test_testcase_invalid_string(self): | ||
1263 | 60 | self.assertRaises(IndexError, self.product.get_testcases, | ||
1264 | 61 | self.milestone, 'bla') | ||
1265 | 62 | |||
1266 | 63 | def test_testcase_invalid_type(self): | ||
1267 | 64 | self.assertRaises(TypeError, self.product.get_testcases, | ||
1268 | 65 | self.milestone, object()) | ||
1269 | 66 | |||
1270 | 67 | def test_testcase_invalid_seriesid(self): | ||
1271 | 68 | self.assertRaises(TypeError, self.product.get_testcases, object(), 3) |