diff --git a/datacontract/model/data_contract_specification.py b/datacontract/model/data_contract_specification.py index 3decdfa8..f725bbdf 100644 --- a/datacontract/model/data_contract_specification.py +++ b/datacontract/model/data_contract_specification.py @@ -1,5 +1,5 @@ import os -from typing import List, Dict +from typing import List, Dict, Optional import pydantic as pyd import yaml @@ -113,6 +113,53 @@ class Quality(pyd.BaseModel): type: str = None specification: str | object = None +class Availability(pyd.BaseModel): + description: Optional[str] = None + percentage: Optional[str] = None + +class Retention(pyd.BaseModel): + description: Optional[str] = None + period: Optional[str] = None + unlimited: Optional[bool] = None + timestampField: Optional[str] = None + +class Latency(pyd.BaseModel): + description: Optional[str] = None + threshold: Optional[str] = None + sourceTimestampField: Optional[str] = None + processedTimestampField: Optional[str] = None + +class Freshness(pyd.BaseModel): + description: Optional[str] = None + threshold: Optional[str] = None + timestampField: Optional[str] = None + +class Frequency(pyd.BaseModel): + description: Optional[str] = None + type: Optional[str] = None + interval: Optional[str] = None + cron: Optional[str] = None + +class Support(pyd.BaseModel): + description: Optional[str] = None + time: Optional[str] = None + responseTime: Optional[str] = None + +class Backup(pyd.BaseModel): + description: Optional[str] = None + interval: Optional[str] = None + cron: Optional[str] = None + recoveryTime: Optional[str] = None + recoveryPoint: Optional[str] = None + +class ServiceLevel(pyd.BaseModel): + availability: Optional[Availability] = None + retention: Optional[Retention] = None + latency: Optional[Latency] = None + freshness: Optional[Freshness] = None + frequency: Optional[Frequency] = None + support: Optional[Support] = None + backup: Optional[Backup] = None class DataContractSpecification(pyd.BaseModel): dataContractSpecification: str = None @@ -125,6 +172,7 @@ class DataContractSpecification(pyd.BaseModel): # schema: Dict[str, str] examples: List[Example] = [] quality: Quality = None + servicelevels: Optional[ServiceLevel] = None @classmethod def from_file(cls, file): diff --git a/datacontract/templates/datacontract.html b/datacontract/templates/datacontract.html index 2138f190..f53fb191 100644 --- a/datacontract/templates/datacontract.html +++ b/datacontract/templates/datacontract.html @@ -465,7 +465,237 @@

{# TODO add definitions #} - {# TODO add service levels #} + {% if datacontract.servicelevels %} +
+
+

Service Levels

+

Servicelevels of the data contract

+
+ {% if datacontract.servicelevels.availability %} +

+ Availability +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.availability.description }} +
+
+
+
Percentage
+
+ {{ datacontract.servicelevels.availability.percentage }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.retention %} +

+ Retention +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.retention.description }} +
+
+
+
Period
+
+ {{ datacontract.servicelevels.retention.period }} +
+
+
+
Unlimited
+
+ {{ datacontract.servicelevels.retention.unlimited }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.latency %} +

+ Latency +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.latency.description }} +
+
+
+
Threshold
+
+ {{ datacontract.servicelevels.latency.threshold }} +
+
+
+
Source Timestamp field
+
+ {{ datacontract.servicelevels.latency.sourceTimestampField + }} +
+
+
+
Processed Timestamp field
+
+ {{ datacontract.servicelevels.latency.processedTimestampField + }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.freshness %} +

+ Freshness +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.freshness.description }} +
+
+
+
Threshold
+
+ {{ datacontract.servicelevels.freshness.threshold }} +
+
+
+
Timestamp field
+
+ {{ datacontract.servicelevels.freshness.timestampField }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.frequency %} +

+ Frequency +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.frequency.description }} +
+
+
+
Type
+
+ {{ datacontract.servicelevels.frequency.type }} +
+
+
+
Interval
+
+ {{ datacontract.servicelevels.frequency.interval }} +
+
+
+
Cron
+
+ {{ datacontract.servicelevels.frequency.cron }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.support %} +

+ Support +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.support.description }} +
+
+
+
Time
+
+ {{ datacontract.servicelevels.support.time }} +
+
+
+
Response Time
+
+ {{ datacontract.servicelevels.support.responseTime }} +
+
+
+
+
+ {% endif %} + {% if datacontract.servicelevels.backup %} +

+ Backup +

+
+
+
+
+
Description
+
+ {{ datacontract.servicelevels.backup.description }} +
+
+
+
Interval
+
+ {{ datacontract.servicelevels.backup.interval }} +
+
+
+
Cron
+
+ {{ datacontract.servicelevels.backup.cron }} +
+
+
+
Recovery Time
+
+ {{ datacontract.servicelevels.backup.recoveryTime }} +
+
+
+
Recovery Point
+
+ {{ datacontract.servicelevels.backup.recoveryPoint }} +
+
+
+
+
+ {% endif %} +
+ {% endif %} {% if quality_specification %}
diff --git a/tests/fixtures/examples/datacontract_servicelevels.yaml b/tests/fixtures/examples/datacontract_servicelevels.yaml new file mode 100644 index 00000000..3ec4df10 --- /dev/null +++ b/tests/fixtures/examples/datacontract_servicelevels.yaml @@ -0,0 +1,58 @@ +dataContractSpecification: 0.9.2 +id: "61111-0002" +info: + title: "Verbraucherpreisindex: Deutschland, Monate" + description: A data contract for the distribution and use of the German Consumer Price Index data. + version: 1.0.0 + owner: my-domain-team +models: + verbraucherpreisindex: + description: Model representing the Consumer Price Index for Germany + fields: + wert: + description: Value of the Consumer Price Index + type: integer + required: true + jahrMonat: + description: Year and month of the data + type: string + required: true + qualitaet: + description: Quality of the data + type: string + enum: + - "vorlaeufig" + - "endgueltig" + verarbeitet: + description: Time when this dataset was processed, year and month + type: string + +examples: + - type: json + description: Example entry for CPI data + model: verbraucherpreisindex + data: |- + [{ "wert": 99, "jahrMonat": "2022-00", "verarbeitet": "2022-01" }, + { "wert": 100, "jahrMonat": "2022-01", "verarbeitet": "2022-02" }, + { "wert": 101, "jahrMonat": "2022-02", "qualitaet": "vorlaeufig", "verarbeitet": "2022-03" }] + +servicelevels: + availability: + percentage: "99.9%" + retention: + period: P5Y + timestampField: jahrMonat + latency: + threshold: P1M + sourceTimestampField: verarbeitet + freshness: + threshold: P1M + timestampField: verarbeitet + frequency: + type: streaming + support: + time: 24/7 + responseTime: P1h + backup: + interval: daily + recoveryTime: 2 hours diff --git a/tests/test_test_examples_json.py b/tests/test_test_examples_json.py index e1128702..45edc87a 100644 --- a/tests/test_test_examples_json.py +++ b/tests/test_test_examples_json.py @@ -21,3 +21,10 @@ def test_json(): print(run) print(run.result) assert run.result == "passed" + +def test_with_service_level(): + data_contract = DataContract(data_contract_file="fixtures/examples/datacontract_servicelevels.yaml", examples=True) + run = data_contract.test() + print(run) + print(run.result) + assert run.result == "passed"