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_folder_contents

from typing import (
    Any,
    List,
    Optional,
    Tuple,
)

from galaxy_test.base.decorators import requires_new_library
from galaxy_test.base.populators import (
    DatasetCollectionPopulator,
    DatasetPopulator,
    LibraryPopulator,
)
from ._framework import ApiTestCase


[docs]class TestFolderContentsApi(ApiTestCase): dataset_populator: DatasetPopulator
[docs] def setUp(self): super().setUp() self.dataset_populator = DatasetPopulator(self.galaxy_interactor) self.dataset_collection_populator = DatasetCollectionPopulator(self.galaxy_interactor) self.library_populator = LibraryPopulator(self.galaxy_interactor) self.library = self.library_populator.new_private_library("FolderContentsTestsLibrary") self.root_folder_id = self._create_folder_in_library("Test Folder Contents")
[docs] @requires_new_library def test_create_hda_with_ldda_message(self, history_id): hda_id = self._create_hda(history_id) ldda_message = "Test message" data = { "from_hda_id": hda_id, "ldda_message": ldda_message, } ldda = self._create_content_in_folder_with_payload(self.root_folder_id, data) self._assert_has_keys(ldda, "name", "id")
[docs] @requires_new_library def test_create_hdca_with_ldda_message(self, history_id): contents = ["dataset01", "dataset02"] hdca_id = self._create_hdca_with_contents(history_id, contents) ldda_message = "Test message" data = { "from_hdca_id": hdca_id, "ldda_message": ldda_message, } lddas = self._create_content_in_folder_with_payload(self.root_folder_id, data) assert len(contents) == len(lddas)
[docs] @requires_new_library def test_index(self, history_id): folder_id = self._create_folder_in_library("Test Folder Contents Index") self._create_subfolder_in(folder_id) self._create_dataset_in_folder(history_id, folder_id) response = self._get(f"folders/{folder_id}/contents") self._assert_index_count_is_correct(response, expected_contents_count=2)
[docs] @requires_new_library def test_index_include_deleted(self, history_id): folder_name = "Test Folder Contents Index include deleted" folder_id = self._create_folder_in_library(folder_name) sub_folder_id = self._create_subfolder_in(folder_id) ldda_id, _ = self._create_dataset_in_folder(history_id, folder_id) self._delete_library_dataset(ldda_id) self._delete_subfolder(sub_folder_id) response = self._get(f"folders/{folder_id}/contents") self._assert_index_count_is_correct(response, expected_contents_count=0) include_deleted = True response = self._get(f"folders/{folder_id}/contents?include_deleted={include_deleted}") index_response = self._assert_index_count_is_correct(response, expected_contents_count=2) for content in index_response["folder_contents"]: assert content["deleted"] is True
[docs] @requires_new_library def test_index_pagination(self, history_id): folder_name = "Test Folder Contents Pagination" folder_id = self._create_folder_in_library(folder_name) num_subfolders = 5 for index in range(num_subfolders): self._create_subfolder_in(folder_id, name=f"Folder_{index}") num_datasets = 5 for _ in range(num_datasets): self._create_dataset_in_folder(history_id, folder_id) total_items = num_datasets + num_subfolders response = self._get(f"folders/{folder_id}/contents") index_response = self._assert_index_count_is_correct(response, expected_contents_count=total_items) original_contents = index_response["folder_contents"] limit = 7 response = self._get(f"folders/{folder_id}/contents?limit={limit}") index_response = self._assert_index_count_is_correct( response, expected_contents_count=limit, expected_total_count=total_items ) limit = 20 response = self._get(f"folders/{folder_id}/contents?limit={limit}") index_response = self._assert_index_count_is_correct(response, expected_contents_count=total_items) offset = 3 response = self._get(f"folders/{folder_id}/contents?offset={offset}") index_response = self._assert_index_count_is_correct( response, expected_contents_count=total_items - offset, expected_total_count=total_items ) offset = 20 response = self._get(f"folders/{folder_id}/contents?offset={offset}") index_response = self._assert_index_count_is_correct( response, expected_contents_count=0, expected_total_count=total_items ) limit = 4 offset = 4 response = self._get(f"folders/{folder_id}/contents?limit={limit}&offset={offset}") index_response = self._assert_index_count_is_correct( response, expected_contents_count=limit, expected_total_count=total_items ) contents = index_response["folder_contents"] expected_query_result = original_contents[offset : offset + limit] for index in range(limit): assert contents[index]["id"] == expected_query_result[index]["id"] limit = 20 offset = 6 response = self._get(f"folders/{folder_id}/contents?limit={limit}&offset={offset}") actual_limit = limit if limit < total_items else total_items - offset index_response = self._assert_index_count_is_correct( response, expected_contents_count=actual_limit, expected_total_count=total_items ) contents = index_response["folder_contents"] expected_query_result = original_contents[offset : offset + actual_limit] for index in range(actual_limit): assert contents[index]["id"] == expected_query_result[index]["id"]
[docs] @requires_new_library def test_index_search_text(self, history_id): folder_name = "Test Folder Contents Index search text" folder_id = self._create_folder_in_library(folder_name) dataset_names = ["AB", "BX", "abx"] for name in dataset_names: self._create_dataset_in_folder(history_id, folder_id, name) subfolder_names = ["Folder_a", "Folder_X"] for name in subfolder_names: self._create_subfolder_in(folder_id, name) all_names = dataset_names + subfolder_names search_terms = ["A", "B", "X"] for search_text in search_terms: matching_names = [name for name in all_names if search_text.casefold() in name.casefold()] response = self._get(f"folders/{folder_id}/contents?search_text={search_text}") index_response = self._assert_index_count_is_correct(response, expected_contents_count=len(matching_names)) contents = index_response["folder_contents"] for content in contents: assert search_text.casefold() in content["name"].casefold()
[docs] @requires_new_library def test_index_permissions(self, history_id): folder_name = "Test Folder Contents Index permissions" folder_id = self._create_folder_in_library(folder_name) _, hda_id = self._create_dataset_in_folder(history_id, folder_id) self._make_dataset_private(hda_id) # Owner can access response = self._get(f"folders/{folder_id}/contents") self._assert_index_count_is_correct(response, expected_contents_count=1) # Admins can access response = self._get(f"folders/{folder_id}/contents", admin=True) self._assert_index_count_is_correct(response, expected_contents_count=1) # Other users can't access with self._different_user(): # Without access to the parent library the user gets a 404... should it be a 403 instead? response = self._get(f"folders/{folder_id}/contents") self._assert_status_code_is(response, 404) # Grant library access to this user different_user_role_id = self.dataset_populator.user_private_role_id() self._allow_library_access_to_user_role(different_user_role_id) # Runs as admin # The user can access the library folder but not the private dataset in it response = self._get(f"folders/{folder_id}/contents") self._assert_index_count_is_correct(response, expected_contents_count=0) # Grant access to this user self._allow_dataset_access(hda_id) response = self._get(f"folders/{folder_id}/contents") self._assert_index_count_is_correct(response, expected_contents_count=1)
[docs] @requires_new_library def test_index_permissions_include_deleted(self, history_id) -> None: folder_name = "Test Folder Contents Index permissions include deleted" folder_id = self._create_folder_in_library(folder_name) num_subfolders = 5 subfolder_ids: List[str] = [] deleted_subfolder_ids: List[str] = [] for index in range(num_subfolders): ldda_id = self._create_subfolder_in(folder_id, name=f"Folder_{index}") subfolder_ids.append(ldda_id) for index, subfolder_id in enumerate(subfolder_ids): if index % 2 == 0: self._delete_subfolder(subfolder_id) deleted_subfolder_ids.append(subfolder_id) num_datasets = 5 ldda_ids: List[str] = [] deleted_ldda_ids: List[str] = [] for _ in range(num_datasets): ldda_id, _ = self._create_dataset_in_folder(history_id, folder_id) ldda_ids.append(ldda_id) for index, ldda_id in enumerate(ldda_ids): if index % 2 == 0: self._delete_library_dataset(ldda_id) deleted_ldda_ids.append(ldda_id) num_total_contents = num_subfolders + num_datasets num_non_deleted = num_total_contents - len(deleted_subfolder_ids) - len(deleted_ldda_ids) # Verify deleted contents are not listed include_deleted = False response = self._get(f"folders/{folder_id}/contents?include_deleted={include_deleted}") self._assert_index_count_is_correct(response, expected_contents_count=num_non_deleted) include_deleted = True # Admins can see everything... response = self._get(f"folders/{folder_id}/contents?include_deleted={include_deleted}", admin=True) self._assert_index_count_is_correct(response, expected_contents_count=num_total_contents) # Owner can see everything too response = self._get(f"folders/{folder_id}/contents?include_deleted={include_deleted}") self._assert_index_count_is_correct(response, expected_contents_count=num_total_contents) # Users with access but no modify permission can't see deleted with self._different_user(): different_user_role_id = self.dataset_populator.user_private_role_id() self._allow_library_access_to_user_role(different_user_role_id) # Runs as admin response = self._get(f"folders/{folder_id}/contents?include_deleted={include_deleted}") self._assert_index_count_is_correct(response, expected_contents_count=num_non_deleted)
[docs] @requires_new_library def test_index_order_by(self, history_id): folder_name = "Test Folder Contents Index Order By" folder_id = self._create_folder_in_library(folder_name) subfolder_names = ["Folder_A", "Folder_B", "Folder_C"] subfolder_descriptions = ["Description Z", "Description Y", "Description X"] for index, name in enumerate(subfolder_names): self._create_subfolder_in(folder_id, name, subfolder_descriptions[index]) dataset_names = ["a", "b", "c"] ldda_messages = ["Message Z", "Message Y", "Message X"] dataset_sizes = [50, 100, 10] file_types = ["txt", "csv", "json"] for index, name in enumerate(dataset_names): self._create_dataset_in_folder( history_id, folder_id, name, content=f"{'0'*dataset_sizes[index]}", ldda_message=ldda_messages[index], file_type=file_types[index], ) # Wait for datasets to finish upload self.dataset_populator.wait_for_history(history_id) # Folders always have priority (they show-up before any dataset regardless of the sorting) and they # can only be sorted by name, description and update_time, the other sorting attributes are ignored sort_desc = False order_by = "name" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "a", "b", "c"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "description" expected_order_by_name = ["Folder_C", "Folder_B", "Folder_A", "c", "b", "a"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "type" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "b", "c", "a"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "size" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "c", "a", "b"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "update_time" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "a", "b", "c"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) sort_desc = True order_by = "name" expected_order_by_name = ["Folder_C", "Folder_B", "Folder_A", "c", "b", "a"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "description" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "a", "b", "c"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "type" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "a", "c", "b"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "size" expected_order_by_name = ["Folder_A", "Folder_B", "Folder_C", "b", "a", "c"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name) order_by = "update_time" expected_order_by_name = ["Folder_C", "Folder_B", "Folder_A", "c", "b", "a"] self._assert_folder_order_by_is_expected(folder_id, order_by, sort_desc, expected_order_by_name)
def _assert_folder_order_by_is_expected( self, folder_id: str, order_by: str, sort_desc: str, expected_order_by_name: List[str] ): response = self._get(f"folders/{folder_id}/contents?order_by={order_by}&sort_desc={sort_desc}") index_response = self._assert_index_count_is_correct( response, expected_contents_count=len(expected_order_by_name) ) for index, item in enumerate(index_response["folder_contents"]): assert item["name"] == expected_order_by_name[index] def _assert_index_count_is_correct( self, raw_response, expected_contents_count: int, expected_total_count: Optional[int] = None ) -> dict: self._assert_status_code_is(raw_response, 200) if expected_total_count is None: expected_total_count = expected_contents_count index_response = raw_response.json() metadata = index_response["metadata"] contents = index_response["folder_contents"] assert metadata["total_rows"] == expected_total_count, "Expected total rows doesn't match" assert len(contents) == expected_contents_count, "Expected number of contents doesn't match" return index_response def _create_folder_in_library(self, name: str) -> str: root_folder_id = self.library["root_folder_id"] return self._create_subfolder_in(root_folder_id, name) def _create_subfolder_in( self, folder_id: str, name: Optional[str] = None, description: Optional[str] = None ) -> str: data = { "name": name or "Test Folder", "description": description or f"The description of {name}", } create_response = self._post(f"folders/{folder_id}", data=data, json=True) self._assert_status_code_is(create_response, 200) folder = create_response.json() return folder["id"] def _create_dataset_in_folder( self, history_id: str, folder_id: str, name: Optional[str] = None, content: Optional[str] = None, ldda_message: Optional[str] = None, **kwds, ) -> Tuple[str, str]: """Returns a tuple with the LDDA ID and the underlying HDA ID""" hda_id = self._create_hda(history_id, name, content, **kwds) data = { "from_hda_id": hda_id, "ldda_message": ldda_message or "Test msg", } ldda = self._create_content_in_folder_with_payload(folder_id, data) return ldda["id"], hda_id def _create_content_in_folder_with_payload(self, folder_id: str, payload) -> Any: create_response = self._post(f"folders/{folder_id}/contents", data=payload, json=True) self._assert_status_code_is(create_response, 200) return create_response.json() def _create_hda(self, history_id: str, name: Optional[str] = None, content: Optional[str] = None, **kwds) -> str: hda = self.dataset_populator.new_dataset(history_id, name=name, content=content, **kwds) hda_id = hda["id"] return hda_id def _create_hdca_with_contents(self, history_id: str, contents: List[str]) -> str: hdca = self.dataset_collection_populator.create_list_in_history( history_id, contents=contents, direct_upload=True, wait=True ).json()["outputs"][0] hdca_id = hdca["id"] return hdca_id def _delete_library_dataset(self, ldda_id: str) -> None: delete_response = self._delete(f"libraries/datasets/{ldda_id}") self._assert_status_code_is(delete_response, 200) def _delete_subfolder(self, folder_id: str) -> None: delete_response = self._delete(f"folders/{folder_id}") self._assert_status_code_is(delete_response, 200) def _allow_library_access_to_user_role(self, role_id: str): library_id = self.library["id"] action = "set_permissions" data = { "access_ids[]": role_id, } response = self._post(f"libraries/{library_id}/permissions?action={action}", data=data, admin=True, json=True) self._assert_status_code_is(response, 200) def _allow_dataset_access(self, dataset_id: str): payload = {"action": "remove_restrictions"} update_response = self._put(f"datasets/{dataset_id}/permissions", payload, admin=True, json=True) self._assert_status_code_is_ok(update_response) def _make_dataset_private(self, dataset_id: str): payload = {"action": "make_private"} update_response = self._put(f"datasets/{dataset_id}/permissions", payload, json=True) self._assert_status_code_is_ok(update_response)