diff --git a/planemo/commands/cmd_lint.py b/planemo/commands/cmd_lint.py index d643ec936..f32ab12e7 100644 --- a/planemo/commands/cmd_lint.py +++ b/planemo/commands/cmd_lint.py @@ -10,7 +10,7 @@ @click.command('lint') -@options.optional_tools_arg(-1) +@options.optional_tools_arg(multiple=True) @options.report_level_option() @options.fail_level_option() @options.skip_option() diff --git a/planemo/commands/cmd_serve.py b/planemo/commands/cmd_serve.py index 1db1fbb90..07ac54615 100644 --- a/planemo/commands/cmd_serve.py +++ b/planemo/commands/cmd_serve.py @@ -6,19 +6,10 @@ @click.command('serve') -@options.optional_tools_arg() -@options.galaxy_root_option() -@options.galaxy_port_option() -@options.install_galaxy_option() -@options.no_cache_galaxy_option() -@options.no_cleanup_option() -@options.test_data_option() -@options.dependency_resolvers_option() -@options.job_config_option() -@options.tool_dependency_dir_option() -@options.brew_dependency_resolution() +@options.optional_tools_arg(multiple=True) +@options.galaxy_serve_options() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Launch a Galaxy instance with the specified tool in the tool panel. The Galaxy tool panel will include just the referenced tool or tools (by @@ -36,4 +27,4 @@ def cli(ctx, path, **kwds): proof yet so please careful and do not try this against production Galaxy instances. """ - galaxy_serve.serve(ctx, path, **kwds) + galaxy_serve.serve(ctx, paths, **kwds) diff --git a/planemo/commands/cmd_shed_create.py b/planemo/commands/cmd_shed_create.py index 3c1a6de22..867c03d78 100644 --- a/planemo/commands/cmd_shed_create.py +++ b/planemo/commands/cmd_shed_create.py @@ -11,17 +11,9 @@ @click.command("shed_create") -@options.shed_project_arg() -@options.shed_owner_option() -@options.shed_name_option() -@options.shed_target_option() -@options.shed_key_option() -@options.shed_email_option() -@options.shed_password_option() -@options.recursive_shed_option() -@options.shed_fail_fast_option() +@options.shed_publish_options() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Create a repository in a Galaxy Tool Shed from a ``.shed.yml`` file. """ tsi = shed.tool_shed_client(ctx, **kwds) @@ -37,5 +29,5 @@ def create(realized_reposiotry): else: return 1 - exit_code = shed.for_each_repository(ctx, create, path, **kwds) + exit_code = shed.for_each_repository(ctx, create, paths, **kwds) sys.exit(exit_code) diff --git a/planemo/commands/cmd_shed_diff.py b/planemo/commands/cmd_shed_diff.py index 0110205fb..dd1720e35 100644 --- a/planemo/commands/cmd_shed_diff.py +++ b/planemo/commands/cmd_shed_diff.py @@ -10,11 +10,7 @@ @click.command("shed_diff") -@options.shed_project_arg() -@options.shed_owner_option() -@options.shed_name_option() -@options.shed_target_option() -@options.shed_fail_fast_option() +@options.shed_read_options() @click.option( "-o", "--output", type=click.Path(file_okay=True, resolve_path=True), @@ -34,9 +30,8 @@ help="Do not attempt smart diff of XML to filter out attributes " "populated by the Tool Shed.", ) -@options.recursive_shed_option() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Produce diff between local repository and Tool Shed contents. By default, this will produce a diff between this repository and what @@ -58,5 +53,5 @@ def cli(ctx, path, **kwds): def diff(realized_repository): return shed.diff_repo(ctx, realized_repository, **kwds) - exit_code = shed.for_each_repository(ctx, diff, path, **kwds) + exit_code = shed.for_each_repository(ctx, diff, paths, **kwds) sys.exit(exit_code) diff --git a/planemo/commands/cmd_shed_download.py b/planemo/commands/cmd_shed_download.py index 05444ecf1..6fd74da54 100644 --- a/planemo/commands/cmd_shed_download.py +++ b/planemo/commands/cmd_shed_download.py @@ -16,7 +16,7 @@ @click.command("shed_download") -@options.shed_project_arg() +@options.shed_read_options() @click.option( '--destination', default="shed_download.tar.gz", @@ -28,13 +28,8 @@ "created as shed_download_.tar.gz by default for instance, " "simpler repositories will just be downloaded to the specified file." ) -@options.shed_owner_option() -@options.shed_name_option() -@options.shed_target_option() -@options.recursive_shed_option() -@options.shed_fail_fast_option() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Download a tool repository as a tarball from the tool shed and extract to the specified directory. """ @@ -43,5 +38,5 @@ def cli(ctx, path, **kwds): def download(realized_repository): return shed.download_tarball(ctx, tsi, realized_repository, **kwds) - exit_code = shed.for_each_repository(ctx, download, path, **kwds) + exit_code = shed.for_each_repository(ctx, download, paths, **kwds) sys.exit(exit_code) diff --git a/planemo/commands/cmd_shed_init.py b/planemo/commands/cmd_shed_init.py index 3cb5d2eb1..491af4c48 100644 --- a/planemo/commands/cmd_shed_init.py +++ b/planemo/commands/cmd_shed_init.py @@ -37,8 +37,7 @@ help='Specify repository category for .shed.yml (may specify multiple).', type=click.Choice(shed.CURRENT_CATEGORIES) ) -@options.shed_owner_option() -@options.shed_name_option() +@options.shed_repo_options() @options.force_option() @pass_context def cli(ctx, path, **kwds): diff --git a/planemo/commands/cmd_shed_lint.py b/planemo/commands/cmd_shed_lint.py index 85708f33b..af14b03a0 100644 --- a/planemo/commands/cmd_shed_lint.py +++ b/planemo/commands/cmd_shed_lint.py @@ -8,7 +8,7 @@ @click.command('shed_lint') -@options.shed_project_arg() +@options.shed_realization_options() @options.report_level_option() @options.fail_level_option() @options.click.option( @@ -18,15 +18,13 @@ help=("Lint tools discovered in the process of linting repositories.") ) @options.lint_xsd_option() -@options.recursive_shed_option() -@options.shed_fail_fast_option() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Check a Tool Shed repository for common problems. """ def lint(realized_repository): return shed_lint.lint_repository(ctx, realized_repository, **kwds) kwds["fail_on_missing"] = False - exit_code = shed.for_each_repository(ctx, lint, path, **kwds) + exit_code = shed.for_each_repository(ctx, lint, paths, **kwds) sys.exit(exit_code) diff --git a/planemo/commands/cmd_shed_serve.py b/planemo/commands/cmd_shed_serve.py new file mode 100644 index 000000000..6308a6983 --- /dev/null +++ b/planemo/commands/cmd_shed_serve.py @@ -0,0 +1,30 @@ +""" +""" +import time +import click + +from planemo.cli import pass_context +from planemo import options +from planemo import galaxy_serve +from planemo import shed +from planemo import io + + +@click.command("shed_serve") +@options.shed_read_options() +@options.galaxy_run_options() +@click.option( + "--skip_dependencies", + is_flag=True, + help="Do not install shed dependencies as part of repository installation." +) +@pass_context +def cli(ctx, paths, **kwds): + """ Serve a transient Galaxy instance after installing repositories + from a remote Tool Shed. + """ + install_args_list = shed.install_arg_lists(ctx, paths, **kwds) + with galaxy_serve.shed_serve(ctx, install_args_list, **kwds) as config: + gx_url = "http://localhost:%d/" % config.port + io.info("Galaxy running with tools installed at %s" % gx_url) + time.sleep(1000000) diff --git a/planemo/commands/cmd_shed_test.py b/planemo/commands/cmd_shed_test.py new file mode 100644 index 000000000..96d9dc6c1 --- /dev/null +++ b/planemo/commands/cmd_shed_test.py @@ -0,0 +1,51 @@ +""" +""" +import socket +import sys + +import click + +from planemo.cli import pass_context +from planemo import options +from planemo import galaxy_serve +from planemo import shed +from planemo import galaxy_test + + +@click.command("shed_test") +@options.shed_read_options() +@options.galaxy_target_options() +@options.test_options() +@click.option( + "--skip_dependencies", + is_flag=True, + help="Do not install shed dependencies as part of repository installation." +) +@pass_context +def cli(ctx, paths, **kwds): + """ Serve a transient Galaxy instance after installing repositories + from a remote Tool Shed. + """ + galaxy_test.process_defaults(ctx, kwds) + install_args_list = shed.install_arg_lists(ctx, paths, **kwds) + port = get_free_port() + kwds["port"] = port + return_code = 1 + with galaxy_serve.shed_serve(ctx, install_args_list, **kwds) as config: + config.kill() + return_code = galaxy_test.run_in_config( + ctx, + config, + installed=True, + **kwds + ) + if return_code: + sys.exit(return_code) + + +def get_free_port(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('localhost', 0)) + port = sock.getsockname()[1] + sock.close() + return port diff --git a/planemo/commands/cmd_shed_upload.py b/planemo/commands/cmd_shed_upload.py index fdec2517e..373f0da1b 100644 --- a/planemo/commands/cmd_shed_upload.py +++ b/planemo/commands/cmd_shed_upload.py @@ -18,18 +18,12 @@ @click.command("shed_upload") -@options.shed_project_arg() +@options.shed_publish_options() @click.option( '-m', '--message', help="Commit message for tool shed upload." ) -@options.shed_owner_option() -@options.shed_name_option() -@options.shed_target_option() -@options.shed_key_option() -@options.shed_email_option() -@options.shed_password_option() @click.option( '--tar_only', is_flag=True, @@ -56,14 +50,12 @@ "'difference' (only attributes populated by the shed would would " "be updated.)" ) -@options.recursive_shed_option() -@options.shed_fail_fast_option() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Handle possible recursion through paths for uploading files to a toolshed """ def upload(realized_repository): return shed.upload_repository(ctx, realized_repository, **kwds) - exit_code = shed.for_each_repository(ctx, upload, path, **kwds) + exit_code = shed.for_each_repository(ctx, upload, paths, **kwds) sys.exit(exit_code) diff --git a/planemo/commands/cmd_test.py b/planemo/commands/cmd_test.py index e59d676b6..d0eb7360a 100644 --- a/planemo/commands/cmd_test.py +++ b/planemo/commands/cmd_test.py @@ -1,87 +1,19 @@ -import os import sys import click from planemo.cli import pass_context -from planemo.io import info, warn from planemo import options from planemo import galaxy_config -from planemo import galaxy_run -from planemo import galaxy_test -from planemo.reports import build_report - -from galaxy.tools.deps.commands import shell - -XUNIT_UPGRADE_MESSAGE = ("This version of Galaxy does not support xUnit - " - "please update to newest development brach.") -NO_XUNIT_MESSAGE = ("Cannot locate xUnit report option for tests - update " - "Galaxy for more detailed breakdown.") -NO_JSON_MESSAGE = ("Cannot locate json report option for tests - update " - "Galaxy for more detailed breakdown.") -NO_TESTS_MESSAGE = "No tests were executed - see Galaxy output for details." -ALL_TESTS_PASSED_MESSAGE = "All %d test(s) executed passed." -PROBLEM_COUNT_MESSAGE = ("There were problems with %d test(s) - out of %d " - "test(s) executed. See %s for detailed breakdown.") -GENERIC_PROBLEMS_MESSAGE = ("One or more tests failed. See %s for detailed " - "breakdown.") -GENERIC_TESTS_PASSED_MESSAGE = "No failing tests encountered." - -RUN_TESTS_CMD = ( - "sh run_tests.sh --report_file %s %s %s " - " functional.test_toolbox" +from planemo.galaxy_test import ( + run_in_config, + process_defaults, ) -OUTPUT_DFEAULTS = { - "output": "tool_test_output.html", - "output_json": "tool_test_output.json", - "output_xunit": None, -} - @click.command('test') -@options.optional_tools_arg() -@click.option( - "--test_output", - type=click.Path(file_okay=True, resolve_path=True), - help=("Output test report (HTML - for humans) defaults to " - "tool_test_output.html."), - default=None, -) -@click.option( - "--test_output_xunit", - type=click.Path(file_okay=True, resolve_path=True), - help="Output test report (xUnit style - for computers).", - default=None, -) -@click.option( - "--test_output_json", - type=click.Path(file_okay=True, resolve_path=True), - help=("Output test report (planemo json) defaults to " - "tool_test_output.json."), - default=None, -) -@click.option( - "--job_output_files", - type=click.Path(file_okay=False, resolve_path=True), - help="Write job outputs to specified directory.", - default=None, -) -@click.option( - "--update_test_data", - is_flag=True, - help="Update test-data directory with job outputs (normally written to " - "directory --job_output_files if specified.)" -) -@click.option( - "--summary", - type=click.Choice(['none', 'minimal', 'compact']), - default="minimal", - help=("Summary style printed to planemo's standard output (see output " - "reports for more complete summary). Set to 'none' to disable " - "completely.") -) +@options.optional_tools_arg(multiple=True) @click.option( "--failed", is_flag=True, @@ -91,19 +23,11 @@ "previously.", default=False, ) -@options.galaxy_root_option() -@options.install_galaxy_option() -@options.no_cache_galaxy_option() -@options.no_cleanup_option() -@options.test_data_option() -@options.tool_data_table_option() -@options.dependency_resolvers_option() -@options.job_config_option() -@options.tool_dependency_dir_option() -@options.brew_dependency_resolution() -@options.shed_dependency_resolution() +@options.galaxy_target_options() +@options.galaxy_config_options() +@options.test_options() @pass_context -def cli(ctx, path, **kwds): +def cli(ctx, paths, **kwds): """Run the tests in the specified tool tests in a Galaxy instance. All referenced tools (by default all the tools in the current working @@ -131,202 +55,10 @@ def cli(ctx, path, **kwds): against that same Galaxy root - but this may not be bullet proof yet so please careful and do not try this against production Galaxy instances. """ - for name, default in OUTPUT_DFEAULTS.items(): - __populate_default_output(ctx, name, kwds, default) + process_defaults(ctx, kwds) kwds["for_tests"] = True - with galaxy_config.galaxy_config(ctx, path, **kwds) as config: - config_directory = config.config_directory - html_report_file = kwds["test_output"] - - job_output_files = kwds.get("job_output_files", None) - if job_output_files is None: - job_output_files = os.path.join(config_directory, "jobfiles") - - xunit_supported, xunit_report_file = __xunit_state(kwds, config) - structured_report_file = __structured_report_file(kwds, config) - - info("Testing using galaxy_root %s", config.galaxy_root) - # TODO: Allow running dockerized Galaxy here instead. - server_ini = os.path.join(config_directory, "galaxy.ini") - config.env["GALAXY_CONFIG_FILE"] = server_ini - config.env["GALAXY_TEST_VERBOSE_ERRORS"] = "true" - config.env["GALAXY_TEST_SAVE"] = job_output_files - - cd_to_galaxy_command = "cd %s" % config.galaxy_root - test_cmd = galaxy_test.GalaxyTestCommand( - html_report_file, - xunit_report_file, - structured_report_file, - failed=kwds["failed"], - ).build() - cmd = "; ".join([ - cd_to_galaxy_command, - galaxy_run.ACTIVATE_COMMAND, # TODO: this should be moved to - # run_tests.sh to match run.sh. - test_cmd, - ]) - action = "Testing tools" - return_code = galaxy_run.run_galaxy_command( - ctx, - cmd, - config.env, - action - ) - if kwds.get('update_test_data', False): - update_cp_args = (job_output_files, config.test_data_dir) - shell('cp -r "%s"/* "%s"' % update_cp_args) - - if xunit_report_file and (not os.path.exists(xunit_report_file)): - warn(NO_XUNIT_MESSAGE) - xunit_report_file = None - - test_results = galaxy_test.GalaxyTestResults( - structured_report_file, - xunit_report_file, - html_report_file, - return_code, - ) - - try: - test_data = test_results.structured_data - new_report = build_report.build_report(test_data) - open(test_results.output_html_path, "w").write(new_report) - except Exception: - pass - - __handle_summary( - test_results, - **kwds - ) - - if return_code: - sys.exit(1) - - -def __populate_default_output(ctx, type, kwds, default): - kwd_key = "test_%s" % type - kwd_value = kwds.get(kwd_key, None) - if kwd_value is None: - global_config = ctx.global_config - global_config_key = "default_test_%s" % type - if global_config_key in global_config: - default_value = global_config[global_config_key] - else: - default_value = default - - if default_value: - default_value = os.path.abspath(default_value) - kwds[kwd_key] = default_value - - -def __handle_summary( - test_results, - **kwds -): - summary_style = kwds.get("summary") - if summary_style == "none": - return - - if test_results.has_details: - __summarize_tests_full( - test_results, - **kwds - ) - else: - if test_results.exit_code: - warn(GENERIC_PROBLEMS_MESSAGE % test_results.output_html_path) - else: - info(GENERIC_TESTS_PASSED_MESSAGE) - - -def __summarize_tests_full( - test_results, - **kwds -): - num_tests = test_results.num_tests - num_problems = test_results.num_problems - - if num_tests == 0: - warn(NO_TESTS_MESSAGE) - return - - if num_problems == 0: - info(ALL_TESTS_PASSED_MESSAGE % num_tests) - - if num_problems: - html_report_file = test_results.output_html_path - message_args = (num_problems, num_tests, html_report_file) - message = PROBLEM_COUNT_MESSAGE % message_args - warn(message) - - for testcase_el in test_results.xunit_testcase_elements: - structured_data_tests = test_results.structured_data_tests - __summarize_test_case(structured_data_tests, testcase_el, **kwds) - - -def __summarize_test_case(structured_data, testcase_el, **kwds): - summary_style = kwds.get("summary") - test_id = galaxy_test.case_id(testcase_el) - passed = len(list(testcase_el)) == 0 - if not passed: - state = click.style("failed", bold=True, fg='red') - else: - state = click.style("passed", bold=True, fg='green') - click.echo(test_id.label + ": " + state) - if summary_style != "minimal": - __print_command_line(structured_data, test_id) - - -def __print_command_line(structured_data, test_id): - try: - test = [d for d in structured_data if d["id"] == test_id.id][0]["data"] - except (KeyError, IndexError): - # Failed to find structured data for this test - likely targetting - # and older Galaxy version. - return - - execution_problem = test.get("execution_problem", None) - if execution_problem: - click.echo("| command: *could not execute job, no command generated* ") - return - - try: - command = test["job"]["command_line"] - except (KeyError, IndexError): - click.echo("| command: *failed to determine command for job* ") - return - - click.echo("| command: %s" % command) - - -def __xunit_state(kwds, config): - xunit_supported = True - if shell("grep -q xunit '%s'/run_tests.sh" % config.galaxy_root): - xunit_supported = False - - xunit_report_file = kwds.get("test_output_xunit", None) - if xunit_report_file is None and xunit_supported: - xunit_report_file = os.path.join(config.config_directory, "xunit.xml") - elif xunit_report_file is not None and not xunit_supported: - warn(XUNIT_UPGRADE_MESSAGE) - xunit_report_file = None - - return xunit_supported, xunit_report_file - - -def __structured_report_file(kwds, config): - structured_data_supported = True - if shell("grep -q structured_data '%s'/run_tests.sh" % config.galaxy_root): - structured_data_supported = False - - structured_report_file = None - structured_report_file = kwds.get("test_output_json", None) - if structured_report_file is None and structured_data_supported: - conf_dir = config.config_directory - structured_report_file = os.path.join(conf_dir, "structured_data.json") - elif structured_report_file is not None and not structured_data_supported: - warn(NO_JSON_MESSAGE) - structured_report_file = None - - return structured_report_file + with galaxy_config.galaxy_config(ctx, paths, **kwds) as config: + return_value = run_in_config(ctx, config, **kwds) + if return_value: + sys.exit(return_value) diff --git a/planemo/commands/cmd_tool_factory.py b/planemo/commands/cmd_tool_factory.py index 47dc4aee5..781cafb6d 100644 --- a/planemo/commands/cmd_tool_factory.py +++ b/planemo/commands/cmd_tool_factory.py @@ -7,16 +7,7 @@ @click.command('tool_factory') -@options.galaxy_root_option() -@options.galaxy_port_option() -@options.install_galaxy_option() -@options.no_cache_galaxy_option() -@options.no_cleanup_option() -@options.test_data_option() -@options.dependency_resolvers_option() -@options.job_config_option() -@options.tool_dependency_dir_option() -@options.brew_dependency_resolution() +@options.galaxy_serve_options() @pass_context def cli(ctx, **kwds): """(Experimental) Launch Galaxy with the Tool Factory 2 available. @@ -26,7 +17,6 @@ def cli(ctx, **kwds): et. al. (10.1093/bioinformatics/bts573). Available at http://www.ncbi.nlm.nih.gov/pubmed/23024011. """ - # TODO: de-duplicate option handling with cmd_serve. mod_dir = os.path.dirname(__file__) tf_dir = os.path.join(mod_dir, '..', '..', 'planemo_ext', 'tool_factory_2') - galaxy_serve.serve(ctx, os.path.abspath(tf_dir), **kwds) + galaxy_serve.serve(ctx, [os.path.abspath(tf_dir)], **kwds) diff --git a/planemo/galaxy_config.py b/planemo/galaxy_config.py index 08c4095e4..0b6d51c63 100644 --- a/planemo/galaxy_config.py +++ b/planemo/galaxy_config.py @@ -5,6 +5,7 @@ import os import random import shutil +import time from six.moves.urllib.request import urlopen from six import iteritems from string import Template @@ -92,10 +93,10 @@ @contextlib.contextmanager -def galaxy_config(ctx, tool_path, for_tests=False, **kwds): - test_data_dir = _find_test_data(tool_path, **kwds) +def galaxy_config(ctx, tool_paths, for_tests=False, **kwds): + test_data_dir = _find_test_data(tool_paths, **kwds) tool_data_table = _find_tool_data_table( - tool_path, + tool_paths, test_data_dir=test_data_dir, **kwds ) @@ -121,14 +122,15 @@ def config_join(*args): _handle_dependency_resolution(config_directory, kwds) _handle_job_metrics(config_directory, kwds) - tool_definition = _tool_conf_entry_for(tool_path) + tool_definition = _tool_conf_entry_for(tool_paths) empty_tool_conf = config_join("empty_tool_conf.xml") - shed_tool_conf = config_join("shed_tool_conf.xml") + shed_tool_conf = _shed_tool_conf(install_galaxy, config_directory) tool_conf = config_join("tool_conf.xml") database_location = config_join("galaxy.sqlite") shed_tools_path = config_join("shed_tools") preseeded_database = True master_api_key = kwds.get("master_api_key", "test_key") + dependency_dir = os.path.join(config_directory, "deps") try: _download_database_template( @@ -151,7 +153,7 @@ def config_join(*args): temp_directory=config_directory, shed_tools_path=shed_tools_path, database_location=database_location, - tool_definition=tool_definition % tool_path, + tool_definition=tool_definition, tool_conf=tool_conf, debug=kwds.get("debug", "true"), master_api_key=master_api_key, @@ -160,6 +162,7 @@ def config_join(*args): ) tool_config_file = "%s,%s" % (tool_conf, shed_tool_conf) properties = dict( + tool_dependency_dir=dependency_dir, file_path="${temp_directory}/files", new_file_path="${temp_directory}/tmp", tool_config_file=tool_config_file, @@ -208,6 +211,7 @@ def config_join(*args): if install_galaxy: _build_eggs_cache(ctx, env, kwds) _build_test_env(properties, env) + env['GALAXY_TEST_SHED_TOOL_CONF'] = shed_tool_conf # No need to download twice - would GALAXY_TEST_DATABASE_CONNECTION # work? @@ -277,6 +281,50 @@ def gi(self): key=self.master_api_key ) + def install_repo(self, *args, **kwds): + self.tool_shed_client.install_repository_revision( + *args, **kwds + ) + + @property + def tool_shed_client(self): + return self.gi.toolShed + + def wait_for_all_installed(self): + def status_ready(repo): + status = repo["status"] + if status in ["Installing", "New"]: + return False + if status == "Installed": + return True + raise Exception("Error installing repo status is %s" % status) + + def not_ready(): + repos = self.tool_shed_client.get_repositories() + return not all(map(status_ready, repos)) + + self._wait_for(not_ready) + + # Taken from Galaxy's twilltestcase. + def _wait_for(self, func, **kwd): + sleep_amount = 0.2 + slept = 0 + walltime_exceeded = 1086400 + while slept <= walltime_exceeded: + result = func() + if result: + time.sleep(sleep_amount) + slept += sleep_amount + sleep_amount *= 1.25 + if slept + sleep_amount > walltime_exceeded: + sleep_amount = walltime_exceeded - slept + else: + break + assert slept < walltime_exceeded, "Action taking too long." + + def cleanup(self): + shutil.rmtree(self.config_directory) + def _download_database_template(galaxy_root, database_location, latest=False): if latest: @@ -333,7 +381,11 @@ def _find_galaxy_root(ctx, **kwds): raise Exception(FAILED_TO_FIND_GALAXY_EXCEPTION) -def _find_test_data(path, **kwds): +def _find_test_data(tool_paths, **kwds): + path = "." + if len(tool_paths) > 0: + path = tool_paths[0] + # Find test data directory associated with path. test_data = kwds.get("test_data", None) if test_data: @@ -346,7 +398,11 @@ def _find_test_data(path, **kwds): return None -def _find_tool_data_table(path, test_data_dir, **kwds): +def _find_tool_data_table(tool_paths, test_data_dir, **kwds): + path = "." + if len(tool_paths) > 0: + path = tool_paths[0] + tool_data_table = kwds.get("tool_data_table", None) if tool_data_table: return os.path.abspath(tool_data_table) @@ -375,12 +431,22 @@ def _search_tool_path_for(path, target, extra_paths=[]): return None -def _tool_conf_entry_for(tool_path): - if os.path.isdir(tool_path): - tool_definition = '''''' +def _tool_conf_entry_for(tool_paths): + tool_definitions = "" + for tool_path in tool_paths: + if os.path.isdir(tool_path): + tool_definitions += '''''' % tool_path + else: + tool_definitions += '''''' % tool_path + return tool_definitions + + +def _shed_tool_conf(install_galaxy, config_directory): + if install_galaxy: + config_dir = os.path.join(config_directory, "galaxy-dev", "config") else: - tool_definition = '''''' - return tool_definition + config_dir = config_directory + return os.path.join(config_dir, "shed_tool_conf.xml") def _install_galaxy_if_needed(ctx, config_directory, kwds): @@ -455,7 +521,6 @@ def _build_test_env(properties, env): # https://bitbucket.org/galaxy/galaxy-central/commits/d7dd1f9 test_property_variants = { 'GALAXY_TEST_MIGRATED_TOOL_CONF': 'migrated_tools_config', - 'GALAXY_TEST_SHED_TOOL_CONF': 'migrated_tools_config', # Hack 'GALAXY_TEST_TOOL_CONF': 'tool_config_file', 'GALAXY_TEST_FILE_DIR': 'test_data_dir', 'GALAXY_TOOL_DEPENDENCY_DIR': 'tool_dependency_dir', @@ -492,8 +557,6 @@ def _handle_dependency_resolution(config_directory, kwds): ) conf_contents = STOCK_DEPENDENCY_RESOLUTION_STRATEGIES[key] open(resolvers_conf, "w").write(conf_contents) - dependency_dir = os.path.join("config_directory", "deps") - kwds["tool_dependency_dir"] = dependency_dir kwds["dependency_resolvers_config_file"] = resolvers_conf diff --git a/planemo/galaxy_serve.py b/planemo/galaxy_serve.py index b2af0f91b..abbe7551d 100644 --- a/planemo/galaxy_serve.py +++ b/planemo/galaxy_serve.py @@ -1,10 +1,12 @@ +import contextlib import os from planemo import galaxy_config from planemo import galaxy_run +from planemo import io -def serve(ctx, path, **kwds): +def serve(ctx, paths, **kwds): # TODO: Preceate a user. # TODO: Setup an admin user. # TODO: Pass through more parameters. @@ -13,7 +15,7 @@ def serve(ctx, path, **kwds): if daemon: kwds["no_cleanup"] = True - with galaxy_config.galaxy_config(ctx, path, **kwds) as config: + with galaxy_config.galaxy_config(ctx, paths, **kwds) as config: # TODO: Allow running dockerized Galaxy here instead. run_script = os.path.join(config.galaxy_root, "run.sh") if daemon: @@ -35,3 +37,24 @@ def serve(ctx, path, **kwds): action, ) return config + + +@contextlib.contextmanager +def shed_serve(ctx, install_args_list, **kwds): + config = serve(ctx, [], daemon=True, **kwds) + install_deps = not kwds.get("skip_dependencies", False) + try: + io.info("Installing repositories - this may take some time...") + for install_args in install_args_list: + install_args["install_tool_dependencies"] = install_deps + install_args["install_repository_dependencies"] = True + install_args["new_tool_panel_section_label"] = "Shed Installs" + config.install_repo( + **install_args + ) + config.wait_for_all_installed() + yield config + finally: + config.kill() + if not kwds.get("no_cleanup", False): + config.cleanup() diff --git a/planemo/galaxy_test/__init__.py b/planemo/galaxy_test/__init__.py new file mode 100644 index 000000000..fb7bb7478 --- /dev/null +++ b/planemo/galaxy_test/__init__.py @@ -0,0 +1,4 @@ +from .actions import run_in_config +from .options import process_defaults + +__all__ = ["run_in_config", "process_defaults"] diff --git a/planemo/galaxy_test/actions.py b/planemo/galaxy_test/actions.py new file mode 100644 index 000000000..c979f0c98 --- /dev/null +++ b/planemo/galaxy_test/actions.py @@ -0,0 +1,206 @@ +import os + +import click + +from . import structures as test_structures +from planemo.io import info, warn +from planemo import galaxy_run +from planemo.reports import build_report + + +from galaxy.tools.deps.commands import shell + +XUNIT_UPGRADE_MESSAGE = ("This version of Galaxy does not support xUnit - " + "please update to newest development brach.") +NO_XUNIT_MESSAGE = ("Cannot locate xUnit report option for tests - update " + "Galaxy for more detailed breakdown.") +NO_JSON_MESSAGE = ("Cannot locate json report option for tests - update " + "Galaxy for more detailed breakdown.") +NO_TESTS_MESSAGE = "No tests were executed - see Galaxy output for details." +ALL_TESTS_PASSED_MESSAGE = "All %d test(s) executed passed." +PROBLEM_COUNT_MESSAGE = ("There were problems with %d test(s) - out of %d " + "test(s) executed. See %s for detailed breakdown.") +GENERIC_PROBLEMS_MESSAGE = ("One or more tests failed. See %s for detailed " + "breakdown.") +GENERIC_TESTS_PASSED_MESSAGE = "No failing tests encountered." + + +def run_in_config(ctx, config, **kwds): + config_directory = config.config_directory + html_report_file = kwds["test_output"] + + job_output_files = kwds.get("job_output_files", None) + if job_output_files is None: + job_output_files = os.path.join(config_directory, "jobfiles") + + xunit_supported, xunit_report_file = __xunit_state(kwds, config) + structured_report_file = __structured_report_file(kwds, config) + + info("Testing using galaxy_root %s", config.galaxy_root) + # TODO: Allow running dockerized Galaxy here instead. + server_ini = os.path.join(config_directory, "galaxy.ini") + config.env["GALAXY_CONFIG_FILE"] = server_ini + config.env["GALAXY_TEST_VERBOSE_ERRORS"] = "true" + config.env["GALAXY_TEST_SAVE"] = job_output_files + + cd_to_galaxy_command = "cd %s" % config.galaxy_root + test_cmd = test_structures.GalaxyTestCommand( + html_report_file, + xunit_report_file, + structured_report_file, + failed=kwds.get("failed", False), + installed=kwds.get("installed", False), + ).build() + cmd = "; ".join([ + cd_to_galaxy_command, + galaxy_run.ACTIVATE_COMMAND, # TODO: this should be moved to + # run_tests.sh to match run.sh. + test_cmd, + ]) + action = "Testing tools" + return_code = galaxy_run.run_galaxy_command( + ctx, + cmd, + config.env, + action + ) + if kwds.get('update_test_data', False): + update_cp_args = (job_output_files, config.test_data_dir) + shell('cp -r "%s"/* "%s"' % update_cp_args) + + if xunit_report_file and (not os.path.exists(xunit_report_file)): + warn(NO_XUNIT_MESSAGE) + xunit_report_file = None + + test_results = test_structures.GalaxyTestResults( + structured_report_file, + xunit_report_file, + html_report_file, + return_code, + ) + + try: + test_data = test_results.structured_data + new_report = build_report.build_report(test_data) + open(test_results.output_html_path, "w").write(new_report) + except Exception: + pass + + __handle_summary( + test_results, + **kwds + ) + + return return_code + + +def __handle_summary( + test_results, + **kwds +): + summary_style = kwds.get("summary") + if summary_style == "none": + return + + if test_results.has_details: + __summarize_tests_full( + test_results, + **kwds + ) + else: + if test_results.exit_code: + warn(GENERIC_PROBLEMS_MESSAGE % test_results.output_html_path) + else: + info(GENERIC_TESTS_PASSED_MESSAGE) + + +def __summarize_tests_full( + test_results, + **kwds +): + num_tests = test_results.num_tests + num_problems = test_results.num_problems + + if num_tests == 0: + warn(NO_TESTS_MESSAGE) + return + + if num_problems == 0: + info(ALL_TESTS_PASSED_MESSAGE % num_tests) + + if num_problems: + html_report_file = test_results.output_html_path + message_args = (num_problems, num_tests, html_report_file) + message = PROBLEM_COUNT_MESSAGE % message_args + warn(message) + + for testcase_el in test_results.xunit_testcase_elements: + structured_data_tests = test_results.structured_data_tests + __summarize_test_case(structured_data_tests, testcase_el, **kwds) + + +def __summarize_test_case(structured_data, testcase_el, **kwds): + summary_style = kwds.get("summary") + test_id = test_structures.case_id(testcase_el) + passed = len(list(testcase_el)) == 0 + if not passed: + state = click.style("failed", bold=True, fg='red') + else: + state = click.style("passed", bold=True, fg='green') + click.echo(test_id.label + ": " + state) + if summary_style != "minimal": + __print_command_line(structured_data, test_id) + + +def __print_command_line(structured_data, test_id): + try: + test = [d for d in structured_data if d["id"] == test_id.id][0]["data"] + except (KeyError, IndexError): + # Failed to find structured data for this test - likely targetting + # and older Galaxy version. + return + + execution_problem = test.get("execution_problem", None) + if execution_problem: + click.echo("| command: *could not execute job, no command generated* ") + return + + try: + command = test["job"]["command_line"] + except (KeyError, IndexError): + click.echo("| command: *failed to determine command for job* ") + return + + click.echo("| command: %s" % command) + + +def __xunit_state(kwds, config): + xunit_supported = True + if shell("grep -q xunit '%s'/run_tests.sh" % config.galaxy_root): + xunit_supported = False + + xunit_report_file = kwds.get("test_output_xunit", None) + if xunit_report_file is None and xunit_supported: + xunit_report_file = os.path.join(config.config_directory, "xunit.xml") + elif xunit_report_file is not None and not xunit_supported: + warn(XUNIT_UPGRADE_MESSAGE) + xunit_report_file = None + + return xunit_supported, xunit_report_file + + +def __structured_report_file(kwds, config): + structured_data_supported = True + if shell("grep -q structured_data '%s'/run_tests.sh" % config.galaxy_root): + structured_data_supported = False + + structured_report_file = None + structured_report_file = kwds.get("test_output_json", None) + if structured_report_file is None and structured_data_supported: + conf_dir = config.config_directory + structured_report_file = os.path.join(conf_dir, "structured_data.json") + elif structured_report_file is not None and not structured_data_supported: + warn(NO_JSON_MESSAGE) + structured_report_file = None + + return structured_report_file diff --git a/planemo/galaxy_test/options.py b/planemo/galaxy_test/options.py new file mode 100644 index 000000000..c04c0f8fd --- /dev/null +++ b/planemo/galaxy_test/options.py @@ -0,0 +1,28 @@ +import os + +OUTPUT_DFEAULTS = { + "output": "tool_test_output.html", + "output_json": "tool_test_output.json", + "output_xunit": None, +} + + +def process_defaults(ctx, kwds): + for name, default in OUTPUT_DFEAULTS.items(): + _populate_default_output(ctx, name, kwds, default) + + +def _populate_default_output(ctx, type, kwds, default): + kwd_key = "test_%s" % type + kwd_value = kwds.get(kwd_key, None) + if kwd_value is None: + global_config = ctx.global_config + global_config_key = "default_test_%s" % type + if global_config_key in global_config: + default_value = global_config[global_config_key] + else: + default_value = default + + if default_value: + default_value = os.path.abspath(default_value) + kwds[kwd_key] = default_value diff --git a/planemo/galaxy_test.py b/planemo/galaxy_test/structures.py similarity index 95% rename from planemo/galaxy_test.py rename to planemo/galaxy_test/structures.py index ec5bc4e7d..7024a2458 100644 --- a/planemo/galaxy_test.py +++ b/planemo/galaxy_test/structures.py @@ -20,11 +20,13 @@ def __init__( xunit_report_file, structured_report_file, failed=False, + installed=False, ): self.html_report_file = html_report_file self.xunit_report_file = xunit_report_file self.structured_report_file = structured_report_file self.failed = failed + self.installed = installed def build(self): xunit_report_file = self.xunit_report_file @@ -38,11 +40,14 @@ def build(self): sd_arg = "--structured_data_report_file %s" % sd_report_file else: sd_arg = "" - tests = "functional.test_toolbox" - if self.failed: - sd = StructuredData(self.structured_report_file) - failed_ids = sd.failed_ids - tests = " ".join(failed_ids) + if self.installed: + tests = "-installed" + else: + tests = "functional.test_toolbox" + if self.failed: + sd = StructuredData(self.structured_report_file) + failed_ids = sd.failed_ids + tests = " ".join(failed_ids) return RUN_TESTS_CMD % (html_report_file, xunit_arg, sd_arg, tests) diff --git a/planemo/options.py b/planemo/options.py index c79980beb..84a9723e2 100644 --- a/planemo/options.py +++ b/planemo/options.py @@ -1,6 +1,7 @@ """ Click definitions for various shared options and arguments. """ +import functools import os import click @@ -187,7 +188,7 @@ def convert(self, value, param, ctx): return super(ProjectOrRepositry, self).convert(value, param, ctx) -def shed_project_arg(): +def shed_project_arg(multiple=True): arg_type = ProjectOrRepositry( exists=True, file_okay=False, @@ -195,11 +196,15 @@ def shed_project_arg(): writable=True, resolve_path=True, ) + name = 'paths' if multiple else 'path' + nargs = -1 if multiple else 1 return click.argument( - 'path', + name, metavar="PROJECT", default=".", type=arg_type, + nargs=nargs, + callback=_optional_tools_default, ) @@ -310,6 +315,90 @@ def shed_password_option(): ) +def shed_realization_options(): + return _compose( + shed_project_arg(multiple=True), + recursive_shed_option(), + shed_fail_fast_option(), + ) + + +def shed_repo_options(): + return _compose( + shed_owner_option(), + shed_name_option(), + ) + + +def shed_publish_options(): + """ Common options for commands that require publishing to a + a shed. + """ + return _compose( + shed_realization_options(), + shed_repo_options(), + shed_target_options(), + ) + + +def shed_read_options(): + """ Common options that require read access to mapped repositories + in a shed. + """ + return _compose( + shed_realization_options(), + shed_repo_options(), + shed_target_options(), + ) + + +def shed_target_options(): + """ Common options for commands that require read-only + interactions with a shed. + """ + return _compose( + shed_email_option(), + shed_key_option(), + shed_password_option(), + shed_target_option(), + ) + + +def galaxy_run_options(): + return _compose( + galaxy_target_options(), + galaxy_port_option(), + ) + + +def galaxy_config_options(): + return _compose( + test_data_option(), + tool_data_table_option(), + dependency_resolvers_option(), + tool_dependency_dir_option(), + brew_dependency_resolution(), + shed_dependency_resolution(), + ) + + +def galaxy_target_options(): + return _compose( + galaxy_root_option(), + install_galaxy_option(), + no_cache_galaxy_option(), + no_cleanup_option(), + job_config_option(), + ) + + +def galaxy_serve_options(): + return _compose( + galaxy_run_options(), + galaxy_config_options(), + ) + + def shed_fail_fast_option(): return click.option( '--fail_fast', @@ -370,3 +459,54 @@ def recursive_option(help="Recursively perform command for subdirectories."): is_flag=True, help=help, ) + + +def test_options(): + return _compose( + click.option( + "--update_test_data", + is_flag=True, + help="Update test-data directory with job outputs (normally" + " written to directory --job_output_files if specified.)" + ), + click.option( + "--test_output", + type=click.Path(file_okay=True, resolve_path=True), + help=("Output test report (HTML - for humans) defaults to " + "tool_test_output.html."), + default=None, + ), + click.option( + "--test_output_xunit", + type=click.Path(file_okay=True, resolve_path=True), + help="Output test report (xUnit style - for computers).", + default=None, + ), + click.option( + "--test_output_json", + type=click.Path(file_okay=True, resolve_path=True), + help=("Output test report (planemo json) defaults to " + "tool_test_output.json."), + default=None, + ), + click.option( + "--job_output_files", + type=click.Path(file_okay=False, resolve_path=True), + help="Write job outputs to specified directory.", + default=None, + ), + click.option( + "--summary", + type=click.Choice(['none', 'minimal', 'compact']), + default="minimal", + help=("Summary style printed to planemo's standard output (see " + "output reports for more complete summary). Set to 'none' " + "to disable completely.") + ) + ) + + +def _compose(*functions): + def compose2(f, g): + return lambda x: f(g(x)) + return functools.reduce(compose2, functions) diff --git a/planemo/shed/__init__.py b/planemo/shed/__init__.py index cc0c8291e..8cf62d2e0 100644 --- a/planemo/shed/__init__.py +++ b/planemo/shed/__init__.py @@ -35,6 +35,7 @@ api_exception_to_message, find_category_ids, download_tar, + latest_installable_revision, ) from .diff import diff_and_remove @@ -152,6 +153,23 @@ def shed_init(ctx, path, **kwds): return 0 +def install_arg_lists(ctx, paths, **kwds): + """ Build a list of install args for resolved repositories. + """ + tsi = tool_shed_client(ctx, **kwds) + install_args_list = [] + + def process_repo(realized_repository): + install_args_list.append(realized_repository.install_args(ctx, tsi)) + return 0 + + exit_code = for_each_repository(ctx, process_repo, paths, **kwds) + if exit_code: + raise RuntimeError("Problem processing repositories, exiting.") + + return install_args_list + + def upload_repository(ctx, realized_repository, **kwds): """Upload a tool directory as a tarball to a tool shed. """ @@ -530,19 +548,20 @@ def build_tarball(realized_path, **kwds): return temp_path -def for_each_repository(ctx, function, path, **kwds): +def for_each_repository(ctx, function, paths, **kwds): ret_codes = [] - with _path_on_disk(path) as raw_path: - try: - for realized_repository in _realize_effective_repositories( - ctx, raw_path, **kwds - ): - ret_codes.append( - function(realized_repository) - ) - except RealizationException: - error(REALIZAION_PROBLEMS_MESSAGE) - return 254 + for path in paths: + with _path_on_disk(path) as raw_path: + try: + for realized_repository in _realize_effective_repositories( + ctx, raw_path, **kwds + ): + ret_codes.append( + function(realized_repository) + ) + except RealizationException: + error(REALIZAION_PROBLEMS_MESSAGE) + return 254 # "Good" returns are Nones, everything else is a -1 and should be # passed upwards. @@ -1053,6 +1072,22 @@ def create(self, ctx, tsi): error(str(e)) return None + def latest_installable_revision(self, ctx, tsi): + repository_id = self.find_repository_id(ctx, tsi) + return latest_installable_revision(tsi, repository_id) + + def install_args(self, ctx, tsi): + """ Arguments for bioblend's install_repository_revision + to install this repository against supplied tsi. + """ + tool_shed_url = tsi.base_url + return dict( + tool_shed_url=tool_shed_url, + name=self.name, + owner=self.owner, + changeset_revision=self.latest_installable_revision(ctx, tsi), + ) + def _glob(path, pattern): pattern = os.path.join(path, pattern) diff --git a/planemo/shed/interface.py b/planemo/shed/interface.py index 6fe9076f1..0d7880035 100644 --- a/planemo/shed/interface.py +++ b/planemo/shed/interface.py @@ -41,6 +41,23 @@ def matches(r): return matching_repos[0] +def latest_installable_revision(tsi, repository_id): + info = tsi.repositories.show_repository(repository_id) + owner = info["owner"] + name = info["name"] + revisions = tsi.repositories.get_ordered_installable_revisions( + name, owner + ) + if len(revisions) == 0: + msg = "Failed to find installable revisions for [{0}, {1}].".format( + owner, + name, + ) + raise Exception(msg) + else: + return revisions[-1] + + def username(tsi): """ Fetch current username from shed given API key/auth. """ diff --git a/setup.py b/setup.py index d0fd48d67..03fead26e 100644 --- a/setup.py +++ b/setup.py @@ -52,6 +52,7 @@ packages=[ 'planemo', 'planemo.commands', + 'planemo.galaxy_test', 'planemo.linters', 'planemo.reports', 'planemo.shed', diff --git a/tests/data/repos/fastqc/.shed.yml b/tests/data/repos/fastqc/.shed.yml new file mode 100644 index 000000000..e43b5912c --- /dev/null +++ b/tests/data/repos/fastqc/.shed.yml @@ -0,0 +1,2 @@ +name: fastqc +owner: devteam diff --git a/tests/data/repos/fastqc/fastqc.xml b/tests/data/repos/fastqc/fastqc.xml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/repos/fastqc/tool_dependencies.xml b/tests/data/repos/fastqc/tool_dependencies.xml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_cmd_shed_serve.py b/tests/test_cmd_shed_serve.py new file mode 100644 index 000000000..b880152dd --- /dev/null +++ b/tests/test_cmd_shed_serve.py @@ -0,0 +1,35 @@ +import functools +import os +import time +import threading + +from .test_utils import ( + CliTestCase, + skip_if_environ, + TEST_REPOS_DIR, +) +from . import network_util + + +class ShedServeTestCase(CliTestCase): + + @skip_if_environ("PLANEMO_SKIP_GALAXY_TESTS") + def test_serve(self): + port = network_util.get_free_port() + serve = functools.partial(self._run, port) + t = threading.Thread(target=serve) + t.daemon = True + t.start() + time.sleep(15) + assert network_util.wait_net_service("127.0.0.1", port) + + def _run(self, port): + fastqc_path = os.path.join(TEST_REPOS_DIR, "fastqc") + test_cmd = [ + "shed_serve", + "--install_galaxy", + "--port", + str(port), + fastqc_path, + ] + self._check_exit_code(test_cmd) diff --git a/tests/test_galaxy_serve.py b/tests/test_galaxy_serve.py index 9254e26d0..85e5f9ea4 100644 --- a/tests/test_galaxy_serve.py +++ b/tests/test_galaxy_serve.py @@ -7,6 +7,7 @@ ) from . import network_util from planemo import galaxy_serve +from planemo import shed class GalaxyServeTestCase(CliTestCase): @@ -36,3 +37,24 @@ def test_serve_daemon(self): config.port, timeout=.1, ) + + @skip_if_environ("PLANEMO_SKIP_GALAXY_TESTS") + def test_shed_serve_daemon(self): + port = network_util.get_free_port() + fastqc_path = os.path.join(TEST_REPOS_DIR, "fastqc") + ctx = self.test_context + install_args_list = shed.install_arg_lists( + ctx, [fastqc_path], + shed_target="toolshed", + ) + with galaxy_serve.shed_serve( + ctx, install_args_list, + port=port, + skip_dependencies=True, + install_galaxy=True, + ) as config: + assert network_util.wait_net_service( + "localhost", + config.port, + timeout=.1, + ) diff --git a/tests/test_galaxy_test.py b/tests/test_galaxy_test.py index 89e2f54d4..1e8a67db7 100644 --- a/tests/test_galaxy_test.py +++ b/tests/test_galaxy_test.py @@ -4,7 +4,7 @@ from .test_utils import TEST_DATA_DIR -from planemo import galaxy_test +from planemo.galaxy_test import structures nose_1_3_report = os.path.join(TEST_DATA_DIR, "xunit_nose_1_3.xml") nose_0_11_report = os.path.join(TEST_DATA_DIR, "xunit_nose_0_11.xml") @@ -19,10 +19,10 @@ def get_test_id_old(): def _get_test_id(path): - xml_tree = galaxy_test.parse_xunit_report(path) + xml_tree = structures.parse_xunit_report(path) root = xml_tree.getroot() - first_testcase = galaxy_test.find_cases(root)[0] - test_id = galaxy_test.case_id(first_testcase) + first_testcase = structures.find_cases(root)[0] + test_id = structures.case_id(first_testcase) assert test_id.label == "cat[0]" expected_id = "functional.test_toolbox.TestForTool_cat.test_tool_000000" assert test_id.id == expected_id diff --git a/tests/test_init_and_test.py b/tests/test_init_and_test.py index 9da48f758..9b5486106 100644 --- a/tests/test_init_and_test.py +++ b/tests/test_init_and_test.py @@ -13,7 +13,6 @@ def test_init_and_test(self): self._check_exit_code(init_cmd) test_cmd = [ "test", - "--no_cache_galaxy", "--install_galaxy", "basic/cat.xml" ] diff --git a/tests/test_shed_test.py b/tests/test_shed_test.py new file mode 100644 index 000000000..bdfe8ee5c --- /dev/null +++ b/tests/test_shed_test.py @@ -0,0 +1,20 @@ +import os + +from .test_utils import ( + CliTestCase, + skip_if_environ, + TEST_REPOS_DIR, +) + + +class ShedTestTestCase(CliTestCase): + + @skip_if_environ("PLANEMO_SKIP_GALAXY_TESTS") + def test_serve(self): + fastqc_path = os.path.join(TEST_REPOS_DIR, "fastqc") + test_cmd = [ + "shed_test", + "--install_galaxy", + fastqc_path, + ] + self._check_exit_code(test_cmd)