#!/usr/bin/env python3
# Copyright (C) 2026 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""" Runs the perfetto Java SDK test suite on a host JVM.

Companion to tools/run_android_test (which runs the same test under ART on a
device or emulator). Uses the JDK pointed to by $JAVA_HOME, the Maven jars
landed by `tools/install-build-deps --java-sdk`, and the host stubs in
src/android_sdk/java/host_stubs/ to compile the perfetto Java SDK and the
PerfettoTraceTest suite for host. Links against the libperfetto_jni.so the
gn+ninja pipeline produces and runs the JUnit suite.

Prerequisites
-------------
  $JAVA_HOME points at a JDK >= 11 install root.
  tools/install-build-deps              # standard C++ toolchain
  tools/install-build-deps --java-sdk   # Maven jars (opt-in)
"""

import logging
import os
import subprocess
import sys

ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
JAVA_DEPS_DIR = os.path.join(ROOT_DIR, 'buildtools/java_sdk')
SDK_DIR = os.path.join(ROOT_DIR, 'src/android_sdk/java')
OUT_DIR = os.path.join(ROOT_DIR, 'out/android_sdk_host_test')

JAVA_PROTOS_TARGET = 'src/android_sdk/java/test:perfetto_test_java_protos'
JAVA_PROTOS_DIR = 'gen/src/android_sdk/java/test'

TEST_CLASS = 'dev.perfetto.sdk.test.PerfettoTraceTest'


def Die(msg):
  logging.error(msg)
  sys.exit(1)


def Run(cmd, **kwargs):
  logging.debug('+ %s', ' '.join(cmd))
  return subprocess.run(cmd, check=True, **kwargs)


def JdkHome():
  jh = os.environ.get('JAVA_HOME')
  if not jh:
    Die('JAVA_HOME not set. Install a JDK >= 11 and set JAVA_HOME.')
  if not os.path.exists(os.path.join(jh, 'include/jni.h')):
    Die('JAVA_HOME=%s does not look like a JDK install (no include/jni.h).' %
        jh)
  return jh


def Glob(root, suffix):
  for dirpath, _, files in os.walk(root):
    for f in files:
      if f.endswith(suffix):
        yield os.path.join(dirpath, f)


def MavenJars():
  jars = sorted(Glob(JAVA_DEPS_DIR, '.jar'))
  if not jars:
    Die('No jars in %s. Run `tools/install-build-deps --java-sdk`.' %
        JAVA_DEPS_DIR)
  return jars


def Classpath(*entries):
  return os.pathsep.join(entries)


def Gn(jdk_home):
  os.makedirs(OUT_DIR, exist_ok=True)
  Run([
      os.path.join(ROOT_DIR, 'tools/gn'), 'gen', OUT_DIR, '--args=' + ' '.join([
          'is_debug=false',
          'enable_perfetto_android_java_sdk=true',
          'jdk_include_path="%s"' % os.path.join(jdk_home, 'include'),
      ])
  ])


def Ninja():
  Run([
      os.path.join(ROOT_DIR, 'tools/ninja'),
      '-C',
      OUT_DIR,
      'libperfetto_jni',
      JAVA_PROTOS_TARGET,
  ])


def Javac(jdk_home, classes_dir, classpath, srcs):
  Run([
      os.path.join(jdk_home, 'bin/javac'), '-d', classes_dir, '-cp', classpath,
      '-source', '11', '-target', '11'
  ] + srcs)


def Jar(jdk_home, jar_path, classes_dir):
  Run([
      os.path.join(jdk_home, 'bin/jar'), 'cf', jar_path, '-C', classes_dir, '.'
  ])


def CompileSdk(jdk_home, jars, java_proto_dir):
  classes = os.path.join(OUT_DIR, 'sdk_classes')
  os.makedirs(classes, exist_ok=True)
  srcs = (
      list(Glob(os.path.join(SDK_DIR, 'main'), '.java')) +
      list(Glob(os.path.join(SDK_DIR, 'host_stubs'), '.java')) +
      list(Glob(java_proto_dir, '.java')))
  Javac(jdk_home, classes, Classpath(*jars), srcs)
  jar = os.path.join(OUT_DIR, 'perfetto_sdk_host.jar')
  Jar(jdk_home, jar, classes)
  return jar


def CompileTest(jdk_home, jars, sdk_jar):
  classes = os.path.join(OUT_DIR, 'test_classes')
  os.makedirs(classes, exist_ok=True)
  srcs = list(Glob(os.path.join(SDK_DIR, 'test'), '.java'))
  Javac(jdk_home, classes, Classpath(sdk_jar, *jars), srcs)
  jar = os.path.join(OUT_DIR, 'perfetto_sdk_host_test.jar')
  Jar(jdk_home, jar, classes)
  return jar


def RunTests(jdk_home, jars, sdk_jar, test_jar):
  env = dict(os.environ, LD_LIBRARY_PATH=OUT_DIR)
  Run([
      os.path.join(jdk_home,
                   'bin/java'), '-Djava.library.path=' + OUT_DIR, '-cp',
      Classpath(sdk_jar, test_jar, *jars), 'org.junit.runner.JUnitCore',
      TEST_CLASS
  ],
      env=env)


def main():
  logging.basicConfig(level=logging.INFO, format='%(message)s')
  jdk_home = JdkHome()
  jars = MavenJars()
  Gn(jdk_home)
  Ninja()
  java_protos = os.path.join(OUT_DIR, JAVA_PROTOS_DIR)
  sdk_jar = CompileSdk(jdk_home, jars, java_protos)
  test_jar = CompileTest(jdk_home, jars, sdk_jar)
  RunTests(jdk_home, jars, sdk_jar, test_jar)


if __name__ == '__main__':
  main()
