#!/usr/bin/env python3

# Copyright (C) 2020 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.

import os
import unittest
from xml.etree import ElementTree
import subprocess
import sys

VERBOSE = True
TEST_CONFIG = os.path.join(os.path.dirname(__file__), "test_igt_gpu_tools.xml")

""" Extracts tests from AndroidTest.xml compatible file
    param: xmlfile str containing path to AndroidTest.xml compatible xml file
"""
def extract_tests_from_xml(xmlfile):
    tree = ElementTree.parse(xmlfile)
    root = tree.getroot()
    return [(o.attrib['key'], o.attrib['value'])
            for o in root.findall("./target_preparer/option")
            if o.attrib['name'] == "push-file"]

def run_command(command):
    serial_number = os.environ.get("ANDROID_SERIAL", "")
    if not serial_number:
        raise "$ANDROID_SERIAL is empty, device must be specified"
    full_command = ["adb", "-s", serial_number, "shell"] + command
    if VERBOSE:
        print("+" + " ".join(full_command))
    ret = subprocess.run(full_command, capture_output=True, universal_newlines=True)
    if VERBOSE:
        print(ret.stdout)
    return ret.stdout

class IGTGpuToolsBinary():
    """Harness object for a specific IGT GPU test binary. """

    """ param: ondevice_test_path The IGT binary path on device """
    def __init__(self, ondevice_test_path):
        self._path = ondevice_test_path
        subtests = run_command([self._path, "--list-subtests"])
        self._subtests = list(filter(lambda x: x != "", subtests.split("\n")))

    """lists subtests detected in tests.
       return: list of strings indicating subtests found in binary.
    """
    def subtests(self):
        return self._subtests;

    """Runs a subtest.

        param: subtest_name One of the subtests listed by self.subtest()
        return: a subprocess.CompletedProcess
    """
    def run_subtest(self, subtest_name):
        if subtest_name not in self._subtests:
            error
        return run_command([self._path, "--run-subtest", subtest_name])

class IGTGpuToolsTest(unittest.TestCase):
    """Tests for DRM/KMS using Intel Graphics Tests suite"""

    """ param: subtest A valid subtest for the binary
        param: the IGT binary to run as a unit test.
    """
    def __init__(self, subtest, binary):
        self._subtest_name = subtest
        self._test_binary = binary
        setattr(self, self._subtest_name, self.runTest)
        super(IGTGpuToolsTest, self).__init__(methodName=self._subtest_name)

    """ Runs the test set in the constructor """
    def runTest(self):
        output = self._test_binary.run_subtest(self._subtest_name)
        for line in output.split("\n"):
            if "Subtest" not in line:
                continue;
            if "SKIP" in line:
                self.skipTest("{} - skipped".format(self._subtest_name))
                break
            if "SUCCESS" in line:
                break
            if "FAIL" in line:
                self.fail(output)
                break
            self.fail("could not parse test output; test runner failure")

ANDROID_RUNNER_REQUIRED_VERBOSITY = 2

def main():
    """main entrypoint for test runner"""

    runner = unittest.TextTestRunner(stream=sys.stderr, verbosity=ANDROID_RUNNER_REQUIRED_VERBOSITY)
    suite = unittest.TestSuite()
    for test, test_path in extract_tests_from_xml(TEST_CONFIG):
        print("Found IGT-GPU-tools test {}".format(test))
        subsuite = unittest.TestSuite()
        binary = IGTGpuToolsBinary(test_path)
        for subtest in binary.subtests():
            print("\tFound subtest {}".format(subtest))
            subsuite.addTest(IGTGpuToolsTest(subtest, binary))
        suite.addTest(subsuite)
    runner.run(suite)

if __name__=="__main__":
    main()