Skip to content

Commit f3c6917

Browse files
committed
Make planemo test a little less error prone.
- Insist that Galaxy produce json and xunit test data. Previously planemo would try to work through without these files and just issue warnings - but the state could be inconsistent. - Some initial unit tests for planemo test - mocking out the actual running of Galaxy (so we can simulate problems generating these files).
1 parent 52dc27e commit f3c6917

File tree

5 files changed

+477
-30
lines changed

5 files changed

+477
-30
lines changed

planemo/galaxy/test/actions.py

+32-28
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import click
55

66
from . import structures as test_structures
7-
from planemo.io import info, warn, shell_join
7+
from planemo.io import error, info, warn, shell_join
88
from planemo.galaxy.run import (
99
run_galaxy_command,
1010
setup_venv,
@@ -14,12 +14,12 @@
1414

1515
from galaxy.tools.deps.commands import shell
1616

17-
XUNIT_UPGRADE_MESSAGE = ("This version of Galaxy does not support xUnit - "
18-
"please update to newest development brach.")
19-
NO_XUNIT_MESSAGE = ("Cannot locate xUnit report option for tests - update "
20-
"Galaxy for more detailed breakdown.")
21-
NO_JSON_MESSAGE = ("Cannot locate json report option for tests - update "
22-
"Galaxy for more detailed breakdown.")
17+
NO_XUNIT_REPORT_MESSAGE = ("Cannot locate xUnit report [%s] for tests - "
18+
"required to build planemo report and summarize "
19+
"tests.")
20+
NO_JSON_REPORT_MESSAGE = ("Cannot locate JSON report [%s] for tests - "
21+
"required to build planemo report and summarize "
22+
"tests.")
2323
NO_TESTS_MESSAGE = "No tests were executed - see Galaxy output for details."
2424
ALL_TESTS_PASSED_MESSAGE = "All %d test(s) executed passed."
2525
PROBLEM_COUNT_MESSAGE = ("There were problems with %d test(s) - out of %d "
@@ -29,7 +29,7 @@
2929
GENERIC_TESTS_PASSED_MESSAGE = "No failing tests encountered."
3030

3131

32-
def run_in_config(ctx, config, **kwds):
32+
def run_in_config(ctx, config, run=run_galaxy_command, **kwds):
3333
"""Run Galaxy tests with the run_tests.sh command.
3434
3535
The specified `config` object describes the context for tool
@@ -42,7 +42,7 @@ def run_in_config(ctx, config, **kwds):
4242
if job_output_files is None:
4343
job_output_files = os.path.join(config_directory, "jobfiles")
4444

45-
xunit_supported, xunit_report_file = _xunit_state(kwds, config)
45+
xunit_report_file = _xunit_state(kwds, config)
4646
structured_report_file = _structured_report_file(kwds, config)
4747

4848
info("Testing using galaxy_root %s", config.galaxy_root)
@@ -75,7 +75,7 @@ def run_in_config(ctx, config, **kwds):
7575
test_cmd,
7676
)
7777
action = "Testing tools"
78-
return_code = run_galaxy_command(
78+
return_code = run(
7979
ctx,
8080
cmd,
8181
config.env,
@@ -85,9 +85,15 @@ def run_in_config(ctx, config, **kwds):
8585
update_cp_args = (job_output_files, config.test_data_dir)
8686
shell('cp -r "%s"/* "%s"' % update_cp_args)
8787

88-
if xunit_report_file and (not os.path.exists(xunit_report_file)):
89-
warn(NO_XUNIT_MESSAGE)
90-
xunit_report_file = None
88+
if not os.path.exists(xunit_report_file):
89+
message = NO_XUNIT_REPORT_MESSAGE % xunit_report_file
90+
error(message)
91+
raise Exception(message)
92+
93+
if not os.path.exists(structured_report_file):
94+
message = NO_JSON_REPORT_MESSAGE % structured_report_file
95+
error(message)
96+
raise Exception(message)
9197

9298
test_results = test_structures.GalaxyTestResults(
9399
structured_report_file,
@@ -243,33 +249,31 @@ def _print_command_line(structured_data, test_id):
243249

244250

245251
def _xunit_state(kwds, config):
246-
xunit_supported = True
247-
if shell("grep -q xunit '%s'/run_tests.sh" % config.galaxy_root):
248-
xunit_supported = False
252+
# This has been supported in Galaxy for well over a year, just going to assume
253+
# it from here on out.
254+
# xunit_supported = True
255+
# if shell("grep -q xunit '%s'/run_tests.sh" % config.galaxy_root):
256+
# xunit_supported = False
249257

250258
xunit_report_file = kwds.get("test_output_xunit", None)
251-
if xunit_report_file is None and xunit_supported:
259+
if xunit_report_file is None:
252260
xunit_report_file = os.path.join(config.config_directory, "xunit.xml")
253-
elif xunit_report_file is not None and not xunit_supported:
254-
warn(XUNIT_UPGRADE_MESSAGE)
255-
xunit_report_file = None
256261

257-
return xunit_supported, xunit_report_file
262+
return xunit_report_file
258263

259264

260265
def _structured_report_file(kwds, config):
261-
structured_data_supported = True
262-
if shell("grep -q structured_data '%s'/run_tests.sh" % config.galaxy_root):
263-
structured_data_supported = False
266+
# This has been supported in Galaxy for well over a year, just going to assume
267+
# it from here on out.
268+
# structured_data_supported = True
269+
# if shell("grep -q structured_data '%s'/run_tests.sh" % config.galaxy_root):
270+
# structured_data_supported = False
264271

265272
structured_report_file = None
266273
structured_report_file = kwds.get("test_output_json", None)
267-
if structured_report_file is None and structured_data_supported:
274+
if structured_report_file is None:
268275
conf_dir = config.config_directory
269276
structured_report_file = os.path.join(conf_dir, "structured_data.json")
270-
elif structured_report_file is not None and not structured_data_supported:
271-
warn(NO_JSON_MESSAGE)
272-
structured_report_file = None
273277

274278
return structured_report_file
275279

tests/data/tt_success.html

+370
Large diffs are not rendered by default.

tests/data/tt_success.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"tests": [{"data": {"status": "success", "inputs": {"input1": {"src": "hda", "id": "2891970512fa2d5a"}}, "job": {"inputs": {"input1": {"src": "hda", "id": "2891970512fa2d5a", "uuid": "3b1f7b73-d96b-4ca8-be81-3aa7a24bac13"}}, "update_time": "2016-05-11T00:55:26.723036", "tool_id": "cat", "outputs": {"out_file1": {"src": "hda", "id": "5729865256bc2525", "uuid": "c7bf3ebb-1bed-45ce-b473-aefba37773ec"}}, "stdout": "", "exit_code": 0, "state": "ok", "create_time": "2016-05-11T00:55:23.253017", "params": {"chromInfo": "\"/home/john/workspace/galaxy/tool-data/shared/ucsc/chrom/hg17.len\"", "dbkey": "\"hg17\"", "queries": "[]"}, "stderr": "", "model_class": "Job", "id": "5729865256bc2525"}}, "id": "functional.test_toolbox.TestForTool_cat.test_tool_000000", "has_data": true}], "version": "0.1", "exit_code": 0, "summary": {"num_skips": 0, "num_errors": 0, "num_failures": 0, "num_tests": 1}}

tests/data/tt_success.xml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?xml version="1.0" encoding="UTF-8"?><testsuite name="nosetests" tests="1" errors="0" failures="0" skip="0"><testcase classname="functional.test_toolbox.TestForTool_cat" name="test_tool_000000" time="12.805"></testcase></testsuite>

tests/test_galaxy_test.py

+73-2
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,85 @@
1-
""" Tests for the galaxy_test module :) """
1+
"""Tests for the `planeo.galaxy.test` module."""
22

33
import os
4+
import shutil
45

5-
from .test_utils import TEST_DATA_DIR
6+
from .test_utils import (
7+
test_context,
8+
TempDirectoryTestCase,
9+
TEST_DATA_DIR,
10+
)
611

712
from planemo.galaxy.test import structures
813
from planemo.galaxy.test.actions import passed
14+
from planemo.galaxy.test.actions import run_in_config
15+
916

1017
nose_1_3_report = os.path.join(TEST_DATA_DIR, "xunit_nose_1_3.xml")
1118
nose_0_11_report = os.path.join(TEST_DATA_DIR, "xunit_nose_0_11.xml")
1219

1320
xunit_report_with_failure = os.path.join(TEST_DATA_DIR, "xunit_failure.xml")
1421

1522

23+
class RunInConfigTestCase(TempDirectoryTestCase):
24+
"""Test cases for ``run_in_config``."""
25+
26+
def setUp(self):
27+
"""Setup mock keywords, context, and Galaxy config for tests."""
28+
super(RunInConfigTestCase, self).setUp()
29+
td = self.temp_directory
30+
self.ctx = test_context()
31+
self.config = _MockConfig(td)
32+
self.kwds = {
33+
"test_output": os.path.join(td, "tests.html"),
34+
"test_output_json": os.path.join(td, "tests.json"),
35+
"test_output_xunit": os.path.join(td, "tests.xml"),
36+
}
37+
38+
def test_normal_execution(self):
39+
"""Test normal operation of run_in_config."""
40+
def mock_galaxy_run(ctx_, command, env, action):
41+
assert ctx_ is self.ctx
42+
assert env["test_key"] == "test_value"
43+
self._copy_good_artifacts(["xml", "html", "json"])
44+
return 0
45+
46+
assert self._do_run(mock_galaxy_run) == 0
47+
48+
def test_failed_to_produce_xunit(self):
49+
"""Test an exception is thrown if not XUnit report is produced."""
50+
def mock_galaxy_run(ctx_, command, env, action):
51+
self._copy_good_artifacts(["json", "html"])
52+
return 0
53+
54+
with self.assertRaises(Exception):
55+
self._do_run(mock_galaxy_run)
56+
57+
def test_failed_to_produce_json(self):
58+
"""Test an exception is thrown if not XUnit report is produced."""
59+
def mock_galaxy_run(ctx_, command, env, action):
60+
self._copy_good_artifacts(["xml", "html"])
61+
return 0
62+
63+
with self.assertRaises(Exception):
64+
self._do_run(mock_galaxy_run)
65+
66+
def _copy_good_artifacts(self, extensions):
67+
for extension in extensions:
68+
source = os.path.join(TEST_DATA_DIR, "tt_success.%s" % extension)
69+
destination = os.path.join(self.temp_directory, "tests.%s" % extension)
70+
shutil.copy(source, destination)
71+
72+
def _do_run(self, mock_run_function):
73+
return run_in_config(self.ctx, self.config, run=mock_run_function, **self.kwds)
74+
75+
1676
def get_test_id_new():
77+
"""Test ID parsing on newer nose dependency."""
1778
_get_test_id(nose_1_3_report)
1879

1980

2081
def get_test_id_old():
82+
"""Test ID parsing on older nose dependency."""
2183
_get_test_id(nose_0_11_report)
2284

2385

@@ -33,10 +95,19 @@ def _get_test_id(path):
3395

3496

3597
def test_passed():
98+
"""Test :func:`passed`."""
3699
xml_tree = structures.parse_xunit_report(xunit_report_with_failure)
37100
root = xml_tree.getroot()
38101
good_testcase_el = structures.find_cases(root)[0]
39102
assert passed(good_testcase_el)
40103

41104
bad_testcase_el = structures.find_cases(root)[1]
42105
assert not passed(bad_testcase_el)
106+
107+
108+
class _MockConfig(object):
109+
110+
def __init__(self, temp_directory):
111+
self.config_directory = temp_directory
112+
self.env = {"test_key": "test_value"}
113+
self.galaxy_root = os.path.join(self.config_directory, "galaxy-dev")

0 commit comments

Comments
 (0)