tobyqin/testcube

View on GitHub
testcube/core/forms.py

Summary

Maintainability
A
1 hr
Test Coverage
import json

from django import forms

from testcube.settings import logger
from .models import ResultAnalysis, Issue, TestResult, ResetResult
from ..runner.models import Task


class AnalysisForm(forms.Form):
    reason = forms.IntegerField(label='Reason',
                                widget=forms.Select(choices=ResultAnalysis.REASON_CHOICES))

    issue_id = forms.CharField(label='Issue ID',
                               required=False,
                               widget=forms.TextInput(
                                   attrs={'placeholder': '(Optional) Example: Issue-12345'}))

    description = forms.CharField(label='Description',
                                  required=True,
                                  widget=forms.Textarea(
                                      attrs={'rows': 4,
                                             'placeholder': 'Why the test failed?'}))

    def load(self, result_id):
        """add initial field value when load the form"""
        result = TestResult.objects.get(id=result_id)
        self.need_analysis = result.outcome != 0
        self.fields['reason'].initial = 0
        if result and result.analysis:
            self.result = result

            self.fields['reason'].initial = result.analysis.reason
            self.fields['description'].initial = result.analysis.description
            self.fields['issue_id'].initial = result.issue_id()

    def save(self, result_id, username):
        """
        to save the analysis form, we will:
        1. create analysis object then link to result id
        2. create issue object if issue id was added
        """
        result = TestResult.objects.get(id=result_id)
        self.need_analysis = result.outcome != 0
        if result:
            reason = self.cleaned_data.get('reason')
            description = self.cleaned_data.get('description')
            issue_id = self.cleaned_data.get('issue_id')

            issue = None
            if issue_id:
                issue, _ = Issue.objects.update_or_create(name=issue_id)
                if description:
                    issue.summary = description
                    issue.save()

            data = {'by': username,
                    'reason': reason,
                    'description': description,
                    'issue': issue}

            if not result.analysis:
                analysis = ResultAnalysis.objects.create(**data)
                analysis.save()
                result.analysis = analysis
                result.save()

            else:
                result.analysis.by = username
                result.analysis.reason = reason
                result.analysis.description = description
                result.analysis.issue = issue
                result.analysis.save()

            self.result = result

        else:
            self.add_error('description', 'Bad result id: ' + result_id)


class ResetForm(forms.Form):
    reason = forms.CharField(label='Reason',
                             required=True,
                             widget=forms.TextInput(
                                 attrs={'placeholder': 'Why do you want to reset this result?'}))

    def save(self, result_id, username):
        """
        main reset logic:
        0. check if reset is in progress, return with error message
        1. get reset profile via result/testcase/product/profile
        2. add a reset task in runner/task
        3. add a reset result in core/reset_result with [in progress] status
        """
        result = TestResult.objects.get(id=result_id)
        reason = self.cleaned_data.get('reason')

        if result.is_reset_in_progress():
            self.add_error('reason', 'Reset is in progress, please wait...')
            return

        profile = result.get_reset_profile()

        if not profile:
            self.add_error('reason', 'Please configure reset profile at first.')
            return

        # add reset result object
        reset = ResetResult(reset_by=username,
                            reset_reason=reason,
                            reset_status=1,  # in progress
                            origin_result=result)

        # if reset with error, abort tasks
        cmd, error = _parse_command(profile.command, result, reset)
        if error:
            self.add_error('reason', 'Failed to reset result {}'.format(error))
            return

        reset.save()

        # now generate cmd with real reset id
        cmd = _parse_command(profile.command, result, reset)[0]

        # add reset task object
        data = {'result_id': result_id,
                'reset_id': reset.id,
                'reason': reason,
                'by': username}

        task = Task(object_name='TestResult',
                    object_id=result_id,
                    description='ResetResult',
                    command=cmd,
                    data=json.dumps(data))

        task.save()


def _parse_command(command, result, reset):
    """
    method to parse reset command.
    for example: http://server/reset_job?testcase={result.testcase.name}&result_id={result.id}
    will be parsed according under current result context.
    """
    try:
        from testcube.runner.models import RunVariables
        try:
            run_variables = result.test_run.run_variables.data_json
        except RunVariables.DoesNotExist:
            run_variables = {}

        assert isinstance(result, TestResult)
        cmd = command.format(result=result, reset=reset, **run_variables)
        return cmd, None
    except Exception as e:
        logger.exception('Failed to parse command: {}'.format(command))

        message = 'while parsing command "{}" due to {}: {}'.format(
            command, type(e).__name__, e.args)
        return command, message