xref: /aosp_15_r20/external/OpenCL-CTS/scripts/test_opencl_cts.py (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1*6467f958SSadaf Ebrahimi#!/usr/bin/env python3
2*6467f958SSadaf Ebrahimi
3*6467f958SSadaf Ebrahimifrom typing import List, Optional, Tuple
4*6467f958SSadaf Ebrahimi
5*6467f958SSadaf Ebrahimiimport argparse
6*6467f958SSadaf Ebrahimiimport os
7*6467f958SSadaf Ebrahimiimport pipes
8*6467f958SSadaf Ebrahimiimport subprocess
9*6467f958SSadaf Ebrahimiimport sys
10*6467f958SSadaf Ebrahimiimport unittest
11*6467f958SSadaf Ebrahimi
12*6467f958SSadaf EbrahimiANDROID_RUNNER_REQUIRED_VERBOSITY = 2
13*6467f958SSadaf Ebrahimi
14*6467f958SSadaf Ebrahimi
15*6467f958SSadaf Ebrahimidef parse_args(args: Optional[List[str]] = None) -> argparse.Namespace:
16*6467f958SSadaf Ebrahimi  parser = argparse.ArgumentParser()
17*6467f958SSadaf Ebrahimi  parser.add_argument('test_name', type=str, help="Name of the test")
18*6467f958SSadaf Ebrahimi  parser.add_argument('binary_path', type=str,
19*6467f958SSadaf Ebrahimi                      help="Full path to the binary on device")
20*6467f958SSadaf Ebrahimi  parser.add_argument('--subtests', type=str, nargs='*',
21*6467f958SSadaf Ebrahimi                      help="Specific subtests to run")
22*6467f958SSadaf Ebrahimi  parser.add_argument('--test_args', type=str, nargs='*',
23*6467f958SSadaf Ebrahimi                      help="Unfiltered arguments to pass to the run command")
24*6467f958SSadaf Ebrahimi
25*6467f958SSadaf Ebrahimi  args = parser.parse_args(args)
26*6467f958SSadaf Ebrahimi  args.subtests = args.subtests or []
27*6467f958SSadaf Ebrahimi  args.test_args = args.test_args or []
28*6467f958SSadaf Ebrahimi
29*6467f958SSadaf Ebrahimi  return args
30*6467f958SSadaf Ebrahimi
31*6467f958SSadaf Ebrahimi
32*6467f958SSadaf Ebrahimidef run_command(command: str) -> Tuple[int, str, str]:
33*6467f958SSadaf Ebrahimi  serial_number = os.environ.get("ANDROID_SERIAL", "")
34*6467f958SSadaf Ebrahimi  if not serial_number:
35*6467f958SSadaf Ebrahimi    raise "$ANDROID_SERIAL is empty, device must be specified"
36*6467f958SSadaf Ebrahimi
37*6467f958SSadaf Ebrahimi  full_command = ["adb", "-s", serial_number, "shell", command]
38*6467f958SSadaf Ebrahimi  ret = subprocess.run(
39*6467f958SSadaf Ebrahimi      full_command, capture_output=True, universal_newlines=True)
40*6467f958SSadaf Ebrahimi  return ret.returncode, ret.stdout, ret.stderr
41*6467f958SSadaf Ebrahimi
42*6467f958SSadaf Ebrahimi
43*6467f958SSadaf Ebrahimidef get_all_subtests(binary_path: str) -> List[str]:
44*6467f958SSadaf Ebrahimi  retcode, output, _ = run_command(f'{binary_path} --help')
45*6467f958SSadaf Ebrahimi
46*6467f958SSadaf Ebrahimi  test_name_line = "Test names"
47*6467f958SSadaf Ebrahimi  index = output.find(test_name_line)
48*6467f958SSadaf Ebrahimi  if index == -1:
49*6467f958SSadaf Ebrahimi    return []
50*6467f958SSadaf Ebrahimi
51*6467f958SSadaf Ebrahimi  test_names_output = output[index:]
52*6467f958SSadaf Ebrahimi  test_names = []
53*6467f958SSadaf Ebrahimi  # Skip the first line which starts with "Test names"
54*6467f958SSadaf Ebrahimi  for test_name in test_names_output.splitlines()[1:]:
55*6467f958SSadaf Ebrahimi    if not test_name.startswith((" ", "\t")):
56*6467f958SSadaf Ebrahimi      break
57*6467f958SSadaf Ebrahimi    test_names.append(test_name.strip())
58*6467f958SSadaf Ebrahimi
59*6467f958SSadaf Ebrahimi  return test_names
60*6467f958SSadaf Ebrahimi
61*6467f958SSadaf Ebrahimi
62*6467f958SSadaf Ebrahimidef get_subtests(binary_path: str, subtests: List[str]) -> List[str]:
63*6467f958SSadaf Ebrahimi  all_subtests = set(get_all_subtests(binary_path))
64*6467f958SSadaf Ebrahimi  if not subtests:
65*6467f958SSadaf Ebrahimi    return all_subtests
66*6467f958SSadaf Ebrahimi
67*6467f958SSadaf Ebrahimi  subtests = set(subtests)
68*6467f958SSadaf Ebrahimi  selected_subtests = subtests & all_subtests
69*6467f958SSadaf Ebrahimi  remaining_subtests = subtests - all_subtests
70*6467f958SSadaf Ebrahimi
71*6467f958SSadaf Ebrahimi  if remaining_subtests:
72*6467f958SSadaf Ebrahimi    print("Could not find subtests: {}".format(', '.join(remaining_subtests)),
73*6467f958SSadaf Ebrahimi          file=sys.stderr)
74*6467f958SSadaf Ebrahimi
75*6467f958SSadaf Ebrahimi  return sorted(list(selected_subtests))
76*6467f958SSadaf Ebrahimi
77*6467f958SSadaf Ebrahimi
78*6467f958SSadaf Ebrahimiclass OpenCLTest(unittest.TestCase):
79*6467f958SSadaf Ebrahimi
80*6467f958SSadaf Ebrahimi  def __init__(self, test_name: str, binary_path: str, args: List[str]):
81*6467f958SSadaf Ebrahimi
82*6467f958SSadaf Ebrahimi    self._test_name = test_name
83*6467f958SSadaf Ebrahimi    self._binary_path = binary_path
84*6467f958SSadaf Ebrahimi    self._args = args
85*6467f958SSadaf Ebrahimi
86*6467f958SSadaf Ebrahimi    self.command = " ".join(
87*6467f958SSadaf Ebrahimi        [self._binary_path, self._test_name] +
88*6467f958SSadaf Ebrahimi        list(map(pipes.quote, self._args))
89*6467f958SSadaf Ebrahimi    )
90*6467f958SSadaf Ebrahimi
91*6467f958SSadaf Ebrahimi    self.test_func_name = self._test_name
92*6467f958SSadaf Ebrahimi    setattr(self, self.test_func_name, self.genericTest)
93*6467f958SSadaf Ebrahimi
94*6467f958SSadaf Ebrahimi    super().__init__(methodName=self.test_func_name)
95*6467f958SSadaf Ebrahimi
96*6467f958SSadaf Ebrahimi  def genericTest(self):
97*6467f958SSadaf Ebrahimi    retcode, output, oerror = run_command(self.command)
98*6467f958SSadaf Ebrahimi
99*6467f958SSadaf Ebrahimi    # TODO(layog): CTS currently return non-zero return code if the
100*6467f958SSadaf Ebrahimi    # implementation is missing for some API even if the API is not supported by
101*6467f958SSadaf Ebrahimi    # the version reported by the driver. Need to patch upstream.
102*6467f958SSadaf Ebrahimi    missing_line = f"ERROR: Test '{self._test_name}' is missing implementation"
103*6467f958SSadaf Ebrahimi    if missing_line in output or missing_line in oerror:
104*6467f958SSadaf Ebrahimi      self.skipTest(f"{self._test_name} API not available in the driver")
105*6467f958SSadaf Ebrahimi
106*6467f958SSadaf Ebrahimi    self.assertFalse(retcode, "Test exited with non-zero status")
107*6467f958SSadaf Ebrahimi
108*6467f958SSadaf Ebrahimi    # TODO(b/158646251): Update upstream to exit with proper error code
109*6467f958SSadaf Ebrahimi    passed_line = "PASSED test."
110*6467f958SSadaf Ebrahimi    self.assertTrue(passed_line in output)
111*6467f958SSadaf Ebrahimi
112*6467f958SSadaf Ebrahimi
113*6467f958SSadaf Ebrahimidef main():
114*6467f958SSadaf Ebrahimi  """main entrypoint for test runner"""
115*6467f958SSadaf Ebrahimi  args = parse_args(sys.argv[1:])
116*6467f958SSadaf Ebrahimi
117*6467f958SSadaf Ebrahimi  # HACK: Name hack to report the actual test name
118*6467f958SSadaf Ebrahimi  OpenCLTest.__name__ = args.test_name
119*6467f958SSadaf Ebrahimi  OpenCLTest.__qualname__ = args.test_name
120*6467f958SSadaf Ebrahimi
121*6467f958SSadaf Ebrahimi  suite = unittest.TestSuite()
122*6467f958SSadaf Ebrahimi  subtests = get_subtests(args.binary_path, args.subtests)
123*6467f958SSadaf Ebrahimi  for subtest in subtests:
124*6467f958SSadaf Ebrahimi    suite.addTest(OpenCLTest(subtest, args.binary_path, args.test_args))
125*6467f958SSadaf Ebrahimi
126*6467f958SSadaf Ebrahimi  runner = unittest.TextTestRunner(
127*6467f958SSadaf Ebrahimi      stream=sys.stderr, verbosity=ANDROID_RUNNER_REQUIRED_VERBOSITY)
128*6467f958SSadaf Ebrahimi  runner.run(suite)
129*6467f958SSadaf Ebrahimi
130*6467f958SSadaf Ebrahimi
131*6467f958SSadaf Ebrahimiif __name__ == "__main__":
132*6467f958SSadaf Ebrahimi  main()
133