Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 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 | |
| 15 | import os |
| 16 | import os.path |
| 17 | import tempfile |
| 18 | import subprocess |
| 19 | import time |
| 20 | import sys |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 21 | import textwrap |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 22 | import its.device |
| 23 | |
| 24 | def 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 | |
Chien-Yu Chen | bad96ca | 2014-10-20 17:30:56 -0700 | [diff] [blame] | 31 | SKIP_RET_CODE = 101 |
| 32 | |
Yin-Chia Yeh | 665dda4 | 2014-10-20 11:23:48 -0700 | [diff] [blame] | 33 | # Not yet mandated tests |
| 34 | NOT_YET_MANDATED = { |
| 35 | "scene0":[ |
| 36 | "test_jitter" |
| 37 | ], |
| 38 | "scene1":[ |
| 39 | "test_ae_precapture_trigger", |
Yin-Chia Yeh | 665dda4 | 2014-10-20 11:23:48 -0700 | [diff] [blame] | 40 | "test_crop_region_raw", |
Zhijun He | 6137f21 | 2014-11-20 13:47:11 -0800 | [diff] [blame] | 41 | "test_ev_compensation_advanced", |
| 42 | "test_ev_compensation_basic", |
Yin-Chia Yeh | 3b1763a | 2014-10-22 10:59:13 -0700 | [diff] [blame] | 43 | "test_yuv_plus_jpeg" |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 44 | ], |
Chien-Yu Chen | f07d5c2 | 2015-07-09 15:37:33 -0700 | [diff] [blame] | 45 | "scene2":[], |
Lu | 7c6f52e | 2015-12-15 14:42:18 -0800 | [diff] [blame] | 46 | "scene3":[], |
Lu | 75f22fc | 2016-02-19 10:54:07 -0800 | [diff] [blame] | 47 | "scene4":[], |
Yin-Chia Yeh | f16d687 | 2016-06-06 13:54:42 -0700 | [diff] [blame^] | 48 | "scene5":[], |
| 49 | "sensor_fusion":[] |
Yin-Chia Yeh | 665dda4 | 2014-10-20 11:23:48 -0700 | [diff] [blame] | 50 | } |
| 51 | |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 52 | # Get all the scene0 and scene1 tests, which can be run using the same |
| 53 | # physical setup. |
Yin-Chia Yeh | f16d687 | 2016-06-06 13:54:42 -0700 | [diff] [blame^] | 54 | scenes = ["scene0", "scene1", "scene2", "scene3", "scene4", "scene5", |
| 55 | "sensor_fusion"] |
| 56 | |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 57 | scene_req = { |
| 58 | "scene0" : None, |
| 59 | "scene1" : "A grey card covering at least the middle 30% of the scene", |
Chien-Yu Chen | f07d5c2 | 2015-07-09 15:37:33 -0700 | [diff] [blame] | 60 | "scene2" : "A picture containing human faces", |
Lu | 7c6f52e | 2015-12-15 14:42:18 -0800 | [diff] [blame] | 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 " |
Lu | 75f22fc | 2016-02-19 10:54:07 -0800 | [diff] [blame] | 64 | "for more details", |
| 65 | "scene5" : "Capture images with a diffuser attached to the camera. See " |
Yin-Chia Yeh | f16d687 | 2016-06-06 13:54:42 -0700 | [diff] [blame^] | 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" |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 74 | } |
Yin-Chia Yeh | 143612d | 2016-04-27 15:44:08 -0700 | [diff] [blame] | 75 | scene_extra_args = { |
| 76 | "scene5" : ["doAF=False"] |
| 77 | } |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 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() |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 87 | print "Saving output files to:", topdir, "\n" |
| 88 | |
Chien-Yu Chen | 1da2313 | 2015-07-22 15:24:41 -0700 | [diff] [blame] | 89 | device_id = its.device.get_device_id() |
| 90 | device_id_arg = "device=" + device_id |
| 91 | print "Testing device " + device_id |
| 92 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 93 | camera_ids = [] |
Yin-Chia Yeh | a2277d0 | 2014-10-20 15:50:23 -0700 | [diff] [blame] | 94 | for s in sys.argv[1:]: |
| 95 | if s[:7] == "camera=" and len(s) > 7: |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 96 | camera_ids.append(s[7:]) |
Yin-Chia Yeh | a2277d0 | 2014-10-20 15:50:23 -0700 | [diff] [blame] | 97 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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', |
Chien-Yu Chen | 1da2313 | 2015-07-22 15:24:41 -0700 | [diff] [blame] | 103 | os.path.join(os.getcwd(),"tools/get_camera_ids.py"), out_arg, |
| 104 | device_id_arg] |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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', '')) |
Yin-Chia Yeh | 665dda4 | 2014-10-20 11:23:48 -0700 | [diff] [blame] | 110 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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 | |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 130 | prev_scene = "" |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 131 | for (scene,testname,testpath) in tests: |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 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] |
Yin-Chia Yeh | 143612d | 2016-04-27 15:44:08 -0700 | [diff] [blame] | 136 | extra_args = scene_extra_args.get(scene, []) |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 137 | cmd = ['python', |
| 138 | os.path.join(os.getcwd(),"tools/validate_scene.py"), |
Yin-Chia Yeh | 143612d | 2016-04-27 15:44:08 -0700 | [diff] [blame] | 139 | camera_id_arg, out_arg, scene_arg, device_id_arg] + \ |
| 140 | extra_args |
Yin-Chia Yeh | 0e0276f | 2015-06-03 15:27:06 -0700 | [diff] [blame] | 141 | retcode = subprocess.call(cmd,cwd=topdir) |
| 142 | assert(retcode == 0) |
| 143 | print "Start running tests for", scene |
| 144 | prev_scene = scene |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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 "") |
Chien-Yu Chen | bad96ca | 2014-10-20 17:30:56 -0700 | [diff] [blame] | 179 | else: |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 180 | skipstr = "" |
Yin-Chia Yeh | 665dda4 | 2014-10-20 11:23:48 -0700 | [diff] [blame] | 181 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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" |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 189 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 190 | if numnotmandatedfail > 0: |
| 191 | msg = "(*) tests are not yet mandated" |
| 192 | print msg |
| 193 | summary += msg + "\n" |
Chien-Yu Chen | bad96ca | 2014-10-20 17:30:56 -0700 | [diff] [blame] | 194 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 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) |
Chien-Yu Chen | 1da2313 | 2015-07-22 15:24:41 -0700 | [diff] [blame] | 200 | its.device.report_result(device_id, camera_id, result, summary_path) |
Chien-Yu Chen | bad96ca | 2014-10-20 17:30:56 -0700 | [diff] [blame] | 201 | |
Yin-Chia Yeh | ab98ada | 2015-03-05 13:28:53 -0800 | [diff] [blame] | 202 | print "ITS tests finished. Please go back to CtsVerifier and proceed" |
Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 203 | |
| 204 | if __name__ == '__main__': |
| 205 | main() |