mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 02:04:04 +08:00
485 lines
17 KiB
Python
485 lines
17 KiB
Python
"""Unit tests for importing and exporting data from model stores."""
|
|
import json
|
|
import os
|
|
from tempfile import mkdtemp, NamedTemporaryFile
|
|
|
|
from galaxy import model
|
|
from galaxy.model import store
|
|
from galaxy.model.metadata import MetadataTempFile
|
|
from galaxy.tools.imp_exp import unpack_tar_gz_archive
|
|
from .tools.test_history_imp_exp import _create_datasets, _mock_app, Dummy
|
|
|
|
|
|
def test_import_export_history():
|
|
"""Test a simple job import/export after decompressing an archive (like history import/export tool)."""
|
|
app = _mock_app()
|
|
|
|
u, h, d1, d2, j = _setup_simple_cat_job(app)
|
|
|
|
imported_history = _import_export_history(app, h, export_files="copy")
|
|
|
|
_assert_simple_cat_job_imported(imported_history)
|
|
|
|
|
|
def test_import_export_bag_archive():
|
|
"""Test a simple job import/export using a BagIt archive."""
|
|
dest_parent = mkdtemp()
|
|
dest_export = os.path.join(dest_parent, "moo.tgz")
|
|
|
|
app = _mock_app()
|
|
|
|
u, h, d1, d2, j = _setup_simple_cat_job(app)
|
|
|
|
with store.BagArchiveModelExportStore(dest_export, app=app, bag_archiver="tgz", export_files="copy") as export_store:
|
|
export_store.export_history(h)
|
|
|
|
model_store = store.BagArchiveImportModelStore(dest_export, app=app, user=u)
|
|
with model_store.target_history(default_history=None) as imported_history:
|
|
model_store.perform_import(imported_history)
|
|
|
|
_assert_simple_cat_job_imported(imported_history)
|
|
|
|
|
|
def test_import_export_datasets():
|
|
"""Test a simple job import/export using a directory."""
|
|
app, h, temp_directory, import_history = _setup_simple_export({"for_edit": False})
|
|
u = h.user
|
|
|
|
_perform_import_from_directory(temp_directory, app, u, import_history)
|
|
|
|
datasets = import_history.datasets
|
|
assert len(datasets) == 2
|
|
imported_job = datasets[1].creating_job
|
|
assert imported_job
|
|
assert imported_job.output_datasets
|
|
assert imported_job.output_datasets[0].dataset == datasets[1]
|
|
|
|
assert imported_job.input_datasets
|
|
assert imported_job.input_datasets[0].dataset == datasets[0]
|
|
|
|
|
|
def test_import_library_require_permissions():
|
|
"""Verify library creation (import) is off by default."""
|
|
app = _mock_app()
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
|
|
library = model.Library(name="my library 1", description="my library description", synopsis="my synopsis")
|
|
root_folder = model.LibraryFolder(name="my library 1", description='folder description')
|
|
library.root_folder = root_folder
|
|
sa_session.add_all((library, root_folder))
|
|
sa_session.flush()
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app) as export_store:
|
|
export_store.export_library(library)
|
|
|
|
error_caught = False
|
|
try:
|
|
import_model_store = store.get_import_model_store_for_directory(temp_directory, app=app, user=u)
|
|
import_model_store.perform_import()
|
|
except AssertionError:
|
|
# TODO: throw and catch a better exception...
|
|
error_caught = True
|
|
|
|
assert error_caught
|
|
|
|
|
|
def test_import_export_library():
|
|
"""Test basics of library, library folder, and library dataset import/export."""
|
|
app = _mock_app()
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
|
|
library = model.Library(name="my library 1", description="my library description", synopsis="my synopsis")
|
|
root_folder = model.LibraryFolder(name="my library 1", description='folder description')
|
|
library.root_folder = root_folder
|
|
sa_session.add_all((library, root_folder))
|
|
sa_session.flush()
|
|
|
|
subfolder = model.LibraryFolder(name="sub folder 1", description="sub folder")
|
|
root_folder.add_folder(subfolder)
|
|
sa_session.add(subfolder)
|
|
|
|
ld = model.LibraryDataset(folder=root_folder, name="my name", info="my library dataset")
|
|
ldda = model.LibraryDatasetDatasetAssociation(
|
|
create_dataset=True, flush=False
|
|
)
|
|
ld.library_dataset_dataset_association = ldda
|
|
root_folder.add_library_dataset(ld)
|
|
|
|
sa_session.add(ld)
|
|
sa_session.add(ldda)
|
|
|
|
sa_session.flush()
|
|
assert len(root_folder.datasets) == 1
|
|
assert len(root_folder.folders) == 1
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app) as export_store:
|
|
export_store.export_library(library)
|
|
|
|
import_model_store = store.get_import_model_store_for_directory(temp_directory, app=app, user=u, import_options=store.ImportOptions(allow_library_creation=True))
|
|
import_model_store.perform_import()
|
|
|
|
all_libraries = sa_session.query(model.Library).all()
|
|
assert len(all_libraries) == 2, len(all_libraries)
|
|
all_lddas = sa_session.query(model.LibraryDatasetDatasetAssociation).all()
|
|
assert len(all_lddas) == 2, len(all_lddas)
|
|
|
|
new_library = [l for l in all_libraries if l.id != library.id][0]
|
|
assert new_library.name == "my library 1"
|
|
assert new_library.description == "my library description"
|
|
assert new_library.synopsis == "my synopsis"
|
|
|
|
new_root = new_library.root_folder
|
|
assert new_root
|
|
assert new_root.name == "my library 1"
|
|
|
|
assert len(new_root.folders) == 1
|
|
assert len(new_root.datasets) == 1
|
|
|
|
|
|
def test_finalize_job_state():
|
|
"""Verify jobs are given finalized states on import."""
|
|
app, h, temp_directory, import_history = _setup_simple_export({"for_edit": False})
|
|
u = h.user
|
|
|
|
with open(os.path.join(temp_directory, store.ATTRS_FILENAME_JOBS), "r") as f:
|
|
job_attrs = json.load(f)
|
|
|
|
for job in job_attrs:
|
|
job["state"] = "queued"
|
|
|
|
with open(os.path.join(temp_directory, store.ATTRS_FILENAME_JOBS), "w") as f:
|
|
json.dump(job_attrs, f)
|
|
|
|
_perform_import_from_directory(temp_directory, app, u, import_history)
|
|
|
|
datasets = import_history.datasets
|
|
assert len(datasets) == 2
|
|
imported_job = datasets[1].creating_job
|
|
assert imported_job
|
|
assert imported_job.state == model.Job.states.ERROR
|
|
|
|
|
|
def test_import_export_edit_datasets():
|
|
"""Test modifying existing HDA and dataset metadata with import."""
|
|
app, h, temp_directory, import_history = _setup_simple_export({"for_edit": True})
|
|
u = h.user
|
|
|
|
# Fabric editing metadata...
|
|
datasets_metadata_path = os.path.join(temp_directory, store.ATTRS_FILENAME_DATASETS)
|
|
with open(datasets_metadata_path, "r") as f:
|
|
datasets_metadata = json.load(f)
|
|
|
|
datasets_metadata[0]["name"] = "my new name 0"
|
|
datasets_metadata[1]["name"] = "my new name 1"
|
|
|
|
assert "dataset" in datasets_metadata[0]
|
|
datasets_metadata[0]["dataset"]["object_store_id"] = "foo1"
|
|
|
|
with open(datasets_metadata_path, "w") as f:
|
|
json.dump(datasets_metadata, f)
|
|
|
|
_perform_import_from_directory(temp_directory, app, u, import_history, store.ImportOptions(allow_edit=True))
|
|
|
|
datasets = import_history.datasets
|
|
assert len(datasets) == 0
|
|
|
|
d1 = h.datasets[0]
|
|
d2 = h.datasets[1]
|
|
|
|
assert d1.name == "my new name 0", d1.name
|
|
assert d2.name == "my new name 1", d2.name
|
|
assert d1.dataset.object_store_id == "foo1", d1.dataset.object_store_id
|
|
|
|
|
|
def test_import_export_edit_collection():
|
|
"""Test modifying existing collections with imports."""
|
|
app = _mock_app()
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
h = model.History(name="Test History", user=u)
|
|
|
|
c1 = model.DatasetCollection(collection_type="list", populated=False)
|
|
hc1 = model.HistoryDatasetCollectionAssociation(history=h, hid=1, collection=c1, name="HistoryCollectionTest1")
|
|
|
|
sa_session.add(hc1)
|
|
sa_session.add(h)
|
|
sa_session.flush()
|
|
|
|
import_history = model.History(name="Test History for Import", user=u)
|
|
sa_session.add(import_history)
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app, for_edit=True) as export_store:
|
|
export_store.add_dataset_collection(hc1)
|
|
|
|
# Fabric editing metadata for collection...
|
|
collections_metadata_path = os.path.join(temp_directory, store.ATTRS_FILENAME_COLLECTIONS)
|
|
datasets_metadata_path = os.path.join(temp_directory, store.ATTRS_FILENAME_DATASETS)
|
|
with open(collections_metadata_path, "r") as f:
|
|
hdcas_metadata = json.load(f)
|
|
|
|
assert len(hdcas_metadata) == 1
|
|
hdca_metadata = hdcas_metadata[0]
|
|
assert hdca_metadata
|
|
assert "id" in hdca_metadata
|
|
assert "collection" in hdca_metadata
|
|
collection_metadata = hdca_metadata["collection"]
|
|
assert "populated_state" in collection_metadata
|
|
assert collection_metadata["populated_state"] == model.DatasetCollection.populated_states.NEW
|
|
|
|
collection_metadata["populated_state"] = model.DatasetCollection.populated_states.OK
|
|
|
|
d1 = model.HistoryDatasetAssociation(extension="txt", create_dataset=True, flush=False)
|
|
d1.hid = 1
|
|
d2 = model.HistoryDatasetAssociation(extension="txt", create_dataset=True, flush=False)
|
|
d2.hid = 2
|
|
serialization_options = model.SerializationOptions(for_edit=True)
|
|
dataset_list = [d1.serialize(app.security, serialization_options),
|
|
d2.serialize(app.security, serialization_options)]
|
|
|
|
dc = model.DatasetCollection(
|
|
id=collection_metadata["id"],
|
|
collection_type="list",
|
|
element_count=2,
|
|
)
|
|
dc.populated_state = model.DatasetCollection.populated_states.OK
|
|
dce1 = model.DatasetCollectionElement(
|
|
element=d1,
|
|
element_index=0,
|
|
element_identifier="first",
|
|
)
|
|
dce2 = model.DatasetCollectionElement(
|
|
element=d2,
|
|
element_index=1,
|
|
element_identifier="second",
|
|
)
|
|
dc.elements = [dce1, dce2]
|
|
with open(datasets_metadata_path, "w") as datasets_f:
|
|
json.dump(dataset_list, datasets_f)
|
|
|
|
hdca_metadata["collection"] = dc.serialize(app.security, serialization_options)
|
|
with open(collections_metadata_path, "w") as collections_f:
|
|
json.dump(hdcas_metadata, collections_f)
|
|
|
|
_perform_import_from_directory(temp_directory, app, u, import_history, store.ImportOptions(allow_edit=True))
|
|
|
|
sa_session.refresh(c1)
|
|
assert c1.populated_state == model.DatasetCollection.populated_states.OK, c1.populated_state
|
|
assert len(c1.elements) == 2
|
|
|
|
|
|
def test_import_export_composite_datasets():
|
|
app = _mock_app()
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
h = model.History(name="Test History", user=u)
|
|
|
|
d1 = _create_datasets(sa_session, h, 1, extension="html")[0]
|
|
d1.dataset.create_extra_files_path()
|
|
sa_session.add_all((h, d1))
|
|
sa_session.flush()
|
|
|
|
primary = NamedTemporaryFile("w")
|
|
primary.write("cool primary file")
|
|
primary.flush()
|
|
app.object_store.update_from_file(
|
|
d1.dataset,
|
|
file_name=primary.name,
|
|
create=True,
|
|
preserve_symlinks=True
|
|
)
|
|
|
|
composite1 = NamedTemporaryFile("w")
|
|
composite1.write("cool composite file")
|
|
composite1.flush()
|
|
|
|
app.object_store.update_from_file(
|
|
d1.dataset,
|
|
extra_dir=os.path.normpath(os.path.join(d1.extra_files_path, "parent_dir")),
|
|
alt_name="child_file",
|
|
file_name=composite1.name,
|
|
create=True,
|
|
preserve_symlinks=True
|
|
)
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app, export_files="copy") as export_store:
|
|
export_store.add_dataset(d1)
|
|
|
|
import_history = model.History(name="Test History for Import", user=u)
|
|
sa_session.add(import_history)
|
|
sa_session.flush()
|
|
_perform_import_from_directory(temp_directory, app, u, import_history)
|
|
assert len(import_history.datasets) == 1
|
|
import_dataset = import_history.datasets[0]
|
|
root_extra_files_path = import_dataset.extra_files_path
|
|
assert len(os.listdir(root_extra_files_path)) == 1
|
|
assert os.listdir(root_extra_files_path)[0] == "parent_dir"
|
|
composite_sub_dir = os.path.join(root_extra_files_path, "parent_dir")
|
|
child_files = os.listdir(composite_sub_dir)
|
|
assert len(child_files) == 1
|
|
with open(os.path.join(composite_sub_dir, child_files[0]), "r") as f:
|
|
contents = f.read()
|
|
assert contents == "cool composite file"
|
|
|
|
|
|
def test_edit_metadata_files():
|
|
app = _mock_app(store_by="uuid")
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
h = model.History(name="Test History", user=u)
|
|
|
|
d1 = _create_datasets(sa_session, h, 1, extension="bam")[0]
|
|
sa_session.add_all((h, d1))
|
|
sa_session.flush()
|
|
index = NamedTemporaryFile("w")
|
|
index.write("cool bam index")
|
|
metadata_dict = {"bam_index": MetadataTempFile.from_JSON({"kwds": {}, "filename": index.name})}
|
|
d1.metadata.from_JSON_dict(json_dict=metadata_dict)
|
|
assert d1.metadata.bam_index
|
|
assert isinstance(d1.metadata.bam_index, model.MetadataFile)
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app, for_edit=True, strip_metadata_files=False) as export_store:
|
|
export_store.add_dataset(d1)
|
|
|
|
import_history = model.History(name="Test History for Import", user=u)
|
|
sa_session.add(import_history)
|
|
sa_session.flush()
|
|
_perform_import_from_directory(temp_directory, app, u, import_history, store.ImportOptions(allow_edit=True))
|
|
|
|
|
|
def test_sessionless_import_edit_datasets():
|
|
app, h, temp_directory, import_history = _setup_simple_export({"for_edit": True})
|
|
# Create a model store without a session and import it.
|
|
import_model_store = store.get_import_model_store_for_directory(temp_directory, import_options=store.ImportOptions(allow_dataset_object_edit=True, allow_edit=True))
|
|
import_model_store.perform_import()
|
|
# Not using app.sa_session but a session mock that has a query/find pattern emulating usage
|
|
# of real sa_session.
|
|
d1 = import_model_store.sa_session.query(model.HistoryDatasetAssociation).find(h.datasets[0].id)
|
|
d2 = import_model_store.sa_session.query(model.HistoryDatasetAssociation).find(h.datasets[1].id)
|
|
assert d1 is not None
|
|
assert d2 is not None
|
|
|
|
|
|
def test_import_datasets_with_ids_fails_if_not_editing_models():
|
|
app, h, temp_directory, import_history = _setup_simple_export({"for_edit": True})
|
|
u = h.user
|
|
|
|
caught = None
|
|
try:
|
|
_perform_import_from_directory(temp_directory, app, u, import_history, store.ImportOptions(allow_edit=False))
|
|
except AssertionError as e:
|
|
# TODO: catch a better exception
|
|
caught = e
|
|
assert caught
|
|
|
|
|
|
def _setup_simple_export(export_kwds):
|
|
app = _mock_app()
|
|
|
|
u, h, d1, d2, j = _setup_simple_cat_job(app)
|
|
|
|
sa_session = app.model.context
|
|
|
|
import_history = model.History(name="Test History for Import", user=u)
|
|
sa_session.add(import_history)
|
|
|
|
temp_directory = mkdtemp()
|
|
with store.DirectoryModelExportStore(temp_directory, app=app, **export_kwds) as export_store:
|
|
export_store.add_dataset(d1)
|
|
export_store.add_dataset(d2)
|
|
|
|
return app, h, temp_directory, import_history
|
|
|
|
|
|
def _assert_simple_cat_job_imported(imported_history):
|
|
assert imported_history.name == "imported from archive: Test History"
|
|
|
|
datasets = imported_history.datasets
|
|
assert len(datasets) == 2
|
|
imported_job = datasets[1].creating_job
|
|
assert imported_job
|
|
assert imported_job.output_datasets
|
|
assert imported_job.output_datasets[0].dataset == datasets[1]
|
|
|
|
assert imported_job.input_datasets
|
|
assert imported_job.input_datasets[0].dataset == datasets[0]
|
|
|
|
with open(datasets[0].file_name, "r") as f:
|
|
assert f.read().startswith("chr1 4225 19670")
|
|
with open(datasets[1].file_name, "r") as f:
|
|
assert f.read().startswith("chr1\t147962192\t147962580\tNM_005997_cds_0_0_chr1_147962193_r\t0\t-")
|
|
|
|
|
|
def _setup_simple_cat_job(app):
|
|
sa_session = app.model.context
|
|
|
|
u = model.User(email="collection@example.com", password="password")
|
|
h = model.History(name="Test History", user=u)
|
|
|
|
d1, d2 = _create_datasets(sa_session, h, 2)
|
|
|
|
j = model.Job()
|
|
j.user = u
|
|
j.tool_id = "cat1"
|
|
|
|
j.add_input_dataset("input1", d1)
|
|
j.add_output_dataset("out_file1", d2)
|
|
|
|
sa_session.add_all((d1, d2, h, j))
|
|
sa_session.flush()
|
|
|
|
app.object_store.update_from_file(d1, file_name="test-data/1.txt", create=True)
|
|
app.object_store.update_from_file(d2, file_name="test-data/2.bed", create=True)
|
|
|
|
return u, h, d1, d2, j
|
|
|
|
|
|
def _import_export_history(app, h, dest_export=None, export_files=None):
|
|
if dest_export is None:
|
|
dest_parent = mkdtemp()
|
|
dest_export = os.path.join(dest_parent, "moo.tgz")
|
|
|
|
with store.TarModelExportStore(dest_export, app=app, export_files=export_files) as export_store:
|
|
export_store.export_history(h)
|
|
|
|
imported_history = import_archive(dest_export, app, h.user)
|
|
assert imported_history
|
|
return imported_history
|
|
|
|
|
|
def _perform_import_from_directory(directory, app, user, import_history, import_options=None):
|
|
import_model_store = store.get_import_model_store_for_directory(directory, app=app, user=user, import_options=import_options)
|
|
with import_model_store.target_history(default_history=import_history):
|
|
import_model_store.perform_import(import_history)
|
|
|
|
|
|
def import_archive(archive_path, app, user):
|
|
dest_parent = mkdtemp()
|
|
dest_dir = os.path.join(dest_parent, 'dest')
|
|
|
|
options = Dummy()
|
|
options.is_url = False
|
|
options.is_file = True
|
|
options.is_b64encoded = False
|
|
|
|
args = (archive_path, dest_dir)
|
|
unpack_tar_gz_archive.main(options, args)
|
|
|
|
new_history = None
|
|
model_store = store.get_import_model_store_for_directory(dest_dir, app=app, user=user)
|
|
with model_store.target_history(default_history=None) as new_history:
|
|
model_store.perform_import(new_history)
|
|
|
|
return new_history
|