From 4d9df551ca1dafee097a58c7bbd1351291362ced Mon Sep 17 00:00:00 2001
From: Gregory Becker <becker33@llnl.gov>
Date: Fri, 17 Jan 2020 13:30:40 -0800
Subject: [PATCH] tests occur in temporary directory, can be kept for debugging

---
 lib/spack/spack/build_environment.py |  5 ++++-
 lib/spack/spack/cmd/test.py          |  4 +++-
 lib/spack/spack/package.py           | 21 +++++++++++++++++++--
 lib/spack/spack/report.py            | 19 +++++++++++--------
 4 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 9d9e03c1c1..ab4c5d69fd 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -857,6 +857,9 @@ def child_process(child_pipe, input_stream):
         if input_stream is not None:
             sys.stdin = input_stream
 
+        # Record starting directory
+        start_dir = os.getcwd()
+
         try:
             if not fake:
                 setup_package(pkg, dirty=dirty, context=context)
@@ -885,7 +888,7 @@ def child_process(child_pipe, input_stream):
 
             test_log = None
             if context == 'test':
-                test_log = os.path.join(os.getcwd(), pkg.test_log_name)
+                test_log = os.path.join(start_dir, pkg.test_log_name)
 
             # make a pickleable exception to send to parent.
             msg = "%s: %s" % (exc_type.__name__, str(exc))
diff --git a/lib/spack/spack/cmd/test.py b/lib/spack/spack/cmd/test.py
index 175ad1ecd9..c89bead6b6 100644
--- a/lib/spack/spack/cmd/test.py
+++ b/lib/spack/spack/cmd/test.py
@@ -22,6 +22,8 @@
 
 
 def setup_parser(subparser):
+    subparser.add_argument('--keep-tmpdir', action='store_true',
+                           help='Keep testing directory for debuggin')
     subparser.add_argument(
         '--log-format',
         default=None,
@@ -100,6 +102,6 @@ def test(parser, args):
     with reporter('test'):
         if args.smoke_test:
             for spec in specs_to_test:
-                spec.package.do_test()
+                spec.package.do_test(not args.keep_tmpdir)
         else:
             raise NotImplementedError
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index b15ab324b3..ec3067edce 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1580,7 +1580,7 @@ def do_install(self, **kwargs):
     def test_log_name(self):
         return 'test-%s' % self.spec.format('{name}-{hash:7}')
 
-    def do_test(self, dirty=False):
+    def do_test(self, remove_directory=False, dirty=False):
         test_log_file = os.path.join(os.getcwd(), self.test_log_name)
 
         def test_process():
@@ -1588,9 +1588,18 @@ def test_process():
                 with logger.force_echo():
                     tty.msg('Testing package %s' %
                             self.spec.format('{name}-{hash:7}'))
+
+                # use debug print levels for log file to record commands
                 old_debug = tty.is_debug()
                 tty.set_debug(True)
+
+                # setup test directory
+                alltestsdir = os.path.join(os.getcwd(), 'spack-tests')
+                testdir = os.path.join(alltestsdir,
+                                       self.spec.format('{name}-{hash}'))
                 try:
+                    mkdirp(testdir)
+                    os.chdir(testdir)
                     self.test()
                 except Exception as e:
                     # Catch the error and print a summary to the log file
@@ -1614,7 +1623,15 @@ def test_process():
                              globals(), locals())
                     else:
                         raise exc_type(*args).with_traceback(traceback)
-                tty.set_debug(old_debug)
+                finally:
+                    # reset debug level
+                    tty.set_debug(old_debug)
+
+                    # cleanup test directory
+                    if remove_directory:
+                        shutil.rmtree(testdir)
+                        if not os.listdir(alltestsdir):
+                            shutil.rmtree(alltestsdir)
 
         spack.build_environment.fork(
             self, test_process, dirty=dirty, fake=False, context='test')
diff --git a/lib/spack/spack/report.py b/lib/spack/spack/report.py
index bf19304301..a62f0d9ab4 100644
--- a/lib/spack/spack/report.py
+++ b/lib/spack/spack/report.py
@@ -34,10 +34,10 @@
 ]
 
 
-def fetch_package_log_by_type(pkg, do_fn):
+def fetch_log(pkg, do_fn, dir):
     log_files = {
         'do_install': pkg.build_log_path,
-        'do_test': os.path.join(os.getcwd(), pkg.test_log_name),
+        'do_test': os.path.join(dir, pkg.test_log_name),
     }
     try:
         with codecs.open(log_files[do_fn.__name__], 'r', 'utf-8') as f:
@@ -63,7 +63,7 @@ class InfoCollector(object):
         specs (list of Spec): specs whose install information will
            be recorded
     """
-    def __init__(self, wrap_class, do_fn, specs):
+    def __init__(self, wrap_class, do_fn, specs, dir):
         #: Class for which to wrap a function
         self.wrap_class = wrap_class
         #: Action to be reported on
@@ -75,6 +75,8 @@ def __init__(self, wrap_class, do_fn, specs):
         #: This is where we record the data that will be included
         #: in our report.
         self.specs = []
+        #: Record directory for test log paths
+        self.dir = dir
 
     def __enter__(self):
         # Initialize the spec report with the data that is available upfront.
@@ -152,7 +154,7 @@ def wrapper(instance, *args, **kwargs):
                 try:
                     value = _install_task(instance, *args, **kwargs)
                     package['result'] = 'success'
-                    package['stdout'] = fetch_package_log_by_type(pkg, do_fn)
+                    package['stdout'] = fetch_log(pkg, do_fn, self.dir)
                     package['installed_from_binary_cache'] = \
                         pkg.installed_from_binary_cache
                     if do_fn.__name__ == 'do_install' and installed_on_entry:
@@ -163,7 +165,7 @@ def wrapper(instance, *args, **kwargs):
                     # didn't work correctly)
                     package['result'] = 'failure'
                     package['message'] = e.message or 'Installation failure'
-                    package['stdout'] = fetch_package_log_by_type(pkg, do_fn)
+                    package['stdout'] = fetch_log(pkg, do_fn, self.dir)
                     package['stdout'] += package['message']
                     package['exception'] = e.traceback
 
@@ -171,7 +173,7 @@ def wrapper(instance, *args, **kwargs):
                     # Everything else is an error (the installation
                     # failed outside of the child process)
                     package['result'] = 'error'
-                    package['stdout'] = fetch_package_log_by_type(pkg, do_fn)
+                    package['stdout'] = fetch_log(pkg, do_fn, self.dir)
                     package['message'] = str(e) or 'Unknown error'
                     package['exception'] = traceback.format_exc()
 
@@ -269,6 +271,7 @@ def __init__(self, function, format_name, args):
 
     def __call__(self, type):
         self.type = type
+        self.dir = os.getcwd()
         return self
 
     def concretization_report(self, msg):
@@ -276,8 +279,8 @@ def concretization_report(self, msg):
 
     def __enter__(self):
         if self.format_name:
-            # Start the collector and patch PackageInstaller._install_task
-            self.collector = InfoCollector(self.function, self.specs)
+            # Start the collector and patch self.function on appropriate class
+            self.collector = InfoCollector(self.function, self.specs, self.dir)
             self.collector.__enter__()
 
     def __exit__(self, exc_type, exc_val, exc_tb):
-- 
GitLab