gsi_util: adding cmd_utils

Adding a run_command function to execute a host command.
Also support reading the stdout and/or stderr of the result if desired,
which might be useful for further parsing and flow decision.

A typical usage will be passing a command sequence:
  cmd_utils.run_command(['echo', '123'])

It also supports running a 'shell' command, by passing a single string:
  cmd_utils.run_command('echo 123', shell=True)

To get the stdout and/or stderr data, just add 'read_stdout=True' and/or
'read_stderr=True':
  cmd_utils.run_command('echo 123', shell=True,
                        read_stdout=True, read_stderr=True),

which returns a namedtuple:
  ('CommandResult', 'returncode stdoutdata, stderrdata').

Note that other keyword arguments will be passed to subprocess.Popen().
e.g., the following command will change current directory to
'my_working_dir' prior to execute the command:
  cmd_utils.run_command('echo 123', shell=True, cwd=my_working_dir)

More usage examples can be found in cmd_utils_unittest.py.

Also adds a run_test.py to search then run ./*tests/*_unittest.py files.

Bug: 70477387
Test: make gsi_util
Test: ./run_test.py
Change-Id: Id3aae935f941818fe7415798937fd07dbbe6ba33
diff --git a/gsi/gsi_util/Android.bp b/gsi/gsi_util/Android.bp
index be7b569..8ec481a 100644
--- a/gsi/gsi_util/Android.bp
+++ b/gsi/gsi_util/Android.bp
@@ -18,6 +18,7 @@
     "gsi_util.py",
     "gsi_util/*.py",
     "gsi_util/commands/*.py",
+    "gsi_util/utils/*.py",
   ],
   version: {
     py2: {