From d01077577d4b5e4101d7e1707df77fe08c9507be Mon Sep 17 00:00:00 2001
From: Lukas Holecek <hluk@email.cz>
Date: Mar 25 2021 14:23:11 +0000
Subject: Cache passing results in ResultsDB consumer


---

diff --git a/greenwave/resources.py b/greenwave/resources.py
index 89d4fad..646af8e 100644
--- a/greenwave/resources.py
+++ b/greenwave/resources.py
@@ -69,12 +69,12 @@ class ResultsRetriever(BaseRetriever):
 
         # Try to get passing test case result from external cache.
         external_cache_key = None
-        if testcase and not self.since:
+        if testcase:
             external_cache_key = (
                 "greenwave.resources:ResultsRetriever|"
                 f"{subject.type} {subject.identifier} {testcase} {scenarios}")
             results = self.get_external_cache(external_cache_key)
-            if results:
+            if results and self._results_match_time(results):
                 return results
 
         params = {
@@ -110,6 +110,13 @@ class ResultsRetriever(BaseRetriever):
             params=params,
             **request_args)
 
+    def _results_match_time(self, results):
+        if not self.since:
+            return True
+
+        until = self.since.split(',')[1]
+        return all(result['submit_time'] < until for result in results)
+
     def get_external_cache(self, key):
         return current_app.cache.get(key)
 
diff --git a/greenwave/tests/test_policies.py b/greenwave/tests/test_policies.py
index e354c30..fd9ac1d 100644
--- a/greenwave/tests/test_policies.py
+++ b/greenwave/tests/test_policies.py
@@ -27,6 +27,7 @@ from greenwave.safe_yaml import SafeYAMLError
 from greenwave.subjects.factory import create_subject
 from greenwave.waivers import waive_answers
 from greenwave.config import TestingConfig, Config
+from greenwave.utils import add_to_timestamp
 
 
 @pytest.fixture(autouse=True)
@@ -37,10 +38,10 @@ def app():
 
 
 class DummyResultsRetriever(ResultsRetriever):
-    def __init__(self, subject=None, testcase=None, outcome='PASSED'):
+    def __init__(self, subject=None, testcase=None, outcome='PASSED', when=''):
         super(DummyResultsRetriever, self).__init__(
             ignore_ids=[],
-            when='',
+            when=when,
             url='')
         self.subject = subject
         self.testcase = testcase
@@ -62,6 +63,7 @@ class DummyResultsRetriever(ResultsRetriever):
                 },
                 'testcase': {'name': self.testcase},
                 'outcome': self.outcome,
+                'submit_time': '2021-03-25T07:26:56.191741',
             }]
         return []
 
@@ -1539,3 +1541,19 @@ def test_cache_passing_results():
     cached = results3.retrieve(subject, testcase='sometest')
     assert results3.retrieve_data_called == 0
     assert cached == retrieved2
+
+    # Match submit_time with "since" parameter.
+    when1 = retrieved2[0]['submit_time']
+    when2 = add_to_timestamp(when1, microseconds=1)
+
+    results3 = DummyResultsRetriever(subject, 'sometest', 'FAILED', when=when1)
+    results3.external_cache = results.external_cache
+    not_cached = results3.retrieve(subject, testcase='sometest')
+    assert results3.retrieve_data_called == 1
+    assert not_cached == retrieved
+
+    results4 = DummyResultsRetriever(subject, 'sometest', 'FAILED', when=when2)
+    results4.external_cache = results.external_cache
+    cached = results4.retrieve(subject, testcase='sometest')
+    assert results4.retrieve_data_called == 0
+    assert cached == retrieved2
diff --git a/greenwave/utils.py b/greenwave/utils.py
index ab48e6e..d09fec9 100644
--- a/greenwave/utils.py
+++ b/greenwave/utils.py
@@ -131,7 +131,7 @@ def sha1_mangle_key(key):
     return hashlib.sha1(key.encode('utf-8')).hexdigest()
 
 
-def right_before_this_time(timestamp):
+def add_to_timestamp(timestamp, **kwargs):
     """
     A utility function that takes a timestamp with format %Y-%m-%dT%H:%M:%S.%f
     and returns the microsecond before that timestamp. It returns always a
@@ -139,6 +139,8 @@ def right_before_this_time(timestamp):
     ask for a decision before a specific timestamp (example: the creation of a
     result).
     """
+    delta = datetime.timedelta(**kwargs)
+
     date_format = '%Y-%m-%dT%H:%M:%S.%f'
 
     if timestamp.endswith(' UTC'):
@@ -148,8 +150,12 @@ def right_before_this_time(timestamp):
         from_date_format = date_format
 
     return datetime.datetime.strftime(
-        datetime.datetime.strptime(timestamp, from_date_format) -
-        datetime.timedelta(microseconds=1), date_format)
+        datetime.datetime.strptime(timestamp, from_date_format) + delta,
+        date_format)
+
+
+def right_before_this_time(timestamp):
+    return add_to_timestamp(timestamp, microseconds=-1)
 
 
 def remove_duplicates(func):

