Imlement result searching based on type tests and by test run id
Related-prod: PRODX-29347, PRODX-30060
Change-Id: I2eaa6f1e5600b7b343056f68836f8e0c8c7e64e6
diff --git a/testrail_bot/control/celery_tasks/tasks.py b/testrail_bot/control/celery_tasks/tasks.py
index 9e68718..ddca36a 100644
--- a/testrail_bot/control/celery_tasks/tasks.py
+++ b/testrail_bot/control/celery_tasks/tasks.py
@@ -8,8 +8,8 @@
@shared_task
-def process_run(run_id, report_id, path, run_date):
- testrail_pipeline.process_test_run(run_id, report_id, path, run_date)
+def process_run(bot_run_id, report_id, path, run_date):
+ testrail_pipeline.process_test_run(bot_run_id, report_id, path, run_date)
@shared_task
diff --git a/testrail_bot/control/celery_tasks/test_rail_api.py b/testrail_bot/control/celery_tasks/test_rail_api.py
index 883261b..5bb0647 100644
--- a/testrail_bot/control/celery_tasks/test_rail_api.py
+++ b/testrail_bot/control/celery_tasks/test_rail_api.py
@@ -29,6 +29,8 @@
def get_entries(plan_id):
return api.plans.get_plan(plan_id)["entries"]
+def get_run_by_id(run_id):
+ return api.runs.get_run(run_id)
def get_run_id(entries, run_name):
entries = list(filter(
diff --git a/testrail_bot/control/celery_tasks/testrail_pipeline.py b/testrail_bot/control/celery_tasks/testrail_pipeline.py
index 04ee22f..f102bac 100644
--- a/testrail_bot/control/celery_tasks/testrail_pipeline.py
+++ b/testrail_bot/control/celery_tasks/testrail_pipeline.py
@@ -29,28 +29,28 @@
data = locals()["custom_filter"](data)
return data
+def process_plan(plan_id, case_id, last_comment, bot_run):
-def process_plan(plan_id, case_id, last_comment, run):
- run_id = test_rail_api.get_run_id(test_rail_api.get_entries(plan_id), run.run_name)
- if not run_id:
- return None, -1.0
+ testrail_run = test_rail_api.get_run_by_id(bot_run.run_id)
+ suite_id = testrail_run['suite_id']
+ runs_in_plan = test_rail_api.get_entries(plan_id)
+ results = []
+ ratio = -1.0
+ for t_run in runs_in_plan:
+ if suite_id == t_run['suite_id']:
+ results = test_rail_api.get_result_for_case(t_run['runs'][0]['id'], case_id)
+ if not results:
+ return None, -2.0
- results = test_rail_api.get_result_for_case(run_id, case_id)
-
- if not results:
- return None, -2.0
-
- status_code = str(results[0]["status_id"])
- if status_code not in [StatusEnum.test_failed, StatusEnum.product_failed]:
- return None, -3.0
-
- comment = apply_filters(results[-1]["comment"], run)
-
- ratio = difflib.SequenceMatcher(
- lambda symbol: symbol in [" ", ",", "\n"],
- last_comment, comment, autojunk=False).ratio()
- if ratio > 0.9:
- return results[0], ratio
+ status_code = str(results[0]["status_id"])
+ if status_code not in [StatusEnum.test_failed, StatusEnum.product_failed]:
+ return None, -3.0
+ comment = apply_filters(results[-1]["comment"], bot_run)
+ ratio = difflib.SequenceMatcher(
+ lambda symbol: symbol in [" ", ",", "\n"],
+ last_comment, comment, autojunk=False).ratio()
+ if ratio > 0.7:
+ return results[0], ratio
return None, ratio
@@ -66,6 +66,9 @@
def get_plans(test_run, run_date, project_id):
+ """
+ Get plans which will be processed
+ """
created_by_id = test_run.created_by_id
kw = {"limit": 100, "created_before": int(run_date)}
if created_by_id:
@@ -85,45 +88,70 @@
return last_run_id
-def get_last_comment(last_run_id, case_id, test_run):
+def get_last_comment(case_id, test_run):
last_result = test_rail_api.get_result_for_case(
- last_run_id, case_id)
+ test_run.run_id, case_id)
return apply_filters(
last_result[0]["comment"], test_run)
-
def process_old_test(f, plan_id, case_id, last_comment, test_run, test):
sim_result, ratio = process_plan(
plan_id, case_id, last_comment, test_run)
if sim_result:
- update_dict = {
- "status_id": sim_result["status_id"],
- "comment": "Marked by TestRailBot because "
- "of similarity with test {} {}%".format(
- sim_result["test_id"], round(100.0 * ratio, 2)),
- "defects": sim_result["defects"]
- }
- f.write("Found similarity: {}\n".format(update_dict))
- f.flush()
- test_rail_api.add_result(test["id"], update_dict)
- return True
- else:
- f.write(
- "Similarity not found due to similarity:{}%\n".format(
- round(100.0 * ratio, 2)))
- f.flush()
- return False
+ if str(sim_result["status_id"]) == StatusEnum.retest:
+ update_dict = {
+ "status_id": sim_result["status_id"],
+ "comment": "NOT marked by TestRailBot because it's not a regular fail, "
+ "similarity with test {} {}%, you can update manualy".format(
+ sim_result["test_id"], round(100.0 * ratio, 2))
+ }
+ f.write("Found similarity trace on the test <a href=https://mirantis.testrail.com/"
+ "index.php?/tests/view/{test_id}>{test_id} </a> : \n {dict}\n"
+ .format(test_id=sim_result["test_id"], dict=update_dict))
+ f.flush()
+ return True
+ elif ratio > 0.9:
+ update_dict = {
+ "status_id": sim_result["status_id"],
+ "comment": "Marked by TestRailBot because "
+ "of similarity with test {} {}%".format(
+ sim_result["test_id"], round(100.0 * ratio, 2)),
+ "defects": sim_result["defects"]
+ }
+ f.write("Found similarity defect <a href=https://mirantis.jira.com/browse/"
+ "{defect}>{defect}</a> on the test <a href=https://mirantis.testrail.com/"
+ "index.php?/tests/view/{test_id}>{test_id} </a> : \n {dict}\n"
+ .format(defect=sim_result["defects"],test_id=sim_result["test_id"], dict=update_dict))
+ f.flush()
+ test_rail_api.add_result(test["id"], update_dict)
+ return True
+ elif ratio > 0.7:
+ f.write("<b style='color:red;'> Found similarity defect <a href=https://mirantis.jira.com/browse/"
+ "{defect}>{defect}</a> on the test <a href=https://mirantis.testrail.com/"
+ "index.php?/tests/view/{test_id}>{test_id} </a>, "
+ "but NOT marked by TestRailBot because of similarity only"
+ " {per}%, you can update manually \n </b>"
+ .format(defect=sim_result["defects"],test_id=sim_result["test_id"], per=round(100.0 * ratio, 2)))
+ f.flush()
+ return True
+ f.write(
+ "Similarity not found due to similarity:{}%\n".format(
+ round(100.0 * ratio, 2)))
+ f.flush()
+ return False
-def process_test(f, test, last_run_id, test_run, plans):
+def process_test(f, test, test_run, plans):
case_id = test["case_id"]
- f.write("Processing test with id {}\n".format(test["id"]))
+ f.write("<b> Processing test <a href=https://mirantis.testrail.com/"
+ "index.php?/tests/view/{test_id}>{test_id}"
+ "</a></b> \n".format(test_id=test["id"]))
f.flush()
- last_comment = get_last_comment(last_run_id, case_id, test_run)
+ last_comment = get_last_comment(case_id, test_run)
for plan_id in plans[1:]:
found = process_old_test(
@@ -131,34 +159,31 @@
if found:
break
else:
- f.write("Automatic test processing failed. Please process "
+ f.write("<b style='color:red;'> Automatic test processing failed. Please process "
"test manualy <a href=https://mirantis.testrail.com/"
"index.php?/tests/view/{test_id}>{test_id}"
- "</a>\n".format(test_id=test["id"]))
+ "</a></b>\n".format(test_id=test["id"]))
f.flush()
-def process_test_run(run_id, report_id, path, run_date):
+def process_test_run(bot_run_id, report_id, path, run_date):
report = models.TestRailReport.objects.get(pk=report_id)
with open(path, "w") as f:
- test_run = models.TestRailTestRun.objects.get(pk=run_id)
- f.write("Start processing {}\n".format(test_run.run_name))
+ bot_test_run = models.TestRailTestRun.objects.get(pk=bot_run_id)
+ test_run = test_rail_api.get_run_by_id(bot_test_run.run_id)
+ f.write("Start processing <a href=https://mirantis.testrail.com/"
+ "index.php?/runs/view/{id}>{name}"
+ "</a>\n".format(id=test_run['id'], name=test_run['name']))
f.flush()
- project_id = get_project_id(f, test_run, report)
+ project_id = get_project_id(f, bot_test_run, report)
if not project_id:
return
- plans = get_plans(test_run, run_date, project_id)
-
- last_plan = plans[0]
- last_run_id = get_last_run_id(f, last_plan, test_run, report)
- if not last_run_id:
- return
-
- failed_tests = test_rail_api.get_failed_tests(last_run_id)
+ plans = get_plans(bot_test_run, run_date, project_id)
+ failed_tests = test_rail_api.get_failed_tests(bot_test_run.run_id)
for test in failed_tests:
- process_test(f, test, last_run_id, test_run, plans)
+ process_test(f, test, bot_test_run, plans)
f.write("Test processing finished")
f.flush()
finish_report(report)
diff --git a/testrail_bot/control/forms.py b/testrail_bot/control/forms.py
index 00567e2..e8280a4 100644
--- a/testrail_bot/control/forms.py
+++ b/testrail_bot/control/forms.py
@@ -11,6 +11,7 @@
"project_name": "Name of the project",
"plan_name": "Name of the Test Plan without date",
"run_name": "Name of the run",
+ "run_id": "ID of the run",
"created_by_id": "If of the user that created Test Run",
"filter_func": "Custom filter function",
"ip_filter": "Change ip to x.x.x.x",
diff --git a/testrail_bot/control/migrations/0018_testrailtestrun_run_id.py b/testrail_bot/control/migrations/0018_testrailtestrun_run_id.py
new file mode 100644
index 0000000..53bedfe
--- /dev/null
+++ b/testrail_bot/control/migrations/0018_testrailtestrun_run_id.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.7 on 2023-01-17 14:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('control', '0017_auto_20200925_1255'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='testrailtestrun',
+ name='run_id',
+ field=models.CharField(blank=True, max_length=300),
+ ),
+ ]
diff --git a/testrail_bot/control/models.py b/testrail_bot/control/models.py
index 7068d38..41e46a0 100644
--- a/testrail_bot/control/models.py
+++ b/testrail_bot/control/models.py
@@ -3,13 +3,14 @@
class TestRailTestRun(models.Model):
- project_name = models.CharField(max_length=300)
- plan_name = models.CharField(max_length=300)
- run_name = models.CharField(max_length=300)
- created_by_id = models.IntegerField()
+ project_name = models.CharField(max_length=300, default="Mirantis Cloud Platform")
+ plan_name = models.CharField(max_length=300, default="[MCP2.0]OSCORE")
+ run_name = models.CharField(max_length=300, blank=True)
+ run_id = models.CharField(max_length=300)
+ created_by_id = models.IntegerField(default='109')
filter_func = models.TextField(null=True, blank=True)
- ip_filter = models.BooleanField(default=False)
- uuid_filter = models.BooleanField(default=False)
+ ip_filter = models.BooleanField(default=True)
+ uuid_filter = models.BooleanField(default=True)
filter_last_traceback = models.BooleanField(default=False)
diff --git a/testrail_bot/control/templates/control/create_run.html b/testrail_bot/control/templates/control/create_run.html
index 61eec45..5b72402 100644
--- a/testrail_bot/control/templates/control/create_run.html
+++ b/testrail_bot/control/templates/control/create_run.html
@@ -8,6 +8,7 @@
<div class="col-xs-8">{% bootstrap_field form.project_name size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.plan_name size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.run_name size='sm' %}</div>
+ <div class="col-xs-8">{% bootstrap_field form.run_id size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.created_by_id size='sm' %}</div>
<div class="col-xs-8">
User to id list: <ul><li>os-qa-bot = <code>109</code></li></ul>
diff --git a/testrail_bot/control/templates/control/help.html b/testrail_bot/control/templates/control/help.html
index 6c63b78..c7124ff 100644
--- a/testrail_bot/control/templates/control/help.html
+++ b/testrail_bot/control/templates/control/help.html
@@ -12,10 +12,11 @@
<li>
Fill input forms:
<ol>
- <li>Enter Project name i.e. <code>Mirantis Cloud Platform</code></li>
- <li>Enter Plan name without date i.e. <code>[MCP2.0]OSCORE</code></li>
- <li>Enter full name of the run i.e. <code>ussuri-core-ceph-ceph-dvr <[MCP2.0_USSURI]Tempest></code></li>
- <li>Fill created_by_id column i.e. <code>109</code></li>
+ <li>Enter Project name or use default <code>Mirantis Cloud Platform</code></li>
+ <li>Enter Plan name without date or use default <code>[MCP2.0]OSCORE</code></li>
+ <li>Enter full name of the run (not required field)<code>ussuri-core-ceph-ceph-dvr <[MCP2.0_USSURI]Tempest></code></li>
+ <li>Enter ID of the run, for example(without letters) <code> 129304 </code></li>
+ <li>Fill created_by_id column or use default <code>109</code></li>
<li>(Optional) Enter custom filtration function.
If not used it should be empty. If used, the function definition should be like:
<pre>
diff --git a/testrail_bot/control/templates/control/index.html b/testrail_bot/control/templates/control/index.html
index f4d8e50..e1382a6 100644
--- a/testrail_bot/control/templates/control/index.html
+++ b/testrail_bot/control/templates/control/index.html
@@ -4,7 +4,7 @@
<div class="list-group">
{% for run in runs %}
<a href="{% url 'single_run' run.id %}" class="list-group-item list-group-item-success">
- Run <b>{{run.run_name}}</b> from <b>{{run.plan_name}}</b> plan in <b>{{run.project_name}}</b> project
+ Run <b>{{run.run_id}}</b> from <b>{{run.plan_name}}</b> plan in <b>{{run.project_name}}</b> project
</a>
{% endfor %}
</div>
diff --git a/testrail_bot/control/templates/control/update_run.html b/testrail_bot/control/templates/control/update_run.html
index 91c953e..3efd2f5 100644
--- a/testrail_bot/control/templates/control/update_run.html
+++ b/testrail_bot/control/templates/control/update_run.html
@@ -8,6 +8,7 @@
<div class="col-xs-8">{% bootstrap_field form.project_name size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.plan_name size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.run_name size='sm' %}</div>
+ <div class="col-xs-8">{% bootstrap_field form.run_id size='sm' %}</div>
<div class="col-xs-8">{% bootstrap_field form.created_by_id size='sm' %}</div>
<div class="col-xs-8">
User to id list: <ul><li>os-qa-bot = <code>109</code></li></ul>
diff --git a/testrail_bot/control/views.py b/testrail_bot/control/views.py
index 67a368d..9077a7c 100644
--- a/testrail_bot/control/views.py
+++ b/testrail_bot/control/views.py
@@ -1,6 +1,7 @@
import datetime
import json
import os
+from .celery_tasks import test_rail_api
from django.shortcuts import render, redirect, HttpResponse
@@ -62,8 +63,11 @@
def submit_run(request, run_id):
run = models.TestRailTestRun.objects.get(pk=run_id)
- report_name = "{}-{}".format(
- run.run_name, datetime.datetime.isoformat(datetime.datetime.now()))
+ testrail_run = test_rail_api.get_run_by_id(run.run_id)
+ if not run.run_name:
+ run.run_name = testrail_run['name']
+ report_name = "{}-run_id-{}-date-{}".format(
+ run.run_name, run.run_id, datetime.datetime.isoformat(datetime.datetime.now()))
path = os.path.join(models.fs.location, report_name)
with open(path, "w"):
pass
diff --git a/testrail_bot/media/images/control/help_1.png b/testrail_bot/media/images/control/help_1.png
index c6ad4f1..d165c60 100644
--- a/testrail_bot/media/images/control/help_1.png
+++ b/testrail_bot/media/images/control/help_1.png
Binary files differ
diff --git a/testrail_bot/media/images/control/help_2.png b/testrail_bot/media/images/control/help_2.png
index c29c3bb..ebc2dbb 100644
--- a/testrail_bot/media/images/control/help_2.png
+++ b/testrail_bot/media/images/control/help_2.png
Binary files differ
diff --git a/testrail_bot/media/images/control/help_3.png b/testrail_bot/media/images/control/help_3.png
index 1a1124f..e9014d4 100644
--- a/testrail_bot/media/images/control/help_3.png
+++ b/testrail_bot/media/images/control/help_3.png
Binary files differ