Home | History | Annotate | Download | only in camera_its
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2016 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 #
     17 
     18 import inspect
     19 import logging
     20 import os
     21 import re
     22 import subprocess
     23 import sys
     24 
     25 from vts.runners.host import asserts
     26 from vts.runners.host import base_test
     27 from vts.runners.host import const
     28 from vts.runners.host import test_runner
     29 
     30 
     31 class CameraITSTest(base_test.BaseTestClass):
     32     """Running CameraITS tests in VTS.
     33 
     34     Attributes:
     35         _TABLET_TYPES: a list of strings, known tablet product types.
     36         dut1: AndroidDevice instance, for 1st device whose front-facing camera
     37               is tested.
     38         dut2: AndroidDevice instance, for 2nd device whose back-facing camera
     39               is tested.
     40         display_device: AndroidDevice instance, for a tablet device used as
     41                         a display screen.
     42     """
     43     _TABLET_TYPES = ["dragon"]
     44 
     45     # TODO: use config file to pass in:
     46     #          - serial for dut and screen
     47     #          - camera id
     48     #       so that we can run other test scenes with ITS-in-a-box
     49     def setUpClass(self):
     50         """Setup ITS running python environment and check for required python modules
     51         """
     52         # When VTS lab infra is used, the provided device order is:
     53         #   DUT (front-facing camera),
     54         #   DUT (back-facing camera),
     55         #   Tablet (display).
     56         # This order shall be preserved when a custom test serving infra is
     57         # used.
     58         self.dut1 = self.android_devices[0]
     59         self.dut2 = self.android_devices[1]
     60         self.display_device = self.android_devices[2]
     61         # In a local run (e.g., using a VTS test harness), the device order
     62         # can be arbitrary. So tablet is detected and chosen as a display
     63         # device. Similarly, we need a mechanism to detect DUT which uses
     64         # front-facing camera (that can be done here or inside another layer).
     65 
     66         if self.dut1.product_type in self._TABLET_TYPES:
     67             temp_device = self.dut1
     68             self.dut1 = self.dut2
     69             self.dut2 = self.dut3
     70             self.display_device = temp_device
     71         elif self.dut2.product_type in self._TABLET_TYPES:
     72             temp_device = self.dut2
     73             self.dut2 = self.display_device
     74             self.display_device = temp_device
     75 
     76         self.device_arg = "device=%s" % self.dut1.serial
     77         self.display_device_arg = "chart=%s" % self.display_device.serial
     78         self.its_path = str(
     79             os.path.abspath(os.path.join(self.data_file_path, 'CameraITS')))
     80         logging.info("cwd: %s", os.getcwd())
     81         logging.info("its_path: %s", self.its_path)
     82         self.out_path = logging.log_path
     83         os.environ["CAMERA_ITS_TOP"] = self.its_path
     84         # Below module check code assumes tradefed is running python 2.7
     85         # If tradefed switches to python3, then we will be checking modules in python3 while ITS
     86         # scripts should be ran in 2.7.
     87         if sys.version_info[:2] != (2, 7):
     88             logging.warning("Python version %s found; "
     89                             "CameraITSTest only tested with Python 2.7." %
     90                             (str(sys.version_info[:3])))
     91         logging.info("===============================")
     92         logging.info("Python path is: %s" % (sys.executable))
     93         logging.info("PYTHONPATH env is: " + os.environ["PYTHONPATH"])
     94         import PIL
     95         if hasattr(PIL, "__version__"):
     96             logging.info("PIL version is %s", PIL.__version__)
     97         logging.info("PIL path is " + inspect.getfile(PIL))
     98         from PIL import Image
     99         logging.info("Image path is " + inspect.getfile(Image))
    100         import numpy
    101         logging.info("numpy version is " + numpy.__version__)
    102         logging.info("numpy path is " + inspect.getfile(numpy))
    103         import scipy
    104         logging.info("scipy version is " + scipy.__version__)
    105         logging.info("scipy path is " + inspect.getfile(scipy))
    106         import matplotlib
    107         logging.info("matplotlib version is " + matplotlib.__version__)
    108         logging.info("matplotlib path is " + inspect.getfile(matplotlib))
    109         from matplotlib import pylab
    110         logging.info("pylab path is " + inspect.getfile(pylab))
    111         logging.info("===============================")
    112         modules = [
    113             "numpy", "PIL", "Image", "matplotlib", "pylab", "scipy.stats",
    114             "scipy.spatial"
    115         ]
    116         for m in modules:
    117             try:
    118                 if m == "Image":
    119                     # Image modules are now imported from PIL
    120                     exec ("from PIL import Image")
    121                 elif m == "pylab":
    122                     exec ("from matplotlib import pylab")
    123                 else:
    124                     exec ("import " + m)
    125             except ImportError as e:
    126                 asserts.fail("Cannot import python module %s: %s" % (m,
    127                                                                      str(e)))
    128 
    129         # Add ITS module path to path
    130         its_path = os.path.join(self.its_path, "pymodules")
    131         env_python_path = os.environ["PYTHONPATH"]
    132         self.pythonpath = env_python_path if its_path in env_python_path else \
    133                 "%s:%s" % (its_path, env_python_path)
    134         os.environ["PYTHONPATH"] = self.pythonpath
    135         logging.info("new PYTHONPATH: %s", self.pythonpath)
    136 
    137     def RunTestcase(self, testpath):
    138         """Runs the given testcase and asserts the result.
    139 
    140         Args:
    141             testpath: string, format tests/[scenename]/[testname].py
    142         """
    143         testname = re.split("/|\.", testpath)[-2]
    144         cmd = [
    145             'python', os.path.join(self.its_path, testpath), self.device_arg,
    146             self.display_device_arg
    147         ]
    148         outdir = self.out_path
    149         outpath = os.path.join(outdir, testname + "_stdout.txt")
    150         errpath = os.path.join(outdir, testname + "_stderr.txt")
    151         logging.info("cwd: %s", os.getcwd())
    152         logging.info("cmd: %s", cmd)
    153         logging.info("outpath: %s", outpath)
    154         logging.info("errpath: %s", errpath)
    155         with open(outpath, "w") as fout, open(errpath, "w") as ferr:
    156             retcode = subprocess.call(
    157                 cmd, stderr=ferr, stdout=fout, cwd=outdir)
    158         if retcode != 0 and retcode != 101:
    159             # Dump all logs to host log if the test failed
    160             with open(outpath, "r") as fout, open(errpath, "r") as ferr:
    161                 logging.info(fout.read())
    162                 logging.error(ferr.read())
    163 
    164         asserts.assertTrue(retcode == 0 or retcode == 101,
    165                            "ITS %s retcode %d" % (testname, retcode))
    166 
    167     def FetchTestPaths(self, scene):
    168         """Returns a list of test paths for a given test scene.
    169 
    170         Args:
    171             scnee: one of ITS test scene name.
    172         """
    173         its_path = self.its_path
    174         paths = [
    175             os.path.join("tests", scene, s)
    176             for s in os.listdir(os.path.join(its_path, "tests", scene))
    177             if s[-3:] == ".py" and s[:4] == "test"
    178         ]
    179         paths.sort()
    180         return paths
    181 
    182     def generateAllTestCases(self):
    183         # Unused packages:
    184         # * No plan to support in the near future
    185         #   - "dng_noise_model"
    186         #   - "inprog"
    187         #   - "rolling_shutter_skew"
    188         # * Not for ITS box (but for diffuser plate)
    189         #   - "scene5"
    190         # * Not for ITS box (but for sensor_fusion rotation rig, high-end only)
    191         #   - "sensor_fusion"
    192         # * Add those scenes to the below list after scene swapping is ported:
    193         #     "scene1"
    194         #     "scene2"
    195         #     "scene3"
    196         #     "scene4"
    197         for test_package_name in ["scene0"]:
    198             testpaths = self.FetchTestPaths(test_package_name)
    199             self.runGeneratedTests(
    200                 test_func=self.RunTestcase,
    201                 settings=testpaths,
    202                 name_func=lambda path: "%s_%s" % (re.split("/|\.", path)[-3], re.split("/|\.", path)[-2]))
    203 
    204 
    205 if __name__ == "__main__":
    206     test_runner.main()
    207