From 1adc078f7f5896ee1a1fe9e0e601b4db5b4c1bc3 Mon Sep 17 00:00:00 2001 From: Kolea PLESCO Date: Thu, 6 Apr 2023 17:00:40 +0300 Subject: [PATCH 1/2] Updates for XPATH Queries --- ted_sws/core/model/manifestation.py | 2 ++ ted_sws/core/model/validation_report.py | 1 + .../conceptual_mapping_generate_sparql_queries.py | 6 ++++-- .../templates/sparql_query_results_report.jinja2 | 10 +++++++++- .../resources/templates/sparql_summary_report.jinja2 | 2 +- .../services/sparql_test_suite_runner.py | 9 +++++++-- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/ted_sws/core/model/manifestation.py b/ted_sws/core/model/manifestation.py index d8ecdea1..7d81764d 100644 --- a/ted_sws/core/model/manifestation.py +++ b/ted_sws/core/model/manifestation.py @@ -35,6 +35,7 @@ class SPARQLQueryRefinedResultType(Enum): INVALID = "invalid" ERROR = "error" WARNING = "warning" + UNKNOWN = "unknown" class Manifestation(PropertyBaseModel): @@ -224,6 +225,7 @@ class SPARQLQueryResult(PropertyBaseModel): fields_covered: Optional[bool] = True missing_fields: Optional[List[str]] = [] error: Optional[str] + message: Optional[str] identifier: Optional[str] class Config: diff --git a/ted_sws/core/model/validation_report.py b/ted_sws/core/model/validation_report.py index 1b3f1355..a92c96a9 100644 --- a/ted_sws/core/model/validation_report.py +++ b/ted_sws/core/model/validation_report.py @@ -30,6 +30,7 @@ class SPARQLValidationSummaryCountReport(PropertyBaseModel): warning: Optional[QueryValidationSummaryCountReportStatus] = QueryValidationSummaryCountReportStatus() invalid: Optional[QueryValidationSummaryCountReportStatus] = QueryValidationSummaryCountReportStatus() error: Optional[QueryValidationSummaryCountReportStatus] = QueryValidationSummaryCountReportStatus() + unknown: Optional[QueryValidationSummaryCountReportStatus] = QueryValidationSummaryCountReportStatus() class SPARQLSummaryQuery(PropertyBaseModel): diff --git a/ted_sws/mapping_suite_processor/services/conceptual_mapping_generate_sparql_queries.py b/ted_sws/mapping_suite_processor/services/conceptual_mapping_generate_sparql_queries.py index 6624c8eb..8384dc11 100644 --- a/ted_sws/mapping_suite_processor/services/conceptual_mapping_generate_sparql_queries.py +++ b/ted_sws/mapping_suite_processor/services/conceptual_mapping_generate_sparql_queries.py @@ -26,13 +26,15 @@ SPARQL_PREFIX_LINE = 'PREFIX {prefix}: <{value}>' SPARQL_LOGGER_NAME = "SPARQL" +SPARQL_XPATH_SEPARATOR = " ;; " + def get_sparql_prefixes(sparql_q: str) -> list: finds: list = re.findall(SPARQL_PREFIX_PATTERN, sparql_q) return sorted(set(finds)) -def concat_field_xpath(base_xpath: str, field_xpath: str, separator: str = ", ") -> str: +def concat_field_xpath(base_xpath: str, field_xpath: str, separator: str = SPARQL_XPATH_SEPARATOR) -> str: base_xpath = base_xpath if not pd.isna(base_xpath) else '' field_xpath = field_xpath if not pd.isna(field_xpath) else '' return separator.join( @@ -137,7 +139,7 @@ def sparql_validation_generator(data: pd.DataFrame, base_xpath: str, controlled_ f"{e_form_bt_name}” in eForms. The corresponding XML element is " \ f"{concat_field_xpath(base_xpath, field_xpath)}. " \ f"The expected ontology instances are epo: {class_path} .\n" \ - f"#xpath: {concat_field_xpath(base_xpath, field_xpath, separator=',')}" \ + f"#xpath: {concat_field_xpath(base_xpath, field_xpath, separator=SPARQL_XPATH_SEPARATOR)}" \ "\n" + "\n" + "\n".join(prefixes) + "\n\n" \ f"ASK WHERE {{ " \ f"{subject_type_display}" \ diff --git a/ted_sws/notice_validator/resources/templates/sparql_query_results_report.jinja2 b/ted_sws/notice_validator/resources/templates/sparql_query_results_report.jinja2 index 1ba7afc5..2b21e4bc 100644 --- a/ted_sws/notice_validator/resources/templates/sparql_query_results_report.jinja2 +++ b/ted_sws/notice_validator/resources/templates/sparql_query_results_report.jinja2 @@ -124,7 +124,7 @@ - {% for _value in ['valid', 'unverifiable', 'warning', 'invalid', 'error'] %} + {% for _value in ['valid', 'unverifiable', 'warning', 'invalid', 'error', 'unknown'] %} {% set _results = validation_results | selectattr("result", "equalto", _value) | list | count %} {{ _value }} @@ -187,8 +187,16 @@ {% endif %} + {% if result.message and (result.message|length > 0) %} +
  • +
    +

    MESSAGE:

    + {{ result.message }} +
  • + {% endif %} {% if result.error and (result.error|length > 0) %}
  • +

    ERROR:

    {{ result.error }}
  • diff --git a/ted_sws/notice_validator/resources/templates/sparql_summary_report.jinja2 b/ted_sws/notice_validator/resources/templates/sparql_summary_report.jinja2 index 0d9fcbfb..02593eee 100644 --- a/ted_sws/notice_validator/resources/templates/sparql_summary_report.jinja2 +++ b/ted_sws/notice_validator/resources/templates/sparql_summary_report.jinja2 @@ -1,4 +1,4 @@ -{% set result_values = ['valid', 'unverifiable', 'warning', 'invalid', 'error'] %} +{% set result_values = ['valid', 'unverifiable', 'warning', 'invalid', 'error', 'unknown'] %} diff --git a/ted_sws/notice_validator/services/sparql_test_suite_runner.py b/ted_sws/notice_validator/services/sparql_test_suite_runner.py index 0c90ea2c..4ac941d0 100644 --- a/ted_sws/notice_validator/services/sparql_test_suite_runner.py +++ b/ted_sws/notice_validator/services/sparql_test_suite_runner.py @@ -12,6 +12,7 @@ ReportNotice from ted_sws.core.model.validation_report_data import ReportPackageNoticeData from ted_sws.data_manager.adapters.repository_abc import NoticeRepositoryABC, MappingSuiteRepositoryABC +from ted_sws.mapping_suite_processor.services.conceptual_mapping_generate_sparql_queries import SPARQL_XPATH_SEPARATOR from ted_sws.notice_transformer.adapters.notice_transformer import NoticeTransformer from ted_sws.notice_validator.adapters.sparql_runner import SPARQLRunner from ted_sws.notice_validator.resources.templates import TEMPLATE_METADATA_KEY @@ -58,8 +59,9 @@ def _sparql_query_from_file_resource(cls, file_resource: FileResource) -> SPARQL if QUERY_METADATA_TITLE in metadata else DEFAULT_QUERY_TITLE description = metadata[QUERY_METADATA_DESCRIPTION] \ if QUERY_METADATA_DESCRIPTION in metadata else DEFAULT_QUERY_DESCRIPTION - xpath = metadata[QUERY_METADATA_XPATH].split(",") if QUERY_METADATA_XPATH in metadata and metadata[ - QUERY_METADATA_XPATH] else DEFAULT_QUERY_XPATH + xpath = metadata[QUERY_METADATA_XPATH].split( + SPARQL_XPATH_SEPARATOR + ) if QUERY_METADATA_XPATH in metadata and metadata[QUERY_METADATA_XPATH] else DEFAULT_QUERY_XPATH query = cls._sanitize_query(file_resource.file_content) return SPARQLQuery(title=title, description=description, xpath=xpath, query=query) @@ -223,6 +225,9 @@ def generate_sparql_validation_summary_report(report_notices: List[ReportNotice] elif validation.result == SPARQLQueryRefinedResultType.ERROR.value: validation_query_result.aggregate.error.count += 1 validation_query_result.aggregate.error.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.UNKNOWN.value: + validation_query_result.aggregate.unknown.count += 1 + validation_query_result.aggregate.unknown.notices.append(notice_data) if not found_validation_query_result: report.validation_results.append(validation_query_result) From 5994de778bae1248b63e14896e9523c361df8236 Mon Sep 17 00:00:00 2001 From: Kolea PLESCO Date: Fri, 7 Apr 2023 21:48:50 +0300 Subject: [PATCH 2/2] Tests coverage --- .../services/shacl_test_suite_runner.py | 8 +- .../services/sparql_test_suite_runner.py | 201 +++++++++++------- tests/unit/core/model/conftest.py | 16 +- tests/unit/notice_validator/conftest.py | 115 +++++++++- .../test_shacl_test_suite_runner.py | 8 +- .../notice_validator/test_sparql_runner.py | 9 +- .../test_sparql_test_suite_runner.py | 7 +- 7 files changed, 264 insertions(+), 100 deletions(-) diff --git a/ted_sws/notice_validator/services/shacl_test_suite_runner.py b/ted_sws/notice_validator/services/shacl_test_suite_runner.py index 0a15dab1..ebbf6899 100644 --- a/ted_sws/notice_validator/services/shacl_test_suite_runner.py +++ b/ted_sws/notice_validator/services/shacl_test_suite_runner.py @@ -185,7 +185,7 @@ def validate_notice_with_shacl_suite(notice: Notice, mapping_suite_package: Mapp :return: """ - def shacl_validation(notice_item: Notice, rdf_manifestation: RDFManifestation, with_html: bool = False) \ + def shacl_validation(notice_item: Notice, rdf_manifestation: RDFManifestation) \ -> List[SHACLTestSuiteValidationReport]: reports = [] shacl_test_suites = mapping_suite_package.shacl_test_suites @@ -199,12 +199,10 @@ def shacl_validation(notice_item: Notice, rdf_manifestation: RDFManifestation, w return sorted(reports, key=lambda x: x.test_suite_identifier) if execute_full_validation: - for report in shacl_validation(notice_item=notice, rdf_manifestation=notice.rdf_manifestation, - with_html=with_html): + for report in shacl_validation(notice_item=notice, rdf_manifestation=notice.rdf_manifestation): notice.set_rdf_validation(rdf_validation=report) - for report in shacl_validation(notice_item=notice, rdf_manifestation=notice.distilled_rdf_manifestation, - with_html=with_html): + for report in shacl_validation(notice_item=notice, rdf_manifestation=notice.distilled_rdf_manifestation): notice.set_distilled_rdf_validation(rdf_validation=report) return notice diff --git a/ted_sws/notice_validator/services/sparql_test_suite_runner.py b/ted_sws/notice_validator/services/sparql_test_suite_runner.py index 4ac941d0..1e517042 100644 --- a/ted_sws/notice_validator/services/sparql_test_suite_runner.py +++ b/ted_sws/notice_validator/services/sparql_test_suite_runner.py @@ -65,6 +65,19 @@ def _sparql_query_from_file_resource(cls, file_resource: FileResource) -> SPARQL query = cls._sanitize_query(file_resource.file_content) return SPARQLQuery(title=title, description=description, xpath=xpath, query=query) + @classmethod + def _refined_result(cls, ask_answer, sparql_query_result, + result: SPARQLQueryRefinedResultType) -> SPARQLQueryRefinedResultType: + if ask_answer and sparql_query_result.fields_covered: + result = SPARQLQueryRefinedResultType.VALID.value + elif not ask_answer and not sparql_query_result.fields_covered: + result = SPARQLQueryRefinedResultType.UNVERIFIABLE.value + elif ask_answer and not sparql_query_result.fields_covered: + result = SPARQLQueryRefinedResultType.WARNING.value + elif not ask_answer and sparql_query_result.fields_covered: + result = SPARQLQueryRefinedResultType.INVALID.value + return result + def _process_sparql_ask_result(self, query_result, sparql_query: SPARQLQuery, sparql_query_result: SPARQLQueryResult): ask_answer = query_result.askAnswer @@ -89,14 +102,7 @@ def _process_sparql_ask_result(self, query_result, sparql_query: SPARQLQuery, sparql_query_result.missing_fields = list(sparql_query_xpath - xpaths_in_notice) # Refined result - if ask_answer and sparql_query_result.fields_covered: - result = SPARQLQueryRefinedResultType.VALID.value - elif not ask_answer and not sparql_query_result.fields_covered: - result = SPARQLQueryRefinedResultType.UNVERIFIABLE.value - elif ask_answer and not sparql_query_result.fields_covered: - result = SPARQLQueryRefinedResultType.WARNING.value - elif not ask_answer and sparql_query_result.fields_covered: - result = SPARQLQueryRefinedResultType.INVALID.value + result = self._refined_result(ask_answer, sparql_query_result, result) sparql_query_result.result = result @@ -155,11 +161,75 @@ def generate_report(self) -> SPARQLTestSuiteValidationReport: return self.sparql_test_suite_execution -def generate_sparql_validation_summary_report(report_notices: List[ReportNotice], mapping_suite_package: MappingSuite, - execute_full_validation: bool = True, - with_html: bool = False, - report: SPARQLValidationSummaryReport = None, - metadata: dict = None) -> SPARQLValidationSummaryReport: +def process_sparql_validation_summary_report_data_with_notice( + notice: Notice, + mapping_suite_package: MappingSuite, + report_notice_path: Path, + report: SPARQLValidationSummaryReport +): + for sparql_validation in notice.rdf_manifestation.sparql_validations: + test_suite_id = sparql_validation.test_suite_identifier + report.test_suite_ids.append(test_suite_id) + mapping_suite_versioned_id = sparql_validation.mapping_suite_identifier + report.mapping_suite_ids.append(mapping_suite_versioned_id) + validation: SPARQLQueryResult + for validation in sparql_validation.validation_results: + validation_query_result: SPARQLValidationSummaryQueryResult + found_validation_query_result = list(filter( + lambda record: + (record.query.query == validation.query.query) + and (record.query.title == validation.query.title) + and (record.test_suite_identifier == test_suite_id), + report.validation_results + )) + if found_validation_query_result: + validation_query_result = found_validation_query_result[0] + else: + validation_query_result = SPARQLValidationSummaryQueryResult( + test_suite_identifier=test_suite_id, + **validation.dict() + ) + notice_data: ReportPackageNoticeData = ReportPackageNoticeData( + notice_id=notice.ted_id, + path=str(report_notice_path), + mapping_suite_versioned_id=mapping_suite_versioned_id, + mapping_suite_identifier=mapping_suite_package.identifier + ) + if validation.result == SPARQLQueryRefinedResultType.VALID.value: + validation_query_result.aggregate.valid.count += 1 + validation_query_result.aggregate.valid.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.UNVERIFIABLE.value: + validation_query_result.aggregate.unverifiable.count += 1 + validation_query_result.aggregate.unverifiable.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.INVALID.value: + validation_query_result.aggregate.invalid.count += 1 + validation_query_result.aggregate.invalid.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.WARNING.value: + validation_query_result.aggregate.warning.count += 1 + validation_query_result.aggregate.warning.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.ERROR.value: + validation_query_result.aggregate.error.count += 1 + validation_query_result.aggregate.error.notices.append(notice_data) + elif validation.result == SPARQLQueryRefinedResultType.UNKNOWN.value: + validation_query_result.aggregate.unknown.count += 1 + validation_query_result.aggregate.unknown.notices.append(notice_data) + if not found_validation_query_result: + report.validation_results.append(validation_query_result) + + +def add_sparql_validation_summary_html_report( + report: SPARQLValidationSummaryReport, + metadata: dict = None +): + template_data: dict = report.dict() + template_data[TEMPLATE_METADATA_KEY] = metadata + html_report = TEMPLATES.get_template(SPARQL_SUMMARY_HTML_REPORT_TEMPLATE).render(template_data) + report.object_data = html_report + + +def init_sparql_validation_summary_report( + report: SPARQLValidationSummaryReport, + report_notices: List[ReportNotice]) -> SPARQLValidationSummaryReport: if report is None: report: SPARQLValidationSummaryReport = SPARQLValidationSummaryReport( object_data="SPARQLValidationSummaryReport", @@ -170,6 +240,32 @@ def generate_sparql_validation_summary_report(report_notices: List[ReportNotice] report.notices = sorted(NoticeTransformer.transform_validation_report_notices(report_notices, group_depth=1) + ( report.notices or []), key=lambda report_data: report_data.notice_id) + return report + + +def finalize_sparql_validation_summary_report(report: SPARQLValidationSummaryReport, metadata: dict = None, + with_html: bool = False): + report.test_suite_ids = list(set(report.test_suite_ids)) + report.mapping_suite_ids = list(set(report.mapping_suite_ids)) + + if with_html: + add_sparql_validation_summary_html_report( + report=report, + metadata=metadata + ) + + +def generate_sparql_validation_summary_report(report_notices: List[ReportNotice], + mapping_suite_package: MappingSuite, + execute_full_validation: bool = True, + with_html: bool = False, + report: SPARQLValidationSummaryReport = None, + metadata: dict = None) -> SPARQLValidationSummaryReport: + report = init_sparql_validation_summary_report( + report=report, + report_notices=report_notices + ) + for report_notice in report_notices: notice = report_notice.notice validate_notice_with_sparql_suite( @@ -178,68 +274,19 @@ def generate_sparql_validation_summary_report(report_notices: List[ReportNotice] execute_full_validation=execute_full_validation, with_html=False ) - for sparql_validation in notice.rdf_manifestation.sparql_validations: - test_suite_id = sparql_validation.test_suite_identifier - report.test_suite_ids.append(test_suite_id) - mapping_suite_versioned_id = sparql_validation.mapping_suite_identifier - report.mapping_suite_ids.append(mapping_suite_versioned_id) - - validation: SPARQLQueryResult - for validation in sparql_validation.validation_results: - validation_query_result: SPARQLValidationSummaryQueryResult - found_validation_query_result = list(filter( - lambda record: - (record.query.query == validation.query.query) - and (record.query.title == validation.query.title) - and (record.test_suite_identifier == test_suite_id), - report.validation_results - )) - - if found_validation_query_result: - validation_query_result = found_validation_query_result[0] - else: - validation_query_result = SPARQLValidationSummaryQueryResult( - test_suite_identifier=test_suite_id, - **validation.dict() - ) - - notice_data: ReportPackageNoticeData = ReportPackageNoticeData( - notice_id=notice.ted_id, - path=str(report_notice.metadata.path), - mapping_suite_versioned_id=mapping_suite_versioned_id, - mapping_suite_identifier=mapping_suite_package.identifier - ) - if validation.result == SPARQLQueryRefinedResultType.VALID.value: - validation_query_result.aggregate.valid.count += 1 - validation_query_result.aggregate.valid.notices.append(notice_data) - elif validation.result == SPARQLQueryRefinedResultType.UNVERIFIABLE.value: - validation_query_result.aggregate.unverifiable.count += 1 - validation_query_result.aggregate.unverifiable.notices.append(notice_data) - elif validation.result == SPARQLQueryRefinedResultType.INVALID.value: - validation_query_result.aggregate.invalid.count += 1 - validation_query_result.aggregate.invalid.notices.append(notice_data) - elif validation.result == SPARQLQueryRefinedResultType.WARNING.value: - validation_query_result.aggregate.warning.count += 1 - validation_query_result.aggregate.warning.notices.append(notice_data) - elif validation.result == SPARQLQueryRefinedResultType.ERROR.value: - validation_query_result.aggregate.error.count += 1 - validation_query_result.aggregate.error.notices.append(notice_data) - elif validation.result == SPARQLQueryRefinedResultType.UNKNOWN.value: - validation_query_result.aggregate.unknown.count += 1 - validation_query_result.aggregate.unknown.notices.append(notice_data) - - if not found_validation_query_result: - report.validation_results.append(validation_query_result) - - report.test_suite_ids = list(set(report.test_suite_ids)) - report.mapping_suite_ids = list(set(report.mapping_suite_ids)) + process_sparql_validation_summary_report_data_with_notice( + notice=notice, + mapping_suite_package=mapping_suite_package, + report_notice_path=report_notice.metadata.path, + report=report + ) - if with_html: - template_data: dict = report.dict() - template_data[TEMPLATE_METADATA_KEY] = metadata - html_report = TEMPLATES.get_template(SPARQL_SUMMARY_HTML_REPORT_TEMPLATE).render(template_data) - report.object_data = html_report + finalize_sparql_validation_summary_report( + report=report, + metadata=metadata, + with_html=with_html + ) return report @@ -255,7 +302,7 @@ def validate_notice_with_sparql_suite(notice: Notice, mapping_suite_package: Map :return: """ - def sparql_validation(notice_item: Notice, rdf_manifestation: RDFManifestation, with_html: bool = False) \ + def sparql_validation(notice_item: Notice, rdf_manifestation: RDFManifestation) \ -> List[SPARQLTestSuiteValidationReport]: reports = [] sparql_test_suites = mapping_suite_package.sparql_test_suites @@ -271,12 +318,10 @@ def sparql_validation(notice_item: Notice, rdf_manifestation: RDFManifestation, return sorted(reports, key=lambda x: x.test_suite_identifier) if execute_full_validation: - for report in sparql_validation(notice_item=notice, rdf_manifestation=notice.rdf_manifestation, - with_html=with_html): + for report in sparql_validation(notice_item=notice, rdf_manifestation=notice.rdf_manifestation): notice.set_rdf_validation(rdf_validation=report) - for report in sparql_validation(notice_item=notice, rdf_manifestation=notice.distilled_rdf_manifestation, - with_html=with_html): + for report in sparql_validation(notice_item=notice, rdf_manifestation=notice.distilled_rdf_manifestation): notice.set_distilled_rdf_validation(rdf_validation=report) return notice diff --git a/tests/unit/core/model/conftest.py b/tests/unit/core/model/conftest.py index 6bb2c0c0..c0dd1ff4 100644 --- a/tests/unit/core/model/conftest.py +++ b/tests/unit/core/model/conftest.py @@ -48,15 +48,15 @@ def publicly_available_notice(fetched_notice_data, normalised_metadata_dict) -> notice.set_preprocessed_xml_manifestation(xml_manifestation) notice._status = NoticeStatus.DISTILLED notice.set_rdf_manifestation(RDFManifestation(object_data="RDF manifestation content", - shacl_validations=[shacl_validation], - sparql_validations=[sparql_validation], - xpath_coverage_validation=xpath_coverage_validation - )) + shacl_validations=[shacl_validation], + sparql_validations=[sparql_validation], + xpath_coverage_validation=xpath_coverage_validation + )) notice.set_distilled_rdf_manifestation(RDFManifestation(object_data="RDF manifestation content", - shacl_validations=[shacl_validation], - sparql_validations=[sparql_validation], - xpath_coverage_validation=xpath_coverage_validation - )) + shacl_validations=[shacl_validation], + sparql_validations=[sparql_validation], + xpath_coverage_validation=xpath_coverage_validation + )) notice._status = NoticeStatus.ELIGIBLE_FOR_PACKAGING notice.set_mets_manifestation(METSManifestation(object_data="METS manifestation content")) notice._status = NoticeStatus.PUBLICLY_AVAILABLE diff --git a/tests/unit/notice_validator/conftest.py b/tests/unit/notice_validator/conftest.py index 893717ec..bb3cbe3e 100644 --- a/tests/unit/notice_validator/conftest.py +++ b/tests/unit/notice_validator/conftest.py @@ -161,6 +161,22 @@ def sparql_file_two(): return FileResource(file_name="better_file", file_content=query) +@pytest.fixture +def sparql_file_three(): + query = """#title: Title Three +#description: this is a description +#xpath: /TED_EXPORT/FORM_SECTION/F03_2014/LEGAL_BASIS/@VALUE_INVALID + +PREFIX epo: +ASK +WHERE +{ + ?this epo:IsRoleOf / epo:hasName ?value . +} + """ + return FileResource(file_name="the_best_file", file_content=query) + + @pytest.fixture def sparql_file_select(): query = """#title: Title One @@ -209,8 +225,9 @@ def false_query_sparql_file(): @pytest.fixture -def sparql_test_suite(sparql_file_one, sparql_file_two): - return SPARQLTestSuite(identifier="sparql_test_package", sparql_tests=[sparql_file_one, sparql_file_two]) +def sparql_test_suite(sparql_file_one, sparql_file_two, sparql_file_three): + return SPARQLTestSuite(identifier="sparql_test_package", + sparql_tests=[sparql_file_one, sparql_file_two, sparql_file_three]) @pytest.fixture @@ -411,6 +428,7 @@ def fake_validation_notice(): "created": '2022-08-07T20:49:15.500870', "mapping_suite_identifier": 'package_F03', "test_suite_identifier": 'cm_assertions', + "fields_covered": False, "validation_results": [ { "query": { @@ -477,6 +495,47 @@ def fake_validation_notice(): "query_result": 'False', "error": None, "identifier": 'sparql_query_46' + }, + { + "query": { + "title": "", + "description": "", + "query": "" + }, + "result": 'unknown', + "query_result": 'False', + "error": None, + "identifier": 'sparql_query_46' + } + ] + }), SPARQLTestSuiteValidationReport(**{ + "object_data": '62f037e2a5458a3a6776138c', + "created": '2022-08-07T20:49:15.500870', + "mapping_suite_identifier": 'package_F03', + "test_suite_identifier": 'cm_assertions', + "fields_covered": True, + "validation_results": [ + { + "query": { + "title": 'II.1.7.4 - Currency', + "description": '“II.1.7.4 - Currency” in SF corresponds to “nan nan” in eForms. The corresponding XML element is /TED_EXPORT/FORM_SECTION/F03_2014/OBJECT_CONTRACT/VAL_TOTAL/@CURRENCY. The expected ontology instances are epo: epo:ResultNotice / epo:NoticeAwardInformation / epo:MonetaryValue / at-voc:currency (from currency.json) .', + "query": 'PREFIX epo: \n\nASK WHERE { { ?this epo:announcesNoticeAwardInformation / epo:hasTotalAwardedValue / epo:hasCurrency ?value } UNION { ?this epo:announcesNoticeAwardInformation / epo:hasProcurementLowestReceivedTenderValue / epo:hasCurrency ?value } UNION { ?this epo:announcesNoticeAwardInformation / epo:hasProcurementHighestReceivedTenderValue / epo:hasCurrency ?value } }' + }, + "result": 'valid', + "query_result": 'True', + "error": None, + "identifier": 'sparql_query_46' + }, + { + "query": { + "title": "", + "description": "", + "query": "" + }, + "result": 'unknown', + "query_result": 'True', + "error": None, + "identifier": 'sparql_query_46' } ] })] @@ -521,12 +580,20 @@ def fake_validation_notice(): } }, { + "resultPath": { + "type": 'uri', + "value": 'http://data.europa.eu/a4g/ontology#hasInternetAddress' + }, "resultSeverity": { "type": 'uri', "value": 'http://www.w3.org/ns/shacl#Info' } }, { + "resultPath": { + "type": 'uri', + "value": 'http://data.europa.eu/a4g/ontology#hasInternetAddress' + }, "resultSeverity": { "type": 'uri', "value": 'http://www.w3.org/ns/shacl#Warning' @@ -536,6 +603,50 @@ def fake_validation_notice(): } } } + }), SHACLTestSuiteValidationReport(**{ + "object_data": '62f037e2a5458a3a6776138a1', + "created": '2022-08-07T20:49:15.500870', + "mapping_suite_identifier": 'package_F03', + "test_suite_identifier": 'epo', + "validation_results": { + "conforms": 'True', + "results_dict": { + "results": { + "bindings": [ + { + "focusNode": { + "type": 'uri', + "value": 'http://data.europa.eu/a4g/resource/ContactPoint/2021-S-250-663165/ab152979-15bf-30c3-b6f3-e0c554cfa9d0' + }, + "message": { + "type": 'literal', + "value": 'Value is not Literal with datatype xsd:anyURI' + }, + "resultPath": { + "type": 'uri', + "value": 'http://data.europa.eu/a4g/ontology#hasInternetAddress' + }, + "resultSeverity": { + "type": 'uri', + "value": 'http://www.w3.org/ns/shacl#Violation' + }, + "sourceConstraintComponent": { + "type": 'uri', + "value": 'http://www.w3.org/ns/shacl#DatatypeConstraintComponent' + }, + "sourceShape": { + "type": 'bnode', + "value": 'Nb24b2cf50dcc4b8cbe40e95f3d032394' + }, + "value": { + "type": 'literal', + "value": 'http://www.lshp.fi' + } + } + ] + } + } + } })] rdf_manifestation = RDFManifestation(object_data="RDF manifestation content", diff --git a/tests/unit/notice_validator/test_shacl_test_suite_runner.py b/tests/unit/notice_validator/test_shacl_test_suite_runner.py index a9b90e89..47a7dffb 100644 --- a/tests/unit/notice_validator/test_shacl_test_suite_runner.py +++ b/tests/unit/notice_validator/test_shacl_test_suite_runner.py @@ -1,7 +1,7 @@ import pytest from ted_sws.core.model.manifestation import RDFManifestation, RDFValidationManifestation, \ - SHACLTestSuiteValidationReport + SHACLTestSuiteValidationReport, QueriedSHACLShapeValidationResult from ted_sws.core.model.notice import NoticeStatus from ted_sws.core.model.validation_report import ReportNotice, SHACLValidationSummaryReport from ted_sws.data_manager.adapters.mapping_suite_repository import MappingSuiteRepositoryInFileSystem @@ -93,10 +93,12 @@ def test_validate_notice_by_id_with_shacl_suite(notice_with_distilled_status, rd mapping_suite_identifier="no_package_here") -def test_generate_shacl_validation_summary_report(notice_with_distilled_status, dummy_mapping_suite, rdf_file_content): +def test_generate_shacl_validation_summary_report(notice_with_distilled_status, fake_validation_notice, + dummy_mapping_suite, rdf_file_content): notice = notice_with_distilled_status assert notice.rdf_manifestation assert notice.distilled_rdf_manifestation + notice.rdf_manifestation.shacl_validations = fake_validation_notice.rdf_manifestation.shacl_validations report_notice: ReportNotice = ReportNotice(notice=notice) report: SHACLValidationSummaryReport = generate_shacl_validation_summary_report( report_notices=[report_notice], @@ -106,4 +108,4 @@ def test_generate_shacl_validation_summary_report(notice_with_distilled_status, assert report.object_data assert report.notices[0].notice_id == notice.ted_id assert report.validation_results - assert len(report.validation_results) > 0 \ No newline at end of file + assert len(report.validation_results) > 0 diff --git a/tests/unit/notice_validator/test_sparql_runner.py b/tests/unit/notice_validator/test_sparql_runner.py index 80f5de24..418e9ca1 100644 --- a/tests/unit/notice_validator/test_sparql_runner.py +++ b/tests/unit/notice_validator/test_sparql_runner.py @@ -1,9 +1,14 @@ +from typing import List + +from ted_sws.core.model.transform import FileResource from ted_sws.notice_validator.adapters.sparql_runner import SPARQLRunner -def test_sparql_runner(query_content,rdf_file_content): +def test_sparql_runner(query_content, rdf_file_content): sparql_runner = SPARQLRunner(rdf_content=rdf_file_content) query_result = sparql_runner.query(query_object=query_content) - assert query_result.askAnswer is False + files: List[FileResource] = [FileResource(file_name="test_file", file_content=rdf_file_content)] + sparql_runner = SPARQLRunner(files=files) + assert sparql_runner.query(query_object=query_content).askAnswer is False diff --git a/tests/unit/notice_validator/test_sparql_test_suite_runner.py b/tests/unit/notice_validator/test_sparql_test_suite_runner.py index 0531fb3f..b62d8d9a 100644 --- a/tests/unit/notice_validator/test_sparql_test_suite_runner.py +++ b/tests/unit/notice_validator/test_sparql_test_suite_runner.py @@ -40,7 +40,8 @@ def test_sparql_query_test_suite_runner(rdf_file_content, sparql_test_suite, dum for execution in test_suite_executions: assert isinstance(execution, SPARQLQueryResult) - assert test_suite_executions[1].result == SPARQLQueryRefinedResultType.VALID.value + assert test_suite_executions[2].result == SPARQLQueryRefinedResultType.VALID.value + assert test_suite_executions[1].result == SPARQLQueryRefinedResultType.WARNING.value assert test_suite_executions[0].result == SPARQLQueryRefinedResultType.INVALID.value @@ -159,10 +160,12 @@ def test_get_metadata_from_freaking_sparql_queries(query_content, query_content_ assert "description" not in metadata -def test_generate_sparql_validation_summary_report(notice_with_distilled_status, dummy_mapping_suite, rdf_file_content): +def test_generate_sparql_validation_summary_report(notice_with_distilled_status, fake_validation_notice, + dummy_mapping_suite, rdf_file_content): notice = notice_with_distilled_status assert notice.rdf_manifestation assert notice.distilled_rdf_manifestation + notice.rdf_manifestation.sparql_validations = fake_validation_notice.rdf_manifestation.sparql_validations report_notice: ReportNotice = ReportNotice(notice=notice) report: SPARQLValidationSummaryReport = generate_sparql_validation_summary_report( report_notices=[report_notice],