From 661241c836c608e51d41542579a9ec7dcf769b14 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Mon, 30 Nov 2020 17:35:21 +0000
Subject: [PATCH] CI: Basic unit tests for wrapper creation/removal

---
 .ci/test_create_remove_wrapper.py | 178 ++++++++++++++++++++++++++++++
 .gitlab-ci.yml                    |  18 +++
 2 files changed, 196 insertions(+)
 create mode 100755 .ci/test_create_remove_wrapper.py
 create mode 100644 .gitlab-ci.yml

diff --git a/.ci/test_create_remove_wrapper.py b/.ci/test_create_remove_wrapper.py
new file mode 100755
index 0000000..42ef5c6
--- /dev/null
+++ b/.ci/test_create_remove_wrapper.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+#
+# test_create_remove_wrapper.py - Test the createFSLWrapper.sh and
+# removeFSLWrapper.sh scripts. Requires Python 3.7.
+#
+# Author: Paul McCarthy <pauldmccarthy@gmail.com>
+#
+
+
+import os.path as op
+import subprocess as sp
+import textwrap as tw
+import os
+import shlex
+import shutil
+import tempfile
+import contextlib
+from unittest import mock
+
+
+BASE_DIR       = op.abspath(op.join(op.dirname(__file__), '..'))
+CREATE_WRAPPER = op.join(BASE_DIR, 'etc', 'fslconf', 'createFSLWrapper.sh')
+REMOVE_WRAPPER = op.join(BASE_DIR, 'etc', 'fslconf', 'removeFSLWrapper.sh')
+
+
+def run(cmd, **kwargs):
+    return sp.run(shlex.split(cmd), check=True, **kwargs)
+
+
+@contextlib.contextmanager
+def temp_fsldir():
+
+    testdir    = tempfile.mkdtemp()
+    prevdir    = os.getcwd()
+    fsldir     = op.join(testdir, 'fsl')
+    wrapperdir = op.join(testdir, 'fsl', 'share', 'fsl', 'bin')
+    try:
+
+        os.chdir(testdir)
+        os.mkdir(fsldir)
+
+        with mock.patch.dict(os.environ, {
+                'FSLDIR'                     : fsldir,
+                'PREFIX'                     : fsldir,
+                'FSL_CREATE_WRAPPER_SCRIPTS' : '1'}):
+            yield fsldir, wrapperdir
+
+    finally:
+        os.chdir(prevdir)
+        shutil.rmtree(testdir)
+
+
+def touch(path):
+    dirname = op.dirname(path)
+    if not op.exists(dirname):
+        os.makedirs(dirname)
+    with open(path, 'wt') as f:
+        f.write('.')
+
+
+def test_env_vars_not_set():
+    """Test that wrapper scripts are not created if the
+    FSL_CREATE_WRAPPER_SCRIPTS, FSLDIR, or PREFIX environment variables
+    are not set.
+    """
+    with temp_fsldir() as (fsldir, wrapperdir):
+        touch(op.join(fsldir, 'bin', 'test_script'))
+
+        env = os.environ.copy()
+        env.pop('FSL_CREATE_WRAPPER_SCRIPTS')
+        run(f'{CREATE_WRAPPER} test_script', env=env)
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+
+        env = os.environ.copy()
+        env.pop('FSLDIR')
+        run(f'{CREATE_WRAPPER} test_script', env=env)
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+
+        env = os.environ.copy()
+        env.pop('PREFIX')
+        run(f'{CREATE_WRAPPER} test_script', env=env)
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+
+        # FSLDIR invalid
+        env = os.environ.copy()
+        env['FSLDIR'] = '/some/non-existent/path'
+        run(f'{CREATE_WRAPPER} test_script', env=env)
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+
+        # FSLDIR != PREFIX
+        env = os.environ.copy()
+        env['FSLDIR'] = op.join(env['PREFIX'], 'other_fsl')
+        run(f'{CREATE_WRAPPER} test_script', env=env)
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+
+
+def test_create_python_wrapper():
+    """Test creation of a wrapper script for a python executable"""
+    with temp_fsldir() as (fsldir, wrapperdir):
+
+        script_path  = op.join(fsldir, 'bin', 'test_script')
+        wrapper_path = op.join(wrapperdir,    'test_script')
+
+        touch(script_path)
+        with open(script_path, 'wt') as f:
+            f.write('#!/usr/bin/env python\n')
+            f.write('print("hello")\n')
+
+        expect = tw.dedent(f"""
+        #!/usr/bin/env bash
+        {fsldir}/bin/python -I {script_path} "$@"
+        """).strip()
+
+        run(f'{CREATE_WRAPPER} test_script')
+
+        assert op.exists(wrapper_path)
+        with open(wrapper_path, 'rt') as f:
+            got = f.read().strip()
+
+        assert got == expect
+
+
+def test_create_other_wrapper():
+    """Test creation of a wrapper script for a non-python executable."""
+    with temp_fsldir() as (fsldir, wrapperdir):
+        script_path  = op.join(fsldir, 'bin', 'test_script')
+        wrapper_path = op.join(wrapperdir,    'test_script')
+
+        touch(script_path)
+        with open(op.join(fsldir, 'bin', 'test_script'), 'wt') as f:
+            f.write('#!/usr/bin/env bash\n')
+            f.write('echo "hello"\n')
+
+        expect = tw.dedent(f"""
+        #!/usr/bin/env bash
+        {script_path} "$@"
+        """).strip()
+
+        run(f'{CREATE_WRAPPER} test_script')
+
+        assert op.exists(wrapper_path)
+        with open(wrapper_path, 'rt') as f:
+            got = f.read().strip()
+
+        assert got == expect
+
+
+def test_permissions_preserved():
+    """Test that wrapper script has same permissions as wrapped script."""
+    with temp_fsldir() as (fsldir, wrapperdir):
+        perms        = [0o777, 0o755, 0o644, 0o600, 0o755, 0o700]
+        script_path  = op.join(fsldir, 'bin', 'test_script')
+        wrapper_path = op.join(wrapperdir,    'test_script')
+        touch(script_path)
+
+        for perm in perms:
+            os.chmod(script_path, perm)
+            run(f'{CREATE_WRAPPER} test_script')
+
+            stat = os.stat(wrapper_path)
+            assert (stat.st_mode & 0o777) == perm
+
+
+def test_create_remove_wrappers():
+    """Tests normal usage. """
+    with temp_fsldir() as (fsldir, wrapperdir):
+        touch(op.join(fsldir, 'bin', 'test_script1'))
+        touch(op.join(fsldir, 'bin', 'test_script2'))
+
+        run(f'{CREATE_WRAPPER} test_script1 test_script2')
+
+        assert op.exists(op.join(wrapperdir, 'test_script1'))
+        assert op.exists(op.join(wrapperdir, 'test_script2'))
+
+        run(f'{REMOVE_WRAPPER} test_script1 test_script2')
+
+        assert not op.exists(op.join(wrapperdir, 'test_script1'))
+        assert not op.exists(op.join(wrapperdir, 'test_script2'))
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..53c22aa
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,18 @@
+include:
+ - project: fsl/fsl-ci-rules
+   file:    .gitlab-ci.yml
+
+stages:
+ - test
+ - fsl-ci-pre
+ - fsl-ci-build
+ - fsl-ci-deploy
+
+test:
+  stage: test
+  image: python:3.7
+  tags:
+    - docker
+  script:
+    - pip install pytest
+    - pytest -v .ci
\ No newline at end of file
-- 
GitLab