tflite: add stable delegate acceleration test config file helper

This is a script mainly to help partners to generate the initial
accel_test.conf file during the bringup stage.

Additionally, this can provide us an easier way to know what tests
are supported/unsupported by a delegate.

BUG=b:332423167
TEST=run `./stable_delegate_accel_test_conf.py --stable_delegate_settings_file=sample_settings.json` on DUT

Change-Id: Ied7be511ec44bdd7e7564aa1fb719123540b60d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tflite/+/5414933
Auto-Submit: Tommy Chiang <ototot@google.com>
Reviewed-by: Shik Chen <shik@chromium.org>
Tested-by: Tommy Chiang <ototot@google.com>
Commit-Queue: Tommy Chiang <ototot@google.com>
diff --git a/script/stable_delegate_accel_test_conf.py b/script/stable_delegate_accel_test_conf.py
new file mode 100755
index 0000000..4de69d4
--- /dev/null
+++ b/script/stable_delegate_accel_test_conf.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A script to generate accel_test.conf for stable_delegate_test_suite."""
+
+import argparse
+import json
+import logging
+from pathlib import Path
+import subprocess
+import sys
+import tempfile
+from typing import List, Optional, TextIO
+
+
+def generate_accel_test_conf(
+    stable_delegate_test_suite: Path,
+    stable_delegate_settings_file: Path,
+    output_file: TextIO,
+    list_passed_tests: bool,
+):
+    assert stable_delegate_test_suite.is_file()
+    assert stable_delegate_settings_file.is_file()
+
+    with tempfile.NamedTemporaryFile() as result_json:
+        stable_delegate_test_suite_cmd = [
+            str(stable_delegate_test_suite.absolute()),
+            "--stable_delegate_settings_file=%s"
+            % (stable_delegate_settings_file.absolute(),),
+            "--gtest_output=json:%s" % (result_json.name,),
+        ]
+        logging.debug("Running: %s", " ".join(stable_delegate_test_suite_cmd))
+        # Skip checking the return code since we expect test failures
+        # due to unsupported ops of the delegate.
+        # pylint: disable-next=subprocess-run-check
+        subprocess.run(
+            stable_delegate_test_suite_cmd,
+            stdout=subprocess.DEVNULL,
+            stderr=subprocess.DEVNULL,
+        )
+        logging.debug("Finished running stable_delegate_test_suite")
+
+        result = json.load(result_json)
+        logging.debug("Parsing %s", result)
+
+        output_file.write(
+            "# Auto-generated by stable_delegate_accel_test_conf.py\n\n"
+        )
+        for testsuite in result["testsuites"]:
+            for test in testsuite["testsuite"]:
+                if "failures" in test:
+                    output_file.write(
+                        "-%s/%s\n" % (testsuite["name"], test["name"])
+                    )
+                elif list_passed_tests:
+                    output_file.write(
+                        "%s/%s\n" % (testsuite["name"], test["name"])
+                    )
+        if not list_passed_tests:
+            output_file.write(".*\n")
+
+    logging.debug("Finished generating accel_test_conf")
+
+
+def setup_argument_parser() -> argparse.ArgumentParser:
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter
+    )
+    parser.add_argument(
+        "--stable_delegate_settings_file",
+        required=True,
+        type=Path,
+        help="The path to the delegate settings JSON file.",
+    )
+    parser.add_argument(
+        "--output",
+        default="accel_test.conf",
+        type=argparse.FileType("w"),
+        help="output path for generated acceleration test config",
+    )
+    parser.add_argument(
+        "--stable_delegate_test_suite",
+        default="/usr/local/bin/stable_delegate_test_suite",
+        type=Path,
+        help="path to the stable_delegate_test_suite binary",
+    )
+    parser.add_argument(
+        "--list_passed_tests",
+        action="store_true",
+        help="list passed tests in the output config file",
+    )
+    parser.add_argument(
+        "--debug",
+        action="store_true",
+        help="enable debug logging",
+    )
+    return parser
+
+
+def main(argv: Optional[List[str]] = None) -> Optional[int]:
+    parser = setup_argument_parser()
+    args = parser.parse_args(argv)
+
+    log_level = logging.DEBUG if args.debug else logging.INFO
+    log_format = "%(asctime)s - %(levelname)s - %(funcName)s: %(message)s"
+    logging.basicConfig(level=log_level, format=log_format)
+
+    generate_accel_test_conf(
+        args.stable_delegate_test_suite,
+        args.stable_delegate_settings_file,
+        args.output,
+        args.list_passed_tests,
+    )
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))