One bugfix and some cosmetics.
authorScott Gasch <[email protected]>
Fri, 3 Jun 2022 03:09:09 +0000 (20:09 -0700)
committerScott Gasch <[email protected]>
Fri, 3 Jun 2022 03:09:09 +0000 (20:09 -0700)
tests/run_tests.py

index f1266e0962cfb44027c3c0cfa2a5a0a98354bf49..5162e238f1d37181b5dc9ea3988e1a443b3231c4 100755 (executable)
@@ -12,7 +12,7 @@ import threading
 import time
 from abc import ABC, abstractmethod
 from dataclasses import dataclass
-from typing import Any, Dict, List, Optional
+from typing import Any, Dict, List, Optional, Tuple
 
 from overrides import overrides
 
@@ -116,12 +116,17 @@ class TestRunner(ABC, thread_utils.ThreadWithReturnValue):
             tests_failed=[],
             tests_timed_out=[],
         )
+        self.tests_started = 0
 
     @abstractmethod
     def get_name(self) -> str:
         """The name of this test collection."""
         pass
 
+    def get_status(self) -> Tuple[int, TestResults]:
+        """Ask the TestRunner for its status."""
+        return (self.tests_started, self.test_results)
+
     @abstractmethod
     def begin(self, params: TestingParameters) -> TestResults:
         """Start execution."""
@@ -152,26 +157,6 @@ class TemplatedTestRunner(TestRunner, ABC):
                 logger.error('Thread %s saw abnormal results; exiting.', self.get_name())
                 raise Exception("Kill myself!")
 
-    def status_report(self, started: int, result: TestResults):
-        """Periodically called to report current status."""
-
-        finished = (
-            len(self.test_results.tests_succeeded)
-            + len(self.test_results.tests_failed)
-            + len(self.test_results.tests_timed_out)
-        )
-        running = started - finished
-        finished_percent = finished / started * 100.0
-        logging.info(
-            '%s: %d/%d in flight; %d/%d finished (%.1f%%).',
-            self.get_name(),
-            running,
-            started,
-            finished,
-            started,
-            finished_percent,
-        )
-
     def persist_output(self, test_name: str, message: str, output: str) -> None:
         """Called to save the output of a test run."""
 
@@ -218,7 +203,7 @@ class TemplatedTestRunner(TestRunner, ABC):
             msg = f'{self.get_name()}: {test_name} ({cmdline}) failed; exit code {e.returncode}'
             logger.error(msg)
             logger.debug('%s: %s output when it failed: %s', self.get_name(), test_name, e.output)
-            self.persist_output(test_name, msg, e.output.decide('utf-8'))
+            self.persist_output(test_name, msg, e.output.decode('utf-8'))
             return TestResults(
                 test_name,
                 [test_name],
@@ -235,12 +220,11 @@ class TemplatedTestRunner(TestRunner, ABC):
         running: List[Any] = []
         for test in interesting_tests:
             running.append(self.run_test(test))
-        started = len(running)
+        self.tests_started = len(running)
 
         for future in smart_future.wait_any(running):
             self.check_for_abort()
             result = future._resolve()
-            self.status_report(started, result)
             logger.debug('Test %s finished.', result.name)
             self.test_results += result
 
@@ -383,6 +367,10 @@ def main() -> Optional[int]:
 
     results: Dict[str, TestResults] = {}
     while len(results) != len(threads):
+        started = 0
+        done = 0
+        failed = 0
+
         for thread in threads:
             if not thread.is_alive():
                 tid = thread.name
@@ -395,7 +383,35 @@ def main() -> Optional[int]:
                                 'Thread %s returned abnormal results; killing the others.', tid
                             )
                             halt_event.set()
-        time.sleep(1.0)
+            else:
+                (s, tr) = thread.get_status()
+                started += s
+                failed += len(tr.tests_failed) + len(tr.tests_timed_out)
+                done += failed + len(tr.tests_succeeded)
+
+        if started > 0:
+            percent_done = done / started
+        else:
+            percent_done = 0.0
+
+        if failed == 0:
+            color = ansi.fg('green')
+        else:
+            color = ansi.fg('red')
+
+        if percent_done < 100.0:
+            print(
+                text_utils.bar_graph(
+                    percent_done,
+                    width=80,
+                    fgcolor=color,
+                ),
+                end='\r',
+                flush=True,
+            )
+        else:
+            print("Finished.\n")
+        time.sleep(0.5)
 
     if config.config['coverage']:
         code_coverage_report()