From c87e751f16f58a1ea1d318c5d808ad6429e021ea Mon Sep 17 00:00:00 2001 From: "Mr. Senko" Date: Sat, 19 Jan 2019 04:31:39 +0200 Subject: [PATCH] [db] Remove TestCaseText model, merge into TestCase.text field - TestCaseText model is removed and provided as TestCase.text field - TestCase.latest_text() is removed in favor of TestCase.text - TestCase.latest_text_version() is removed in favor of TestCase.history.latest().history_id - TestCase.get_text_with_version() will read from the history - TestCase.add_text() is removed - TestCase.get_text_versions() - removed - TestCaseRun.latest_text() is removed - TestCaseRun.get_text_with_version() is removed in favor of TestCase.get_text_with_version() - NoneText is removed - tcms.core.utils.checksum is removed - tcms.utils.dict_utils is removed - update existing templates and forms - update test suite to generate historical records Closes #198 --- docs/source/modules/tcms.core.utils.rst | 1 - docs/source/modules/tcms.utils.dict_utils.rst | 7 -- docs/source/modules/tcms.utils.rst | 1 - tcms/core/utils/checksum.py | 10 -- tcms/issuetracker/types.py | 37 ++----- tcms/templates/case/edit.html | 31 +----- tcms/templates/case/get_details.html | 20 +--- tcms/templates/case/get_details_case_run.html | 29 +----- tcms/templates/case/history.html | 65 ------------- tcms/templates/case/printable.html | 21 +--- tcms/testcases/forms.py | 5 +- ...06_merge_text_field_into_testcase_model.py | 76 +++++++++++++++ tcms/testcases/models.py | 97 ++----------------- tcms/testcases/templates/testcases/get.html | 18 +--- tcms/testcases/tests/test_models.py | 12 +-- tcms/testcases/tests/test_views.py | 24 +---- tcms/testcases/urls/case_urls.py | 1 - tcms/testcases/views.py | 91 ++--------------- tcms/testplans/models.py | 13 +-- tcms/testplans/tests/tests.py | 16 +-- tcms/testruns/forms.py | 4 +- tcms/testruns/models.py | 35 +------ tcms/testruns/tests/test_views.py | 23 ++--- tcms/testruns/views.py | 8 +- tcms/tests/__init__.py | 12 +++ tcms/tests/factories.py | 17 +--- tcms/utils/dict_utils.py | 29 ------ tcms/xmlrpc/api/testcase.py | 32 ------ tcms/xmlrpc/serializer.py | 1 + tcms/xmlrpc/tests/test_testcase.py | 21 +--- tcms/xmlrpc/tests/test_testrun.py | 1 + 31 files changed, 166 insertions(+), 592 deletions(-) delete mode 100644 docs/source/modules/tcms.utils.dict_utils.rst delete mode 100644 tcms/core/utils/checksum.py delete mode 100644 tcms/templates/case/history.html create mode 100644 tcms/testcases/migrations/0006_merge_text_field_into_testcase_model.py delete mode 100644 tcms/utils/dict_utils.py diff --git a/docs/source/modules/tcms.core.utils.rst b/docs/source/modules/tcms.core.utils.rst index 29045a8f7f..519e0052ca 100644 --- a/docs/source/modules/tcms.core.utils.rst +++ b/docs/source/modules/tcms.core.utils.rst @@ -11,7 +11,6 @@ Submodules .. toctree:: - tcms.core.utils.checksum tcms.core.utils.mailto tcms.core.utils.validations diff --git a/docs/source/modules/tcms.utils.dict_utils.rst b/docs/source/modules/tcms.utils.dict_utils.rst deleted file mode 100644 index 5e26f44e75..0000000000 --- a/docs/source/modules/tcms.utils.dict_utils.rst +++ /dev/null @@ -1,7 +0,0 @@ -tcms.utils.dict\_utils module -============================= - -.. automodule:: tcms.utils.dict_utils - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/modules/tcms.utils.rst b/docs/source/modules/tcms.utils.rst index ed10b33256..4deec6f885 100644 --- a/docs/source/modules/tcms.utils.rst +++ b/docs/source/modules/tcms.utils.rst @@ -11,6 +11,5 @@ Submodules .. toctree:: - tcms.utils.dict_utils tcms.utils.permissions diff --git a/tcms/core/utils/checksum.py b/tcms/core/utils/checksum.py deleted file mode 100644 index 834d69e68e..0000000000 --- a/tcms/core/utils/checksum.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -import hashlib - - -def checksum(value): - if value is None: - return '' - _checksum = hashlib.sha256() - _checksum.update(value.encode("UTF-8")) # pylint: disable=objects-update-used - return _checksum.hexdigest() diff --git a/tcms/issuetracker/types.py b/tcms/issuetracker/types.py index 0e68775af0..1919b700b6 100644 --- a/tcms/issuetracker/types.py +++ b/tcms/issuetracker/types.py @@ -155,19 +155,14 @@ def report_issue_from_testcase(self, caserun): args = {} args['cf_build_id'] = caserun.run.build.name - # this is a TestCaseText model or NoneText - txt = caserun.get_text_with_version(case_text_version=caserun.case_text_version) - setup = txt.setup - action = txt.action - effect = txt.effect + txt = caserun.case.get_text_with_version(case_text_version=caserun.case_text_version) comment = "Filed from caserun %s\n\n" % caserun.get_full_url() comment += "Version-Release number of selected " \ "component (if applicable):\n" comment += '%s\n\n' % caserun.build.name - comment += "Steps to Reproduce: \n%s\n%s\n\n" % (setup, action) + comment += "Steps to Reproduce: \n%s\n\n" % txt comment += "Actual results: \n\n\n" - comment += "Expected results:\n%s\n\n" % effect args['comment'] = comment args['component'] = caserun.case.component.values_list('name', @@ -256,11 +251,8 @@ def report_issue_from_testcase(self, caserun): args['reporter'] = self.rpc.user(tested_by.username).key except jira.JIRAError: pass - # this is a TestCaseText model or NoneText - txt = caserun.get_text_with_version(case_text_version=caserun.case_text_version) - setup = txt.setup - action = txt.action - effect = txt.effect + + txt = caserun.case.get_text_with_version(case_text_version=caserun.case_text_version) comment = "Filed from caserun %s\n\n" % caserun.get_full_url() comment += "Product:\n%s\n\n" % caserun.run.plan.product.name @@ -268,9 +260,8 @@ def report_issue_from_testcase(self, caserun): comment += "Version-Release number of selected " \ "component (if applicable):\n" comment += "%s\n\n" % caserun.build.name - comment += "Steps to Reproduce: \n%s\n%s\n\n" % (setup, action) + comment += "Steps to Reproduce: \n%s\n\n" % txt comment += "Actual results: \n\n\n" - comment += "Expected results:\n%s\n\n" % effect args['description'] = comment url = self.tracker.base_url @@ -321,11 +312,7 @@ def report_issue_from_testcase(self, caserun): 'title': 'Failed test: %s' % caserun.case.summary, } - # this is a TestCaseText model or NoneText - txt = caserun.get_text_with_version(case_text_version=caserun.case_text_version) - setup = txt.setup - action = txt.action - effect = txt.effect + txt = caserun.case.get_text_with_version(case_text_version=caserun.case_text_version) comment = "Filed from caserun %s\n\n" % caserun.get_full_url() comment += "Product:\n%s\n\n" % caserun.run.plan.product.name @@ -333,9 +320,8 @@ def report_issue_from_testcase(self, caserun): comment += "Version-Release number of selected " \ "component (if applicable):\n" comment += "%s\n\n" % caserun.build.name - comment += "Steps to Reproduce: \n%s\n%s\n\n" % (setup, action) + comment += "Steps to Reproduce: \n%s\n\n" % txt comment += "Actual results: \n\n\n" - comment += "Expected results:\n%s\n\n" % effect args['body'] = comment url = self.tracker.base_url @@ -371,11 +357,7 @@ def report_issue_from_testcase(self, caserun): 'issue[title]': 'Failed test: %s' % caserun.case.summary, } - # this is a TestCaseText model or NoneText - txt = caserun.get_text_with_version(case_text_version=caserun.case_text_version) - setup = txt.setup - action = txt.action - effect = txt.effect + txt = caserun.case.get_text_with_version(case_text_version=caserun.case_text_version) comment = "Filed from caserun %s\n\n" % caserun.get_full_url() comment += "**Product**:\n%s\n\n" % caserun.run.plan.product.name @@ -384,9 +366,8 @@ def report_issue_from_testcase(self, caserun): comment += "Version-Release number of selected " \ "component (if applicable):\n" comment += "%s\n\n" % caserun.build.name - comment += "**Steps to Reproduce**: \n%s\n%s\n\n" % (setup, action) + comment += "**Steps to Reproduce**: \n%s\n\n" % txt comment += "**Actual results**: \n\n\n" - comment += "**Expected results**:\n%s\n\n" % effect args['issue[description]'] = comment url = self.tracker.base_url diff --git a/tcms/templates/case/edit.html b/tcms/templates/case/edit.html index b6b5c0f378..7bed815e9e 100644 --- a/tcms/templates/case/edit.html +++ b/tcms/templates/case/edit.html @@ -46,13 +46,6 @@ {% block contents %}
- - {% if test_case %} - - Edit History - - {% endif %} - {% if test_case %}
{% else %} @@ -113,24 +106,10 @@ {% endif %}
-
- -
- {% if test_case.latest_text.author %} - - {{ test_case.latest_text.author.username }} - - {% endif %} -
-
{{ test_case.create_date }}
-
- -
{{ test_case.latest_text.create_date }}
-
{% endif %}
@@ -157,15 +136,7 @@

Setup

-
{{ form.setup }}
-

Actions

-
{{ form.action }}
-
-
-

Break down

-
{{ form.breakdown }}
-

Expected Results

-
{{ form.effect }}
+
{{ form.text }}
{% if notify_form %} diff --git a/tcms/templates/case/get_details.html b/tcms/templates/case/get_details.html index b77c3938a5..c97b6a4f6f 100644 --- a/tcms/templates/case/get_details.html +++ b/tcms/templates/case/get_details.html @@ -3,13 +3,9 @@ - - - - - -
-

Setup:

-
{{ test_case_text.setup|markdown2html }}
-
-

Breakdown:

-
{{ test_case_text.breakdown|markdown2html }}
+
+

Text:

+
{{ test_case.text|markdown2html }}

Attachment:

@@ -56,16 +52,6 @@

bug:

-

Actions:

-
{{ test_case_text.action|markdown2html }}
-
-

Expected Results:

-
{{ test_case_text.effect|markdown2html }}
-

Notes:

diff --git a/tcms/templates/case/get_details_case_run.html b/tcms/templates/case/get_details_case_run.html index 5fa6d0bb79..985a7704c8 100644 --- a/tcms/templates/case/get_details_case_run.html +++ b/tcms/templates/case/get_details_case_run.html @@ -129,33 +129,10 @@

Change Log

- - - - - - - - diff --git a/tcms/templates/case/history.html b/tcms/templates/case/history.html deleted file mode 100644 index 14eaad6a18..0000000000 --- a/tcms/templates/case/history.html +++ /dev/null @@ -1,65 +0,0 @@ -{% extends "tcms_base.html" %} -{% load static %} -{% load extra_filters %} -{% block subtitle %}Case History{% endblock %} - -{% block custom_stylesheet %} -{% endblock %} - -{% block custom_javascript %} - - -{% endblock %} - -{% block contents %} -
-

{{ testcase.summary }} History

-
-
+
-

Setup

-
{{ test_case_text.setup|markdown2html }}
-
-
-
-

Breakdown

-
{{ test_case_text.breakdown|markdown2html }}
-
-
-
-

Actions

-
{{ test_case_text.action|markdown2html }}
-
- -
-
-

Expected Results

-
{{ test_case_text.effect|markdown2html }}
+

Text

+
{{ test_case_text|markdown2html }}
- - - - - - {% for text in test_case_texts %} - - - - - - {% ifequal text.case_text_version select_case_text_version %} - - - - {% endifequal %} - {% endfor %} -
Text VersionModified DateChanged By
{{ text.case_text_version }}{{ text.create_date }}{{ text.author__email }}
-
- {% for text in text_to_show %} -
- SETUP: - {{ text.setup|markdown2html }} -
-
- ACTION: - {{ text.action|markdown2html }} -
-
- EXPECTED RESULT: - {{ text.effect|markdown2html }} -
-
- BREAKDOWN: - {{ text.breakdown|markdown2html }} -
- {% endfor %} -
-
-
- -{% endblock %} diff --git a/tcms/templates/case/printable.html b/tcms/templates/case/printable.html index e41532d3c8..a7586988b3 100644 --- a/tcms/templates/case/printable.html +++ b/tcms/templates/case/printable.html @@ -47,28 +47,13 @@

Test Plan Document

Test Cases

- {% for case_id, test_cases in test_cases.items %} + {% for test_case in test_cases %}
- {% for test_case in test_cases %} -

TC-{{ test_case.case_id }}: {{ test_case.case__summary }}

+

TC-{{ test_case.case_id }}: {{ test_case.summary }}

-

Set up

- {{ test_case.setup|markdown2html }} + {{ test_case.text|markdown2html }}
-
-

Actions

- {{ test_case.action|markdown2html }} -
-
-

Expected Results

- {{ test_case.effect|markdown2html }} -
-
-

Breakdown

- {{ test_case.breakdown|markdown2html }} -
- {% endfor %}
{% endfor %}
diff --git a/tcms/testcases/forms.py b/tcms/testcases/forms.py index f912f119a1..9f99796b87 100644 --- a/tcms/testcases/forms.py +++ b/tcms/testcases/forms.py @@ -105,10 +105,7 @@ class BaseCaseForm(forms.Form): widget=forms.Textarea, required=False ) - setup = forms.CharField(label="Setup", widget=SimpleMDE(), required=False) - action = forms.CharField(label="Actions", widget=SimpleMDE(), required=False) - effect = forms.CharField(label="Expect results", widget=SimpleMDE(), required=False) - breakdown = forms.CharField(label="Breakdown", widget=SimpleMDE(), required=False) + text = forms.CharField(widget=SimpleMDE(), required=False) def __init__(self, *args, **kwargs): if args: diff --git a/tcms/testcases/migrations/0006_merge_text_field_into_testcase_model.py b/tcms/testcases/migrations/0006_merge_text_field_into_testcase_model.py new file mode 100644 index 0000000000..f4a3ad0b65 --- /dev/null +++ b/tcms/testcases/migrations/0006_merge_text_field_into_testcase_model.py @@ -0,0 +1,76 @@ +from django.db import migrations, models + + +def convert_test_case_text(test_case_text): + return """**Setup:** +%s + +**Actions:** +%s + +**Expected result:** +%s + +**Breakdown:** +%s +""" % (test_case_text.setup, + test_case_text.action, + test_case_text.effect, + test_case_text.breakdown) + + +def forward_copy_data(apps, schema_editor): + TestCase = apps.get_model('testcases', 'TestCase') + TestCaseText = apps.get_model('testcases', 'TestCaseText') + + for test_case in TestCase.objects.all(): + latest_text = TestCaseText.objects.filter(case=test_case.pk).order_by('-pk').first() + if latest_text: + test_case.case_text = convert_test_case_text(latest_text) + test_case.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('testcases', '0005_remove_unused_fields'), + ] + + operations = [ + # add new field to hold TC text but use a temporary name + # b/c `text` is also the name of the pre-existing reverse relationship + migrations.AddField( + model_name='historicaltestcase', + name='case_text', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='testcase', + name='case_text', + field=models.TextField(blank=True), + ), + + # copy the data from the related model + migrations.RunPython(forward_copy_data), + + # remove the related model + migrations.RemoveField( + model_name='testcasetext', + name='author', + ), + migrations.DeleteModel( + name='TestCaseText', + ), + + # rename the new field to what is inside the model source + migrations.RenameField( + model_name='historicaltestcase', + old_name='case_text', + new_name='text', + ), + migrations.RenameField( + model_name='testcase', + old_name='case_text', + new_name='text', + ), + ] diff --git a/tcms/testcases/models.py b/tcms/testcases/models.py index 0dbd036970..e83c3266a5 100644 --- a/tcms/testcases/models.py +++ b/tcms/testcases/models.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from datetime import datetime - from django.conf import settings from django.urls import reverse from django.db import models @@ -9,7 +7,6 @@ import vinaigrette from tcms.core.models import TCMSActionModel -from tcms.core.utils.checksum import checksum from tcms.core.history import KiwiHistoricalRecords from tcms.issuetracker.types import IssueTrackerType from tcms.testcases.fields import MultipleEmailField @@ -22,20 +19,6 @@ ) -class NoneText: # pylint: disable=too-few-public-methods - author = None - case_text_version = 0 - action = '' - effect = '' - setup = '' - breakdown = '' - create_date = datetime.now() - - @classmethod - def serialize(cls): - return {} - - class TestCaseStatus(TCMSActionModel): id = models.AutoField( db_column='case_status_id', max_length=6, primary_key=True @@ -106,6 +89,7 @@ class TestCase(TCMSActionModel): summary = models.CharField(max_length=255) requirement = models.CharField(max_length=255, blank=True, null=True) notes = models.TextField(blank=True, null=True) + text = models.TextField(blank=True) case_status = models.ForeignKey(TestCaseStatus, on_delete=models.CASCADE) category = models.ForeignKey(Category, related_name='category_case', @@ -135,9 +119,6 @@ class TestCase(TCMSActionModel): tag = models.ManyToManyField('management.Tag', related_name='case', through='testcases.TestCaseTag') - # todo: Auto-generated attributes from back-references: - # 'texts' : list of TestCaseTexts (from TestCaseTexts.case) - def __str__(self): return self.summary @@ -171,6 +152,7 @@ def create(cls, author, values): priority=values['priority'], default_tester=values['default_tester'], notes=values['notes'], + text=values['text'], ) # todo: should use add_tag @@ -288,40 +270,6 @@ def add_component(self, component): def add_tag(self, tag): return TestCaseTag.objects.get_or_create(case=self, tag=tag) - def add_text( - self, - action, - effect, - setup, - breakdown, - author=None, - create_date=datetime.now(), - case_text_version=1): - if not author: - author = self.author - - new_checksum = checksum(action + effect + setup + breakdown) - latest_text = self.latest_text() - old_checksum = checksum(latest_text.action + - latest_text.effect + - latest_text.setup + - latest_text.breakdown) - - if old_checksum == new_checksum: - return latest_text - - case_text_version = self.latest_text_version() + 1 - return TestCaseText.objects.create( - case=self, - case_text_version=case_text_version, - create_date=create_date, - author=author, - action=action, - effect=effect, - setup=setup, - breakdown=breakdown - ) - def add_to_plan(self, plan): TestCasePlan.objects.get_or_create(case=self, plan=plan) @@ -367,27 +315,11 @@ def get_previous_and_next(self, pk_list): def get_text_with_version(self, case_text_version=None): if case_text_version: try: - return TestCaseText.objects.get( - case__case_id=self.case_id, - case_text_version=case_text_version - ) - except TestCaseText.DoesNotExist: - return NoneText - - return self.latest_text() - - def latest_text(self, text_required=True): - text = self.text - if not text_required: - text = text.defer('action', 'effect', 'setup', 'breakdown') - latest_text = text.order_by('-case_text_version').first() - return latest_text or NoneText - - def latest_text_version(self): - latest_version = self.text.order_by('-case_text_version').only('case_text_version').first() - if latest_version: - return latest_version.case_text_version - return 0 + return self.history.get(history_id=case_text_version).text + except ObjectDoesNotExist: + return self.text + + return self.text def remove_bug(self, bug_id, run_id=None): query = Bug.objects.filter( @@ -424,21 +356,6 @@ def _get_email_conf(self): emailing = property(_get_email_conf) -class TestCaseText(TCMSActionModel): - case = models.ForeignKey(TestCase, related_name='text', on_delete=models.CASCADE) - case_text_version = models.IntegerField() - author = models.ForeignKey(settings.AUTH_USER_MODEL, db_column='who', on_delete=models.CASCADE) - create_date = models.DateTimeField(db_column='creation_ts', auto_now_add=True) - action = models.TextField(blank=True) - effect = models.TextField(blank=True) - setup = models.TextField(blank=True) - breakdown = models.TextField(blank=True) - - class Meta: - ordering = ['case', '-case_text_version'] - unique_together = ('case', 'case_text_version') - - class TestCasePlan(models.Model): plan = models.ForeignKey('testplans.TestPlan', on_delete=models.CASCADE) case = models.ForeignKey(TestCase, on_delete=models.CASCADE) diff --git a/tcms/testcases/templates/testcases/get.html b/tcms/testcases/templates/testcases/get.html index 1c666a260f..1eaec79a89 100644 --- a/tcms/testcases/templates/testcases/get.html +++ b/tcms/testcases/templates/testcases/get.html @@ -26,23 +26,7 @@

- {% trans 'Setup' %}: - {{ test_case_text.setup|markdown2html }} -

- -

- {% trans 'Actions' %}: - {{ test_case_text.action|markdown2html }} -

- -

- {% trans 'Expected result' %}: - {{ test_case_text.effect|markdown2html }} -

- -

- {% trans 'Breakdown' %}: - {{ test_case_text.breakdown|markdown2html }} + {{ test_case.text|markdown2html }}

diff --git a/tcms/testcases/tests/test_models.py b/tcms/testcases/tests/test_models.py index 2bc2873dcc..dfa104298b 100644 --- a/tcms/testcases/tests/test_models.py +++ b/tcms/testcases/tests/test_models.py @@ -13,7 +13,6 @@ from tcms.tests.factories import ComponentFactory from tcms.tests.factories import BuildFactory from tcms.tests.factories import TestCaseComponentFactory -from tcms.tests.factories import TestCaseEmailSettingsFactory from tcms.tests.factories import TestCaseFactory from tcms.tests.factories import TestCaseRunFactory from tcms.tests.factories import TestCaseTagFactory @@ -165,14 +164,11 @@ class TestSendMailOnCaseIsUpdated(BasePlanCase): """Test send mail on case post_save signal is triggered""" @classmethod def setUpTestData(cls): - super(TestSendMailOnCaseIsUpdated, cls).setUpTestData() + super().setUpTestData() - cls.case.add_text('action', 'effect', 'setup', 'breakdown') - - cls.email_setting = TestCaseEmailSettingsFactory( - case=cls.case, - notify_on_case_update=True, - auto_to_case_author=True) + cls.case.emailing.notify_on_case_update = True + cls.case.emailing.auto_to_case_author = True + cls.case.emailing.save() cls.case_editor = User.objects.create_user(username='editor') # This is actually done when update a case. Setting current_user diff --git a/tcms/testcases/tests/test_views.py b/tcms/testcases/tests/test_views.py index 04e14ad427..87545a12b5 100644 --- a/tcms/testcases/tests/test_views.py +++ b/tcms/testcases/tests/test_views.py @@ -24,10 +24,6 @@ class TestGetCaseRunDetailsAsDefaultUser(BaseCaseRun): """Assert what a default user (non-admin) will see""" - @classmethod - def setUpTestData(cls): - super(TestGetCaseRunDetailsAsDefaultUser, cls).setUpTestData() - def test_user_in_default_group_sees_comments(self): # test for https://github.com/kiwitcms/Kiwi/issues/74 initiate_user_with_default_setups(self.tester) @@ -37,7 +33,7 @@ def test_user_in_default_group_sees_comments(self): url, { 'case_run_id': self.case_run_1.pk, - 'case_text_version': self.case_run_1.case.latest_text_version() + 'case_text_version': self.case_run_1.case.history.latest().history_id, } ) @@ -69,7 +65,7 @@ def test_user_sees_bugs(self): url, { 'case_run_id': self.case_run_1.pk, - 'case_text_version': self.case_run_1.case.latest_text_version() + 'case_text_version': self.case_run_1.case.history.latest().history_id, } ) @@ -161,10 +157,7 @@ def setUpTestData(cls): 'script': '', 'priority': cls.case_1.priority.pk, 'tag': 'RHEL', - 'setup': '', - 'action': '', - 'breakdown': '', - 'effect': '', + 'text': 'Given-When-Then', 'cc_list': '', } @@ -264,18 +257,9 @@ class TestPrintablePage(BasePlanCase): @classmethod def setUpTestData(cls): - super(TestPrintablePage, cls).setUpTestData() + super().setUpTestData() cls.printable_url = reverse('testcases-printable') - cls.case_1.add_text(action='action', - effect='effect', - setup='setup', - breakdown='breakdown') - cls.case_2.add_text(action='action', - effect='effect', - setup='setup', - breakdown='breakdown') - def test_printable_page(self): # printing only 1 of the cases response = self.client.post(self.printable_url, diff --git a/tcms/testcases/urls/case_urls.py b/tcms/testcases/urls/case_urls.py index 054cb292cf..9019aed97d 100644 --- a/tcms/testcases/urls/case_urls.py +++ b/tcms/testcases/urls/case_urls.py @@ -7,7 +7,6 @@ urlpatterns = [ url(r'^(?P\d+)/$', views.get, name='testcases-get'), url(r'^(?P\d+)/edit/$', views.edit, name='testcases-edit'), - url(r'^(?P\d+)/history/$', views.text_history, name='testcases-text_history'), url(r'^(?P\d+)/attachment/$', views.attachment, name='testcases-attachment'), url(r'^(?P\d+)/readonly-pane/$', views.SimpleTestCaseView.as_view(), name='case-readonly-pane'), diff --git a/tcms/testcases/views.py b/tcms/testcases/views.py index 37258701f2..f0b3c76740 100644 --- a/tcms/testcases/views.py +++ b/tcms/testcases/views.py @@ -19,7 +19,7 @@ from tcms.search import remove_from_request_path from tcms.search.order import order_case_queryset from tcms.testcases.models import TestCase, TestCaseStatus, \ - TestCasePlan, TestCaseText + TestCasePlan from tcms.management.models import Priority, Tag from tcms.testplans.models import TestPlan from tcms.testruns.models import TestCaseRun @@ -28,7 +28,6 @@ SearchCaseForm, EditCaseForm, CaseNotifyForm, \ CloneCaseForm from tcms.testplans.forms import SearchPlanForm -from tcms.utils.dict_utils import create_dict_from_query from tcms.testcases.fields import MultipleEmailField @@ -98,12 +97,6 @@ def group_case_bugs(bugs): def create_testcase(request, form, test_plan): """Create testcase""" test_case = TestCase.create(author=request.user, values=form.cleaned_data) - test_case.add_text(case_text_version=1, - author=request.user, - action=form.cleaned_data['action'], - effect=form.cleaned_data['effect'], - setup=form.cleaned_data['setup'], - breakdown=form.cleaned_data['breakdown']) # Assign the case to the plan if test_plan: @@ -547,7 +540,6 @@ def get_context_data(self, **kwargs): data.update({ 'test_case': case, 'review_mode': self.review_mode, - 'test_case_text': case.latest_text(), 'components': case.component.only('name'), 'tags': case.tag.only('name'), 'case_comments': get_comments(case), @@ -620,14 +612,10 @@ def get(request, case_id): 'assignee', 'case', 'case', 'status').order_by('run__plan', 'run') - # Get the case texts - tc_text = test_case.get_text_with_version(request.GET.get('case_text_version')) - # Render the page context_data = { 'test_case': test_case, 'test_case_runs': tcrs, - 'test_case_text': tc_text, } url_params = "?case=%d" % test_case.pk @@ -671,7 +659,7 @@ def printable(request, template_name='case/printable.html'): # this in the browser # search only by case PK. Used when printing selected cases case_ids = request.POST.getlist('case') - case_filter = {'case__in': case_ids} + case_filter = {'pk__in': case_ids} test_plan = None # plan_pk is passed from the TestPlan.printable function @@ -682,19 +670,15 @@ def printable(request, template_name='case/printable.html'): test_plan = TestPlan.objects.get(pk=plan_pk) # search cases from a TestPlan, used when printing entire plan case_filter = { - 'case__in': test_plan.case.all(), - 'case__case_status': TestCaseStatus.objects.get(name='CONFIRMED').pk, + 'pk__in': test_plan.case.all(), + 'case_status': TestCaseStatus.objects.get(name='CONFIRMED').pk, } except (ValueError, TestPlan.DoesNotExist): test_plan = None - tcs = create_dict_from_query( - TestCaseText.objects.filter(**case_filter).values( - 'case_id', 'case__summary', 'setup', 'action', 'effect', 'breakdown' - ).order_by('case_id', '-case_text_version'), - 'case_id', - True - ) + tcs = TestCase.objects.filter(**case_filter).values( + 'case_id', 'summary', 'text' + ).order_by('case_id') context_data = { 'test_plan': test_plan, @@ -722,6 +706,7 @@ def update_testcase(request, test_case, tc_form): 'category', 'priority', 'notes', + 'text', 'is_automated', 'script', 'arguments', @@ -772,12 +757,6 @@ def edit(request, case_id, template_name='case/edit.html'): update_testcase(request, test_case, form) - test_case.add_text(author=request.user, - action=form.cleaned_data['action'], - effect=form.cleaned_data['effect'], - setup=form.cleaned_data['setup'], - breakdown=form.cleaned_data['breakdown']) - # Notification update_case_email_settings(test_case, n_form) @@ -829,7 +808,6 @@ def edit(request, case_id, template_name='case/edit.html'): )) else: - tctxt = test_case.latest_text() # Notification form initial n_form = CaseNotifyForm(initial={ 'notify_on_case_update': test_case.emailing.notify_on_case_update, @@ -865,10 +843,7 @@ def edit(request, case_id, template_name='case/edit.html'): 'category': test_case.category_id, 'notes': test_case.notes, 'component': components, - 'setup': tctxt.setup, - 'action': tctxt.action, - 'effect': tctxt.effect, - 'breakdown': tctxt.breakdown, + 'text': test_case.text, }) form.populate(product_id=test_case.category.product_id) @@ -882,42 +857,6 @@ def edit(request, case_id, template_name='case/edit.html'): return render(request, template_name, context_data) -def text_history(request, case_id, template_name='case/history.html'): - """View test plan text history""" - - test_case = get_object_or_404(TestCase, case_id=case_id) - test_plan = plan_from_request_or_none(request) - tctxts = test_case.text.values('case_id', - 'case_text_version', - 'author__email', - 'create_date').order_by('-case_text_version') - - context = { - 'testplan': test_plan, - 'testcase': test_case, - 'test_case_texts': tctxts.iterator(), - } - - try: - case_text_version = int(request.GET.get('case_text_version')) - text_to_show = test_case.text.filter(case_text_version=case_text_version) - text_to_show = text_to_show.values('action', - 'effect', - 'setup', - 'breakdown') - - context.update({ - 'select_case_text_version': case_text_version, - 'text_to_show': text_to_show.iterator(), - }) - except (TypeError, ValueError): - # If case_text_version is not a valid number, no text to display for a - # selected text history - pass - - return render(request, template_name, context) - - @permission_required('testcases.add_testcase') def clone(request, template_name='case/clone.html'): """Clone one case or multiple case into other plan or plans""" @@ -955,6 +894,7 @@ def clone(request, template_name='case/clone.html'): category=tc_src.category, priority=tc_src.priority, notes=tc_src.notes, + text=tc_src.text, author=clone_form.cleaned_data[ 'maintain_case_orignal_author'] and tc_src.author or request.user, @@ -977,17 +917,6 @@ def clone(request, template_name='case/clone.html'): test_plan.add_case(tc_dest, sortkey) - tc_dest.add_text( - author=clone_form.cleaned_data[ - 'maintain_case_orignal_author'] and - tc_src.author or request.user, - create_date=tc_src.latest_text().create_date, - action=tc_src.latest_text().action, - effect=tc_src.latest_text().effect, - setup=tc_src.latest_text().setup, - breakdown=tc_src.latest_text().breakdown - ) - for tag in tc_src.tag.all(): tc_dest.add_tag(tag=tag) else: diff --git a/tcms/testplans/models.py b/tcms/testplans/models.py index c03e888c3d..4664acf79c 100644 --- a/tcms/testplans/models.py +++ b/tcms/testplans/models.py @@ -213,7 +213,8 @@ def clone(self, new_name=None, product=None, version=None, category=tc_category, priority=tpcase_src.priority, author=author, - default_tester=default_tester) + default_tester=default_tester, + text=tpcase_src.text) # Add case to plan. tp_dest.add_case(tpcase_dest, tcp.sortkey) @@ -231,16 +232,6 @@ def clone(self, new_name=None, product=None, version=None, description=component.description) tpcase_dest.add_component(new_c) - - text = tpcase_src.latest_text() - - if text: - tpcase_dest.add_text(author=text.author, - action=text.action, - effect=text.effect, - setup=text.setup, - breakdown=text.breakdown, - create_date=text.create_date) else: for tpcase_src in tpcases_src: tcp = get_object_or_404(TestCasePlan, plan=self, case=tpcase_src) diff --git a/tcms/testplans/tests/tests.py b/tcms/testplans/tests/tests.py index 5cccd0d741..8075fabdf6 100644 --- a/tcms/testplans/tests/tests.py +++ b/tcms/testplans/tests/tests.py @@ -17,7 +17,7 @@ from tcms.tests.factories import ClassificationFactory from tcms.tests.factories import ProductFactory -from tcms.tests.factories import TestCaseFactory, TestCaseTextFactory +from tcms.tests.factories import TestCaseFactory from tcms.tests.factories import TestPlanFactory from tcms.tests.factories import PlanTypeFactory from tcms.tests.factories import UserFactory @@ -49,14 +49,12 @@ def setUpTestData(cls): type=cls.plan_type) # add TestCases to plan with status CONFIRMED for _i in range(5): - case = TestCaseFactory(plan=[cls.test_plan], - case_status=TestCaseStatus.objects.get(name='CONFIRMED')) - TestCaseTextFactory(case=case) + TestCaseFactory(plan=[cls.test_plan], + case_status=TestCaseStatus.objects.get(name='CONFIRMED')) # also add a few PROPOSED TestCases for _i in range(3): - case = TestCaseFactory(plan=[cls.test_plan]) - TestCaseTextFactory(case=case) + TestCaseFactory(plan=[cls.test_plan]) cls.plan_id = cls.test_plan.pk cls.child_plan = TestPlanFactory(parent=cls.test_plan) @@ -103,11 +101,7 @@ def test_plan_printable(self): confirmed = TestCaseStatus.objects.get(name='CONFIRMED') for case in self.test_plan.case.filter(case_status=confirmed): self.assertContains(response, case.summary) - # factory sets all 4 - self.assertContains(response, case.latest_text().setup) - self.assertContains(response, case.latest_text().action) - self.assertContains(response, case.latest_text().effect) - self.assertContains(response, case.latest_text().breakdown) + self.assertContains(response, case.text) def test_plan_attachment(self): location = reverse('plan-attachment', diff --git a/tcms/testruns/forms.py b/tcms/testruns/forms.py index 4503eafd85..3b9f8d75cf 100644 --- a/tcms/testruns/forms.py +++ b/tcms/testruns/forms.py @@ -170,9 +170,7 @@ def clean_assignee(self): def clean_case_text_version(self): data = self.cleaned_data.get('case_text_version') if not data and self.cleaned_data.get('case'): - tc_ltxt = self.cleaned_data['case'].latest_text() - if tc_ltxt: - data = tc_ltxt.case_text_version + data = self.cleaned_data['case'].history.latest().history_id return data diff --git a/tcms/testruns/models.py b/tcms/testruns/models.py index 77cc74cdf2..530466acd4 100755 --- a/tcms/testruns/models.py +++ b/tcms/testruns/models.py @@ -12,7 +12,7 @@ from tcms.core.models import TCMSActionModel from tcms.core.history import KiwiHistoricalRecords from tcms.core.contrib.linkreference.models import LinkReference -from tcms.testcases.models import Bug, TestCaseText, NoneText +from tcms.testcases.models import Bug from tcms.xmlrpc.serializer import TestCaseRunXMLRPCSerializer from tcms.xmlrpc.serializer import TestRunXMLRPCSerializer from tcms.xmlrpc.utils import distinct_filter @@ -99,8 +99,7 @@ def add_case_run(self, case, status=1, assignee=None, sortkey=0): _case_text_version = case_text_version if not _case_text_version: - _case_text_version = case.latest_text( - text_required=False).case_text_version + _case_text_version = case.history.latest().history_id _assignee = assignee \ or (case.default_tester_id and case.default_tester) \ @@ -338,36 +337,6 @@ def get_bugs(self): def get_bugs_count(self): return self.get_bugs().count() - def get_text_versions(self): - return TestCaseText.objects.filter( - case__pk=self.case.pk - ).values_list('case_text_version', flat=True) - - def get_text_with_version(self, case_text_version=None): - if case_text_version: - try: - return TestCaseText.objects.get( - case__case_id=self.case_id, - case_text_version=case_text_version - ) - except TestCaseText.DoesNotExist: - return NoneText - try: - return TestCaseText.objects.get( - case__case_id=self.case_id, - case_text_version=self.case_text_version - ) - except TestCaseText.DoesNotExist: - return NoneText - - def latest_text(self): - try: - return TestCaseText.objects.filter( - case__case_id=self.case_id - ).order_by('-case_text_version')[0] - except IndexError: - return NoneText - def _get_absolute_url(self): # NOTE: this returns the URL to the TestRun containing this TestCaseRun! return reverse('testruns-get', args=[self.run_id]) diff --git a/tcms/testruns/tests/test_views.py b/tcms/testruns/tests/test_views.py index 74272b62f2..7aebe4068d 100644 --- a/tcms/testruns/tests/test_views.py +++ b/tcms/testruns/tests/test_views.py @@ -166,7 +166,7 @@ def test_create_a_new_run(self): self.assertEqual(self.tester, case_run.assignee) self.assertEqual(TestCaseRunStatus.objects.get(name='IDLE'), case_run.status) - self.assertEqual(0, case_run.case_text_version) + self.assertEqual(case.history.latest().history_id, case_run.case_text_version) self.assertEqual(new_run.build, case_run.build) self.assertEqual(None, case_run.close_date) @@ -474,30 +474,27 @@ class TestUpdateCaseRunText(BaseCaseRun): @classmethod def setUpTestData(cls): - super(TestUpdateCaseRunText, cls).setUpTestData() + super().setUpTestData() cls.update_url = reverse('testruns-update_case_run_text', args=[cls.test_run.pk]) # To increase case text version - cls.case_run_1.case.add_text(action='action', - effect='effect', - setup='setup', - breakdown='breakdown') - cls.case_run_1.case.add_text(action='action_1', - effect='effect_1', - setup='setup_1', - breakdown='breakdown_1') + cls.case_run_1.case.text = "Scenario Version 1" + cls.case_run_1.case.save() + + cls.case_run_1.case.text = "Scenario Version 2" + cls.case_run_1.case.save() def test_update_selected_case_runs(self): + self.assertNotEqual(self.case_run_1.case.history.latest().history_id, + self.case_run_1.case_text_version) response = self.client.post(self.update_url, {'case_run': [self.case_run_1.pk]}, follow=True) self.assertContains(response, '1 CaseRun(s) updated:') - - self.assertEqual(self.case_run_1.case.latest_text_version(), - self.case_run_1.latest_text().case_text_version) + self.assertEqual(self.case_run_1.case.text, "Scenario Version 2") class TestEditRun(BaseCaseRun): diff --git a/tcms/testruns/views.py b/tcms/testruns/views.py index cb99ab8415..a5c92629df 100755 --- a/tcms/testruns/views.py +++ b/tcms/testruns/views.py @@ -699,13 +699,13 @@ def update_case_run_text(request, run_id): count = 0 updated_test_case_runs = '' for test_case_run in test_case_runs: - latest_text = test_case_run.latest_text().case_text_version - if test_case_run.case_text_version != latest_text: + latest_version = test_case_run.case.history.latest().history_id + if test_case_run.case_text_version != latest_version: count += 1 updated_test_case_runs += '

  • %s: %s -> %s
  • ' % ( - test_case_run.case.summary, test_case_run.case_text_version, latest_text + test_case_run.case.summary, test_case_run.case_text_version, latest_version ) - test_case_run.case_text_version = latest_text + test_case_run.case_text_version = latest_version test_case_run.save() info = "

    %s

      %s
    " % (_("%d CaseRun(s) updated:") % count, updated_test_case_runs) diff --git a/tcms/tests/__init__.py b/tcms/tests/__init__.py index 82ec29533e..4135e432dc 100644 --- a/tcms/tests/__init__.py +++ b/tcms/tests/__init__.py @@ -126,24 +126,31 @@ def setUpTestData(cls): reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case.save() # will generate history object + cls.case_1 = TestCaseFactory( author=cls.tester, default_tester=None, reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_1.save() # will generate history object + cls.case_2 = TestCaseFactory( author=cls.tester, default_tester=None, reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_2.save() # will generate history object + cls.case_3 = TestCaseFactory( author=cls.tester, default_tester=None, reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_3.save() # will generate history object cls.case_4 = TestCaseFactory( author=cls.tester, @@ -151,18 +158,23 @@ def setUpTestData(cls): reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_4.save() # will generate history object + cls.case_5 = TestCaseFactory( author=cls.tester, default_tester=None, reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_5.save() # will generate history object + cls.case_6 = TestCaseFactory( author=cls.tester, default_tester=None, reviewer=cls.tester, case_status=cls.case_status_confirmed, plan=[cls.plan]) + cls.case_6.save() # will generate history object class BaseCaseRun(BasePlanCase): diff --git a/tcms/tests/factories.py b/tcms/tests/factories.py index e9128a92e9..7a8dce04ff 100644 --- a/tcms/tests/factories.py +++ b/tcms/tests/factories.py @@ -183,6 +183,7 @@ class Meta: author = factory.SubFactory(UserFactory) default_tester = factory.SubFactory(UserFactory) reviewer = factory.SubFactory(UserFactory) + text = factory.Sequence(lambda n: 'Given-When-Then %d' % n) @factory.post_generation def plan(self, create, extracted, **kwargs): @@ -237,20 +238,6 @@ class Meta: tag = factory.SubFactory(TagFactory) -class TestCaseTextFactory(DjangoModelFactory): - - class Meta: - model = 'testcases.TestCaseText' - - case = factory.SubFactory(TestCaseFactory) - case_text_version = 1 - author = factory.SubFactory(UserFactory) - action = 'action' - effect = 'effect' - setup = 'setup' - breakdown = 'breakdown' - - class TestCaseEmailSettingsFactory(DjangoModelFactory): class Meta: @@ -298,7 +285,7 @@ class Meta: assignee = factory.SubFactory(UserFactory) tested_by = factory.SubFactory(UserFactory) - case_text_version = 1 + case_text_version = factory.LazyAttribute(lambda obj: obj.case.history.latest().history_id) close_date = None sortkey = factory.Sequence(lambda n: n) run = factory.SubFactory(TestRunFactory) diff --git a/tcms/utils/dict_utils.py b/tcms/utils/dict_utils.py deleted file mode 100644 index 83c0d72bde..0000000000 --- a/tcms/utils/dict_utils.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - - -def create_dict_from_query(query, key_field, skip_others=False): - """ - Group values based on a particular field. - - @param query: Django values() query, ordered by key_field - or any other iterator that returns dicts - @param key_field: field name by which to grup - @param skip_others: if given the result will contain only the - first record matching key_field. This is useful when - we want to filter only the latest varsions of some - records. - - @return: dict where keys are key_field values and - values are a list of the query records. - """ - result_dict = {} - for record in query: - key_value = record[key_field] - - if key_value in result_dict: - if not skip_others: - result_dict[key_value].append(record) - else: - result_dict[key_value] = [record] - - return result_dict diff --git a/tcms/xmlrpc/api/testcase.py b/tcms/xmlrpc/api/testcase.py index 6f954d736c..e73a0b6985 100644 --- a/tcms/xmlrpc/api/testcase.py +++ b/tcms/xmlrpc/api/testcase.py @@ -269,20 +269,11 @@ def create(values, **kwargs): if form.is_valid(): # Create the case test_case = TestCase.create(author=request.user, values=form.cleaned_data) - - # Add case text to the case - test_case.add_text( - action=form.cleaned_data['action'] or '', - effect=form.cleaned_data['effect'] or '', - setup=form.cleaned_data['setup'] or '', - breakdown=form.cleaned_data['breakdown'] or '', - ) else: # Print the errors if the form is not passed validation. raise ValueError(form_errors_to_list(form)) result = test_case.serialize() - result['text'] = test_case.latest_text().serialize() return result @@ -298,14 +289,11 @@ def filter(query): # pylint: disable=redefined-builtin :param query: Field lookups for :class:`tcms.testcases.models.TestCase` :type query: dict :return: Serialized list of :class:`tcms.testcases.models.TestCase` objects. - The key ``text`` holds a the latest version of a serialized - :class:`tcms.testcases.models.TestCaseText` object! :rtype: list(dict) """ results = [] for case in TestCase.objects.filter(**query).distinct(): serialized_case = case.serialize() - serialized_case['text'] = case.latest_text().serialize() results.append(serialized_case) return results @@ -322,9 +310,6 @@ def update(case_id, values, **kwargs): :param case_id: PK of TestCase to be modified :type case_id: int :param values: Field values for :class:`tcms.testcases.models.TestCase`. - The special keys ``setup``, ``breakdown``, ``action`` and - ``effect`` are recognized and will cause update of the underlying - :class:`tcms.testcases.models.TestCaseText` object! :type values: dict :return: Serialized :class:`tcms.testcases.models.TestCase` object :rtype: dict @@ -347,23 +332,6 @@ def update(case_id, values, **kwargs): if key not in ['component', 'tag'] and hasattr(test_case, key): setattr(test_case, key, form.cleaned_data[key]) test_case.save() - - # if we're updating the text if any one of these parameters was - # specified - if any(x in ['setup', 'action', 'effect', 'breakdown'] for x in values.keys()): - action = form.cleaned_data.get('action', '').strip() - effect = form.cleaned_data.get('effect', '').strip() - setup = form.cleaned_data.get('setup', '').strip() - breakdown = form.cleaned_data.get('breakdown', '').strip() - author = kwargs.get(REQUEST_KEY).user - - test_case.add_text( - author=author, - action=action, - effect=effect, - setup=setup, - breakdown=breakdown, - ) else: raise ValueError(form_errors_to_list(form)) diff --git a/tcms/xmlrpc/serializer.py b/tcms/xmlrpc/serializer.py index 307b32cb41..01a2590a90 100644 --- a/tcms/xmlrpc/serializer.py +++ b/tcms/xmlrpc/serializer.py @@ -473,6 +473,7 @@ class TestCaseXMLRPCSerializer(QuerySetBasedXMLRPCSerializer): 'extra_link': ('extra_link', do_nothing), 'is_automated': ('is_automated', do_nothing), 'notes': ('notes', do_nothing), + 'text': ('text', do_nothing), 'requirement': ('requirement', do_nothing), 'script': ('script', do_nothing), 'summary': ('summary', do_nothing), diff --git a/tcms/xmlrpc/tests/test_testcase.py b/tcms/xmlrpc/tests/test_testcase.py index 8a3c787c2d..1ca88abe37 100644 --- a/tcms/xmlrpc/tests/test_testcase.py +++ b/tcms/xmlrpc/tests/test_testcase.py @@ -78,37 +78,24 @@ class TestUpdate(XmlrpcAPIBaseTest): def _fixture_setup(self): super(TestUpdate, self)._fixture_setup() - self.testcase = TestCaseFactory() + self.testcase = TestCaseFactory(text='') def test_update_text_and_product(self): - case_text = self.testcase.latest_text() - self.assertEqual('', case_text.setup) - self.assertEqual('', case_text.breakdown) - self.assertEqual('', case_text.action) - self.assertEqual('', case_text.effect) - self.assertNotEqual(self.api_user, case_text.author) + self.assertEqual('', self.testcase.text) # update the test case updated = self.rpc_client.exec.TestCase.update( # pylint: disable=objects-update-used self.testcase.pk, { 'summary': 'This was updated', - 'setup': 'new', - 'breakdown': 'new', - 'action': 'new', - 'effect': 'new', + 'text': 'new TC text', } ) self.testcase.refresh_from_db() # refresh before assertions self.assertEqual(updated['case_id'], self.testcase.pk) self.assertEqual('This was updated', self.testcase.summary) - case_text = self.testcase.latest_text() # grab text again - self.assertEqual('new', case_text.setup) - self.assertEqual('new', case_text.breakdown) - self.assertEqual('new', case_text.action) - self.assertEqual('new', case_text.effect) - self.assertEqual(self.api_user, case_text.author) + self.assertEqual('new TC text', self.testcase.text) class TestAddTag(XmlrpcAPIBaseTest): diff --git a/tcms/xmlrpc/tests/test_testrun.py b/tcms/xmlrpc/tests/test_testrun.py index 8d18fdb501..22340c92d2 100644 --- a/tcms/xmlrpc/tests/test_testrun.py +++ b/tcms/xmlrpc/tests/test_testrun.py @@ -27,6 +27,7 @@ def _fixture_setup(self): self.plan = TestPlanFactory(author=self.api_user) self.test_case = TestCaseFactory() + self.test_case.save() # generate history object self.plan.add_case(self.test_case) self.test_run = TestRunFactory(plan=self.plan)