Changeset View
Changeset View
Standalone View
Standalone View
swh/deposit/tests/cli/test_client.py
# Copyright (C) 2020 The Software Heritage developers | # Copyright (C) 2020 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
import ast | import ast | ||||
from collections import OrderedDict | |||||
import contextlib | import contextlib | ||||
import json | import json | ||||
import logging | import logging | ||||
import os | import os | ||||
from unittest.mock import MagicMock | from unittest.mock import MagicMock | ||||
import pytest | import pytest | ||||
import yaml | import yaml | ||||
from swh.deposit.api.checks import check_metadata | |||||
from swh.deposit.cli import deposit as cli | from swh.deposit.cli import deposit as cli | ||||
from swh.deposit.cli.client import InputError, _client, _collection, _url, generate_slug | from swh.deposit.cli.client import ( | ||||
InputError, | |||||
_client, | |||||
_collection, | |||||
_url, | |||||
generate_metadata, | |||||
generate_slug, | |||||
) | |||||
from swh.deposit.client import MaintenanceError, PublicApiDepositClient | from swh.deposit.client import MaintenanceError, PublicApiDepositClient | ||||
from swh.deposit.parsers import parse_xml | from swh.deposit.parsers import parse_xml | ||||
from ..conftest import TEST_USER | from ..conftest import TEST_USER | ||||
@pytest.fixture | @pytest.fixture | ||||
def deposit_config(): | def deposit_config(): | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | down_for_maintenance_log_record = ( | ||||
logging.ERROR, | logging.ERROR, | ||||
"Database backend maintenance: Temporarily unavailable, try again later.", | "Database backend maintenance: Temporarily unavailable, try again later.", | ||||
) | ) | ||||
assert down_for_maintenance_log_record in caplog.record_tuples | assert down_for_maintenance_log_record in caplog.record_tuples | ||||
client_mock_api_down.service_document.assert_called_once_with() | client_mock_api_down.service_document.assert_called_once_with() | ||||
def test_cli_client_generate_metadata_ok(slug): | |||||
"""Generated metadata is well formed and pass service side metadata checks | |||||
""" | |||||
actual_metadata_xml = generate_metadata( | |||||
"deposit-client", "project-name", "external-id", authors=["some", "authors"] | |||||
) | |||||
actual_metadata = dict(parse_xml(actual_metadata_xml)) | |||||
assert actual_metadata["author"] == "deposit-client" | |||||
assert actual_metadata["title"] == "project-name" | |||||
assert actual_metadata["updated"] is not None | |||||
assert actual_metadata["codemeta:name"] == "project-name" | |||||
assert actual_metadata["codemeta:identifier"] == "external-id" | |||||
assert actual_metadata["codemeta:author"] == [ | |||||
OrderedDict([("codemeta:name", "some")]), | |||||
OrderedDict([("codemeta:name", "authors")]), | |||||
] | |||||
ardumont: With this ^, we won't have that kind of unpleasant surprise any more. | |||||
checks_ok, detail = check_metadata(actual_metadata) | |||||
assert checks_ok is True | |||||
assert detail is None | |||||
def test_cli_single_minimal_deposit( | def test_cli_single_minimal_deposit( | ||||
sample_archive, slug, patched_tmp_path, requests_mock_datadir, cli_runner | sample_archive, slug, patched_tmp_path, requests_mock_datadir, cli_runner | ||||
): | ): | ||||
""" This ensure a single deposit upload through the cli is fine, cf. | """ This ensure a single deposit upload through the cli is fine, cf. | ||||
https://docs.softwareheritage.org/devel/swh-deposit/getting-started.html#single-deposit | https://docs.softwareheritage.org/devel/swh-deposit/getting-started.html#single-deposit | ||||
""" # noqa | """ # noqa | ||||
metadata_path = os.path.join(patched_tmp_path, "metadata.xml") | metadata_path = os.path.join(patched_tmp_path, "metadata.xml") | ||||
Show All 24 Lines | ): | ||||
assert json.loads(result.output) == { | assert json.loads(result.output) == { | ||||
"deposit_id": "615", | "deposit_id": "615", | ||||
"deposit_status": "partial", | "deposit_status": "partial", | ||||
"deposit_status_detail": None, | "deposit_status_detail": None, | ||||
"deposit_date": "Oct. 8, 2020, 4:57 p.m.", | "deposit_date": "Oct. 8, 2020, 4:57 p.m.", | ||||
} | } | ||||
with open(metadata_path) as fd: | with open(metadata_path) as fd: | ||||
assert ( | actual_metadata = dict(parse_xml(fd.read())) | ||||
fd.read() | assert actual_metadata["author"] == TEST_USER["username"] | ||||
== f"""\ | assert actual_metadata["codemeta:name"] == "test-project" | ||||
<?xml version="1.0" encoding="utf-8"?> | assert actual_metadata["title"] == "test-project" | ||||
<entry xmlns="http://www.w3.org/2005/Atom" \ | assert actual_metadata["updated"] is not None | ||||
xmlns:codemeta="https://doi.org/10.5063/SCHEMA/CODEMETA-2.0"> | assert actual_metadata["codemeta:identifier"] == slug | ||||
\t<codemeta:name>test-project</codemeta:name> | assert actual_metadata["codemeta:author"] == OrderedDict( | ||||
\t<codemeta:identifier>{slug}</codemeta:identifier> | [("codemeta:name", "Jane Doe")] | ||||
\t<codemeta:author> | |||||
\t\t<codemeta:name>Jane Doe</codemeta:name> | |||||
\t</codemeta:author> | |||||
</entry>""" | |||||
) | ) | ||||
def test_cli_validation_metadata( | def test_cli_validation_metadata( | ||||
sample_archive, caplog, patched_tmp_path, cli_runner, slug | sample_archive, caplog, patched_tmp_path, cli_runner, slug | ||||
): | ): | ||||
"""Multiple metadata flags scenario (missing, conflicts) properly fails the calls | """Multiple metadata flags scenario (missing, conflicts) properly fails the calls | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | assert json.loads(result.output) == { | ||||
"deposit_id": "615", | "deposit_id": "615", | ||||
"deposit_status": "partial", | "deposit_status": "partial", | ||||
"deposit_status_detail": None, | "deposit_status_detail": None, | ||||
"deposit_date": "Oct. 8, 2020, 4:57 p.m.", | "deposit_date": "Oct. 8, 2020, 4:57 p.m.", | ||||
} | } | ||||
with open(metadata_path) as fd: | with open(metadata_path) as fd: | ||||
metadata_xml = fd.read() | metadata_xml = fd.read() | ||||
actual_metadata = parse_xml(metadata_xml) | actual_metadata = dict(parse_xml(metadata_xml)) | ||||
assert actual_metadata["codemeta:identifier"] is not None | assert actual_metadata["codemeta:identifier"] is not None | ||||
def test_cli_multisteps_deposit( | def test_cli_multisteps_deposit( | ||||
sample_archive, datadir, slug, requests_mock_datadir, cli_runner | sample_archive, datadir, slug, requests_mock_datadir, cli_runner | ||||
): | ): | ||||
""" First deposit a partial deposit (no metadata, only archive), then update the metadata part. | """ First deposit a partial deposit (no metadata, only archive), then update the metadata part. | ||||
https://docs.softwareheritage.org/devel/swh-deposit/getting-started.html#multisteps-deposit | https://docs.softwareheritage.org/devel/swh-deposit/getting-started.html#multisteps-deposit | ||||
▲ Show 20 Lines • Show All 246 Lines • Show Last 20 Lines |
With this ^, we won't have that kind of unpleasant surprise any more.