CameraITS: report skipped tests

Add skip_unless method to its.caps to exit a test with a return code
if the test is skipped.

Bug: 17994909

Change-Id: Ic6619c4219490160c638951351ee63170e3e7f6e
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index b27e75e..5167614 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -14,6 +14,28 @@
 
 import unittest
 import its.objects
+import sys
+
+
+def skip_unless(cond):
+    """Skips the test if the condition is false.
+
+    If a test is skipped, then it is exited and returns the special code
+    of 101 to the calling shell, which can be used by an external test
+    harness to differentiate a skip from a pass or fail.
+
+    Args:
+        cond: Boolean, which must be true for the test to not skip.
+
+    Returns:
+        Nothing.
+    """
+    SKIP_RET_CODE = 101
+
+    if not cond:
+        print "Test skipped"
+        sys.exit(SKIP_RET_CODE)
+
 
 def full(props):
     """Returns whether a device is a FULL capability camera2 device.
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
index f3d49be..fdf72be 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
@@ -39,9 +39,7 @@
 
         # Capture at the smallest resolution.
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         _, fmt = its.objects.get_fastest_manual_capture_settings(props)
         w,h = fmt["width"], fmt["height"]
diff --git a/apps/CameraITS/tests/scene0/test_camera_properties.py b/apps/CameraITS/tests/scene0/test_camera_properties.py
index 05fc364..eb638f0 100644
--- a/apps/CameraITS/tests/scene0/test_camera_properties.py
+++ b/apps/CameraITS/tests/scene0/test_camera_properties.py
@@ -26,10 +26,10 @@
 
         pprint.pprint(props)
 
-        # Test that a handful of required keys are present.
-        if its.caps.manual_sensor(props):
-            assert(props.has_key('android.sensor.info.sensitivityRange'))
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
+        # Test that a handful of required keys are present.
+        assert(props.has_key('android.sensor.info.sensitivityRange'))
         assert(props.has_key('android.sensor.orientation'))
         assert(props.has_key('android.scaler.streamConfigurationMap'))
         assert(props.has_key('android.lens.facing'))
diff --git a/apps/CameraITS/tests/scene0/test_capture_result_dump.py b/apps/CameraITS/tests/scene0/test_capture_result_dump.py
index c8b1f8f..6646557 100644
--- a/apps/CameraITS/tests/scene0/test_capture_result_dump.py
+++ b/apps/CameraITS/tests/scene0/test_capture_result_dump.py
@@ -27,9 +27,7 @@
         # Arbitrary capture request exposure values; image content is not
         # important for this test, only the metadata.
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         req,fmt = its.objects.get_fastest_manual_capture_settings(props)
         cap = cam.do_capture(req, fmt)
diff --git a/apps/CameraITS/tests/scene0/test_gyro_bias.py b/apps/CameraITS/tests/scene0/test_gyro_bias.py
index 64a5ff0..5e2a745 100644
--- a/apps/CameraITS/tests/scene0/test_gyro_bias.py
+++ b/apps/CameraITS/tests/scene0/test_gyro_bias.py
@@ -39,9 +39,7 @@
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         # Only run test if the appropriate caps are claimed.
-        if not its.caps.sensor_fusion(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.sensor_fusion(props))
 
         print "Collecting gyro events"
         cam.start_sensor_events()
diff --git a/apps/CameraITS/tests/scene0/test_jitter.py b/apps/CameraITS/tests/scene0/test_jitter.py
index 29b3047..82e8e38 100644
--- a/apps/CameraITS/tests/scene0/test_jitter.py
+++ b/apps/CameraITS/tests/scene0/test_jitter.py
@@ -33,9 +33,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         req, fmt = its.objects.get_fastest_manual_capture_settings(props)
         caps = cam.do_capture([req]*50, [fmt])
diff --git a/apps/CameraITS/tests/scene0/test_param_sensitivity_burst.py b/apps/CameraITS/tests/scene0/test_param_sensitivity_burst.py
index eb9a3c1..a2a6d44 100644
--- a/apps/CameraITS/tests/scene0/test_param_sensitivity_burst.py
+++ b/apps/CameraITS/tests/scene0/test_param_sensitivity_burst.py
@@ -27,9 +27,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         sens_range = props['android.sensor.info.sensitivityRange']
         sens_step = (sens_range[1] - sens_range[0]) / NUM_STEPS
diff --git a/apps/CameraITS/tests/scene0/test_sensor_events.py b/apps/CameraITS/tests/scene0/test_sensor_events.py
index 61f0383..5973de2 100644
--- a/apps/CameraITS/tests/scene0/test_sensor_events.py
+++ b/apps/CameraITS/tests/scene0/test_sensor_events.py
@@ -26,9 +26,7 @@
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         # Only run test if the appropriate caps are claimed.
-        if not its.caps.sensor_fusion(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.sensor_fusion(props))
 
         cam.start_sensor_events()
         time.sleep(1)
diff --git a/apps/CameraITS/tests/scene0/test_unified_timestamps.py b/apps/CameraITS/tests/scene0/test_unified_timestamps.py
index cdc9567..019e6c5 100644
--- a/apps/CameraITS/tests/scene0/test_unified_timestamps.py
+++ b/apps/CameraITS/tests/scene0/test_unified_timestamps.py
@@ -25,9 +25,7 @@
         props = cam.get_camera_properties()
 
         # Only run test if the appropriate caps are claimed.
-        if not its.caps.sensor_fusion(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.sensor_fusion(props))
 
         # Get the timestamp of a captured image.
         req, fmt = its.objects.get_fastest_manual_capture_settings(props)
diff --git a/apps/CameraITS/tests/scene1/test_3a.py b/apps/CameraITS/tests/scene1/test_3a.py
index b53fc73..08cd747 100644
--- a/apps/CameraITS/tests/scene1/test_3a.py
+++ b/apps/CameraITS/tests/scene1/test_3a.py
@@ -23,9 +23,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.read_3a(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.read_3a(props))
 
         sens, exp, gains, xform, focus = cam.do_3a(get_results=True)
         print "AE: sensitivity %d, exposure %dms" % (sens, exp/1000000)
diff --git a/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py b/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
index 59b7db1..6357a31 100644
--- a/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
+++ b/apps/CameraITS/tests/scene1/test_ae_precapture_trigger.py
@@ -30,9 +30,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         _,fmt = its.objects.get_fastest_manual_capture_settings(props)
 
diff --git a/apps/CameraITS/tests/scene1/test_auto_vs_manual.py b/apps/CameraITS/tests/scene1/test_auto_vs_manual.py
index a9d5ce4..5b002f8 100644
--- a/apps/CameraITS/tests/scene1/test_auto_vs_manual.py
+++ b/apps/CameraITS/tests/scene1/test_auto_vs_manual.py
@@ -32,10 +32,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.manual_sensor(props) or
-            not its.caps.manual_post_proc(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props) and
+            its.caps.manual_post_proc(props))
 
         # Converge 3A and get the estimates.
         sens, exp, gains, xform, focus = cam.do_3a(get_results=True)
diff --git a/apps/CameraITS/tests/scene1/test_black_white.py b/apps/CameraITS/tests/scene1/test_black_white.py
index e471602..9f5e8d6 100644
--- a/apps/CameraITS/tests/scene1/test_black_white.py
+++ b/apps/CameraITS/tests/scene1/test_black_white.py
@@ -32,9 +32,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         expt_range = props['android.sensor.info.exposureTimeRange']
         sens_range = props['android.sensor.info.sensitivityRange']
diff --git a/apps/CameraITS/tests/scene1/test_burst_sameness_manual.py b/apps/CameraITS/tests/scene1/test_burst_sameness_manual.py
index 3858c0c..e9df2a7 100644
--- a/apps/CameraITS/tests/scene1/test_burst_sameness_manual.py
+++ b/apps/CameraITS/tests/scene1/test_burst_sameness_manual.py
@@ -39,9 +39,7 @@
 
         # Capture at the smallest resolution.
         props = cam.get_camera_properties()
-        if not its.caps.manual_sensor(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props))
 
         _, fmt = its.objects.get_fastest_manual_capture_settings(props)
         e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
diff --git a/apps/CameraITS/tests/scene1/test_capture_result.py b/apps/CameraITS/tests/scene1/test_capture_result.py
index 304e811..6186b6a 100644
--- a/apps/CameraITS/tests/scene1/test_capture_result.py
+++ b/apps/CameraITS/tests/scene1/test_capture_result.py
@@ -34,10 +34,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.manual_sensor(props) or
-            not its.caps.manual_post_proc(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props) and
+            its.caps.manual_post_proc(props))
 
         manual_tonemap = [0,0, 1,1] # Linear
         manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9])
diff --git a/apps/CameraITS/tests/scene1/test_crop_region_raw.py b/apps/CameraITS/tests/scene1/test_crop_region_raw.py
index 07343dd..e582011 100644
--- a/apps/CameraITS/tests/scene1/test_crop_region_raw.py
+++ b/apps/CameraITS/tests/scene1/test_crop_region_raw.py
@@ -49,10 +49,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.compute_target_exposure(props) or
-            not its.caps.raw16(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+            its.caps.raw16(props))
 
         a = props['android.sensor.info.activeArraySize']
         ax, ay = a["left"], a["top"]
diff --git a/apps/CameraITS/tests/scene1/test_crop_regions.py b/apps/CameraITS/tests/scene1/test_crop_regions.py
index 5824363..f7136d6 100644
--- a/apps/CameraITS/tests/scene1/test_crop_regions.py
+++ b/apps/CameraITS/tests/scene1/test_crop_regions.py
@@ -35,10 +35,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.compute_target_exposure(props) or
-            not its.caps.freeform_crop(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+            its.caps.freeform_crop(props))
 
         a = props['android.sensor.info.activeArraySize']
         ax, ay = a["left"], a["top"]
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index 8676358..3b5fd78 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -44,9 +44,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         e,s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
         expt_range = props['android.sensor.info.exposureTimeRange']
diff --git a/apps/CameraITS/tests/scene1/test_format_combos.py b/apps/CameraITS/tests/scene1/test_format_combos.py
index a021102..8714ab6 100644
--- a/apps/CameraITS/tests/scene1/test_format_combos.py
+++ b/apps/CameraITS/tests/scene1/test_format_combos.py
@@ -33,10 +33,8 @@
     with its.device.ItsSession() as cam:
 
         props = cam.get_camera_properties()
-        if (not its.caps.compute_target_exposure(props) or
-            not its.caps.raw16(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+            its.caps.raw16(props))
 
         successes = []
         failures = []
diff --git a/apps/CameraITS/tests/scene1/test_jpeg.py b/apps/CameraITS/tests/scene1/test_jpeg.py
index bc2d64e..fba4162 100644
--- a/apps/CameraITS/tests/scene1/test_jpeg.py
+++ b/apps/CameraITS/tests/scene1/test_jpeg.py
@@ -29,9 +29,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         req = its.objects.manual_capture_request(s, e, True)
diff --git a/apps/CameraITS/tests/scene1/test_latching.py b/apps/CameraITS/tests/scene1/test_latching.py
index bef41ac..e798151 100644
--- a/apps/CameraITS/tests/scene1/test_latching.py
+++ b/apps/CameraITS/tests/scene1/test_latching.py
@@ -33,9 +33,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.full(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.full(props))
 
         _,fmt = its.objects.get_fastest_manual_capture_settings(props)
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
diff --git a/apps/CameraITS/tests/scene1/test_linearity.py b/apps/CameraITS/tests/scene1/test_linearity.py
index fed0324..90ad3ab 100644
--- a/apps/CameraITS/tests/scene1/test_linearity.py
+++ b/apps/CameraITS/tests/scene1/test_linearity.py
@@ -47,9 +47,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         e,s = its.target.get_target_exposure_combos(cam)["midSensitivity"]
         s /= 2
diff --git a/apps/CameraITS/tests/scene1/test_param_color_correction.py b/apps/CameraITS/tests/scene1/test_param_color_correction.py
index 82f2342..35e5234 100644
--- a/apps/CameraITS/tests/scene1/test_param_color_correction.py
+++ b/apps/CameraITS/tests/scene1/test_param_color_correction.py
@@ -37,9 +37,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         # Baseline request
         e, s = its.target.get_target_exposure_combos(cam)["midSensitivity"]
diff --git a/apps/CameraITS/tests/scene1/test_param_exposure_time.py b/apps/CameraITS/tests/scene1/test_param_exposure_time.py
index 390fd3c..b883e10 100644
--- a/apps/CameraITS/tests/scene1/test_param_exposure_time.py
+++ b/apps/CameraITS/tests/scene1/test_param_exposure_time.py
@@ -34,9 +34,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         e,s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         for i,e_mult in enumerate([0.8, 0.9, 1.0, 1.1, 1.2]):
diff --git a/apps/CameraITS/tests/scene1/test_param_flash_mode.py b/apps/CameraITS/tests/scene1/test_param_flash_mode.py
index 6d1be4f..28ccc29 100644
--- a/apps/CameraITS/tests/scene1/test_param_flash_mode.py
+++ b/apps/CameraITS/tests/scene1/test_param_flash_mode.py
@@ -26,9 +26,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         flash_modes_reported = []
         flash_states_reported = []
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index 618f8a7..62b5020 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -44,9 +44,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         # NR mode 0 with low gain
         e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
diff --git a/apps/CameraITS/tests/scene1/test_param_sensitivity.py b/apps/CameraITS/tests/scene1/test_param_sensitivity.py
index c26e9f9..b837f21 100644
--- a/apps/CameraITS/tests/scene1/test_param_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_param_sensitivity.py
@@ -36,9 +36,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         expt,_ = its.target.get_target_exposure_combos(cam)["midSensitivity"]
         sens_range = props['android.sensor.info.sensitivityRange']
diff --git a/apps/CameraITS/tests/scene1/test_param_tonemap_mode.py b/apps/CameraITS/tests/scene1/test_param_tonemap_mode.py
index fbd452c..d4932a0 100644
--- a/apps/CameraITS/tests/scene1/test_param_tonemap_mode.py
+++ b/apps/CameraITS/tests/scene1/test_param_tonemap_mode.py
@@ -38,9 +38,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
         e /= 2
diff --git a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
index bf0e2ea..8819ca8 100644
--- a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
@@ -37,11 +37,9 @@
     with its.device.ItsSession() as cam:
 
         props = cam.get_camera_properties()
-        if not its.caps.raw16(props) or \
-           not its.caps.manual_sensor(props) or \
-           not its.caps.read_3a(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.raw16(props) and
+           its.caps.manual_sensor(props) and
+           its.caps.read_3a(props))
 
         # Expose for the scene with min sensitivity
         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
index 8e36219..3ff8128 100644
--- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
@@ -35,11 +35,9 @@
     with its.device.ItsSession() as cam:
 
         props = cam.get_camera_properties()
-        if (not its.caps.raw16(props) or
-            not its.caps.manual_sensor(props) or
-            not its.caps.read_3a(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.raw16(props) and
+            its.caps.manual_sensor(props) and
+            its.caps.read_3a(props))
 
         # Expose for the scene with min sensitivity
         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
diff --git a/apps/CameraITS/tests/scene1/test_tonemap_sequence.py b/apps/CameraITS/tests/scene1/test_tonemap_sequence.py
index 7af51c5..435528a 100644
--- a/apps/CameraITS/tests/scene1/test_tonemap_sequence.py
+++ b/apps/CameraITS/tests/scene1/test_tonemap_sequence.py
@@ -31,10 +31,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.manual_sensor(props) or
-            not its.caps.manual_post_proc(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.manual_sensor(props) and
+            its.caps.manual_post_proc(props))
 
         sens, exp_time, _,_,_ = cam.do_3a(do_af=False,get_results=True)
 
diff --git a/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py b/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py
index 2367ca2..92ab2eb 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_jpeg_all.py
@@ -29,9 +29,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         # Use a manual request with a linear tonemap so that the YUV and JPEG
         # should look the same (once converted by the its.image module).
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
index 4924c7b..a8f17aa 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
@@ -25,10 +25,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.raw(props) or
-            not its.caps.read_3a(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.raw(props) and
+            its.caps.read_3a(props))
 
         cam.do_3a()
 
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
index 15aa17c..6daa243 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
@@ -32,9 +32,7 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if not its.caps.compute_target_exposure(props):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props))
 
         # Use a manual request with a linear tonemap so that the YUV and JPEG
         # should look the same (once converted by the its.image module).
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
index d392fc6..ab8f773 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
@@ -29,10 +29,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-        if (not its.caps.compute_target_exposure(props) or
-            not its.caps.raw16(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+            its.caps.raw16(props))
 
         # Use a manual request with a linear tonemap so that the YUV and RAW
         # should look the same (once converted by the its.image module).
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
index 62d3510..028fb56 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
@@ -29,11 +29,8 @@
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
-
-        if (not its.caps.compute_target_exposure(props) or
-            not its.caps.raw10(props)):
-            print "Test skipped"
-            return
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+            its.caps.raw10(props))
 
         # Use a manual request with a linear tonemap so that the YUV and RAW
         # should look the same (once converted by the its.image module).
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index f1984e8..77b5ce5 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -27,6 +27,8 @@
     Script should be run from the top-level CameraITS directory.
     """
 
+    SKIP_RET_CODE = 101
+
     # Not yet mandated tests
     NOT_YET_MANDATED = {
         "scene0":[
@@ -70,7 +72,9 @@
 
     # Run each test, capturing stdout and stderr.
     numpass = 0
+    numskip = 0
     numnotmandatedfail = 0
+    numfail = 0
     for (scene,testname,testpath) in tests:
         cmd = ['python', os.path.join(os.getcwd(),testpath)] + sys.argv[1:]
         outdir = os.path.join(topdir,scene)
@@ -80,22 +84,37 @@
         with open(outpath,"w") as fout, open(errpath,"w") as ferr:
             retcode = subprocess.call(cmd,stderr=ferr,stdout=fout,cwd=outdir)
         t1 = time.time()
-        retstr = "PASS "
-        if retcode != 0:
-            retstr = "FAIL*" if testname in NOT_YET_MANDATED[scene] else "FAIL "
 
-        if retstr == "FAIL*":
+        if retcode == 0:
+            retstr = "PASS "
+            numpass += 1
+        elif retcode == SKIP_RET_CODE:
+            retstr = "SKIP "
+            numskip += 1
+        elif retcode != 0 and testname in NOT_YET_MANDATED[scene]:
+            retstr = "FAIL*"
             numnotmandatedfail += 1
+        else:
+            retstr = "FAIL "
+            numfail += 1
 
         print "%s %s/%s [%.1fs]" % (retstr, scene, testname, t1-t0)
-        if retcode == 0 or testname in NOT_YET_MANDATED[scene]:
-            numpass += 1
 
-    print "\n%d / %d tests passed (%.1f%%)" % (
-            numpass, len(tests), 100.0*float(numpass)/len(tests))
+    if numskip > 0:
+        skipstr = ", %d test%s skipped" % (numskip, "s" if numskip > 1 else "")
+    else:
+        skipstr = ""
+
+    print "\n%d / %d tests passed (%.1f%%)%s" % (
+            numpass + numnotmandatedfail, len(tests) - numskip,
+            100.0 * float(numpass + numnotmandatedfail) / (len(tests) - numskip)
+                if len(tests) != numskip else 100.0,
+            skipstr)
+
     if numnotmandatedfail > 0:
         print "(*) tests are not yet mandated"
-    its.device.ItsSession.report_result(camera_id, numpass == len(tests))
+
+    its.device.ItsSession.report_result(camera_id, numfail == 0)
 
 if __name__ == '__main__':
     main()