def _report_data_context(self): data = {} form = self._get_search_form() if form.is_valid(): summary_header_data = super(CustomDetailReport, self)._report_data_context() data.update(summary_header_data) build_ids = [build['build'] for build in data['builds']] status_matrix = self.walk_matrix_row_by_row( self._data.generate_status_matrix(build_ids) ) status_ids = (TestCaseRunStatus.id_failed(),) failed_case_runs = self.read_case_runs(build_ids, status_ids) status_ids = (TestCaseRunStatus.id_blocked(),) blocked_case_runs = self.read_case_runs(build_ids, status_ids) data.update({ 'status_matrix': status_matrix, 'failed_case_runs': failed_case_runs, 'blocked_case_runs': blocked_case_runs, }) else: data['report_errors'] = form.errors data['form'] = form return data
def _report_data_context(self): data = {} form = self._get_search_form() if form.is_valid(): summary_header_data = super(CustomDetailReport, self)._report_data_context() data.update(summary_header_data) build_ids = [build.pk for build in data['builds']] # TODO: remove this after upgrading MySQL-python to 1.2.5 build_ids = tuple(workaround_single_value_for_in_clause(build_ids)) status_matrix = self.walk_matrix_row_by_row( self._data.generate_status_matrix(build_ids)) # TODO: remove this after upgrading MySQL-python to 1.2.5 status_ids = workaround_single_value_for_in_clause( (TestCaseRunStatus.name_to_id('FAILED'),)) failed_case_runs = self.read_case_runs(build_ids, status_ids) # TODO: remove this after upgrading MySQL-python to 1.2.5 status_ids = workaround_single_value_for_in_clause( (TestCaseRunStatus.name_to_id('BLOCKED'),)) blocked_case_runs = self.read_case_runs(build_ids, status_ids) data.update({ 'status_matrix': status_matrix, 'failed_case_runs': failed_case_runs, 'blocked_case_runs': blocked_case_runs, }) else: data['report_errors'] = form.errors data['form'] = form return data
def _report_data_context(self): data = {} form = self._get_search_form() if form.is_valid(): summary_header_data = super(CustomDetailReport, self)._report_data_context() data.update(summary_header_data) build_ids = [build.pk for build in data['builds']] # TODO: remove this after upgrading MySQL-python to 1.2.5 build_ids = workaround_single_value_for_in_clause(build_ids) status_matrix = self.walk_matrix_row_by_row( self._data.generate_status_matrix(build_ids)) # TODO: remove this after upgrading MySQL-python to 1.2.5 status_ids = workaround_single_value_for_in_clause( (TestCaseRunStatus.id_failed(), )) failed_case_runs = self.read_case_runs(build_ids, status_ids) # TODO: remove this after upgrading MySQL-python to 1.2.5 status_ids = workaround_single_value_for_in_clause( (TestCaseRunStatus.id_blocked(), )) blocked_case_runs = self.read_case_runs(build_ids, status_ids) data.update({ 'status_matrix': status_matrix, 'failed_case_runs': failed_case_runs, 'blocked_case_runs': blocked_case_runs, }) else: data['report_errors'] = form.errors data['form'] = form return data
def calculate_associated_data(runs: QuerySet) -> None: """Calculate associated data and set to each run in place The associated data include: * completed progress of each test run * the environment of each test run """ run_ids = [run.pk for run in runs] qs = (TestCaseRun.objects.filter( case_run_status=TestCaseRunStatus.name_to_id('FAILED'), run__in=run_ids).values('run', 'case_run_status').annotate( count=Count('pk')).order_by('run', 'case_run_status')) failure_subtotal = magic_convert(qs, key_name='run', value_name='count') completed_status_ids = TestCaseRunStatus.completed_status_ids() qs = (TestCaseRun.objects.filter( case_run_status__in=completed_status_ids, run__in=run_ids).values( 'run', 'case_run_status').annotate(count=Count('pk')).order_by( 'run', 'case_run_status')) completed_subtotal = { run_id: sum((item['count'] for item in stats_rows)) for run_id, stats_rows in itertools.groupby(qs.iterator(), key=itemgetter('run')) } qs = (TestCaseRun.objects.filter(run__in=run_ids).values('run').annotate( cases_count=Count('case'))) cases_subtotal = magic_convert(qs, key_name='run', value_name='cases_count') # Relative env groups to runs result = (TCMSEnvGroup.objects.filter(plans__run__in=run_ids).values( 'plans__run', 'name')) runs_env_groups = {item['plans__run']: item['name'] for item in result} for run in runs: run_id = run.pk cases_count = cases_subtotal.get(run_id, 0) if cases_count: completed_percent = completed_subtotal.get( run_id, 0) * 1.0 / cases_count * 100 failure_percent = failure_subtotal.get(run_id, 0) * 1.0 / cases_count * 100 else: completed_percent = failure_percent = 0 run.associated_data = { 'stats': { 'cases': cases_count, 'completed_percent': completed_percent, 'failure_percent': failure_percent, }, 'env_group': runs_env_groups.get(run_id), }
def get_context_data(self, **kwargs): data = super(TestingReportCaseRuns, self).get_context_data(**kwargs) query_args = self.request.GET form = self._get_form(query_args) if form.is_valid(): test_case_runs = self.get_case_runs(form) status_names = TestCaseRunStatus.get_names() priority_values = Priority.get_values() testers_ids, assignees_ids = self._get_testers_assignees_ids( test_case_runs) testers = self.get_related_testers(testers_ids) assignees = self.get_related_assignees(assignees_ids) data['test_case_runs_count'] = len(test_case_runs) data['test_case_runs'] = self.walk_case_runs(test_case_runs, status_names, priority_values, testers, assignees) else: data['form_errors'] = form.errors return data
def get_context_data(self, **kwargs): data = super(TestingReportCaseRuns, self).get_context_data(**kwargs) query_args = self.request.GET form = self._get_form(query_args) if form.is_valid(): test_case_runs = self.get_case_runs(form) status_names = TestCaseRunStatus.as_dict() priority_values = Priority.get_values() testers_ids, assignees_ids = self._get_testers_assignees_ids( test_case_runs) testers = self.get_related_testers(testers_ids) assignees = self.get_related_assignees(assignees_ids) data['test_case_runs_count'] = len(test_case_runs) data['test_case_runs'] = self.walk_case_runs(test_case_runs, status_names, priority_values, testers, assignees) else: data['form_errors'] = form.errors return data
def filter(query): # pylint: disable=redefined-builtin """ .. function:: XML-RPC TestCaseRunStatus.filter(query) Search and return the list of test case run statuses. :param query: Field lookups for :class:`tcms.testruns.models.TestCaseRunStatus` :type query: dict :return: Serialized list of :class:`tcms.testruns.models.TestCaseRunStatus` objects :rtype: list(dict) """ return TestCaseRunStatus.to_xmlrpc(query)
def walk_case_runs(): """Walking case runs for helping rendering case runs table""" priorities = dict(Priority.objects.values_list('pk', 'value')) testers, assignees = open_run_get_users(test_case_runs) comments_subtotal = open_run_get_comments_subtotal( [cr.pk for cr in test_case_runs]) case_run_status = TestCaseRunStatus.get_names() for case_run in test_case_runs: yield (case_run, testers.get(case_run.tested_by_id, None), assignees.get(case_run.assignee_id, None), priorities.get(case_run.case.priority_id), case_run_status[case_run.case_run_status_id], comments_subtotal.get(case_run.pk, 0))
def walk_case_runs(self, test_case_runs): # todo: this is the same method as in testruns/views.py status_names = TestCaseRunStatus.get_names() priority_values = dict(Priority.objects.values_list('pk', 'value')) testers_ids, assignees_ids = _get_testers_assignees_ids(test_case_runs) testers = self.get_related_users(testers_ids) assignees = self.get_related_users(assignees_ids) for case_run in test_case_runs: status_name = status_names[case_run.case_run_status_id] priority_value = priority_values[case_run.case.priority_id] tester_username = testers.get(case_run.tested_by_id, None) assignee_username = assignees.get(case_run.assignee_id, None) yield case_run, status_name, priority_value, ( case_run.assignee_id, assignee_username), ( case_run.tested_by_id, tester_username)
def get_case_run_status(request, id=None): """ Params: $case_run_status_id - Integer(Optional): ID of the status to return Returns: Hash: Matching case run status object hash when your specific the case_run_status_id or return all of case run status. It will return error the case run status you specific id not found. Example: # Get all of case run status >>> TestCaseRun.get_case_run_status() # Get case run status by ID 1 >>> TestCaseRun.get_case_run_status(1) """ if id: return TestCaseRunStatus.objects.get(id=id).serialize() return TestCaseRunStatus.to_xmlrpc()
def walk_case_runs(): """Walking case runs for helping rendering case runs table""" priorities = Priority.get_values() testers, assignees = open_run_get_users(tcrs) comments_subtotal = open_run_get_comments_subtotal( [cr.pk for cr in tcrs]) case_run_status = TestCaseRunStatus.as_dict() issues_subtotal = tr.subtotal_issues_by_case_run() for case_run in tcrs: yield ( case_run, testers.get(case_run.tested_by_id, None), assignees.get(case_run.assignee_id, None), priorities.get(case_run.case.priority_id), case_run_status[case_run.case_run_status_id], comments_subtotal.get(case_run.pk, 0), issues_subtotal.get(case_run.pk, 0), )
def get_case_run_status(request, case_run_status_id=None): """Get case run status :param int case_run_status_id: optional case run status ID. :return: a mapping representing a case run status of specified ID. Otherwise, a list of mappings of all case run status will be returned, if ``case_run_status_id`` is omitted. :rtype: dict or list[dict] Example:: # Get all of case run status >>> TestCaseRun.get_case_run_status() # Get case run status by ID 1 >>> TestCaseRun.get_case_run_status(1) """ if case_run_status_id: return TestCaseRunStatus.objects.get(pk=case_run_status_id).serialize() return TestCaseRunStatus.to_xmlrpc()
def case_runs_filter_criteria(form): filter_criteria = {} priority = form.cleaned_data['priority'] if priority: filter_criteria['case__priority__pk'] = priority tester = form.cleaned_data['tester'] if tester is not None: if tester == 0: filter_criteria['tested_by'] = None else: filter_criteria['tested_by__pk'] = tester status = form.cleaned_data['status'] if status: status_id = TestCaseRunStatus.get_names_ids()[status.upper()] filter_criteria['case_run_status'] = status_id return filter_criteria
def case_runs_filter_criteria(self, form): filter_criteria = {} priority = form.cleaned_data['priority'] if priority: filter_criteria['case__priority__pk'] = priority tester = form.cleaned_data['tester'] if tester is not None: if tester == 0: filter_criteria['tested_by'] = None else: filter_criteria['tested_by__pk'] = tester status = form.cleaned_data['status'] if status: status_id = TestCaseRunStatus.get_names_ids()[status.upper()] filter_criteria['case_run_status'] = status_id return filter_criteria
def update_case_run_status(request): """Update Case Run status.""" now = datetime.datetime.now() data = request.POST.copy() ctype = data.get("content_type") vtype = data.get('value_type', 'str') object_pk_str = data.get("object_pk") field = data.get('field') value = data.get('value') object_pk = [int(a) for a in object_pk_str.split(',')] if not field or not value or not object_pk or not ctype: return JsonResponseBadRequest({ 'message': 'Following fields are required - ' 'content_type, object_pk, field and value.' }) # Convert the value type # FIXME: Django bug here: update() keywords must be strings field = str(field) value, error = get_value_by_type(value, vtype) if error: return JsonResponseBadRequest({'message': error}) has_perms = check_permission(request, ctype) if not has_perms: return JsonResponseForbidden({'message': 'Permission Denied.'}) model = utils.get_model(ctype) targets = model._default_manager.filter(pk__in=object_pk) if not targets: return JsonResponseBadRequest({'message': 'No record found'}) if not hasattr(targets[0], field): return JsonResponseBadRequest( {'message': f'{ctype} has no field {field}'}) if hasattr(targets[0], 'log_action'): for t in targets: try: t.log_action(who=request.user, field=field, original_value=getattr(t, field), new_value=TestCaseRunStatus.id_to_name(value)) except (AttributeError, User.DoesNotExist): pass objects_update(targets, **{field: value}) if hasattr(model, 'mail_scene'): from tcms.core.mailto import mailto mail_context = model.mail_scene( objects=targets, field=field, value=value, ctype=ctype, object_pk=object_pk, ) if mail_context: mail_context['context']['user'] = request.user mailto(**mail_context) # Special hacking for updating test case run status if ctype == 'testruns.testcaserun' and field == 'case_run_status': for t in targets: field = 'close_date' t.log_action(who=request.user, field=field, original_value=getattr(t, field) or '', new_value=now) if t.tested_by != request.user: field = 'tested_by' t.log_action(who=request.user, field=field, original_value=getattr(t, field) or '', new_value=request.user) field = 'assignee' try: assignee = t.assginee if assignee != request.user: t.log_action(who=request.user, field=field, original_value=getattr(t, field) or '', new_value=request.user) # t.assignee = request.user t.save() except (AttributeError, User.DoesNotExist): pass targets.update(close_date=now, tested_by=request.user) return JsonResponse({})
def update_case_run_status(request): ''' Update Case Run status. ''' now = datetime.datetime.now() data = request.POST.copy() ctype = data.get("content_type") vtype = data.get('value_type', 'str') object_pk_str = data.get("object_pk") field = data.get('field') value = data.get('value') object_pk = [int(a) for a in object_pk_str.split(',')] if not field or not value or not object_pk or not ctype: return say_no('Following fields are required - content_type, ' 'object_pk, field and value.') # Convert the value type # FIXME: Django bug here: update() keywords must be strings field = str(field) value, error = get_value_by_type(value, vtype) if error: return say_no(error) has_perms = check_permission(request, ctype) if not has_perms: return say_no('Permission Dinied.') model = apps.get_model(*ctype.split(".", 1)) targets = model._default_manager.filter(pk__in=object_pk) if not targets: return say_no('No record found') if not hasattr(targets[0], field): return say_no('%s has no field %s' % (ctype, field)) if hasattr(targets[0], 'log_action'): for t in targets: try: t.log_action(who=request.user, action='Field {} changed from {} to {}.'.format( field, getattr(t, field), TestCaseRunStatus.id_to_string(value), )) except (AttributeError, User.DoesNotExist): pass objects_update(targets, **{field: value}) if hasattr(model, 'mail_scene'): from tcms.core.utils.mailto import mailto mail_context = model.mail_scene( objects=targets, field=field, value=value, ctype=ctype, object_pk=object_pk, ) if mail_context: mail_context['context']['user'] = request.user try: mailto(**mail_context) except Exception: pass # Special hacking for updating test case run status if ctype == 'testruns.testcaserun' and field == 'case_run_status': for t in targets: field = 'close_date' t.log_action(who=request.user, action='Field %s changed from %s to %s.' % (field, getattr(t, field), now)) if t.tested_by != request.user: field = 'tested_by' t.log_action(who=request.user, action='Field %s changed from %s to %s.' % (field, getattr(t, field), request.user)) field = 'assignee' try: assignee = t.assginee if assignee != request.user: t.log_action(who=request.user, action='Field %s changed from %s to %s.' % (field, getattr(t, field), request.user)) # t.assignee = request.user t.save() except (AttributeError, User.DoesNotExist): pass targets.update(close_date=now, tested_by=request.user) return HttpResponse(json.dumps({'rc': 0, 'response': 'ok'}))
def _report_data_context(self): form = self._get_search_form() context = {'form': form} if not form.is_valid(): context.update({'builds': ()}) return context _data = self.data_class(form) self._data = _data builds = _data._get_builds() build_ids = [build.pk for build in builds] # TODO: remove this after upgrading MySQL-python to 1.2.5 build_ids = workaround_single_value_for_in_clause(build_ids) if build_ids: # Summary header data runs_subtotal = _data.runs_subtotal() plans_subtotal = _data.plans_subtotal() case_runs_subtotal = _data.case_runs_subtotal() isautomated_subtotal = _data.cases_isautomated_subtotal() # Staus matrix used to render progress bar for each build case_runs_status_matrix = _data.status_matrix() status_names_ids = TestCaseRunStatus.get_names_ids() # FIXME: this would raise KeyError once status names are modified # to other ones. passed_id = status_names_ids['PASSED'] failed_id = status_names_ids['FAILED'] for build in builds: bid = build.pk build.runs_count = runs_subtotal.get(bid, 0) build.plans_count = plans_subtotal.get(bid, 0) build.case_runs_count = case_runs_subtotal.get(bid, 0) status_subtotal = case_runs_status_matrix.get(bid, {}) passed_count = status_subtotal.get(passed_id, 0) failed_count = status_subtotal.get(failed_id, 0) c = case_runs_subtotal.get(bid, 0) if c: build.passed_case_runs_percent = passed_count * 100.0 / c build.failed_case_runs_percent = failed_count * 100.0 / c else: build.passed_case_runs_percent = .0 build.failed_case_runs_percent = .0 build.passed_case_runs_count = passed_count build.failed_case_runs_count = failed_count build.case_runs_count = c context.update({ # TODO: replace following three TOTAL key lookup with total # method invocation. 'total_runs_count': runs_subtotal.get('TOTAL', 0), 'total_plans_count': plans_subtotal.get('TOTAL', 0), 'total_count': isautomated_subtotal.get('TOTAL', 0), 'manual_count': isautomated_subtotal.get(0, 0), 'auto_count': isautomated_subtotal.get(1, 0), 'both_count': isautomated_subtotal.get(2, 0), }) context.update({'builds': builds}) return context
def load_runs_of_one_plan(request, plan_id, template_name='plan/common/json_plan_runs.txt'): """A dedicated view to return a set of runs of a plan This view is used in a plan detail page, for the contained testrun tab. It replaces the original solution, with a paginated resultset in return, serves as a performance healing. Also, in order for user to locate the data, it accepts field lookup parameters collected from the filter panel in the UI. """ column_names = [ '', 'run_id', 'summary', 'manager__username', 'default_tester__username', 'start_date', 'build__name', 'stop_date', 'total_num_caseruns', 'failure_caseruns_percent', 'successful_caseruns_percent', ] test_plan = TestPlan.objects.get(plan_id=plan_id) form = PlanFilterRunForm(request.GET) if form.is_valid(): queryset = test_plan.run.filter(**form.cleaned_data) queryset = queryset.select_related('build', 'manager', 'default_tester').order_by('-pk') data_table_result = DataTableResult(request.GET, queryset, column_names) response_data = data_table_result.get_response_data() searched_runs = response_data['querySet'] # Get associated statistics data run_filters = dict(('run__{0}'.format(key), value) for key, value in form.cleaned_data.items()) query_set = TestCaseRun.objects.filter( case_run_status=TestCaseRunStatus.id_failed(), **run_filters).values('run', 'case_run_status').annotate( count=Count('pk')).order_by('run', 'case_run_status') failure_subtotal = magic_convert(query_set, key_name='run', value_name='count') query_set = TestCaseRun.objects.filter( case_run_status=TestCaseRunStatus.id_passed(), **run_filters).values('run', 'case_run_status').annotate( count=Count('pk')).order_by('run', 'case_run_status') success_subtotal = magic_convert(query_set, key_name='run', value_name='count') query_set = TestCaseRun.objects.filter( **run_filters).values('run').annotate( count=Count('case')).order_by('run') cases_subtotal = magic_convert(query_set, key_name='run', value_name='count') for run in searched_runs: run_id = run.pk cases_count = cases_subtotal.get(run_id, 0) if cases_count: failure_percent = failure_subtotal.get( run_id, 0) * 1.0 / cases_count * 100 success_percent = success_subtotal.get( run_id, 0) * 1.0 / cases_count * 100 else: failure_percent = success_percent = 0 run.nitrate_stats = { 'cases': cases_count, 'failure_percent': failure_percent, 'success_percent': success_percent, } else: response_data = { 'sEcho': int(request.GET.get('sEcho', 0)), 'iTotalRecords': 0, 'iTotalDisplayRecords': 0, 'querySet': TestRun.objects.none(), } json_data = render_to_string(template_name, response_data, request=request) return HttpResponse(json_data, content_type='application/json')
def _report_data_context(self): form = self._get_search_form() context = {'form': form} if not form.is_valid(): context.update({'builds': ()}) return context _data = self.data_class(form) self._data = _data builds = _data._get_builds() build_ids = [build.pk for build in builds] # TODO: remove this after upgrading MySQL-python to 1.2.5 build_ids = workaround_single_value_for_in_clause(build_ids) if build_ids: # Summary header data runs_subtotal = _data.runs_subtotal() plans_subtotal = _data.plans_subtotal() case_runs_subtotal = _data.case_runs_subtotal() isautomated_subtotal = _data.cases_isautomated_subtotal() # Staus matrix used to render progress bar for each build case_runs_status_matrix = _data.status_matrix() # FIXME: this would raise KeyError once status names are modified # to other ones. passed_id = TestCaseRunStatus.name_to_id('PASSED') failed_id = TestCaseRunStatus.name_to_id('FAILED') for build in builds: bid = build.pk build.runs_count = runs_subtotal.get(bid, 0) build.plans_count = plans_subtotal.get(bid, 0) build.case_runs_count = case_runs_subtotal.get(bid, 0) status_subtotal = case_runs_status_matrix.get(bid, {}) passed_count = status_subtotal.get(passed_id, 0) failed_count = status_subtotal.get(failed_id, 0) c = case_runs_subtotal.get(bid, 0) if c: build.passed_case_runs_percent = passed_count * 100.0 / c build.failed_case_runs_percent = failed_count * 100.0 / c else: build.passed_case_runs_percent = .0 build.failed_case_runs_percent = .0 build.passed_case_runs_count = passed_count build.failed_case_runs_count = failed_count build.case_runs_count = c context.update({ # method invocation. 'total_runs_count': runs_subtotal.total, 'total_plans_count': plans_subtotal.total, 'total_count': isautomated_subtotal.total, 'manual_count': isautomated_subtotal.get(0, 0), 'auto_count': isautomated_subtotal.get(1, 0), 'both_count': isautomated_subtotal.get(2, 0), }) context.update({'builds': builds}) return context
def update_case_run_status(request): """Update Case Run status.""" now = datetime.datetime.now() data = request.POST.copy() ctype = data.get("content_type") vtype = data.get('value_type', 'str') object_pk_str = data.get("object_pk") field = data.get('field') value = data.get('value') object_pk = [int(a) for a in object_pk_str.split(',')] if not field or not value or not object_pk or not ctype: return say_no( 'Following fields are required - content_type, ' 'object_pk, field and value.') # Convert the value type # FIXME: Django bug here: update() keywords must be strings field = str(field) value, error = get_value_by_type(value, vtype) if error: return say_no(error) has_perms = check_permission(request, ctype) if not has_perms: return say_no('Permission Dinied.') model = utils.get_model(ctype) targets = model._default_manager.filter(pk__in=object_pk) if not targets: return say_no('No record found') if not hasattr(targets[0], field): return say_no('%s has no field %s' % (ctype, field)) if hasattr(targets[0], 'log_action'): for t in targets: try: t.log_action( who=request.user, field=field, original_value=getattr(t, field), new_value=TestCaseRunStatus.id_to_name(value)) except (AttributeError, User.DoesNotExist): pass objects_update(targets, **{field: value}) if hasattr(model, 'mail_scene'): from tcms.core.utils.mailto import mailto mail_context = model.mail_scene( objects=targets, field=field, value=value, ctype=ctype, object_pk=object_pk, ) if mail_context: mail_context['context']['user'] = request.user mailto(**mail_context) # Special hacking for updating test case run status if ctype == 'testruns.testcaserun' and field == 'case_run_status': for t in targets: field = 'close_date' t.log_action( who=request.user, field=field, original_value=getattr(t, field) or '', new_value=now) if t.tested_by != request.user: field = 'tested_by' t.log_action( who=request.user, field=field, original_value=getattr(t, field) or '', new_value=request.user) field = 'assignee' try: assignee = t.assginee if assignee != request.user: t.log_action( who=request.user, field=field, original_value=getattr(t, field) or '', new_value=request.user) # t.assignee = request.user t.save() except (AttributeError, User.DoesNotExist): pass targets.update(close_date=now, tested_by=request.user) return HttpResponse(json.dumps({'rc': 0, 'response': 'ok'}))