1# Copyright 2014 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import os 16import os.path 17import tempfile 18import subprocess 19import time 20import sys 21import textwrap 22import its.device 23 24def main(): 25 """Run all the automated tests, saving intermediate files, and producing 26 a summary/report of the results. 27 28 Script should be run from the top-level CameraITS directory. 29 """ 30 31 SKIP_RET_CODE = 101 32 33 # Not yet mandated tests 34 NOT_YET_MANDATED = { 35 "scene0":[ 36 "test_jitter" 37 ], 38 "scene1":[ 39 "test_ae_precapture_trigger", 40 "test_crop_region_raw", 41 "test_ev_compensation_advanced", 42 "test_ev_compensation_basic", 43 "test_yuv_plus_jpeg" 44 ], 45 "scene2":[], 46 "scene3":[], 47 "scene4":[], 48 "scene5":[], 49 "sensor_fusion":[] 50 } 51 52 # Get all the scene0 and scene1 tests, which can be run using the same 53 # physical setup. 54 scenes = ["scene0", "scene1", "scene2", "scene3", "scene4", "scene5", 55 "sensor_fusion"] 56 57 scene_req = { 58 "scene0" : None, 59 "scene1" : "A grey card covering at least the middle 30% of the scene", 60 "scene2" : "A picture containing human faces", 61 "scene3" : "A chart containing sharp edges like ISO 12233", 62 "scene4" : "A specific test page of a circle covering at least the " 63 "middle 50% of the scene. See CameraITS.pdf section 2.3.4 " 64 "for more details", 65 "scene5" : "Capture images with a diffuser attached to the camera. See " 66 "CameraITS.pdf section 2.3.4 for more details", 67 "sensor_fusion" : "Rotating checkboard pattern. See " 68 "sensor_fusion/SensorFusion.pdf for detailed " 69 "instructions. Note that this test will be skipped " 70 "on devices not supporting REALTIME camera timestamp." 71 "If that is the case, no scene setup is required and " 72 "you can just answer Y when being asked if the scene " 73 "is okay" 74 } 75 scene_extra_args = { 76 "scene5" : ["doAF=False"] 77 } 78 tests = [] 79 for d in scenes: 80 tests += [(d,s[:-3],os.path.join("tests", d, s)) 81 for s in os.listdir(os.path.join("tests",d)) 82 if s[-3:] == ".py"] 83 tests.sort() 84 85 # Make output directories to hold the generated files. 86 topdir = tempfile.mkdtemp() 87 print "Saving output files to:", topdir, "\n" 88 89 device_id = its.device.get_device_id() 90 device_id_arg = "device=" + device_id 91 print "Testing device " + device_id 92 93 camera_ids = [] 94 for s in sys.argv[1:]: 95 if s[:7] == "camera=" and len(s) > 7: 96 camera_ids.append(s[7:]) 97 98 # user doesn't specify camera id, run through all cameras 99 if not camera_ids: 100 camera_ids_path = os.path.join(topdir, "camera_ids.txt") 101 out_arg = "out=" + camera_ids_path 102 cmd = ['python', 103 os.path.join(os.getcwd(),"tools/get_camera_ids.py"), out_arg, 104 device_id_arg] 105 retcode = subprocess.call(cmd,cwd=topdir) 106 assert(retcode == 0) 107 with open(camera_ids_path, "r") as f: 108 for line in f: 109 camera_ids.append(line.replace('\n', '')) 110 111 print "Running ITS on the following cameras:", camera_ids 112 113 for camera_id in camera_ids: 114 # Loop capturing images until user confirm test scene is correct 115 camera_id_arg = "camera=" + camera_id 116 print "Preparing to run ITS on camera", camera_id 117 118 os.mkdir(os.path.join(topdir, camera_id)) 119 for d in scenes: 120 os.mkdir(os.path.join(topdir, camera_id, d)) 121 122 print "Start running ITS on camera: ", camera_id 123 # Run each test, capturing stdout and stderr. 124 summary = "ITS test result summary for camera " + camera_id + "\n" 125 numpass = 0 126 numskip = 0 127 numnotmandatedfail = 0 128 numfail = 0 129 130 prev_scene = "" 131 for (scene,testname,testpath) in tests: 132 if scene != prev_scene and scene_req[scene] != None: 133 out_path = os.path.join(topdir, camera_id, scene+".jpg") 134 out_arg = "out=" + out_path 135 scene_arg = "scene=" + scene_req[scene] 136 extra_args = scene_extra_args.get(scene, []) 137 cmd = ['python', 138 os.path.join(os.getcwd(),"tools/validate_scene.py"), 139 camera_id_arg, out_arg, scene_arg, device_id_arg] + \ 140 extra_args 141 retcode = subprocess.call(cmd,cwd=topdir) 142 assert(retcode == 0) 143 print "Start running tests for", scene 144 prev_scene = scene 145 cmd = ['python', os.path.join(os.getcwd(),testpath)] + \ 146 sys.argv[1:] + [camera_id_arg] 147 outdir = os.path.join(topdir,camera_id,scene) 148 outpath = os.path.join(outdir,testname+"_stdout.txt") 149 errpath = os.path.join(outdir,testname+"_stderr.txt") 150 t0 = time.time() 151 with open(outpath,"w") as fout, open(errpath,"w") as ferr: 152 retcode = subprocess.call(cmd,stderr=ferr,stdout=fout,cwd=outdir) 153 t1 = time.time() 154 155 if retcode == 0: 156 retstr = "PASS " 157 numpass += 1 158 elif retcode == SKIP_RET_CODE: 159 retstr = "SKIP " 160 numskip += 1 161 elif retcode != 0 and testname in NOT_YET_MANDATED[scene]: 162 retstr = "FAIL*" 163 numnotmandatedfail += 1 164 else: 165 retstr = "FAIL " 166 numfail += 1 167 168 msg = "%s %s/%s [%.1fs]" % (retstr, scene, testname, t1-t0) 169 print msg 170 summary += msg + "\n" 171 if retcode != 0 and retcode != SKIP_RET_CODE: 172 # Dump the stderr if the test fails 173 with open (errpath, "r") as error_file: 174 errors = error_file.read() 175 summary += errors + "\n" 176 177 if numskip > 0: 178 skipstr = ", %d test%s skipped" % (numskip, "s" if numskip > 1 else "") 179 else: 180 skipstr = "" 181 182 test_result = "\n%d / %d tests passed (%.1f%%)%s" % ( 183 numpass + numnotmandatedfail, len(tests) - numskip, 184 100.0 * float(numpass + numnotmandatedfail) / (len(tests) - numskip) 185 if len(tests) != numskip else 100.0, 186 skipstr) 187 print test_result 188 summary += test_result + "\n" 189 190 if numnotmandatedfail > 0: 191 msg = "(*) tests are not yet mandated" 192 print msg 193 summary += msg + "\n" 194 195 result = numfail == 0 196 print "Reporting ITS result to CtsVerifier" 197 summary_path = os.path.join(topdir, camera_id, "summary.txt") 198 with open(summary_path, "w") as f: 199 f.write(summary) 200 its.device.report_result(device_id, camera_id, result, summary_path) 201 202 print "ITS tests finished. Please go back to CtsVerifier and proceed" 203 204if __name__ == '__main__': 205 main() 206