diff --git a/lib/galaxy/tools/xsd/galaxy.xsd b/lib/galaxy/tools/xsd/galaxy.xsd
index d32b0f60e5e..40ae2fa7fe3 100644
--- a/lib/galaxy/tools/xsd/galaxy.xsd
+++ b/lib/galaxy/tools/xsd/galaxy.xsd
@@ -1062,18 +1062,18 @@ of ``type`` ``data``.
- Define extra composite input files for test input.
+ Define extra composite input files for test
+input. The specified ``ftype`` on the parent ``param`` should specify a composite
+datatype with defined static composite files. The order of the defined composite
+files on the datatype must match the order specified with these elements and All
+non-optional composite inputs must be specified as part of the ``param``.
+
Path relative to test-data of composite file.
-
-
- Optional datatype of composite file for test input.
-
-
diff --git a/test/api/test_tools.py b/test/api/test_tools.py
index 435b54d477f..0dcfe546bac 100644
--- a/test/api/test_tools.py
+++ b/test/api/test_tools.py
@@ -6,7 +6,8 @@ from base.populators import (
DatasetCollectionPopulator,
DatasetPopulator,
LibraryPopulator,
- skip_without_tool
+ skip_without_tool,
+ skip_without_datatype,
)
from galaxy.tools.verify.test_data import TestDataResolver
@@ -119,6 +120,71 @@ class ToolsTestCase(api.ApiTestCase):
rdata_metadata = self._upload_and_get_details(open(rdata_path, "rb"), file_type="auto")
self.assertEquals(rdata_metadata["file_ext"], "rdata")
+ @skip_without_datatype("velvet")
+ def test_composite_datatype(self):
+ with self.dataset_populator.test_history() as history_id:
+ dataset = self._velvet_upload(history_id, extra_inputs={
+ "files_1|url_paste": "roadmaps content",
+ "files_1|type": "upload_dataset",
+ "files_2|url_paste": "log content",
+ "files_2|type": "upload_dataset",
+ })
+
+ roadmaps_content = self._get_roadmaps_content(history_id, dataset)
+ assert roadmaps_content.strip() == "roadmaps content", roadmaps_content
+
+ @skip_without_datatype("velvet")
+ def test_composite_datatype_space_to_tab(self):
+ # Like previous test but set one upload with space_to_tab to True to
+ # verify that works.
+ with self.dataset_populator.test_history() as history_id:
+ dataset = self._velvet_upload(history_id, extra_inputs={
+ "files_1|url_paste": "roadmaps content",
+ "files_1|type": "upload_dataset",
+ "files_1|space_to_tab": "Yes",
+ "files_2|url_paste": "log content",
+ "files_2|type": "upload_dataset",
+ })
+
+ roadmaps_content = self._get_roadmaps_content(history_id, dataset)
+ assert roadmaps_content.strip() == "roadmaps\tcontent", roadmaps_content
+
+ @skip_without_datatype("velvet")
+ def test_composite_datatype_posix_lines(self):
+ # Like previous test but set one upload with space_to_tab to True to
+ # verify that works.
+ with self.dataset_populator.test_history() as history_id:
+ dataset = self._velvet_upload(history_id, extra_inputs={
+ "files_1|url_paste": "roadmaps\rcontent",
+ "files_1|type": "upload_dataset",
+ "files_1|space_to_tab": "Yes",
+ "files_2|url_paste": "log\rcontent",
+ "files_2|type": "upload_dataset",
+ })
+
+ roadmaps_content = self._get_roadmaps_content(history_id, dataset)
+ assert roadmaps_content.strip() == "roadmaps\ncontent", roadmaps_content
+
+ def _velvet_upload(self, history_id, extra_inputs):
+ payload = self.dataset_populator.upload_payload(
+ history_id,
+ "sequences content",
+ file_type="velvet",
+ extra_inputs=extra_inputs,
+ )
+ run_response = self.dataset_populator.tools_post(payload)
+ self.dataset_populator.wait_for_tool_run(history_id, run_response)
+ datasets = run_response.json()["outputs"]
+
+ assert len(datasets) == 1
+ dataset = datasets[0]
+
+ return dataset
+
+ def _get_roadmaps_content(self, history_id, dataset):
+ roadmaps_content = self.dataset_populator.get_history_dataset_content(history_id, dataset=dataset, filename="Roadmaps")
+ return roadmaps_content
+
def test_unzip_collection(self):
with self.dataset_populator.test_history() as history_id:
hdca_id = self.__build_pair(history_id, ["123", "456"])
diff --git a/test/base/interactor.py b/test/base/interactor.py
index 1433169854c..736527477f5 100644
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -188,10 +188,7 @@ class GalaxyInteractorApi(object):
file_name = self.functional_test_case.get_filename(composite_file.get('value'), shed_tool_id=shed_tool_id)
files["files_%s|file_data" % i] = open(file_name, 'rb')
tool_input.update({
- # "files_%d|NAME" % i: name,
"files_%d|type" % i: "upload_dataset",
- # TODO:
- # "files_%d|space_to_tab" % i: composite_file.get( 'space_to_tab', False )
})
name = test_data['name']
else:
diff --git a/test/base/populators.py b/test/base/populators.py
index c45316e9715..169b9935cfb 100644
--- a/test/base/populators.py
+++ b/test/base/populators.py
@@ -2,6 +2,7 @@ import contextlib
import json
import time
+from functools import wraps
from operator import itemgetter
import requests
@@ -26,8 +27,9 @@ DEFAULT_TIMEOUT = 60 # Secs to wait for state to turn ok
def skip_without_tool(tool_id):
- """ Decorate an API test method as requiring a specific tool,
- have nose skip the test case is the tool is unavailable.
+ """Decorate an API test method as requiring a specific tool.
+
+ Have test framework skip the test case is the tool is unavailable.
"""
def method_wrapper(method):
@@ -39,21 +41,46 @@ def skip_without_tool(tool_id):
tool_ids = [itemgetter("id")(_) for _ in tools]
return tool_ids
+ @wraps(method)
def wrapped_method(api_test_case, *args, **kwargs):
- if tool_id not in get_tool_ids(api_test_case):
- from nose.plugins.skip import SkipTest
- raise SkipTest()
-
+ _raise_skip_if(tool_id not in get_tool_ids(api_test_case))
return method(api_test_case, *args, **kwargs)
- # Must preserve method name so nose can detect and report tests by
- # name.
- wrapped_method.__name__ = method.__name__
return wrapped_method
return method_wrapper
+def skip_without_datatype(extension):
+ """Decorate an API test method as requiring a specific datatype.
+
+ Have test framework skip the test case is the tool is unavailable.
+ """
+
+ def has_datatype(api_test_case):
+ index_response = api_test_case.galaxy_interactor.get("datatypes")
+ assert index_response.status_code == 200, "Failed to fetch datatypes for target Galaxy."
+ datatypes = index_response.json()
+ assert isinstance(datatypes, list)
+ return extension in datatypes
+
+ def method_wrapper(method):
+ @wraps(method)
+ def wrapped_method(api_test_case, *args, **kwargs):
+ _raise_skip_if(not has_datatype(api_test_case))
+ method(api_test_case, *args, **kwargs)
+
+ return wrapped_method
+
+ return method_wrapper
+
+
+def _raise_skip_if(check):
+ if check:
+ from nose.plugins.skip import SkipTest
+ raise SkipTest()
+
+
# Deprecated mixin, use dataset populator instead.
# TODO: Rework existing tests to target DatasetPopulator in a setup method instead.
class TestsDatasets:
@@ -80,15 +107,23 @@ class BaseDatasetPopulator(object):
"""
def new_dataset(self, history_id, content='TestData123', wait=False, **kwds):
+ run_response = self.new_dataset_request(history_id, content=content, wait=wait, **kwds)
+ return run_response.json()["outputs"][0]
+
+ def new_dataset_request(self, history_id, content='TestData123', wait=False, **kwds):
payload = self.upload_payload(history_id, content, **kwds)
- run_response = self._post("tools", data=payload)
- run = run_response.json()
+ run_response = self.tools_post(payload)
if wait:
- assert run_response.status_code == 200, run
- job = run["jobs"][0]
- self.wait_for_job(job["id"])
- self.wait_for_history(history_id, assert_ok=True)
- return run["outputs"][0]
+ self.wait_for_tool_run(history_id, run_response)
+ return run_response
+
+ def wait_for_tool_run(self, history_id, run_response):
+ run = run_response.json()
+ assert run_response.status_code == 200, run
+ job = run["jobs"][0]
+ self.wait_for_job(job["id"])
+ self.wait_for_history(history_id, assert_ok=True)
+ return run_response
def wait_for_history(self, history_id, assert_ok=False, timeout=DEFAULT_TIMEOUT):
try:
@@ -144,6 +179,7 @@ class BaseDatasetPopulator(object):
upload_params["files_0|space_to_tab"] = kwds["space_to_tab"]
if "auto_decompress" in kwds:
upload_params["files_0|auto_decompress"] = kwds["auto_decompress"]
+ upload_params.update(kwds.get("extra_inputs", {}))
return self.run_tool_payload(
tool_id='upload1',
inputs=upload_params,
@@ -163,15 +199,25 @@ class BaseDatasetPopulator(object):
**kwds
)
- def run_tool(self, tool_id, inputs, history_id, **kwds):
+ def run_tool(self, tool_id, inputs, history_id, assert_ok=True, **kwds):
payload = self.run_tool_payload(tool_id, inputs, history_id, **kwds)
- tool_response = self._post("tools", data=payload)
- api_asserts.assert_status_code_is(tool_response, 200)
- return tool_response.json()
+ tool_response = self.tools_post(payload)
+ if assert_ok:
+ api_asserts.assert_status_code_is(tool_response, 200)
+ return tool_response.json()
+ else:
+ return tool_response
- def get_history_dataset_content(self, history_id, wait=True, **kwds):
+ def tools_post(self, payload):
+ tool_response = self._post("tools", data=payload)
+ return tool_response
+
+ def get_history_dataset_content(self, history_id, wait=True, filename=None, **kwds):
dataset_id = self.__history_content_id(history_id, wait=wait, **kwds)
- display_response = self.__get_contents_request(history_id, "/%s/display" % dataset_id)
+ data = {}
+ if filename:
+ data["filename"] = filename
+ display_response = self.__get_contents_request(history_id, "/%s/display" % dataset_id, data=data)
assert display_response.status_code == 200, display_response.content
return display_response.content
@@ -212,11 +258,11 @@ class BaseDatasetPopulator(object):
history_content_id = history_contents[-1]["id"]
return history_content_id
- def __get_contents_request(self, history_id, suffix=""):
+ def __get_contents_request(self, history_id, suffix="", data={}):
url = "histories/%s/contents" % history_id
if suffix:
url = "%s%s" % (url, suffix)
- return self._get(url)
+ return self._get(url, data=data)
class DatasetPopulator(BaseDatasetPopulator):
@@ -231,8 +277,8 @@ class DatasetPopulator(BaseDatasetPopulator):
return self.galaxy_interactor.post(route, data, files=files)
- def _get(self, route):
- return self.galaxy_interactor.get(route)
+ def _get(self, route, data={}):
+ return self.galaxy_interactor.get(route, data=data)
def _summarize_history(self, history_id):
self.galaxy_interactor._summarize_history(history_id)
@@ -305,8 +351,8 @@ class WorkflowPopulator(BaseWorkflowPopulator, ImporterGalaxyInterface):
def _post(self, route, data={}):
return self.galaxy_interactor.post(route, data)
- def _get(self, route):
- return self.galaxy_interactor.get(route)
+ def _get(self, route, data={}):
+ return self.galaxy_interactor.get(route, data=data)
# Required for ImporterGalaxyInterface interface - so we can recurisvely import
# nested workflows.
@@ -526,8 +572,8 @@ def wait_on_state(state_func, skip_states=["running", "queued", "new", "ready"],
class GiPostGetMixin:
"""Mixin for adapting Galaxy testing populators helpers to bioblend."""
- def _get(self, route):
- return self._gi.make_get_request(self.__url(route))
+ def _get(self, route, data={}):
+ return self._gi.make_get_request(self.__url(route), data)
def _post(self, route, data={}):
data = data.copy()
diff --git a/test/functional/tools/composite.xml b/test/functional/tools/composite.xml
index 8f8edbe58f3..f4c5e5bfc1b 100644
--- a/test/functional/tools/composite.xml
+++ b/test/functional/tools/composite.xml
@@ -10,9 +10,9 @@
-
-
-
+
+
+
diff --git a/test/functional/tools/composite_output.xml b/test/functional/tools/composite_output.xml
index 6bb1bf1e78f..cc29995c1e3 100644
--- a/test/functional/tools/composite_output.xml
+++ b/test/functional/tools/composite_output.xml
@@ -10,9 +10,9 @@
-
-
-
+
+
+