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