def add_issue(self, issue_key, issue_tracker, summary=None, description=None, case_run=None, link_external_tracker=False): """Add issue to case or case run :param str issue_key: issue key to add. :param issue_tracker: to which the issue is added. :type issue_tracker: :class:`IssueTracker` :param str summary: issue's summary. It's optional. :param str description: a longer description for the issue. It's optional. :param case_run: If specified, that means issue is added to a test case run and also associated with this case. If omitted, it just means issue is added to this case only. :type case_run: :class:`TestCaseRun` :param bool link_external_tracker: whether to add the issue to issue tracker's external tracker just after issue is added. Default to not to do that. :return: newly created issue. If issue already exists (checking the existence of issue key), nothing changes and just return immediately with None. :rtype: :class:`Issue` :raises ValueError: if passed case run is not associated with this case. .. versionchanged:: 4.2 ``bug_id`` is replaced with ``issue_key``. ``bug_system_id`` is replaced with ``issue_tracker``. """ if case_run and case_run.case != self: raise ValueError( 'Case run {} is not associated with case {}'.format( case_run, self)) existing_issue = Issue.objects.filter( issue_key=issue_key, tracker=issue_tracker).only('issue_key').first() if existing_issue is not None: log.info('Issue %s already exist. Skip add.', issue_key) return existing_issue issue = Issue(issue_key=issue_key, tracker=issue_tracker, case=self, case_run=case_run, summary=summary, description=description) issue.full_clean() issue.save() if link_external_tracker: service = find_service(issue_tracker) service.add_external_tracker(issue_key) return issue
def attach_issue(request, values): """Add one or more issues to the selected test cases. :param dict values: a mapping containing these data to create a test run. * issue_key: (str) **Required** the issue key. * case_run: (int) **Required** ID of Case * tracker: (int) **Required** ID of issue tracker that issue should belong to. * summary: (str) optional issue's summary * description: (str) optional issue' description :return: a list which is empty on success or a list of mappings with failure codes if a failure occured. :rtype: list Example:: # Attach an issue 67890 to case run 12345 TestCaseRun.attach_issue({ 'case_run': [12345], 'issue_key': '67890', 'tracker': 1, 'summary': 'Testing TCMS', 'description': 'Just foo and bar', }) .. versionchanged:: 4.2 Some arguments passed via ``values`` are changed. ``case_run_id`` is changed to ``case_run``, ``bug_id`` is changed to ``issue_key``, ``bz_system_id`` is changed to ``tracker``. ``issue_key`` accepts string instead of integer. ``case_run`` within ``values`` must be a list of test case ids. """ if isinstance(values, dict): values = [ values, ] for value in values: form = CaseRunIssueForm(value) if form.is_valid(): service = find_service(form.cleaned_data['tracker']) issue_key = form.cleaned_data['issue_key'] summary = form.cleaned_data['summary'] description = form.cleaned_data['description'] case_runs = form.cleaned_data['case_run'] for case_run in case_runs: service.add_issue(issue_key, case_run.case, case_run=case_run, summary=summary, description=description) else: raise ValueError(form_error_messags_to_list(form))
def attach_issue(request, values): """Add one or more issues to the selected test cases. :param dict values: a mapping containing these data to create a test run. * issue_key: (str) **Required** the issue key. * case_run: (int) **Required** ID of Case * tracker: (int) **Required** ID of issue tracker that issue should belong to. * summary: (str) optional issue's summary * description: (str) optional issue' description :return: a list which is empty on success or a list of mappings with failure codes if a failure occured. :rtype: list Example:: # Attach an issue 67890 to case run 12345 >>> TestCaseRun.attach_issue({ 'case_run': [12345], 'issue_key': '67890', 'tracker': 1, 'summary': 'Testing TCMS', 'description': 'Just foo and bar', }) .. versionchanged:: 4.2 Some arguments passed via ``values`` are changed. ``case_run_id`` is changed to ``case_run``, ``bug_id`` is changed to ``issue_key``, ``bz_system_id`` is changed to ``tracker``. ``issue_key`` accepts string instead of integer. ``case_run`` within ``values`` must be a list of test case ids. """ if isinstance(values, dict): values = [values, ] for value in values: form = CaseRunIssueForm(value) if form.is_valid(): service = find_service(form.cleaned_data['tracker']) issue_key = form.cleaned_data['issue_key'] summary = form.cleaned_data['summary'] description = form.cleaned_data['description'] case_runs = form.cleaned_data['case_run'] for case_run in case_runs: service.add_issue( issue_key, case_run.case, case_run=case_run, summary=summary, description=description) else: raise ValueError(form_error_messags_to_list(form))
def add_issue(self, issue_key, issue_tracker, summary=None, description=None, case_run=None, link_external_tracker=False): """Add issue to case or case run :param str issue_key: issue key to add. :param issue_tracker: to which the issue is added. :type issue_tracker: :class:`IssueTracker` :param str summary: issue's summary. It's optional. :param str description: a longer description for the issue. It's optional. :param case_run: If specified, that means issue is added to a test case run and also associated with this case. If omitted, it just means issue is added to this case only. :type case_run: :class:`TestCaseRun` :param bool link_external_tracker: whether to add the issue to issue tracker's external tracker just after issue is added. Default to not to do that. :return: newly created issue. If issue already exists (checking the existence of issue key), nothing changes and just return immediately with None. :rtype: :class:`Issue` :raises ValueError: if passed case run is not associated with this case. .. versionchanged:: 4.2 ``bug_id`` is replaced with ``issue_key``. ``bug_system_id`` is replaced with ``issue_tracker``. """ if case_run and case_run.case != self: raise ValueError('Case run {} is not associated with case {}' .format(case_run, self)) existing_issue = Issue.objects.filter( issue_key=issue_key, tracker=issue_tracker ).only('issue_key').first() if existing_issue is not None: log.info('Issue %s already exist. Skip add.', issue_key) return existing_issue issue = Issue(issue_key=issue_key, tracker=issue_tracker, case=self, case_run=case_run, summary=summary, description=description) issue.full_clean() issue.save() if link_external_tracker: service = find_service(issue_tracker) service.add_external_tracker(issue_key) return issue
def add(self): # TODO: make a migration for the permission if not self.request.user.has_perm('issuetracker.add_issue'): return JsonResponse({'messages': ['Permission denied.']}, status=http.HTTPStatus.FORBIDDEN) form = CaseRunIssueForm(request.GET) if not form.is_valid(): msgs = form_error_messags_to_list(form) return JsonResponse({'messages': msgs}, status=http.HTTPStatus.BAD_REQUEST) service = find_service(form.cleaned_data['tracker']) issue_key = form.cleaned_data['issue_key'] link_et = form.cleaned_data['link_external_tracker'] case_runs = form.cleaned_data['case_run'] # FIXME: maybe, make sense to validate in the form. if not all(case_run.run_id == self.run.pk for case_run in case_runs): return JsonResponse( { 'messages': [f'Not all case runs belong to run {self.run.pk}.'] }, status=http.HTTPStatus.BAD_REQUEST) try: for case_run in case_runs: service.add_issue(issue_key, case_run.case, case_run=case_run, add_case_to_issue=link_et) except ValidationError as e: logger.exception( 'Failed to add issue to case run %s. Error reported: %s', form.case_run.pk, str(e)) return JsonResponse({'messages': [str(e)]}, status=http.HTTPStatus.BAD_REQUEST) return self.run_issues_info(case_runs)
def add(self): # TODO: make a migration for the permission if not self.request.user.has_perm('issuetracker.add_issue'): return JsonResponse({'messages': ['Permission denied.']}, status=http_client.FORBIDDEN) form = CaseRunIssueForm(request.GET) if not form.is_valid(): msgs = form_error_messags_to_list(form) return JsonResponse({'messages': msgs}, status=http_client.BAD_REQUEST) service = find_service(form.cleaned_data['tracker']) issue_key = form.cleaned_data['issue_key'] link_et = form.cleaned_data['link_external_tracker'] case_runs = form.cleaned_data['case_run'] # FIXME: maybe, make sense to validate in the form. if not all(case_run.run_id == self.run.pk for case_run in case_runs): return JsonResponse( {'messages': [ 'Not all case runs belong to run {}.'.format(self.run.pk) ]}, status=http_client.BAD_REQUEST) try: for case_run in case_runs: service.add_issue(issue_key, case_run.case, case_run=case_run, add_case_to_issue=link_et) except ValidationError as e: logger.exception( 'Failed to add issue to case run %s. Error reported: %s', form.case_run.pk, str(e)) return JsonResponse({'messages': [str(e)]}, status=http_client.BAD_REQUEST) return self.run_issues_info(case_runs)
def test_find_the_service(self): srv = services.find_service(self.issue_tracker_2) self.assertTrue(isinstance(srv, services.IssueTrackerService)) self.assertEqual(self.issue_tracker_2, srv.tracker_model)
def get_context_data(self, **kwargs): """Generate report for specific TestRun There are four data source to generate this report. 1. TestRun 2. Test case runs included in the TestRun 3. Comments associated with each test case run 4. Statistics 5. Issues """ run_id = int(self.kwargs['run_id']) run = TestRun.objects.select_related('manager', 'plan').get(pk=run_id) case_runs = (TestCaseRun.objects.filter(run=run).select_related( 'case_run_status', 'case', 'tested_by', 'case__category').only('close_date', 'case_run_status__name', 'case__category__name', 'case__summary', 'case__is_automated', 'case__is_automated_proposed', 'tested_by__username')) comments = self.get_caseruns_comments(run.pk) run_stats = stats_case_runs_status([run.pk])[run.pk] run_issues = Issue.objects.filter( case_run__run=run_id).select_related('tracker') by_case_run_pk = attrgetter('case_run.pk') issues_by_case_run = { case_run_id: [(item.issue_key, item.get_absolute_url()) for item in issues] for case_run_id, issues in itertools.groupby( sorted(run_issues, key=by_case_run_pk), by_case_run_pk) } manual_count = 0 automated_count = 0 manual_automated_count = 0 case_run: TestCaseRun for case_run in case_runs: case_run.display_issues = issues_by_case_run.get(case_run.pk, ()) user_comments = comments.get(case_run.pk, []) case_run.user_comments = user_comments is_automated = case_run.case.is_automated if is_automated == 1: automated_count += 1 elif is_automated == 0: manual_count += 1 else: manual_automated_count += 1 display_issues_by_tracker = [ (tracker.name, find_service(tracker).make_issues_display_url( sorted(map(attrgetter('issue_key'), issues)))) for tracker, issues in itertools.groupby( sorted(run_issues, key=attrgetter('tracker.pk')), attrgetter('tracker')) ] display_issues_by_tracker.sort(key=itemgetter(0)) run_issues_display_info = [(issue.issue_key, issue.get_absolute_url()) for issue in run_issues] context = super().get_context_data(**kwargs) context.update({ 'test_run': run, 'test_case_runs': case_runs, 'display_issues_by_tracker': display_issues_by_tracker, 'test_case_runs_count': len(case_runs), 'test_case_run_issues': run_issues_display_info, 'test_case_run_mode_stats': { 'manual': manual_count, 'automated': automated_count, 'manual_automated': manual_automated_count, }, 'test_run_stats': run_stats, }) return context
def get_redirect_url(self, *args, **kwargs): case_run_id = self.kwargs['case_run_id'] tracker_id = int(self.request.GET['issueTrackers']) case_run = get_object_or_404(TestCaseRun, pk=case_run_id) bz_model = IssueTracker.objects.get(pk=tracker_id) return find_service(bz_model).make_issue_report_url(case_run)