Warning
This document is for an old release of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.
Source code for galaxy_test.api.test_pages
from typing import (
Any,
Dict,
List,
Optional,
Union,
)
from unittest import SkipTest
from requests import delete
from requests.models import Response
from galaxy.exceptions import error_codes
from galaxy_test.api.sharable import SharingApiTests
from galaxy_test.base import api_asserts
from galaxy_test.base.populators import (
DatasetPopulator,
skip_without_tool,
WorkflowPopulator,
)
from ._framework import ApiTestCase
[docs]class BasePageApiTestCase(ApiTestCase):
[docs] def setUp(self):
super().setUp()
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
self.workflow_populator = WorkflowPopulator(self.galaxy_interactor)
def _create_valid_page_with_slug(self, slug):
return self.dataset_populator.new_page(slug=slug)
def _create_valid_page_as(self, other_email, slug):
run_as_user = self._setup_user(other_email)
page_request = self._test_page_payload(slug=slug)
page_response = self._post("pages", page_request, headers={"run-as": run_as_user["id"]}, admin=True, json=True)
self._assert_status_code_is(page_response, 200)
return page_response.json()
def _test_page_payload(self, **kwds):
return self.dataset_populator.new_page_payload(**kwds)
[docs]class PageApiTestCase(BasePageApiTestCase, SharingApiTests):
api_name = "pages"
[docs] def create(self, name: str) -> str:
response_json = self._create_valid_page_with_slug(name)
return response_json["id"]
[docs] def test_create(self):
response_json = self._create_valid_page_with_slug("mypage")
self._assert_has_keys(response_json, "slug", "title", "id")
[docs] @skip_without_tool("cat")
def test_create_from_report(self):
test_data = """
input_1:
value: 1.bed
type: File
"""
with self.dataset_populator.test_history() as history_id:
summary = self.workflow_populator.run_workflow(
"""
class: GalaxyWorkflow
inputs:
input_1: data
outputs:
output_1:
outputSource: first_cat/out_file1
steps:
first_cat:
tool_id: cat
in:
input1: input_1
""",
test_data=test_data,
history_id=history_id,
)
workflow_id = summary.workflow_id
invocation_id = summary.invocation_id
report_json = self.workflow_populator.workflow_report_json(workflow_id, invocation_id)
assert "markdown" in report_json
self._assert_has_keys(report_json, "markdown", "render_format")
assert report_json["render_format"] == "markdown"
markdown_content = report_json["markdown"]
page_request = dict(
slug="invocation-report",
title="Invocation Report",
invocation_id=invocation_id,
)
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 200)
page_response = page_response.json()
show_response = self._get(f"pages/{page_response['id']}")
self._assert_status_code_is(show_response, 200)
show_json = show_response.json()
self._assert_has_keys(show_json, "slug", "title", "id")
self.assertEqual(show_json["slug"], "invocation-report")
self.assertEqual(show_json["title"], "Invocation Report")
self.assertEqual(show_json["content_format"], "markdown")
markdown_content = show_json["content"]
assert "## Workflow Outputs" in markdown_content
assert "## Workflow Inputs" in markdown_content
assert "## About This Report" not in markdown_content
[docs] def test_index(self):
create_response_json = self._create_valid_page_with_slug("indexpage")
assert self._users_index_has_page_with_id(create_response_json)
[docs] def test_index_deleted(self):
response1 = self._create_valid_page_with_slug("indexdeletedpageundeleted")
response2 = self._create_valid_page_with_slug("indexdeletedpagedeleted")
assert self._users_index_has_page_with_id(response1)
assert self._users_index_has_page_with_id(response2)
delete_response = self._delete(f"pages/{response2['id']}")
delete_response.raise_for_status()
assert self._users_index_has_page_with_id(response1)
assert not self._users_index_has_page_with_id(response2)
assert self._users_index_has_page_with_id(response2, dict(deleted=True))
[docs] def test_index_user_id_security(self):
user_id = self.dataset_populator.user_id()
response1 = self._create_valid_page_with_slug("indexuseridsecurity")
assert self._users_index_has_page_with_id(response1, dict(user_id=user_id))
with self._different_user():
response = self._index_raw()
assert response.status_code == 200
response = self._index_raw(dict(user_id=user_id))
assert response.status_code == 403
[docs] def test_index_user_published(self):
user_id = self.dataset_populator.user_id()
response1 = self._create_valid_page_with_slug("indexuseridpublish1")
with self._different_user():
response2 = self._create_valid_page_with_slug("indexuseridpublish2")
self._make_public(response2["id"])
assert self._users_index_has_page_with_id(response1)
assert self._users_index_has_page_with_id(response2)
assert self._users_index_has_page_with_id(response1, dict(user_id=user_id))
assert not self._users_index_has_page_with_id(response2, dict(user_id=user_id))
[docs] def test_index_show_published(self):
with self._different_user():
response = self._create_valid_page_with_slug("indexshowpublish2")
self._make_public(response["id"])
assert self._users_index_has_page_with_id(response)
assert self._users_index_has_page_with_id(response, dict(show_published=True))
assert not self._users_index_has_page_with_id(response, dict(show_published=False))
[docs] def test_index_ordering(self):
older1 = self._create_valid_page_with_slug("indexorderingcreatedfirst")["id"]
newer1 = self._create_valid_page_with_slug("indexorderingcreatedsecond")["id"]
index_ids = self._index_ids()
assert index_ids.index(older1) > index_ids.index(newer1)
index_ids = self._index_ids(dict(sort_desc=True)) # the default but verify it works when explicit
assert index_ids.index(older1) > index_ids.index(newer1)
index_ids = self._index_ids(dict(sort_desc=False))
assert index_ids.index(older1) < index_ids.index(newer1)
# update older1 so the update time is newer...
revision_data = dict(content="<p>NewContent!</p>")
self._post(f"pages/{older1}/revisions", data=revision_data).raise_for_status()
index_ids = self._index_ids()
assert index_ids.index(older1) < index_ids.index(newer1)
# if we switch to create time instead of update time, older1 still appears later in
# in the list...
index_ids = self._index_ids(dict(sort_by="create_time"))
assert index_ids.index(older1) > index_ids.index(newer1)
[docs] def test_limit_offset(self):
older1 = self._create_valid_page_with_slug("indexlimitoffsetcreatedfirst")["id"]
newer1 = self._create_valid_page_with_slug("indexlimitoffsetcreatedsecond")["id"]
index_ids = self._index_ids(dict(limit=1))
assert newer1 in index_ids
assert older1 not in index_ids
index_ids = self._index_ids(dict(limit=1, offset=1))
assert newer1 not in index_ids
assert older1 in index_ids
[docs] def test_cannot_create_pages_with_same_slug(self):
page_request = self._test_page_payload(slug="mypage1")
page_response_1 = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response_1, 200)
page_response_2 = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response_2, 400)
self._assert_error_code_is(page_response_2, error_codes.error_codes_by_name["USER_SLUG_DUPLICATE"])
[docs] def test_cannot_create_pages_with_invalid_slug(self):
page_request = self._test_page_payload(slug="invalid slug!")
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
[docs] def test_cannot_create_page_with_invalid_content_format(self):
page_request = self._test_page_payload(slug="mypageinvalidformat")
page_request["content_format"] = "xml"
page_response_1 = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response_1, 400)
self._assert_error_code_is(page_response_1, error_codes.error_codes_by_name["USER_REQUEST_INVALID_PARAMETER"])
[docs] def test_page_requires_name(self):
page_request = self._test_page_payload(slug="requires-name")
del page_request["title"]
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
self._assert_error_code_is(page_response, error_codes.error_codes_by_name["USER_REQUEST_MISSING_PARAMETER"])
[docs] def test_page_requires_slug(self):
page_request = self._test_page_payload()
del page_request["slug"]
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
[docs] def test_delete(self):
response_json = self._create_valid_page_with_slug("testdelete")
delete_response = delete(self._api_url(f"pages/{response_json['id']}", use_key=True))
self._assert_status_code_is(delete_response, 204)
[docs] def test_400_on_delete_invalid_page_id(self):
delete_response = delete(self._api_url(f"pages/{self._random_key()}", use_key=True))
self._assert_status_code_is(delete_response, 400)
self._assert_error_code_is(delete_response, error_codes.error_codes_by_name["MALFORMED_ID"])
[docs] def test_403_on_delete_unowned_page(self):
page_response = self._create_valid_page_as("others_page@bx.psu.edu", "otherspage")
delete_response = delete(self._api_url(f"pages/{page_response['id']}", use_key=True))
self._assert_status_code_is(delete_response, 403)
self._assert_error_code_is(delete_response, error_codes.error_codes_by_name["USER_DOES_NOT_OWN_ITEM"])
[docs] def test_400_on_invalid_id_encoding(self):
page_request = self._test_page_payload(slug="invalid-id-encding")
page_request["content"] = """<p>Page!<div class="embedded-item" id="History-invaidencodedid"></div></p>"""
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
self._assert_error_code_is(page_response, error_codes.error_codes_by_name["MALFORMED_ID"])
[docs] def test_400_on_invalid_id_encoding_markdown(self):
page_request = self._test_page_payload(slug="invalid-id-encding-markdown", content_format="markdown")
page_request["content"] = """```galaxy\nhistory_dataset_display(history_dataset_id=badencoding)\n```\n"""
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
self._assert_error_code_is(page_response, error_codes.error_codes_by_name["MALFORMED_ID"])
[docs] def test_400_on_invalid_embedded_content(self):
valid_id = self.dataset_populator.new_history()
page_request = self._test_page_payload(slug="invalid-embed-content")
page_request["content"] = f"""<p>Page!<div class="embedded-item" id="CoolObject-{valid_id}"></div></p>"""
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
self._assert_error_code_is(page_response, error_codes.error_codes_by_name["USER_REQUEST_INVALID_PARAMETER"])
assert "embedded HTML content" in page_response.text
[docs] def test_400_on_invalid_markdown_call(self):
page_request = self._test_page_payload(slug="invalid-markdown-call", content_format="markdown")
page_request["content"] = """```galaxy\njob_metrics(job_id)\n```\n"""
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 400)
self._assert_error_code_is(page_response, error_codes.error_codes_by_name["MALFORMED_CONTENTS"])
[docs] def test_show(self):
response_json = self._create_valid_page_with_slug("pagetoshow")
show_response = self._get(f"pages/{response_json['id']}")
self._assert_status_code_is(show_response, 200)
show_json = show_response.json()
self._assert_has_keys(show_json, "slug", "title", "id")
self.assertEqual(show_json["slug"], "pagetoshow")
self.assertEqual(show_json["title"], "MY PAGE")
self.assertEqual(show_json["content"], "<p>Page!</p>")
self.assertEqual(show_json["content_format"], "html")
[docs] def test_403_on_unowner_show(self):
response_json = self._create_valid_page_as("others_page_show@bx.psu.edu", "otherspageshow")
show_response = self._get(f"pages/{response_json['id']}")
self._assert_status_code_is(show_response, 403)
self._assert_error_code_is(show_response, error_codes.error_codes_by_name["USER_CANNOT_ACCESS_ITEM"])
[docs] def test_pdf_when_service_available(self):
configuration = self.dataset_populator.get_configuration()
can_produce_markdown = configuration["markdown_to_pdf_available"]
if not can_produce_markdown:
raise SkipTest("Skipping test because server does not implement markdown conversion to PDF")
page_request = self._test_page_payload(slug="md-page-to-pdf", content_format="markdown")
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 200)
page_id = page_response.json()["id"]
pdf_response = self._get(f"pages/{page_id}.pdf")
api_asserts.assert_status_code_is(pdf_response, 200)
assert "application/pdf" in pdf_response.headers["content-type"]
assert pdf_response.content[0:4] == b"%PDF"
[docs] def test_400_on_download_pdf_when_unsupported_content_format(self):
page_request = self._test_page_payload(slug="html-page-to-pdf", content_format="html")
page_response = self._post("pages", page_request, json=True)
self._assert_status_code_is(page_response, 200)
page_id = page_response.json()["id"]
pdf_response = self._get(f"pages/{page_id}.pdf")
self._assert_status_code_is(pdf_response, 400)
def _make_public(self, page_id: str) -> dict:
sharing_response = self._put(f"pages/{page_id}/publish")
assert sharing_response.status_code == 200
return sharing_response.json()
def _share_with_user(self, page_id: str, user_id_or_email: str):
data = {"user_ids": [user_id_or_email]}
response = self._put(f"pages/{page_id}/share_with_users", data, json=True)
api_asserts.assert_status_code_is_ok(response)
def _index_raw(self, params: Optional[Dict[str, Any]] = None) -> Response:
index_response = self._get("pages", data=params or {})
return index_response
def _index(self, params: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
index_response = self._index_raw(params)
self._assert_status_code_is(index_response, 200)
return index_response.json()
def _index_ids(self, params: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
return [p["id"] for p in self._index(params)]
def _users_index_has_page_with_id(
self, has_id: Union[Dict[str, Any], str], params: Optional[Dict[str, Any]] = None
):
pages = self._index(params)
if isinstance(has_id, dict):
target_id = has_id["id"]
else:
target_id = has_id
return target_id in (_["id"] for _ in pages)