Skip to content

Commit 43e3b0f

Browse files
authored
Merge pull request #564 from OP-TED/feature/SWS1-25
Feature tests
2 parents adc2f3f + 2b5c535 commit 43e3b0f

8 files changed

Lines changed: 17860 additions & 6 deletions

File tree

docs/antora/modules/ROOT/attachments/FATs/2025-01-16-TED-SWS-FAT-complete.html

Lines changed: 17583 additions & 0 deletions
Large diffs are not rendered by default.

tests/features/notice_metadata_processor/conftest.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import pathlib
2+
13
import pytest
24

35
from ted_sws import config
6+
from ted_sws.core.model.manifestation import XMLManifestation
7+
from ted_sws.core.model.notice import Notice
48
from ted_sws.data_manager.adapters.mapping_suite_repository import MappingSuiteRepositoryInFileSystem, \
59
MappingSuiteRepositoryMongoDB
10+
from ted_sws.data_sampler.services.notice_xml_indexer import index_notice
611
from ted_sws.notice_metadata_processor.services.metadata_normalizer import normalise_notice
712
from tests import TEST_DATA_PATH
813
from tests.fakes.fake_repository import FakeNoticeRepository
@@ -34,6 +39,7 @@ def normalised_notice(notice_2020):
3439
normalise_notice(notice=notice)
3540
return notice
3641

42+
3743
@pytest.fixture
3844
def normalised_eForm_notice(indexed_eform_notice_622690):
3945
notice = indexed_eform_notice_622690.copy()
@@ -51,3 +57,39 @@ def mapping_suite_repository_with_mapping_suite(notice_eligibility_repository_pa
5157
def clean_mapping_suite_repository(mongodb_client):
5258
mapping_suite_repository = MappingSuiteRepositoryMongoDB(mongodb_client=mongodb_client)
5359
return mapping_suite_repository
60+
61+
62+
@pytest.fixture
63+
def sample_ef_html_unsafe_notice_path() -> pathlib.Path:
64+
return TEST_DATA_PATH / "notice_normalisation" / "ef_html_unsafe_notice.xml"
65+
66+
67+
@pytest.fixture
68+
def sample_indexed_ef_html_unsafe_notice(
69+
sample_ef_html_unsafe_notice_path: pathlib.Path) -> Notice:
70+
notice: Notice = Notice(ted_id=sample_ef_html_unsafe_notice_path.name)
71+
notice.set_xml_manifestation(
72+
XMLManifestation(object_data=sample_ef_html_unsafe_notice_path.read_text()))
73+
74+
return index_notice(notice)
75+
76+
77+
@pytest.fixture
78+
def sample_sf_html_unsafe_notice_path() -> pathlib.Path:
79+
return TEST_DATA_PATH / "notice_normalisation" / "sf_html_unsafe_notice.xml"
80+
81+
82+
@pytest.fixture
83+
def sample_indexed_sf_html_unsafe_notice(
84+
sample_sf_html_unsafe_notice_path: pathlib.Path) -> Notice:
85+
notice: Notice = Notice(ted_id=sample_sf_html_unsafe_notice_path.name)
86+
notice.set_xml_manifestation(
87+
XMLManifestation(object_data=sample_sf_html_unsafe_notice_path.read_text()))
88+
89+
return index_notice(notice)
90+
91+
92+
@pytest.fixture
93+
def html_incompatible_str() -> str:
94+
"""Provides a test string containing HTML incompatible characters."""
95+
return "Construction work & planning <br />"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Feature: Notice Normalisation
2+
As a User
3+
I want to normalize notice data
4+
So that it meets the required format
5+
6+
Scenario: Normalising notice with spaces in notice ID
7+
Given an EF notice with spaces in notice ID
8+
And an SF notice with spaces in notice ID
9+
When the EF notice is normalised
10+
Then the EF notice ID should not contain leading or trailing spaces
11+
When the SF notice is normalised
12+
Then the SF notice ID should not contain leading or trailing spaces
13+
14+
Scenario: Processing HTML incompatible string
15+
Given an HTML incompatible string
16+
When the string cannot be parsed as XML
17+
And the string is converted to HTML compatible format
18+
Then the resulting string should be well-formed XML
19+
20+
Scenario: Normalising notice with HTML incompatible title
21+
Given an EF notice with HTML incompatible title
22+
And an SF notice with HTML incompatible title
23+
When the EF notice is normalised
24+
Then all EF notice titles should be valid XML
25+
When the SF notice is normalised
26+
Then all SF notice titles should be valid XML
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from xml.etree import ElementTree
2+
from xml.etree.ElementTree import ParseError
3+
4+
import pytest
5+
from pytest_bdd import scenario, given, when, then
6+
7+
from ted_sws.core.model.metadata import LanguageTaggedString
8+
from ted_sws.core.model.notice import Notice
9+
from ted_sws.notice_metadata_processor.adapters.notice_metadata_normaliser import get_html_compatible_string
10+
from ted_sws.notice_metadata_processor.services.metadata_normalizer import normalise_notice
11+
12+
13+
def html_str(content: str) -> str:
14+
return f"""<?xml version="1.0" encoding="UTF-8"?> <body>{content}</body>"""
15+
16+
17+
@scenario('notice_normalisation.feature', 'Normalising notice with spaces in notice ID')
18+
def test_normalising_notice_with_spaces():
19+
"""Test normalisation of notices with spaces in ID."""
20+
21+
22+
@scenario('notice_normalisation.feature', 'Processing HTML incompatible string')
23+
def test_processing_html_incompatible_string():
24+
"""Test processing of HTML incompatible strings."""
25+
26+
27+
@scenario('notice_normalisation.feature', 'Normalising notice with HTML incompatible title')
28+
def test_normalising_notice_with_html_incompatible_title():
29+
"""Test normalisation of notices with HTML incompatible titles."""
30+
31+
32+
# Shared fixtures and steps
33+
@given('an EF notice with spaces in notice ID')
34+
def an_ef_notice_with_spaces_in_notice_id(sample_indexed_ef_html_unsafe_notice: Notice) -> Notice:
35+
"""Provide EF notice fixture."""
36+
return sample_indexed_ef_html_unsafe_notice
37+
38+
39+
@given('an SF notice with spaces in notice ID')
40+
def an_sf_notice_with_spaces_in_notice_id(sample_indexed_sf_html_unsafe_notice: Notice) -> Notice:
41+
"""Provide SF notice fixture."""
42+
return sample_indexed_sf_html_unsafe_notice
43+
44+
45+
@when('the EF notice is normalised', target_fixture='normalised_ef_notice')
46+
def the_ef_notice_is_normalised(sample_indexed_ef_html_unsafe_notice: Notice) -> Notice:
47+
"""Normalize EF notice."""
48+
return normalise_notice(sample_indexed_ef_html_unsafe_notice)
49+
50+
51+
@when('the SF notice is normalised', target_fixture='normalised_sf_notice')
52+
def the_sf_notice_is_normalised(sample_indexed_sf_html_unsafe_notice: Notice) -> Notice:
53+
"""Normalize SF notice."""
54+
return normalise_notice(sample_indexed_sf_html_unsafe_notice)
55+
56+
57+
@then('the EF notice ID should not contain leading or trailing spaces')
58+
def the_ef_notice_id_should_not_contain_leading_or_trailing_spaces(normalised_ef_notice: Notice):
59+
"""Verify EF notice ID has no extra spaces."""
60+
assert normalised_ef_notice.normalised_metadata.notice_publication_number.strip() == \
61+
normalised_ef_notice.normalised_metadata.notice_publication_number
62+
63+
64+
@then('the SF notice ID should not contain leading or trailing spaces')
65+
def the_sf_notice_id_should_not_contain_leading_or_trailing_spaces(normalised_sf_notice: Notice):
66+
"""Verify SF notice ID has no extra spaces."""
67+
assert normalised_sf_notice.normalised_metadata.notice_publication_number.strip() == \
68+
normalised_sf_notice.normalised_metadata.notice_publication_number
69+
70+
71+
# HTML incompatible string scenario steps
72+
@given('an HTML incompatible string', target_fixture='incompatible_string')
73+
def an_html_incompatible_string(html_incompatible_str: str) -> str:
74+
"""Provide HTML incompatible string fixture."""
75+
return html_incompatible_str
76+
77+
78+
@when('the string cannot be parsed as XML')
79+
def the_string_cannot_be_parsed_as_xml(html_incompatible_str: str):
80+
"""Verify string cannot be parsed as XML."""
81+
with pytest.raises(ParseError):
82+
ElementTree.fromstring(html_incompatible_str)
83+
84+
85+
@when('the string is converted to HTML compatible format', target_fixture='compatible_string')
86+
def the_string_is_converted_to_html_compatible_format(html_incompatible_str: str) -> LanguageTaggedString:
87+
"""Convert string to HTML compatible format."""
88+
return get_html_compatible_string(LanguageTaggedString(text=html_incompatible_str))
89+
90+
91+
@then('the resulting string should be well-formed XML')
92+
def the_resulting_string_should_be_well_formed_xml(compatible_string: LanguageTaggedString):
93+
"""Verify string is well-formed XML."""
94+
ElementTree.fromstring(html_str(compatible_string.text))
95+
96+
97+
# HTML incompatible title scenario steps
98+
@given('an EF notice with HTML incompatible title')
99+
def an_ef_notice_with_html_incompatible_title(sample_indexed_ef_html_unsafe_notice: Notice) -> Notice:
100+
"""Provide EF notice with incompatible title fixture."""
101+
return sample_indexed_ef_html_unsafe_notice
102+
103+
104+
@given('an SF notice with HTML incompatible title')
105+
def an_sf_notice_with_html_incompatible_title(sample_indexed_sf_html_unsafe_notice: Notice) -> Notice:
106+
"""Provide SF notice with incompatible title fixture."""
107+
return sample_indexed_sf_html_unsafe_notice
108+
109+
110+
@then('all EF notice titles should be valid XML')
111+
def all_ef_notice_titles_should_be_valid_xml(normalised_ef_notice: Notice):
112+
"""Verify all EF notice titles are valid XML."""
113+
[ElementTree.fromstring(html_str(title.text)) for title in normalised_ef_notice.normalised_metadata.title]
114+
115+
116+
@then('all SF notice titles should be valid XML')
117+
def all_sf_notice_titles_should_be_valid_xml(normalised_sf_notice: Notice):
118+
"""Verify all SF notice titles are valid XML."""
119+
[ElementTree.fromstring(html_str(title.text)) for title in normalised_sf_notice.normalised_metadata.title]

tests/features/notice_packager/conftest.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import json
2+
from typing import Dict
3+
14
import pytest
25

3-
from ted_sws.core.model.manifestation import RDFManifestation
46
from ted_sws.core.model.notice import NoticeStatus, Notice
7+
from ted_sws.notice_packager.model.metadata import PackagerMetadata
58
from tests import TEST_DATA_PATH
69

710

@@ -12,3 +15,26 @@ def package_eligible_notice(publicly_available_notice) -> Notice:
1215
TEST_DATA_PATH / "notice_packager" / "templates" / "2021_S_004_003545_0.notice.rdf").read_text()
1316
notice.update_status_to(NoticeStatus.ELIGIBLE_FOR_PACKAGING)
1417
return notice
18+
19+
20+
@pytest.fixture
21+
def template_sample_metadata_json() -> Dict:
22+
"""Load template metadata from JSON file."""
23+
return json.load((TEST_DATA_PATH / "notice_packager" / "template_metadata.json").open())
24+
25+
26+
@pytest.fixture
27+
def template_sample_metadata(template_sample_metadata_json) -> PackagerMetadata:
28+
"""Create PackagerMetadata from JSON."""
29+
return PackagerMetadata(**template_sample_metadata_json)
30+
31+
@pytest.fixture
32+
def work_id_str() -> str:
33+
"""Returns the work_id as str"""
34+
return "work_id"
35+
36+
37+
@pytest.fixture
38+
def work_id_predicate() -> str:
39+
"""Returns the URI predicate for the CDM work identifier."""
40+
return "http://publications.europa.eu/ontology/cdm#work_id"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
Feature: Template Generator
3+
The system is able to generate METS packages based on jinja templates.
4+
5+
Scenario: Template Generator generates METS DMD RDF that has work_id
6+
Given a PackagerMetadata
7+
And a work_id predicate
8+
When METS DMD RDF generator is executed
9+
Then METS DMD RDF is a valid RDF
10+
And work_id persist in METS DMD RDF
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""Tests for Template Generator's METS DMD RDF generation."""
2+
3+
from urllib.parse import urlparse, ParseResult
4+
from pytest_bdd import given, when, then, scenario
5+
from rdflib import Graph
6+
7+
from ted_sws.notice_packager.adapters.template_generator import TemplateGenerator
8+
from ted_sws.notice_packager.model.metadata import PackagerMetadata
9+
10+
11+
@scenario('test_template_generator.feature', 'Template Generator generates METS DMD RDF that has work_id')
12+
def test_package_a_ted_notice_in_a_mets_package() -> None:
13+
"""Test METS package generation with work_id."""
14+
15+
16+
@given('a PackagerMetadata')
17+
def a_packager_metadata(template_sample_metadata: PackagerMetadata) -> None:
18+
"""Verify PackagerMetadata existence."""
19+
assert template_sample_metadata
20+
assert isinstance(template_sample_metadata, PackagerMetadata)
21+
22+
23+
@given('a work_id predicate')
24+
def a_work_id_predicate(work_id_predicate: str, work_id_str: str) -> None:
25+
"""Check work_id predicate validity."""
26+
assert work_id_predicate
27+
assert isinstance(work_id_predicate, str)
28+
assert work_id_str in work_id_predicate
29+
valid_url: ParseResult = urlparse(work_id_predicate)
30+
assert valid_url.netloc
31+
assert valid_url.fragment == work_id_str
32+
33+
34+
@when("METS DMD RDF generator is executed", target_fixture="mets_xml_dmd_rdf")
35+
def mets_dmd_rdf_generator_is_executed(template_sample_metadata: PackagerMetadata) -> str:
36+
"""Generate METS DMD RDF."""
37+
return TemplateGenerator.mets_xml_dmd_rdf_generator(template_sample_metadata)
38+
39+
40+
@then("METS DMD RDF is a valid RDF")
41+
def mets_dmd_rdf_is_a_valid_rdf(mets_xml_dmd_rdf: str) -> None:
42+
"""Validate RDF format."""
43+
Graph().parse(data=mets_xml_dmd_rdf, format="xml")
44+
45+
46+
@then("work_id persist in METS DMD RDF")
47+
def work_id_persist_in_mets_dmd_rdf(mets_xml_dmd_rdf: str, work_id_str: str) -> None:
48+
"""Verify work_id presence in RDF."""
49+
assert work_id_str in mets_xml_dmd_rdf

tests/unit/notice_metadata_processor/test_metadata_normaliser.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import pathlib
21
from xml.etree import ElementTree
32
from xml.etree.ElementTree import ParseError
43

@@ -20,9 +19,11 @@
2019
extract_and_normalise_notice_metadata
2120
from ted_sws.resources.mapping_files_registry import MappingFilesRegistry
2221

22+
2323
def html_str(content: str) -> str:
2424
return f"""<?xml version="1.0" encoding="UTF-8"?> <body>{content}</body>"""
2525

26+
2627
def test_metadata_normaliser_by_notice(indexed_notice):
2728
notice = normalise_notice(indexed_notice)
2829
assert notice.normalised_metadata
@@ -261,17 +262,15 @@ def test_get_html_compatible_string(html_incompatible_str: str):
261262

262263
compatible_str: LanguageTaggedString = get_html_compatible_string(LanguageTaggedString(text=html_incompatible_str))
263264

264-
265265
# Parse to check if str is well-formed (HTML-safe sequences or elements)
266266
ElementTree.fromstring(html_str(compatible_str.text))
267267

268268

269269
def test_normalising_notice_with_html_incompatible_title(sample_indexed_ef_html_unsafe_notice: Notice,
270-
sample_indexed_sf_html_unsafe_notice: Notice):
271-
270+
sample_indexed_sf_html_unsafe_notice: Notice):
272271
normalised_ef_notice: Notice = normalise_notice(sample_indexed_ef_html_unsafe_notice)
273272

274-
[ElementTree.fromstring(html_str(title.text)) for title in normalised_ef_notice.normalised_metadata.title ]
273+
[ElementTree.fromstring(html_str(title.text)) for title in normalised_ef_notice.normalised_metadata.title]
275274

276275
normalised_sf_notice: Notice = normalise_notice(sample_indexed_sf_html_unsafe_notice)
277276

0 commit comments

Comments
 (0)