Fix for caching of nonexisted test results for case
Add timeout option for some TestRail commands
Fix python warnings

PRODX-38927

Change-Id: I1e85889318a1d19e4346b1aaf63a1cfcd6fb11be
diff --git a/testrail_bot/control/celery_tasks/test_rail_api.py b/testrail_bot/control/celery_tasks/test_rail_api.py
index c441d37..cc3bfdb 100644
--- a/testrail_bot/control/celery_tasks/test_rail_api.py
+++ b/testrail_bot/control/celery_tasks/test_rail_api.py
@@ -26,7 +26,7 @@
         return None
 
 
-@cached()
+@cached(timeout=24*60*60)
 def get_suite_by_id(suite_id: int) -> dict:
     return api.suites.get_suite(suite_id)
 
@@ -42,13 +42,13 @@
     return suite_name.split(']')[1]
 
 
-@cached()
+@cached(timeout=24*60*60)
 def get_plans(project_id: int, **kwargs) -> List[dict]:
     plans = api.plans.get_plans(project_id=project_id, **kwargs)['plans']
     return plans
 
 
-@cached()
+@cached(timeout=1*60*60)
 def get_entries(plan_id: int) -> List[dict]:
     return api.plans.get_plan(plan_id)["entries"]
 
@@ -57,7 +57,7 @@
     return api.runs.get_run(run_id)
 
 
-@lru_cache
+@cached()
 def get_run_name(run_id: int) -> str:
     return get_run_by_id(run_id)["name"]
 
@@ -115,7 +115,8 @@
     return entries[0]["runs"][0]["id"]
 
 
-@cached()
+@cached(timeout=2*60*60,
+        condition_for_endless_cache=lambda x: x is None)
 @retry(ReadTimeout, delay=1, jitter=2, tries=3)
 def get_result_for_case(run_id: int,
                         case_id: int,
diff --git a/testrail_bot/control/utils.py b/testrail_bot/control/utils.py
index 6c7738a..2038aba 100644
--- a/testrail_bot/control/utils.py
+++ b/testrail_bot/control/utils.py
@@ -1,8 +1,6 @@
 from parse import parse
 from typing import Dict, List, Callable, Any
-from functools import wraps
 from django.core.cache import cache
-import difflib
 
 
 def parse_title(test_name):
@@ -63,18 +61,33 @@
     return r
 
 
-def cached(timeout: int = None) -> Callable:
+def cached(timeout: int = None,
+           condition_for_endless_cache: Callable = lambda x: False
+           ) -> Callable:
+    """
+    :param timeout: (in seconds) usage accordingly
+    https://docs.djangoproject.com/en/4.2/topics/cache/#basic-usage
+    :param condition_for_endless_cache: Callable should return boolean.
+    Checks a result of function. If Result meets requirements of condition
+    then the endless timeout will be set. Or it will use provided timeout
+    otherwise
+
+    :return: decorator
+    """
     def decorator(func: Callable) -> Callable:
         def wrapper(*args, **kwargs) -> Any:
             cache_key = f'{func.__name__}_{args}_{kwargs}'
             cache_key = replace_all(cache_key, "{}()\'\" .,:", "_")
-            result = cache.get(cache_key)
-            if result is None:
+            cached_value = cache.get(cache_key)
+            if cached_value is None:
                 print(f"{func.__name__} MISS")
                 result = func(*args, **kwargs)
-                cache.set(cache_key, result, timeout=timeout)
-                return result
+                _timeout = None \
+                    if condition_for_endless_cache(result) \
+                    else timeout
 
+                cache.set(cache_key, result, timeout=_timeout)
+                return result
             print(f"{func.__name__} hit")
 
             # # FIXME Assert to test the caching mechanism
@@ -85,7 +98,7 @@
             # assert result == _result
             # # ENDFIXME
 
-            return result
+            return cached_value
         return wrapper
     return decorator