Files
galaxy/test/unit/workflows/test_trs_proxy.py
T
mvdbeek 64e74b8b48 Tighten TRS url check
Fixes
https://sentry.galaxyproject.org/share/issue/5b8d495edd6545278d4d93d0ed69ac3a/:
```
Message
Uncaught exception in exposed API method:
Stack Trace

Newest

gaierror: [Errno -2] Name or service not known
  File "urllib3/connection.py", line 174, in _new_conn
    conn = connection.create_connection(
  File "urllib3/util/connection.py", line 72, in create_connection
    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
  File "socket.py", line 962, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7f8e35406450>: Failed to establish a new connection: [Errno -2] Name or service not known
  File "urllib3/connectionpool.py", line 715, in urlopen
    httplib_response = self._make_request(
  File "urllib3/connectionpool.py", line 416, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "urllib3/connection.py", line 244, in request
    super(HTTPConnection, self).request(method, url, body=body, headers=headers)
  File "http/client.py", line 1286, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "http/client.py", line 1332, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "http/client.py", line 1281, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "http/client.py", line 1041, in _send_output
    self.send(msg)
  File "http/client.py", line 979, in send
    self.connect()
  File "urllib3/connection.py", line 205, in connect
    conn = self._new_conn()
  File "urllib3/connection.py", line 186, in _new_conn
    raise NewConnectionError(
MaxRetryError: HTTPConnectionPool(host='https', port=80): Max retries exceeded with url: //training.galaxyproject.org/training-material//api/ga4gh/trs/v2/tools/variant-analysis-microbial-variants/versions/microbial_variant_calling/GALAXY/descriptor (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f8e35406450>: Failed to establish a new connection: [Errno -2] Name or service not known'))
  File "requests/adapters.py", line 486, in send
    resp = conn.urlopen(
  File "urllib3/connectionpool.py", line 799, in urlopen
    retries = retries.increment(
  File "urllib3/util/retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
ConnectionError: HTTPConnectionPool(host='https', port=80): Max retries exceeded with url: //training.galaxyproject.org/training-material//api/ga4gh/trs/v2/tools/variant-analysis-microbial-variants/versions/microbial_variant_calling/GALAXY/descriptor (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f8e35406450>: Failed to establish a new connection: [Errno -2] Name or service not known'))
  File "galaxy/web/framework/decorators.py", line 346, in decorator
    rval = func(self, trans, *args, **kwargs)
  File "galaxy/webapps/galaxy/api/workflows.py", line 261, in create
    archive_data = server.get_version_descriptor(trs_tool_id, trs_version_id)
  File "galaxy/workflow/trs_proxy.py", line 115, in get_version_descriptor
    return self._get(trs_api_url)["content"]
  File "galaxy/workflow/trs_proxy.py", line 126, in _get
    response = requests.get(url, params=params, timeout=DEFAULT_SOCKET_TIMEOUT)
  File "galaxy/util/requests.py", line 29, in wrapper
    rval = f(*args, **kwargs)
  File "requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
  File "requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 519, in send
    raise ConnectionError(e, request=request)
```
which happened for https://usegalaxy.org/workflows/trs_import?run_form=true&trs_url=http%3A%2F%2Flocalhost%3A4000%2F%2Ftraining-material%2F%2Fapi%2Fga4gh%2Ftrs%2Fv2%2Ftools%2Fvariant-analysis-microbial-variants%2Fversions%2Fmicrobial_variant_calling"
2024-09-18 10:31:23 +02:00

168 lines
5.7 KiB
Python

import base64
from os import environ
import pytest
import yaml
from galaxy.exceptions import ConfigDoesNotAllowException
from galaxy.workflow.trs_proxy import (
GA4GH_GALAXY_DESCRIPTOR,
parse_search_kwds,
TrsProxy,
)
# search test is very brittle (depends on production values) and is very slow.
# still good to know search is working though - even if manually
search_test = pytest.mark.skipif(
not environ.get("GALAXY_TEST_INCLUDE_DOCKSTORE_SEARCH"), reason="GALAXY_TEST_INCLUDE_DOCKSTORE_SEARCH not set"
)
def test_proxy():
proxy = TrsProxy()
server = proxy.get_server("dockstore")
assert "dockstore" == proxy.get_servers()[0]["id"]
assert proxy.get_servers()[0]["api_url"] == server._trs_url
tool_id = "#workflow/github.com/jmchilton/galaxy-workflow-dockstore-example-1/mycoolworkflow"
tool = server.get_tool(tool_id)
assert "description" in tool
b64_tool_id = base64.b64encode(tool_id.encode("UTF-8"))
tool = server.get_tool(b64_tool_id, tool_id_b64_encoded=True)
assert "description" in tool
versions = server.get_versions(tool_id)
assert isinstance(versions, list)
assert len(versions) >= 1
version_id = versions[0]["name"]
version = server.get_version(tool_id, version_id)
assert "descriptor_type" in version
assert GA4GH_GALAXY_DESCRIPTOR in version["descriptor_type"]
descriptor = server.get_version_descriptor(tool_id, version_id)
content = yaml.safe_load(descriptor)
assert "inputs" in content
def test_match_url():
proxy = TrsProxy()
valid_dockstore = proxy._match_url(
"https://dockstore.org/api/ga4gh/trs/v2/tools/"
"quay.io%2Fcollaboratory%2Fdockstore-tool-bedtools-genomecov/versions/0.3",
)
assert valid_dockstore
assert valid_dockstore["trs_base_url"] == "https://dockstore.org/api"
# Should unquote
assert valid_dockstore["tool_id"] == "quay.io/collaboratory/dockstore-tool-bedtools-genomecov"
assert valid_dockstore["version_id"] == "0.3"
valid_dockstore_unescaped = proxy._match_url(
"https://dockstore.org/api/ga4gh/trs/v2/tools/"
"#workflow/github.com/jmchilton/galaxy-workflow-dockstore-example-1/mycoolworkflow/versions/master",
)
assert valid_dockstore_unescaped
assert valid_dockstore_unescaped["trs_base_url"] == "https://dockstore.org/api"
assert (
valid_dockstore_unescaped["tool_id"]
== "#workflow/github.com/jmchilton/galaxy-workflow-dockstore-example-1/mycoolworkflow"
)
assert valid_dockstore_unescaped["version_id"] == "master"
valid_workflow_hub = proxy._match_url("https://workflowhub.eu/ga4gh/trs/v2/tools/344/versions/1")
assert valid_workflow_hub
assert valid_workflow_hub["trs_base_url"] == "https://workflowhub.eu"
assert valid_workflow_hub["tool_id"] == "344"
assert valid_workflow_hub["version_id"] == "1"
valid_arbitrary_trs = proxy._match_url(
"https://my-trs-server.golf/stuff/ga4gh/trs/v2/tools/hello-world/versions/version-1"
)
assert valid_arbitrary_trs
assert valid_arbitrary_trs["trs_base_url"] == "https://my-trs-server.golf/stuff"
assert valid_arbitrary_trs["tool_id"] == "hello-world"
assert valid_arbitrary_trs["version_id"] == "version-1"
ignore_extra = proxy._match_url(
"https://workflowhub.eu/ga4gh/trs/v2/tools/344/versions/1/CWL/descriptor/ro-crate-metadata.json",
)
assert ignore_extra
assert ignore_extra["trs_base_url"] == "https://workflowhub.eu"
assert ignore_extra["tool_id"] == "344"
assert ignore_extra["version_id"] == "1"
invalid = proxy._match_url("https://workflowhub.eu/workflows/1")
assert invalid is None
missing_version = proxy._match_url("https://workflowhub.eu/ga4gh/trs/v2/tools/344")
assert missing_version is None
blank = proxy.match_url("", [])
assert blank is None
not_url = proxy.match_url("1234", [])
assert not_url is None
expected_exception = None
try:
proxy.match_url("https://localhost", [])
except ConfigDoesNotAllowException as e:
expected_exception = e
assert expected_exception, "matching url against localhost should fail"
def test_server_from_url():
proxy = TrsProxy()
server = proxy.server_from_url("https://workflowhub.eu")
assert "https://workflowhub.eu" == server._trs_url
tool_id = "138"
tool = server.get_tool(tool_id)
assert "description" in tool
b64_tool_id = base64.b64encode(tool_id.encode("UTF-8"))
tool = server.get_tool(b64_tool_id, tool_id_b64_encoded=True)
assert "description" in tool
versions = server.get_versions(tool_id)
assert isinstance(versions, list)
assert len(versions) >= 1
version_id = versions[0]["id"] # Dockstore and WorkflowHub differ here! Spec is not clear
version = server.get_version(tool_id, version_id)
assert "descriptor_type" in version
assert GA4GH_GALAXY_DESCRIPTOR in version["descriptor_type"]
descriptor = server.get_version_descriptor(tool_id, version_id)
content = yaml.safe_load(descriptor)
assert "steps" in content
@search_test
def test_search():
proxy = TrsProxy()
server = proxy.get_server("dockstore")
search_kwd = parse_search_kwds("documentation")
response = server.get_tools(**search_kwd)
assert len(response) == 1
search_kwd = parse_search_kwds("n:example")
response = server.get_tools(**search_kwd)
assert len(response) == 2
search_kwd = parse_search_kwds("organization:jmchilton")
response = server.get_tools(**search_kwd)
assert len(response) == 2
search_kwd = parse_search_kwds("organization:jmchiltonx")
response = server.get_tools(**search_kwd)
assert len(response) == 0
response = server.get_tools(descriptorType="GALAXY")
assert len(response) == 2