run_pytest: Add '--quickstart' mode

Add an argument to `run_pytest` to make it skip things like namespacing
and parallelism in case a user just wants to run a single test quickly.

Namespacing in particular is enabled by default because tests may break
each other or interfere with parts of the running system if not isolated
in a namespace. As such, this setting is not recommended for general use.
You have been warned!

BUG=None
TEST=`run_pytest --quickstart scripts/loman_unittest.py`

Change-Id: I0ca67b2affca6b19c30bc85e2798e18110a9395a
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2159078
Commit-Queue: Chris McDonald <cjmcdonald@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
Tested-by: Chris McDonald <cjmcdonald@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Michael Mortensen <mmortensen@google.com>
Auto-Submit: Chris McDonald <cjmcdonald@chromium.org>
diff --git a/scripts/run_pytest.py b/scripts/run_pytest.py
index 5655368..7ab49b3 100644
--- a/scripts/run_pytest.py
+++ b/scripts/run_pytest.py
@@ -7,6 +7,7 @@
 
 from __future__ import print_function
 
+import argparse
 import os
 import sys
 
@@ -16,10 +17,17 @@
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import gs
+from chromite.lib import cros_logging as logging
 from chromite.lib import namespaces
 
 
 def main(argv):
+  parser = get_parser()
+  opts, pytest_args = parser.parse_known_args()
+  if opts.quick:
+    if not cros_build_lib.IsInsideChroot():
+      logging.warn('Running tests from inside the chroot will start up faster.')
+
   ensure_chroot_exists()
   re_execute_inside_chroot(argv)
 
@@ -27,9 +35,18 @@
   # we run tests. This is a partial workaround for crbug.com/468838.
   gs.GSContext.GetDefaultGSUtilBin()
 
-  re_execute_with_namespace([sys.argv[0]] + argv)
+  if opts.quick:
+    logging.info('Skipping test namespacing due to --quickstart.')
+    # Default to running in a single process under --quickstart. User args can
+    # still override this.
+    pytest_args = ['-n', '0'] + pytest_args
+  else:
+    # Namespacing is enabled by default because tests may break each other or
+    # interfere with parts of the running system if not isolated in a namespace.
+    # Disabling namespaces is not recommended for general use.
+    re_execute_with_namespace([sys.argv[0]] + argv)
 
-  sys.exit(pytest.main(argv))
+  sys.exit(pytest.main(pytest_args))
 
 
 def re_execute_with_namespace(argv, network=False):
@@ -73,3 +90,20 @@
   chroot = os.path.join(constants.SOURCE_ROOT, constants.DEFAULT_CHROOT_DIR)
   if not os.path.exists(chroot) and not cros_build_lib.IsInsideChroot():
     cros_build_lib.run(['cros_sdk', '--create'])
+
+
+def get_parser():
+  """Build the parser for command line arguments."""
+  parser = argparse.ArgumentParser(
+      description=__doc__,
+      epilog='To see the help output for pytest, run `pytest --help` inside '
+      'the chroot.',
+  )
+  parser.add_argument(
+      '--quickstart',
+      dest='quick',
+      action='store_true',
+      help='Skip normal test sandboxing and namespacing for faster start up '
+      'time.',
+  )
+  return parser