1 | # -*- coding: utf-8 -*- |
||
2 | |||
3 | from itertools import groupby |
||
4 | |||
5 | from django.conf import settings |
||
6 | from django.db.models import F |
||
7 | from django.contrib.contenttypes.models import ContentType |
||
8 | from django_comments.models import Comment |
||
9 | |||
10 | from tcms.testcases.models import Bug |
||
11 | from tcms.testruns.models import TestExecution |
||
12 | from tcms.testruns.models import TestExecutionStatus |
||
13 | |||
14 | |||
15 | def get_run_bug_ids(run_id): |
||
16 | """Get list of pairs of bug ID and bug link that are added to a run |
||
17 | |||
18 | :param int run_id: ID of test run. |
||
19 | :return: list of pairs of bug ID and bug link. |
||
20 | :rtype: list |
||
21 | """ |
||
22 | return Bug.objects.values( |
||
23 | 'bug_id', |
||
24 | 'bug_system', |
||
25 | 'bug_system__tracker_type', |
||
26 | 'bug_system__url_reg_exp' |
||
27 | ).distinct().filter(case_run__run=run_id) |
||
28 | |||
29 | |||
30 | class TestExecutionDataMixin: |
||
31 | """Data for test executions""" |
||
32 | |||
33 | @staticmethod |
||
34 | def stats_mode_executions(executions): |
||
35 | """ |
||
36 | Statistics from executions mode |
||
37 | |||
38 | :param executions: iteratable object to access each execution |
||
39 | :type executions: iterable, list, tuple |
||
40 | :return: mapping between mode and the count. Example return value is |
||
41 | `{ 'manual': I, 'automated': J }` |
||
42 | :rtype: dict |
||
43 | """ |
||
44 | manual_count = 0 |
||
45 | automated_count = 0 |
||
46 | |||
47 | for execution in executions: |
||
48 | if execution.case.is_automated: |
||
49 | automated_count += 1 |
||
50 | else: |
||
51 | manual_count += 1 |
||
52 | |||
53 | return { |
||
54 | 'manual': manual_count, |
||
55 | 'automated': automated_count, |
||
56 | } |
||
57 | |||
58 | @staticmethod |
||
59 | def get_execution_bugs(run_pk): |
||
60 | """Get execution bugs for run report |
||
61 | |||
62 | :param int run_pk: run's pk whose executions' bugs will be retrieved. |
||
63 | :return: the mapping between execution id and bug information containing |
||
64 | formatted bug URL. |
||
65 | :rtype: dict |
||
66 | """ |
||
67 | |||
68 | bugs = Bug.objects.filter( |
||
69 | case_run__run=run_pk |
||
70 | ).values( |
||
71 | 'case_run', |
||
72 | 'bug_id', |
||
73 | 'bug_system__url_reg_exp' |
||
74 | ).order_by('case_run') |
||
75 | |||
76 | rows = [] |
||
77 | for row in bugs: |
||
78 | row['bug_url'] = row['bug_system__url_reg_exp'] % row['bug_id'] |
||
79 | rows.append(row) |
||
80 | |||
81 | case_run_bugs = {} |
||
82 | for case_run_id, bugs_info in groupby(rows, lambda row: row['case_run']): |
||
83 | case_run_bugs[case_run_id] = list(bugs_info) |
||
84 | |||
85 | return case_run_bugs |
||
86 | |||
87 | @staticmethod |
||
88 | def get_execution_comments(run_pk): |
||
89 | """Get executions' comments |
||
90 | |||
91 | :param run_pk: run's pk whose comments will be retrieved. |
||
92 | :type run_pk: int |
||
93 | :return: the mapping between execution id and comments |
||
94 | :rtype: dict |
||
95 | """ |
||
96 | # note: cast to string b/c object_pk is a Textield and PostgreSQL |
||
97 | # doesn't like TEXT in <list of integers> |
||
98 | # in Django 1.10 we have the Cast() function for similar cases, see |
||
99 | # https://docs.djangoproject.com/en/1.10/ref/models/database-functions/#cast |
||
100 | object_pks = [] |
||
101 | for test_case_run in TestExecution.objects.filter(run=run_pk).only('pk'): |
||
102 | object_pks.append(str(test_case_run.pk)) |
||
103 | |||
104 | comments = Comment.objects.filter( |
||
105 | site=settings.SITE_ID, |
||
106 | content_type=ContentType.objects.get_for_model(TestExecution).pk, |
||
107 | is_public=True, |
||
108 | is_removed=False, |
||
109 | object_pk__in=object_pks |
||
110 | ).annotate( |
||
111 | case_run_id=F('object_pk') |
||
112 | ).values( |
||
113 | 'case_run_id', |
||
114 | 'submit_date', |
||
115 | 'comment', |
||
116 | 'user_name' |
||
117 | ).order_by('case_run_id') |
||
118 | |||
119 | rows = [] |
||
120 | for row in comments: |
||
121 | rows.append(row) |
||
122 | |||
123 | case_run_comments = {} |
||
124 | for key, groups in groupby(rows, lambda row: row['case_run_id']): |
||
125 | case_run_comments[int(key)] = list(groups) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
126 | |||
127 | return case_run_comments |
||
128 | |||
129 | @staticmethod |
||
130 | def get_summary_stats(executions): |
||
131 | """Get summary statistics from executions |
||
132 | |||
133 | Statistics targets: |
||
134 | |||
135 | - the number of pending test executionss, whose status is IDLE |
||
136 | - the number of completed test executionss, whose status are PASSED, |
||
137 | ERROR, FAILED, WAIVED |
||
138 | |||
139 | :param executions: iterable object containing executionss |
||
140 | :type executions: iterable |
||
141 | :return: a mapping between statistics target and its value |
||
142 | :rtype: dict |
||
143 | """ |
||
144 | idle_count = 0 |
||
145 | complete_count = 0 |
||
146 | for case_run in executions: |
||
147 | if case_run.status.name in TestExecutionStatus.idle_status_names: |
||
148 | idle_count += 1 |
||
149 | elif case_run.status.name in TestExecutionStatus.complete_status_names: |
||
150 | complete_count += 1 |
||
151 | |||
152 | return {'idle': idle_count, 'complete': complete_count} |
||
153 |