Imlement result searching based on pattern
Related-prod: PRODX-30060
Change-Id: I4495db03a23c4edadfcf938a598ec84376c73ff9
diff --git a/testrail_bot/control/celery_tasks/test_rail_api.py b/testrail_bot/control/celery_tasks/test_rail_api.py
index 5bb0647..7a27ac9 100644
--- a/testrail_bot/control/celery_tasks/test_rail_api.py
+++ b/testrail_bot/control/celery_tasks/test_rail_api.py
@@ -19,6 +19,17 @@
else:
return None
+def get_suite_by_id(suite_id):
+ return api.suites.get_suite(suite_id)
+
+
+def get_suite_name_by_id(suite_id):
+ return api.suites.get_suite(suite_id)['name']
+
+def get_suite_test_type(suite_id):
+ suite_name = get_suite_name_by_id(suite_id)
+ return suite_name.split(']')[1]
+
def get_plans(project_id, plan_name, **kwargs):
plans = api.plans.get_plans(project_id, **kwargs)['plans']
@@ -29,9 +40,11 @@
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(
lambda x: x["name"] == run_name,
diff --git a/testrail_bot/control/celery_tasks/testrail_pipeline.py b/testrail_bot/control/celery_tasks/testrail_pipeline.py
index f102bac..829e054 100644
--- a/testrail_bot/control/celery_tasks/testrail_pipeline.py
+++ b/testrail_bot/control/celery_tasks/testrail_pipeline.py
@@ -29,29 +29,52 @@
data = locals()["custom_filter"](data)
return data
-def process_plan(plan_id, case_id, last_comment, bot_run):
+def get_runs_by_pattern(runs_in_plan, test_pattern, suite_id):
+ run = []
+ for t_run in runs_in_plan:
+ if test_pattern in t_run['name'] and t_run['suite_id'] == suite_id:
+ run.append( t_run['runs'][0]['id'])
+ return run
+def process_plan(plan_id, case_id, last_comment, bot_run):
+ """
+ This function performs a search for a similar failure within a test plan.
+
+ :param plan_id: id of test plan
+ :param case_id: id of test case for failed test
+ :param last_comment: last trace for failed test
+ :param bot_run: number of result reports from tab 'Reports'
+ """
+ runs = []
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)
+ test_pattern = bot_run.test_pattern
+ if test_pattern:
+ runs = get_runs_by_pattern(runs_in_plan, test_pattern, suite_id)
+ else:
+ runs = [t_run['runs'][0]['id'] for t_run in runs_in_plan if suite_id == t_run['suite_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
+ run_id = 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"], 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
+ for run_id in runs:
+ results = test_rail_api.get_result_for_case(run_id, case_id)
+ if not results:
+ return None, -2.0, run_id
+
+ status_code = str(results[0]["status_id"])
+ if status_code not in [StatusEnum.test_failed, StatusEnum.product_failed]:
+ return None, -3.0, run_id
+ 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, run_id
+ return None, ratio, run_id
def get_project_id(f, test_run, report):
@@ -76,18 +99,6 @@
return test_rail_api.get_plans(project_id, test_run.plan_name, **kw)
-def get_last_run_id(f, last_plan, test_run, report):
- last_run_id = test_rail_api.get_run_id(
- test_rail_api.get_entries(last_plan), test_run.run_name)
- if not last_run_id:
- f.write("No {} in {} plan\n".format(
- test_run.run_name, last_plan))
- f.flush()
- finish_report(report)
- return None
- return last_run_id
-
-
def get_last_comment(case_id, test_run):
last_result = test_rail_api.get_result_for_case(
test_run.run_id, case_id)
@@ -96,7 +107,7 @@
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(
+ sim_result, ratio, run_id = process_plan(
plan_id, case_id, last_comment, test_run)
if sim_result:
if str(sim_result["status_id"]) == StatusEnum.retest:
@@ -136,8 +147,9 @@
f.flush()
return True
f.write(
- "Similarity not found due to similarity:{}%\n".format(
- round(100.0 * ratio, 2)))
+ "Similarity not found due to similarity:{per}, in run <a href=https://mirantis.testrail.com/"
+ "index.php?/runs/view/{run_id}>{run_id} </a>\n".format(
+ per=round(100.0 * ratio, 2), run_id=run_id))
f.flush()
return False
@@ -167,6 +179,17 @@
def process_test_run(bot_run_id, report_id, path, run_date):
+ """
+ This function processes a created bot test run. It retrieves a list
+ of test plans to process, gathers the failed tests from the test run,
+ and passes them for processing using the 'process_test' function.
+ All the failed tests are processed
+
+ :param bot_run_id: number of result reports from tab 'Reports'
+ :param report_id: number of run from tab 'Test Run'
+ :param path: path to report results
+ :param run_date: date until which to retrieve test plans
+ """
report = models.TestRailReport.objects.get(pk=report_id)
with open(path, "w") as f:
bot_test_run = models.TestRailTestRun.objects.get(pk=bot_run_id)
@@ -181,6 +204,8 @@
return
plans = get_plans(bot_test_run, run_date, project_id)
+
+ # failed_tests: all failed tests in test run
failed_tests = test_rail_api.get_failed_tests(bot_test_run.run_id)
for test in failed_tests:
process_test(f, test, bot_test_run, plans)
diff --git a/testrail_bot/control/forms.py b/testrail_bot/control/forms.py
index cc516ac..51d4fb2 100644
--- a/testrail_bot/control/forms.py
+++ b/testrail_bot/control/forms.py
@@ -15,6 +15,7 @@
"project_name": "Name of the project",
"plan_name": "Name of the Test Plan without date",
"run_name": "Name of the run",
+ "test_pattern": "Test run pattern",
"run_id": "ID of the run",
"created_by_id": "ID of the user that created Test Run",
"filter_func": "Custom filter function",
diff --git a/testrail_bot/control/migrations/0020_auto_20231009_1423.py b/testrail_bot/control/migrations/0020_auto_20231009_1423.py
new file mode 100644
index 0000000..e2dc295
--- /dev/null
+++ b/testrail_bot/control/migrations/0020_auto_20231009_1423.py
@@ -0,0 +1,53 @@
+# Generated by Django 3.0.7 on 2023-10-09 14:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('control', '0019_testrailtestrun_timestamp_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='testrailtestrun',
+ name='test_pattern',
+ field=models.CharField(blank=True, max_length=300),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='created_by_id',
+ field=models.IntegerField(default='109'),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='ip_filter',
+ field=models.BooleanField(default=True),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='plan_name',
+ field=models.CharField(default='[MCP2.0]OSCORE', max_length=300),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='project_name',
+ field=models.CharField(default='Mirantis Cloud Platform', max_length=300),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='run_id',
+ field=models.CharField(max_length=300),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='run_name',
+ field=models.CharField(blank=True, max_length=300),
+ ),
+ migrations.AlterField(
+ model_name='testrailtestrun',
+ name='uuid_filter',
+ field=models.BooleanField(default=True),
+ ),
+ ]
diff --git a/testrail_bot/control/models.py b/testrail_bot/control/models.py
index 915fc0b..f4c846f 100644
--- a/testrail_bot/control/models.py
+++ b/testrail_bot/control/models.py
@@ -9,6 +9,7 @@
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)
+ test_pattern = 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)
diff --git a/testrail_bot/control/templates/control/create_run.html b/testrail_bot/control/templates/control/create_run.html
index 07c7b0a..136b7c1 100644
--- a/testrail_bot/control/templates/control/create_run.html
+++ b/testrail_bot/control/templates/control/create_run.html
@@ -11,6 +11,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.test_pattern 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">
diff --git a/testrail_bot/control/templates/control/update_run.html b/testrail_bot/control/templates/control/update_run.html
index c70ab0c..8ccd94e 100644
--- a/testrail_bot/control/templates/control/update_run.html
+++ b/testrail_bot/control/templates/control/update_run.html
@@ -11,6 +11,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.test_pattern 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">
diff --git a/testrail_bot/control/views.py b/testrail_bot/control/views.py
index bc052a1..db624a6 100644
--- a/testrail_bot/control/views.py
+++ b/testrail_bot/control/views.py
@@ -65,10 +65,13 @@
def submit_run(request, run_id):
run = models.TestRailTestRun.objects.get(pk=run_id)
testrail_run = test_rail_api.get_run_by_id(run.run_id)
+ run_name = ''
if not run.run_name:
- run.run_name = testrail_run['name']
+ run_name += testrail_run['name']
+ if run.test_pattern:
+ run_name += "-" + run.test_pattern
report_name = "{}-run_id-{}-date-{}".format(
- run.run_name, run.run_id, datetime.datetime.isoformat(datetime.datetime.now()))
+ 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