scripts/unit-test: Support running tests only

By default we will still run all of the checks so that our CI coverage
is still sane. However, this will make it possible for developers to
trivially run just the test cases of the project for faster turnaround
time for developing. Just set TEST_ONLY=1 in your environment to skip
all of the slow checks like valgrind / coverage / clang-tidy.

Tested:
    Ran under an autotools build and meson build to verify that the
    behavior is still as expected.

Change-Id: I0b420e1c3e779863b90288ce72fc056400226734
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/run-unit-test-docker.sh b/run-unit-test-docker.sh
index 2ebc224..8ad6430 100755
--- a/run-unit-test-docker.sh
+++ b/run-unit-test-docker.sh
@@ -37,6 +37,7 @@
 UNIT_TEST_PY="unit-test.py"
 FORMAT_CODE_SH="format-code.sh"
 DBUS_UNIT_TEST_PY="dbus-unit-test.py"
+TEST_ONLY="${TEST_ONLY:-}"
 DBUS_SYS_CONFIG_FILE=${dbus_sys_config_file:-"/usr/share/dbus-1/system.conf"}
 MAKEFLAGS="${MAKEFLAGS:-""}"
 DOCKER_WORKDIR="${DOCKER_WORKDIR:-$WORKSPACE}"
@@ -89,7 +90,7 @@
 
 # Unit test and parameters
 UNIT_TEST="${DOCKER_WORKDIR}/${UNIT_TEST_PY},-w,${DOCKER_WORKDIR},\
--p,${UNIT_TEST_PKG},-b,$BRANCH,-v"
+-p,${UNIT_TEST_PKG},-b,$BRANCH,-v${TEST_ONLY:+,-t}"
 
 # Run the docker unit test container with the unit test execution script
 echo "Executing docker image"
diff --git a/scripts/unit-test.py b/scripts/unit-test.py
index 1406435..229f5db 100755
--- a/scripts/unit-test.py
+++ b/scripts/unit-test.py
@@ -429,9 +429,12 @@
             enFlag('silent-rules', False),
             enFlag('examples', build_for_testing),
             enFlag('tests', build_for_testing),
-            enFlag('code-coverage', build_for_testing),
-            enFlag('valgrind', build_for_testing),
         ]
+        if not TEST_ONLY:
+            conf_flags.extend([
+                enFlag('code-coverage', build_for_testing),
+                enFlag('valgrind', build_for_testing),
+            ])
         # Add any necessary configure flags for package
         if CONFIGURE_FLAGS.get(pkg) is not None:
             conf_flags.extend(CONFIGURE_FLAGS.get(pkg))
@@ -660,6 +663,9 @@
                         help="Workspace directory location(i.e. /home)")
     parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
                         help="OpenBMC package to be unit tested")
+    parser.add_argument("-t", "--test-only", dest="TEST_ONLY",
+                        action="store_true", required=False, default=False,
+                        help="Only run test cases, no other validation")
     parser.add_argument("-v", "--verbose", action="store_true",
                         help="Print additional package status messages")
     parser.add_argument("-r", "--repeat", help="Repeat tests N times",
@@ -670,6 +676,7 @@
     args = parser.parse_args(sys.argv[1:])
     WORKSPACE = args.WORKSPACE
     UNIT_TEST_PKG = args.PACKAGE
+    TEST_ONLY = args.TEST_ONLY
     BRANCH = args.BRANCH
     if args.verbose:
         def printline(*line):
@@ -715,52 +722,61 @@
         # Run package unit tests
         build_and_install(UNIT_TEST_PKG, True)
         if os.path.isfile(CODE_SCAN_DIR + '/meson.build'):
-            # Run valgrind if it is supported
-            if is_valgrind_safe():
-                check_call_cmd(top_dir, 'meson', 'test', '-C', 'build',
-                               '--wrap', 'valgrind')
+            if not TEST_ONLY:
+                # Run valgrind if it is supported
+                if is_valgrind_safe():
+                    check_call_cmd(top_dir, 'meson', 'test', '-C', 'build',
+                                   '--wrap', 'valgrind')
 
-            # Run clang-tidy only if the project has a configuration
-            if os.path.isfile('.clang-tidy'):
-                check_call_cmd(top_dir, 'run-clang-tidy-6.0.py', '-p', 'build')
-            # Run the basic clang static analyzer otherwise
-            else:
-                os.environ['SCANBUILD'] = 'scan-build-6.0'
-                check_call_cmd(top_dir, 'ninja', '-C', 'build', 'scan-build')
-
-            # Run tests through sanitizers
-            # b_lundef is needed if clang++ is CXX since it resolves the asan
-            # symbols at runtime only. We don't want to set it earlier in the
-            # build process to ensure we don't have undefined runtime code.
-            check_call_cmd(top_dir, 'meson', 'configure', 'build',
-                           '-Db_sanitize=address,undefined', '-Db_lundef=false')
-            check_call_cmd(top_dir, 'meson', 'test', '-C', 'build',
-                           '--logbase', 'testlog-ubasan')
-            # TODO: Fix memory sanitizer
-            #check_call_cmd(top_dir, 'meson', 'configure', 'build',
-            #               '-Db_sanitize=memory')
-            #check_call_cmd(top_dir, 'meson', 'test', '-C', 'build'
-            #               '--logbase', 'testlog-msan')
-            check_call_cmd(top_dir, 'meson', 'configure', 'build',
-                           '-Db_sanitize=none', '-Db_lundef=true')
-
-            # Run coverage checks
-            check_call_cmd(top_dir, 'meson', 'configure', 'build',
-                           '-Db_coverage=true')
-            check_call_cmd(top_dir, 'meson', 'test', '-C', 'build')
-            # Only build coverage HTML if coverage files were produced
-            for root, dirs, files in os.walk('build'):
-                if any([f.endswith('.gcda') for f in files]):
+                # Run clang-tidy only if the project has a configuration
+                if os.path.isfile('.clang-tidy'):
+                    check_call_cmd(top_dir, 'run-clang-tidy-6.0.py', '-p',
+                                   'build')
+                # Run the basic clang static analyzer otherwise
+                else:
+                    os.environ['SCANBUILD'] = 'scan-build-6.0'
                     check_call_cmd(top_dir, 'ninja', '-C', 'build',
-                                   'coverage-html')
-                    break
-            check_call_cmd(top_dir, 'meson', 'configure', 'build',
-                           '-Db_coverage=false')
+                                   'scan-build')
+
+                # Run tests through sanitizers
+                # b_lundef is needed if clang++ is CXX since it resolves the
+                # asan symbols at runtime only. We don't want to set it earlier
+                # in the build process to ensure we don't have undefined
+                # runtime code.
+                check_call_cmd(top_dir, 'meson', 'configure', 'build',
+                               '-Db_sanitize=address,undefined',
+                               '-Db_lundef=false')
+                check_call_cmd(top_dir, 'meson', 'test', '-C', 'build',
+                               '--logbase', 'testlog-ubasan')
+                # TODO: Fix memory sanitizer
+                #check_call_cmd(top_dir, 'meson', 'configure', 'build',
+                #               '-Db_sanitize=memory')
+                #check_call_cmd(top_dir, 'meson', 'test', '-C', 'build'
+                #               '--logbase', 'testlog-msan')
+                check_call_cmd(top_dir, 'meson', 'configure', 'build',
+                               '-Db_sanitize=none', '-Db_lundef=true')
+
+                # Run coverage checks
+                check_call_cmd(top_dir, 'meson', 'configure', 'build',
+                               '-Db_coverage=true')
+                check_call_cmd(top_dir, 'meson', 'test', '-C', 'build')
+                # Only build coverage HTML if coverage files were produced
+                for root, dirs, files in os.walk('build'):
+                    if any([f.endswith('.gcda') for f in files]):
+                        check_call_cmd(top_dir, 'ninja', '-C', 'build',
+                                       'coverage-html')
+                        break
+                check_call_cmd(top_dir, 'meson', 'configure', 'build',
+                               '-Db_coverage=false')
+            else:
+                check_call_cmd(top_dir, 'meson', 'test', '-C', 'build')
         else:
             run_unit_tests(top_dir)
-            maybe_run_valgrind(top_dir)
-            maybe_run_coverage(top_dir)
-        run_cppcheck(top_dir)
+            if not TEST_ONLY:
+                maybe_run_valgrind(top_dir)
+                maybe_run_coverage(top_dir)
+        if not TEST_ONLY:
+            run_cppcheck(top_dir)
 
         os.umask(prev_umask)
 
@@ -773,11 +789,12 @@
                        str(multiprocessing.cpu_count()))
         if make_target_exists('test'):
             check_call_cmd(top_dir, 'ctest', '.')
-        maybe_run_valgrind(top_dir)
-        maybe_run_coverage(top_dir)
-        run_cppcheck(top_dir)
-        if os.path.isfile('.clang-tidy'):
-            check_call_cmd(top_dir, 'run-clang-tidy-6.0.py', '-p', '.')
+        if not TEST_ONLY:
+            maybe_run_valgrind(top_dir)
+            maybe_run_coverage(top_dir)
+            run_cppcheck(top_dir)
+            if os.path.isfile('.clang-tidy'):
+                check_call_cmd(top_dir, 'run-clang-tidy-6.0.py', '-p', '.')
 
     else:
         print "Not a supported repo for CI Tests, exit"