From 4daa0a335063c7aa92e0cc95db93459dd4dc8777 Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Tue, 27 Nov 2018 20:08:04 -0500 Subject: [PATCH 1/5] Add test suite Simple tests so far: - test resolution for - auto - copy - hard - soft - test parsington with argument `1+3` --- jgo/jgo.py | 17 ++++--- setup.py | 2 + tests/test_parsington.py | 105 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 tests/test_parsington.py diff --git a/jgo/jgo.py b/jgo/jgo.py index 52e1ee1..5945302 100644 --- a/jgo/jgo.py +++ b/jgo/jgo.py @@ -187,7 +187,9 @@ def launch_java( jvm_args, main_class, *app_args, - additional_jars=[] + additional_jars=[], + stdout=None, + stderr=None ): java = executable_path('java') if not java: @@ -196,7 +198,7 @@ def launch_java( cp = classpath_separator().join([os.path.join(jar_dir, '*')] + additional_jars) _logger.debug("class path: %s", cp) jvm_args = tuple(arg for arg in jvm_args) if jvm_args else tuple() - return subprocess.run((java, '-cp', cp) + jvm_args + (main_class,) + app_args) + return subprocess.run((java, '-cp', cp) + jvm_args + (main_class,) + app_args, stdout=stdout, stderr=stderr) def run_and_combine_outputs(command, *args): return subprocess.check_output((command,) + args, stderr=subprocess.STDOUT) @@ -211,7 +213,7 @@ def find_endpoint(argv, shortcuts={}): indices.append(index) return -1 if len(indices) == 0 else indices[-1] -def jgo_main(argv=sys.argv[1:]): +def jgo_main(argv=sys.argv[1:], stdout=None, stderr=None): epilog=''' The endpoint should have one of the following formats: @@ -246,7 +248,7 @@ def jgo_main(argv=sys.argv[1:]): try: - run(parser, argv=argv) + return run(parser, argv=argv, stdout=stdout, stderr=stderr) except subprocess.CalledProcessError as e: _logger.error("Error in %s: %s", e.cmd, e) _logger.debug("Debug Trace:", exc_info=True) @@ -483,7 +485,7 @@ def resolve_dependencies( return primary_endpoint, workspace -def run(parser, argv=sys.argv[1:]): +def run(parser, argv=sys.argv[1:], stdout=None, stderr=None): config = default_config() if not '--ignore-jgorc' in argv: @@ -545,8 +547,7 @@ def run(parser, argv=sys.argv[1:]): try: with open(main_class_file, 'r') as f: main_class = f.readline() - launch_java(workspace, jvm_args, main_class, *program_args, additional_jars=args.additional_jars) - return + return launch_java(workspace, jvm_args, main_class, *program_args, additional_jars=args.additional_jars, stdout=stdout, stderr=stderr) except FileNotFoundError: pass @@ -573,7 +574,7 @@ def run(parser, argv=sys.argv[1:]): f.write(main_class) - launch_java(workspace, jvm_args, main_class, *program_args, additional_jars=args.additional_jars) + return launch_java(workspace, jvm_args, main_class, *program_args, additional_jars=args.additional_jars, stdout=stdout, stderr=stderr) diff --git a/setup.py b/setup.py index 6a08526..c974140 100644 --- a/setup.py +++ b/setup.py @@ -17,10 +17,12 @@ license='Public domain', url='https://github.com/scijava/jgo', packages=['jgo'], + test_suite='nose.collector', entry_points={ 'console_scripts': [ 'jgo=jgo.jgo:jgo_main' ] }, python_requires='>=3', + tests_require=['nose>=1.0'] ) diff --git a/tests/test_parsington.py b/tests/test_parsington.py new file mode 100644 index 0000000..04997ae --- /dev/null +++ b/tests/test_parsington.py @@ -0,0 +1,105 @@ +import glob +import io +import jgo +import os +import pathlib +import unittest +import shutil +import subprocess +import tempfile + +import logging +_logger = logging.getLogger(__name__) + + +IGNORE_JGORC = '--ignore-jgorc' +LINK_TYPE = '--link-type' +PARSINGTON_VERSION = '1.0.4' +PARSINGTON_ENDPOINT = 'org.scijava:parsington:{}'.format(PARSINGTON_VERSION) + +def run_parsington(cache_dir, link_type, parsington_args): + argv = (IGNORE_JGORC, LINK_TYPE, link_type, PARSINGTON_ENDPOINT) + parsington_args + os.environ[jgo.jgo.jgo_cache_dir_environment_variable()] = cache_dir + return jgo.jgo.jgo_main(argv=argv, stdout=subprocess.PIPE) + +def resolve_parsington(cache_dir, link_type, m2_repo): + return jgo.resolve_dependencies( + PARSINGTON_ENDPOINT, + m2_repo=m2_repo, + cache_dir=cache_dir, + link_type=link_type) + +class ParsingtonTest(unittest.TestCase): + + def test_resolve_hard(self): + tmp_dir = tempfile.mkdtemp(prefix='jgo-test-cache-dir') + m2_repo = os.path.join(str(pathlib.Path.home()), '.m2', 'repository') + try: + _, workspace = resolve_parsington(cache_dir=tmp_dir, link_type='hard', m2_repo=m2_repo) + jars = glob.glob(os.path.join(workspace, '*jar')) + self.assertEqual(len(jars), 1, 'Expected exactly one jar in workspace') + self.assertEqual(jars[0], os.path.join(workspace, 'parsington-%s.jar' % PARSINGTON_VERSION), 'Expected parsington jar') + self.assertFalse(os.path.islink(jars[0]), 'Expected hard link but found symbolic link.') + self.assertTrue(os.path.isfile(jars[0])) + self.assertGreaterEqual(os.stat(jars[0]).st_nlink, 2, 'Expected ref count of at least 2 for hard link.') + except OSError as e: + if e.errno == 18: + _logger.warning('Unable to cross-device hard link, skipping hard link test: %s', str(e)) + else: + raise e + finally: + shutil.rmtree(tmp_dir) + + def test_resolve_soft(self): + tmp_dir = tempfile.mkdtemp(prefix='jgo-test-cache-dir') + m2_repo = os.path.join(str(pathlib.Path.home()), '.m2', 'repository') + try: + _, workspace = resolve_parsington(cache_dir=tmp_dir, link_type='soft', m2_repo=m2_repo) + jars = glob.glob(os.path.join(workspace, '*jar')) + self.assertEqual(len(jars), 1, 'Expected exactly one jar in workspace') + self.assertEqual(jars[0], os.path.join(workspace, 'parsington-%s.jar' % PARSINGTON_VERSION), 'Expected parsington jar') + self.assertTrue(os.path.islink(jars[0]), 'Expected soft link.') + finally: + shutil.rmtree(tmp_dir) + + def test_resolve_copy(self): + tmp_dir = tempfile.mkdtemp(prefix='jgo-test-cache-dir') + m2_repo = os.path.join(str(pathlib.Path.home()), '.m2', 'repository') + try: + _, workspace = resolve_parsington(cache_dir=tmp_dir, link_type='copy', m2_repo=m2_repo) + jars = glob.glob(os.path.join(workspace, '*jar')) + self.assertEqual(len(jars), 1, 'Expected exactly one jar in workspace') + self.assertEqual(jars[0], os.path.join(workspace, 'parsington-%s.jar' % PARSINGTON_VERSION), 'Expected parsington jar') + self.assertFalse(os.path.islink(jars[0]), 'Expected copied file but found symbolic link.') + self.assertTrue(os.path.isfile(jars[0])) + self.assertEqual(os.stat(jars[0]).st_nlink, 1, 'Expected ref count of exactly 1 for copied file.') + finally: + shutil.rmtree(tmp_dir) + + def test_resolve_auto(self): + tmp_dir = tempfile.mkdtemp(prefix='jgo-test-cache-dir') + m2_repo = os.path.join(str(pathlib.Path.home()), '.m2', 'repository') + try: + _, workspace = resolve_parsington(cache_dir=tmp_dir, link_type='auto', m2_repo=m2_repo) + jars = glob.glob(os.path.join(workspace, '*jar')) + self.assertEqual(len(jars), 1, 'Expected exactly one jar in workspace') + self.assertEqual(jars[0], os.path.join(workspace, 'parsington-%s.jar' % PARSINGTON_VERSION), 'Expected parsington jar') + finally: + shutil.rmtree(tmp_dir) + + def test_run_jgo(self): + tmp_dir = tempfile.mkdtemp(prefix='jgo-test-cache-dir') + + try: + completed_process = run_parsington(cache_dir=tmp_dir, link_type='auto', parsington_args=('1+3',)) + self.assertEqual(completed_process.returncode, 0, 'Expected return code zero.') + self.assertEqual(completed_process.stdout.decode('ascii').strip(), str(1+3)) + finally: + shutil.rmtree(tmp_dir) + + +if __name__ == '__main__': + unittest.main() + + + From 13614e11b769a8aee747bdf3f1699be6383805f6 Mon Sep 17 00:00:00 2001 From: Curtis Rueden Date: Wed, 19 Dec 2018 13:46:05 -0600 Subject: [PATCH 2/5] Add initial Travis CI configuration --- .travis.yml | 14 ++++++++++++++ .travis/build.sh | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 .travis.yml create mode 100755 .travis/build.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0822380 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: python +jdk: oraclejdk8 +python: + - "3.6" + - "3.7" +branches: + only: + - master + - "/[0-9]+\\.[0-9]+\\.[0-9]+.*/" +install: true +script: ".travis/build.sh" +cache: + directories: + - "~/.m2/repository" diff --git a/.travis/build.sh b/.travis/build.sh new file mode 100755 index 0000000..3e921fd --- /dev/null +++ b/.travis/build.sh @@ -0,0 +1,2 @@ +python setup.py test +pip install . --user From a5cf1146728581bc06bbaa5448aaa1dc55794b3f Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Mon, 14 Jan 2019 13:47:33 -0500 Subject: [PATCH 3/5] Do not install into --user space in travis build script --- .travis/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/build.sh b/.travis/build.sh index 3e921fd..ebec77f 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -1,2 +1,2 @@ python setup.py test -pip install . --user +pip install . From 6ca45ac4c1965bd389ed947cd6b7dfb3c2128933 Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Mon, 14 Jan 2019 13:51:17 -0500 Subject: [PATCH 4/5] Use only python3.6 for travis testing 3.7 seems unavailable on travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0822380..d709909 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python jdk: oraclejdk8 python: - "3.6" - - "3.7" branches: only: - master From 0baa04ab3ddb56294af3358d06569226eedd8e76 Mon Sep 17 00:00:00 2001 From: Philipp Hanslovsky Date: Mon, 14 Jan 2019 14:06:50 -0500 Subject: [PATCH 5/5] Test jgo installation --- .travis/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis/build.sh b/.travis/build.sh index ebec77f..797c22f 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -1,2 +1,5 @@ python setup.py test pip install . +python -c 'import sys; sys.path.remove(""); import jgo' +which jgo +test "$(jgo org.scijava:parsington 1+3)" -eq 4