diff --git a/Dockerfile b/Dockerfile index 76a8c85..d484c09 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-slim-buster +FROM python:3.11-slim-buster WORKDIR /app COPY requirements.txt requirements.txt diff --git a/README.md b/README.md index 74bcdb0..508ee07 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,158 @@ -# systeem-tests +# ZGW-Gherkin + +## Table of Contents + +- [How to Add tests](#how-to-add-tests) + - [Before You Begin](#before-you-begin) + - [Project Structure](#structure) + - [Example](#example) + - [Adding Tags](#adding-tags) +- [How to Run](#how-to-run) + - [Run Locally](#run-locally) + - [Run on Docker](#run-on-docker) + +# How to Add tests + +## Before you begin + +Basic usages can be found here: + +https://behave.readthedocs.io/en/latest/ + +## Structure + +The basic structure for every gherkin project is the following: + +``` +|-- environment.py +|-- features +| |-- example.feature +|-- steps +| |-- example.py +|-- flows +| |-- flow.py +``` + +`flows` is the only one that is specific to this project. + +## Example + +Let's say you want to add a gherkin test: + +```gherkin +#language: nl + +Functionaliteit: Catalogi items moeten aan bepaalde regels voldoen + Om te testen dat een catalogi items aan te maken zijn + Als een gebruiker van het ZGW + Wil ik het systeem kunnen bevragen en waar nodig aanvullen + Zodat ik de catalogus als basis kan gebruiken voor verdere acties + +Scenario: aanmaken van een catalogus + Gegeven de catalogus-api is beschikbaar + Als er een nieuwe valide catalogus aangemaakt wordt + Dan krijgt de gebruiker statuscode 201 terug +``` + +You would add a feature file to `features`, let's call it `example.feature` + +Depending on your IDE running this feature file would already create steps (pycharm understands behave for example). + +But you would need to add these steps to `steps` let's call that file `example.py` + +```python +from behave import * + +@step("de catalogus-api is beschikbaar") +def step_impl(context): + response = context.client.catalogus.check_available() + assert response.status_code == 200 + return + +@step("er een nieuwe valide catalogus aangemaakt wordt") +def step_impl(context): + context.flow.setup_catalogus() + context.response = context.flow.catalogus + return + + +@step("krijgt de gebruiker statuscode {status_code:d} terug") +def step_impl(context, status_code): + response = context.response + assert response.status_code == status_code +``` + +Now if you look at the actual code you would see that the last `THEN` is part of `generic.py` that is because this step is shared across most tests. +It makes sense to assert at some point that the correct `status_code` is returned so having that `step` is a shareable step makes sense. + +Now most if not all `steps` use the `context.flow` this houses all logic related to creating/updating/deleting and keeping track of items created during tests. +The `flow` uses the `client/*` (`from client import endpoints, zgw`) to make the actual calls. Where each specific action for a specific api is housed. + +Feel free to change this system. At time of this writing the number of features and calls was manageable but it might well get out of hand and become a mess. + +## Adding Tags + +Tags are a specific way that behave interacts with tests. Here they are used to created certain fixtures. + +See the docs: https://behave.readthedocs.io/en/latest/tutorial/#controlling-things-with-tags + +Example: + +```gherkin +#language: nl + +Functionaliteit: Catalogi items moeten aan bepaalde regels voldoen + Om te testen dat een catalogi items aan te maken zijn + Als een gebruiker van het ZGW + Wil ik het systeem kunnen bevragen en waar nodig aanvullen + Zodat ik de catalogus als basis kan gebruiken voor verdere acties + +@token.set +@catalogus +Scenario: een aangemaakt catalogus is via filters terug te vinden + Gegeven de catalogus-api is beschikbaar + Als de catalogus wordt gezocht met parameters + | parameter | + | rsin | + | domein | + Dan krijgt de gebruiker de catalogus terug met de juiste informatie +``` + +The `Scenario` has two tags. One which sets a token and one that creates a catalogus before the test. +This way scenario's can be kept clean, you do not need a `given` step that says: "create a token and set that token and create a catalogus". + +How are these tags handled? In `environment.py` there is a function: + +```python +def before_tag(context, tag): + print(f"working on tag: {tag}") + match tag: + case "catalogus": + use_fixture(setup_flow, context) + context.flow.setup_catalogus() + case "token.set": + set_token(context) + case "zaak.basis": + use_fixture(setup_flow, context) + context.flow.prerequisites_zaak() + case "zaak.compleet": + use_fixture(setup_flow, context) + context.flow.complete_zaak() + case _: + print(f"unknown tag: {tag}") + + return +``` + +This will match a tag and then runs that as part of either the flow (so you have the catalogus_id within that Object for example) or as a different function (such as setting the token). + +If you create a new tag be sure that add it to the `allow_list` within `envoriment.py`: + +```python +VALID_TAGS = ["archiveren.valide", "catalogus", "zaak.basis", "zaak.compleet"] +``` + +# How to run ## Run locally diff --git a/client/__init__.py b/client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/client/endpoints.py b/client/endpoints.py new file mode 100644 index 0000000..371757b --- /dev/null +++ b/client/endpoints.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass + + +@dataclass +class EndPoints: + brc: str + ztc: str + zrc: str + drc: str + vrl: str + token_issuer: str diff --git a/client/zgw.py b/client/zgw.py new file mode 100644 index 0000000..969ae7b --- /dev/null +++ b/client/zgw.py @@ -0,0 +1,446 @@ +import string +import urllib +from urllib.parse import urljoin + +import requests + +from client.endpoints import EndPoints + + +class BaseClient: + def __init__(self): + self.application = "application/json" + self.token = "" + + @staticmethod + def parse_url(*args): + url = "" + for i, arg in enumerate(args): + url = urljoin(url, arg) + if not url.endswith("/") and len(args) != i + 1: + url = url + "/" + return url + + @staticmethod + def parse_query(query_parameters): + return "?" + (urllib.parse.urlencode(query_parameters)) + + def _get_header(self): + return { + "Accept": self.application, + "Content-Type": self.application, + "Authorization": self.token, + } + + def _get_full_header(self): + return { + "Content-Crs": "EPSG:4326", + "Accept-Crs": "EPSG:4326", + "Accept": self.application, + "Content-Type": self.application, + "Authorization": self.token, + } + + def _get_header_without_auth(self): + return { + "Accept": self.application, + "Content-Type": self.application, + } + + def set_token(self, token: str): + self.token = token + + +class Client(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, endpoints: EndPoints): + super().__init__() + self.endpoints = endpoints + self.besluiten = BesluitenApi(base_url=endpoints.brc) + self.catalogus = CatalogusApi(base_url=endpoints.ztc) + self.documenten = DocumentenApi(base_url=endpoints.drc) + self.token_issuer = TokenIssuerApi(base_url=endpoints.token_issuer) + self.referentie = ReferentieApi(base_url=endpoints.vrl) + self.zaken = ZakenApi(base_url=endpoints.zrc) + + +class BesluitenApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.base_url = base_url + self.version = "/api/v1" + + def check_available(self): + method = "GET" + header = self._get_header_without_auth() + response = requests.request(method, self.base_url, headers=header) + return response + + +class CatalogusApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.publish = "publish" + self.catalogussen_endpoint = "catalogussen" + self.besluittype_endpoint = "besluittypen" + self.informatieobjecttypen_endpoint = "informatieobjecttypen" + self.zaaktype_endpoint = "zaaktypen" + self.zaaktype_informatie_endpoint = "zaaktype-informatieobjecttypen" + self.eigenschappen_endpoint = "eigenschappen" + self.resultaattype_endpoint = "resultaattypen" + self.statustype_endpoint = "statustypen" + self.roltype_endpoint = "roltypen" + self.base_url = base_url + self.version = "/api/v1" + + def check_available(self): + method = "GET" + header = self._get_header_without_auth() + response = requests.request(method, self.base_url, headers=header) + return response + + def create_catalogus(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.catalogussen_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_besluittype(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.besluittype_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_informatieobjecttype(self, body: dict): + method = "POST" + url = self.parse_url( + self.base_url, self.version, self.informatieobjecttypen_endpoint + ) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_zaaktype(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.zaaktype_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def patch_zaaktype(self, uuid: str, body: dict): + method = "PATCH" + url = self.parse_url(self.base_url, self.version, self.zaaktype_endpoint, uuid) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def patch_besluittype(self, uuid: str, body: dict): + method = "PATCH" + url = self.parse_url(self.base_url, self.version, self.besluittype_endpoint, uuid) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_zaaktype_informatieobjecttype_relation(self, body): + method = "POST" + url = self.parse_url( + self.base_url, self.version, self.zaaktype_informatie_endpoint + ) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_eigenschap(self, body): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.eigenschappen_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_resultaattype(self, body): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.resultaattype_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_statustype(self, body): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.statustype_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_roltype(self, body): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.roltype_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def publish_type(self, reference_url): + method = "POST" + header = self._get_header() + body = {} + url = self.parse_url(reference_url, self.publish) + response = requests.request(method, url, headers=header, json=body) + return response + + def search_catalogus(self, query_arguments: dict): + method = "GET" + param = self.parse_query(query_arguments) + base = self.parse_url(self.base_url, self.version, self.catalogussen_endpoint) + url = urljoin(base, param) + header = self._get_header() + response = requests.request(method, url, headers=header) + return response + + def retrieve_zaaktype(self, url: string, query_arguments: dict = None): + method = "GET" + header = self._get_header() + if query_arguments: + param = self.parse_query(query_arguments) + url = urljoin(url, param) + response = requests.request(method, url, headers=header) + return response + + def retrieve_catalogus_object(self, url: string, query_arguments: dict = None): + method = "GET" + header = self._get_header() + if query_arguments: + param = self.parse_query(query_arguments) + url = urljoin(url, param) + response = requests.request(method, url, headers=header) + return response + def search_zaaktype(self, query_arguments: dict): + method = "GET" + param = self.parse_query(query_arguments) + base = self.parse_url(self.base_url, self.version, self.zaaktype_endpoint) + url = urljoin(base, param) + header = self._get_header() + response = requests.request(method, url, headers=header) + return response + + def search_resultaattype(self, url: str): + method = "GET" + header = self._get_full_header() + response = requests.request(method, url, headers=header) + return response + + +class DocumentenApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.base_url = base_url + self.enkelvoudiginformatieobjecten = "enkelvoudiginformatieobjecten" + self.gebruiksrechten = "gebruiksrechten" + self.version = "/api/v1" + + def check_available(self): + method = "GET" + header = self._get_header_without_auth() + response = requests.request(method, self.base_url, headers=header) + return response + + def create_enkelvoudiginformatieobjecten(self, body: dict): + method = "POST" + url = self.parse_url( + self.base_url, self.version, self.enkelvoudiginformatieobjecten + ) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_gebruiksrechten(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.gebruiksrechten) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + +class TokenIssuerApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.token_endpoint = "register/" + self.base_url = base_url + self.version = "/api/v1" + + def create_admin_token(self, client_id): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.token_endpoint) + header = self._get_header() + body = { + "clientIds": [client_id], + "label": "testAdminToken", + "heeftAlleAutorisaties": True, + "autorisaties": [], + } + response = requests.request(method, url, headers=header, json=body) + return response + + def create_token(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.token_endpoint) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response + + +class ReferentieApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.base_url = base_url + self.resultaten = "resultaten" + self.omschrijvingen = "resultaattypeomschrijvingen" + self.version = "/api/v1" + + def check_available(self): + method = "GET" + header = self._get_header_without_auth() + response = requests.request(method, self.base_url, headers=header) + return response + + def get_resultaten(self): + method = "GET" + header = self._get_header() + url = self.parse_url(self.base_url, self.version, self.resultaten) + response = requests.request(method, url, headers=header) + return response + + def get_omschrijvingen(self): + method = "GET" + header = self._get_header() + url = self.parse_url(self.base_url, self.version, self.omschrijvingen) + response = requests.request(method, url, headers=header) + return response + + +class ZakenApi(BaseClient): + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + + def __init__(self, base_url: str): + super().__init__() + self.zaken_endpoint = "zaken" + self.resultaten_endpoint = "resultaten" + self.status_endpoint = "statussen" + self.zaakinformatie_object_endpoint = "zaakinformatieobjecten" + self.zaakobjecten_endpoint = "zaakobjecten" + self.zaakeigenschappen_endpoint = "zaakeigenschappen" + self.rollen_endpoint = "rollen" + self.klantcontacten_endpoint = "klantcontacten" + self.base_url = base_url + self.version = "/api/v1" + + def check_available(self): + method = "GET" + header = self._get_header_without_auth() + response = requests.request(method, self.base_url, headers=header) + return response + + def create_zaak(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.zaken_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def search_zaak(self, params: str): + method = "GET" + header = self._get_full_header() + url = self.parse_url(self.base_url, self.version, self.zaken_endpoint, params) + response = requests.request(method, url, headers=header) + return response + + def search_zaken(self, query_arguments: dict): + method = "GET" + header = self._get_full_header() + param = self.parse_query(query_parameters=query_arguments) + base = self.parse_url(self.base_url, self.version, self.zaken_endpoint) + url = urljoin(base, param) + response = requests.request(method, url, headers=header) + return response + + def search_zaakinformatieobject(self, url: str): + method = "GET" + header = self._get_full_header() + response = requests.request(method, url, headers=header) + return response + + def create_resultaat(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.resultaten_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_status(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.status_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_rollen(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.rollen_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_zaakeigenschappen(self, body: dict, uuid: str): + method = "POST" + url = self.parse_url( + self.base_url, + self.version, + self.zaken_endpoint, + uuid, + self.zaakeigenschappen_endpoint, + ) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_zaakobjecten(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.zaakobjecten_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def create_klantcontacten(self, body: dict): + method = "POST" + url = self.parse_url(self.base_url, self.version, self.klantcontacten_endpoint) + header = self._get_full_header() + response = requests.request(method, url, headers=header, json=body) + return response + + def relate_informatieobject(self, body): + method = "POST" + + url = self.parse_url( + self.base_url, self.version, self.zaakinformatie_object_endpoint + ) + header = self._get_header() + response = requests.request(method, url, headers=header, json=body) + return response diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..abbcb70 --- /dev/null +++ b/config.ini @@ -0,0 +1,26 @@ +[kubernetes] +ac = http://k8s-ac-local.test +brc = http://k8s-brc-local.test +drc = http://k8s-drc-local.test +token-issuer = http://k8s-tokens-local.test +vrl = http://k8s-vrl-local.test +zrc = http://k8s-zrc-local.test +ztc = http://k8s-ztc-local.test + +[test] +ac = https://autorisatie-api.test.vng.cloud +brc = https://besluiten-api.test.vng.cloud +drc = https://documenten-api.test.vng.cloud +token-issuer = https://zaken-auth.test.vng.cloud/ +vrl = https://referentielijsten-api.vng.cloud +zrc = https://zaken-api.test.vng.cloud +ztc = https://catalogi-api.test.vng.cloud + +[production] +ac = https://autorisatie-api.vng.cloud +brc = https://besluiten-api.vng.cloud +drc = https://documenten-api.vng.cloud +token-issuer = https://zaken-auth.vng.cloud/ +vrl = https://referentielijsten-api.vng.cloud +zrc = https://zaken-api.vng.cloud +ztc = https://catalogi-api.vng.cloud \ No newline at end of file diff --git a/environment.py b/environment.py index 8adecc9..efc17db 100644 --- a/environment.py +++ b/environment.py @@ -1,19 +1,178 @@ -from behave import fixture, use_fixture +import configparser import os +from datetime import datetime + +from behave import fixture, use_fixture + +from client import endpoints, zgw +from flows import flow +from util import randomizer + +VALID_TAGS = ["archiveren.valide", "catalogus", "zaak.basis", "zaak.compleet"] @fixture def setup(context, *args, **kwargs): - token = os.environ.get("TOKEN") - if token is None: - # todo we want to get a token if none is set using the token tool - print("no token set please use ENV var") - context.token = token - ztc_address = os.environ.get("ZTC_ADDRESS") - if ztc_address is None: - ztc_address = "https://zaken-api.vng.cloud/api/v1" - context.ztc_address = ztc_address + # variables will be read from the config.ini + env = os.environ.get("ENV", "test") + + config = configparser.ConfigParser() + config.read("config.ini") + api_config = config[env] + + zgw_endpoints = get_external_endpoints(api_config) + + client = zgw.Client(endpoints=zgw_endpoints) + context.client = client + + if env == "kubernetes": + internal_service_endpoints = get_internal_service_endpoints() + context.internal_service_endpoints = internal_service_endpoints + + context.token = _token(client=client)["authorization"] + print(context.token) + return + + +@fixture() +def setup_flow(context, *args, **kwargs): + try: + internal_endpoints = context.internal_service_endpoints + except AttributeError: + print("internal endpoints left empty") + internal_endpoints = None + f = flow.Flow( + client=context.client, + internal_service_endpoints=internal_endpoints, + ) + context.flow = f + + +def _token(client: zgw): + random_string = randomizer.create_random_string(12) + client_id = "testRun" + random_string + return client.token_issuer.create_admin_token(client_id=client_id).json() + + +def get_external_endpoints(config): + brc_address = config["brc"] + from_env = os.environ.get("BRC_ADDRESS") + if from_env is not None: + brc_address = from_env + + drc_address = config["drc"] + from_env = os.environ.get("DRC_ADDRESS") + if from_env is not None: + drc_address = from_env + + token_issuer = config["token-issuer"] + from_env = os.environ.get("TOKEN_ISSUER_ADDRESS") + if from_env is not None: + token_issuer = from_env + + vrl_address = config["vrl"] + from_env = os.environ.get("VRL_ADDRESS") + if from_env is not None: + vrl_address = from_env + + ztc_address = config["ztc"] + from_env = os.environ.get("ZTC_ADDRESS") + if from_env is not None: + ztc_address = from_env + + zrc_address = config["zrc"] + from_env = os.environ.get("ZRC_ADDRESS") + if from_env is not None: + zrc_address = from_env + + return endpoints.EndPoints( + brc=brc_address, + drc=drc_address, + vrl=vrl_address, + token_issuer=token_issuer, + zrc=zrc_address, + ztc=ztc_address, + ) + + +def get_internal_service_endpoints(): + namespace = os.environ.get("NAMESPACE", "zgw") + + internal_brc_address = os.environ.get("INTERNAL_BRC_ADDRESS") + if internal_brc_address is None: + internal_brc_address = f"http://brc.{namespace}.svc.cluster.local:8000" + + internal_drc_address = os.environ.get("INTERNAL_DRC_ADDRESS") + if internal_drc_address is None: + internal_drc_address = f"http://drc.{namespace}.svc.cluster.local:8000" + + internal_vrl_address = os.environ.get("INTERNAL_VRL_ADDRESS") + if internal_vrl_address is None: + internal_vrl_address = f"http://vrl.{namespace}.svc.cluster.local:8000" + + internal_ztc_address = os.environ.get("INTERNAL_ZTC_ADDRESS") + if internal_ztc_address is None: + internal_ztc_address = f"http://ztc.{namespace}.svc.cluster.local:8000" + + internal_zrc_address = os.environ.get("INTERNAL_ZRC_ADDRESS") + if internal_zrc_address is None: + internal_zrc_address = f"http://zrc.{namespace}.svc.cluster.local:8000" + + internal_token_address = os.environ.get("INTERNAL_TOKEN_ADDRESS") + if internal_token_address is None: + internal_token_address = ( + f"http://token-issuer.{namespace}.svc.cluster.local:8000" + ) + + internal_service_endpoints = endpoints.EndPoints( + brc=internal_brc_address, + drc=internal_drc_address, + vrl=internal_vrl_address, + zrc=internal_zrc_address, + ztc=internal_ztc_address, + token_issuer=internal_token_address, + ) + + return internal_service_endpoints + + +def set_token(context): + context.client.catalogus.set_token(context.token) + context.client.documenten.set_token(context.token) + context.client.zaken.set_token(context.token) + return + + +def before_tag(context, tag): + print(f"working on tag: {tag}") + match tag: + case "catalogus": + use_fixture(setup_flow, context) + context.flow.setup_catalogus() + case "token.set": + set_token(context) + case "zaak.basis": + use_fixture(setup_flow, context) + context.flow.prerequisites_zaak() + case "zaak.compleet": + use_fixture(setup_flow, context) + context.flow.complete_zaak() + case _: + print(f"unknown tag: {tag}") + + return def before_feature(context, feature): + print(f'starttime: {datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")}') + print(f"working on feature: {feature}") use_fixture(setup, context) + + +def before_scenario(context, scenario): + print(f"working on scenario: {scenario}") + for tag in scenario.tags: + for inner_tag in VALID_TAGS: + if inner_tag == tag: + return + use_fixture(setup_flow, context) diff --git a/features/archiveren.feature b/features/archiveren.feature new file mode 100644 index 0000000..d39ab2a --- /dev/null +++ b/features/archiveren.feature @@ -0,0 +1,26 @@ +#language: nl + +Functionaliteit: laden van de juiste fixture + + +@token.set +@zaak.basis +Abstract Scenario: registreren eindstatus zaak en afleiden juiste archiveringsparameters + Gegeven er wordt een valide zaak aangemaakt met + En dat deze zaak een begin status heeft + #todo + En deze zaak nog niet de eindstatus bereikt heeft + En dat de archiefnominatie van de zaak nog niet bekend is + #todo fixture + En voor alle aan deze zaak gerelateerde informatieobjecten de status heeft en indicatie_gebruiksrecht + En er een resultaat aan de zaak wordt toegevoegd met een resultaattype + En dat het resultaattype archiefnominatie en archiefactietermijn en archiefprocedure heeft + En dat deze zaak geen einddatum heeft + Als een medewerker de eindstatus vastlegt + Dan reageert de Zaken API met een code 201 + En registreert de Zaken API bij archiefstatus de waarde en archiefnominatie + En registreert de Zaken API bij archiefactietermijn de einddatum van de zaak, verhooogd met bij het resultaattype geregistreerde archiefactietermijn + + Voorbeelden: ARC-001 + | archief_status | informatieobject_status | indicatie_gebruiksrecht | archiefnominatie | archiefactietermijn | archiefprocedure | archiefstatus | + | nog_te_archiveren | gearchiveerd | True | vernietigen | P10Y | afgehandeld | gearchiveerd | diff --git a/features/catalogus.feature b/features/catalogus.feature new file mode 100644 index 0000000..ef2c37a --- /dev/null +++ b/features/catalogus.feature @@ -0,0 +1,23 @@ +#language: nl + +Functionaliteit: Catalogi items moeten aan bepaalde regels voldoen + Om te testen dat een catalogi items aan te maken zijn + Als een gebruiker van het ZGW + Wil ik het systeem kunnen bevragen en waar nodig aanvullen + Zodat ik de catalogus als basis kan gebruiken voor verdere acties + +Scenario: aanmaken van een catalogus + Gegeven de catalogus-api is beschikbaar + En er is een valide token gezet + Als er een nieuwe valide catalogus aangemaakt wordt + Dan krijgt de gebruiker statuscode 201 terug + +@token.set +@catalogus +Scenario: een aangemaakt catalogus is via filters terug te vinden + Gegeven de catalogus-api is beschikbaar + Als de catalogus wordt gezocht met parameters + | parameter | + | rsin | + | domein | + Dan krijgt de gebruiker de catalogus terug met de juiste informatie diff --git a/features/historie_model.feature b/features/historie_model.feature new file mode 100644 index 0000000..302b4aa --- /dev/null +++ b/features/historie_model.feature @@ -0,0 +1,48 @@ +#language: nl + +Functionaliteit: Het grote historiemodel + Om te testen dat een zaak die bestaat ook daadwerkelijk op te halen is + Als een gebruiker van het ZGW + Wil ik het systeem kunnen bevragen + Zodat ik gegevens terug krijg + + @token.set + Scenario: Historie van een zaaktype met gerelateerde zaaktypen laat de correcte gerelateerde zaaktypen zien + Gegeven de catalogus-api is beschikbaar + Als er een nieuwe valide catalogus aangemaakt wordt + En er een valide informatieobjecttype aangemaakt wordt + En er een besluittype aangemaakt wordt met het informatieobjecttype + En er een zaaktype aangemaakt wordt + En er een valide eigenschap aangemaakt wordt + En er een valide statussen aangemaakt wordt + En er een valide rol aangemaakt wordt + En er een valide zaaktypeinformatieobjecttype met zaaktype_url en het informatieobjecttype + En er een zaaktype wordt aangemaakt met een gerelateerd zaaktype + En er een valide eigenschap aangemaakt wordt + En er een valide statussen aangemaakt wordt + En er een valide rol aangemaakt wordt + En deze zaaktypen worden gepubliceerd + En het zaaktype met gerelateerd zaaktype opgevraagd wordt verwijst het gerelateerde zaaktype naar het eerste zaaktype + En er een nieuw concept versie zaaktype met zaaktypeidentificatie van het gerelateerde zaaktype wordt aangemaakt + En het gerelateerde zaaktype een datum van vandaag krijgt + En het nieuwe concept wordt gepubliceerd + En het zaaktype opgevraagd word + Dan moeten de gerelateerdeZaaktype naar de juiste versie wijzen + + @token.set + Scenario: Historie van een zaaktype met besluittype moet het correct besluittype laten zien + Gegeven de catalogus-api is beschikbaar + Als er een nieuwe valide catalogus aangemaakt wordt + En er een valide informatieobjecttype aangemaakt wordt + En er een besluittype aangemaakt wordt met het informatieobjecttype + En het besluittype gepubliceerd wordt + En het besluittype een datum van vandaag krijgt + En er een zaaktype aangemaakt wordt met identificatie en besluittype + En er een valide eigenschap aangemaakt wordt + En er een valide statussen aangemaakt wordt + En er een valide rol aangemaakt wordt + En er een valide zaaktypeinformatieobjecttype met zaaktype_url en het informatieobjecttype + En deze zaaktypen worden gepubliceerd + En er een nieuwe besluittype wordt aangemaakt door de reactietermijn omhoog te zetten + En het zaaktype opgevraagd word + Dan moeten de besluittypen naar de juiste versie wijzen diff --git a/features/zaak.feature b/features/zaak.feature index bebb882..6474281 100644 --- a/features/zaak.feature +++ b/features/zaak.feature @@ -6,17 +6,78 @@ Functionaliteit: Zaken moeten bevraagbaar zijn via de zaken-api Wil ik het systeem kunnen bevragen Zodat ik gegevens terug krijg -Scenario: zaak heeft veld: 'vertrouwelijkheidsaanduiding' met 'Openbaar' + @token.set + Abstract Scenario: Een complete zaak aanmaken + Gegeven de catalogus-api is beschikbaar + En de zaken-api is beschikbaar + Als er een nieuwe valide catalogus aangemaakt wordt + En er een valide besluittype aangemaakt wordt + En er een valide informatieobjecttype aangemaakt wordt + En er een valide deelzaaktype aangemaakt wordt + En er een valide zaaktype aangemaakt wordt + En er een relatie wordt gelegd tussen het zaaktype en informatieobjecttype + En er een valide eigenschap aangemaakt wordt + En er een valide statussen aangemaakt wordt + En er een valide rol aangemaakt wordt + En de benodigde typen worden gepubliceerd + En er een valide enkelvoudiginformatieobject aangemaakt wordt + En er valide gebruiksrechten worden aangemaakt + En er een valide enkelvoudiginformatieobject aangemaakt wordt met + En er wordt een valide zaak aangemaakt met + Dan is er een zaak aangemaakt met statuscode 201 terug + En is de zaak terug te vinden + + Voorbeelden: Zaak + | veld | waarde | archief_status | + | indicatieGebruiksrecht | null | nog_te_archiveren | + + @token.set + @zaak.basis + Abstract Scenario: Zaak sluiten zet einddatum, archiefactiedatum en archiefnominatie (ZRC-008-A) + Gegeven de zaken-api is beschikbaar + Als er wordt een valide zaak aangemaakt met + En er een resultaat aan de zaak wordt toegevoegd met een resultaattype + En er een eindstatus met de datum van vandaag aan de zaak wordt toegevoegd + Dan staan einddatum op vandaag, archiefactiedatum op jaar in de toekomst en archiefnominatie op + + Voorbeelden: ZRC-008-A + | archief_status | archiefactiedatum | archiefnominatie | + | nog_te_archiveren | 10 | vernietigen | + + @token.set + @zaak.basis + Abstract Scenario: Zaak afsluiten en heropenen zet einddatum, archiefactiedatum en archiefnominatie op null (ZRC-008-B) Gegeven de zaken-api is beschikbaar - Als zaken wordt gezocht met de volgende parameters - | naam | waarde | - | identificatie | ZAAK-2019-0000002193 | - Dan heeft de response 1 zaak met de volgende gegevens - | naam | waarde | - | uuid | 1053b85b-2e72-4218-9fc3-3b67dda82c2e | - | identificatie | ZAAK-2019-0000002193 | - | vertrouwelijkheidaanduiding | openbaar | - | startdatum | 2019-04-09 | - | verantwoordelijkeOrganisatie | 000000000 | - | zaaktype | https://catalogi-api.vng.cloud/api/v1/zaaktypen/693d51a9-6c3f-4742-99e1-2d421cb75dc0 | - | betalingsindicatie | geheel | \ No newline at end of file + Als er wordt een valide zaak aangemaakt met + En er een resultaat aan de zaak wordt toegevoegd met een resultaattype + En er een eindstatus met de datum van vandaag aan de zaak wordt toegevoegd + En de zaak wordt heropend met een begin statustype + Dan staan einddatum, archiefactiedatum en archiefnominatie op null + + Voorbeelden: ZRC-008-B + | archief_status | + | nog_te_archiveren | + + @token.set + @zaak.compleet + Abstract Scenario: Expand op de zaken-api get mogelijk + Gegeven er is een zaak beschikbaar + Als het veld geexpand wordt bij de list operatie + Dan is het veld opgenomen in de response + + Voorbeelden: Expand + | veld | + | zaaktype,rollen.statussen.zaak.rollen,status.zaak,zaakobjecten,zaakinformatieobjecten | + | status.zaak.zaaktype.zaak.zaaktype.zaak | + + + @token.set + @zaak.compleet + Abstract Scenario: Expand op de zaken-api get niet mogelijk bij te lange of te diepe queries + Gegeven er is een zaak beschikbaar + Als het veld geexpand wordt bij de list operatie + Dan krijgt de gebruiker statuscode 400 terug + + Voorbeelden: Expand + | veld | + | rollen.zaak.rollen.zaak.rollen.zaak.rollen.zaak | diff --git a/flows/__init__.py b/flows/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flows/flow.py b/flows/flow.py new file mode 100644 index 0000000..15b4021 --- /dev/null +++ b/flows/flow.py @@ -0,0 +1,765 @@ +from datetime import datetime, timedelta + +from util import randomizer + + +class Flow: + def __init__(self, client, internal_service_endpoints): + self.deelzaak_type = None + self.besluit_type = None + self.zaaktypen_list = [] + self.zaak_uuid = None + self.zaak_eigenschap_url = None + self.client = client + self.internal_service_endpoints = internal_service_endpoints + self.creatie_datum = datetime.today().strftime("%Y-%m-%d") + self.geldigheid = datetime.today().strftime("%Y-%m-%d") + self.statustype_begin = None + self.statustype_eind = None + self.resultaattype_url = None + self.resultaattypeomschrijving_url = None + self.zaaktype_eigenschap_url = None + self.zaaktype_url = None + self.deelzaaktype_url = None + self.procestype_url = None + self.informatieobjecttype_url = None + self.besluittype_url = None + self.catalogus_url = None + self.naam = None + self.catalogus = None + self.valid_resin = self._create_valid_rsin() + self.bron_organisatie = None + self.enkelvoudig_informatieobject_url = None + self.informatieobject_type = None + self.selectie_lijst_url = None + self.zaak_url = None + self.zaak = None + self.resultaattype = None + self.resultaat_url = None + self.roltype_url = None + self.status = None + self.rol_url = None + self.zaakinformatieobject_url = None + + def prerequisites_zaak(self): + self.setup_catalogus() + self.besluittype() + self.informatieobjecttype() + self.deelzaaktype() + self.zaaktype() + self.zaaktype_informatie_relation() + self.eigenschappen() + self.resultaattypen() + self.statustype_begin_end() + self.roltype() + self.publish_types() + self.enkelvoudiginformatieobject() + self.gebruiksrechten() + + def complete_zaak(self): + self.prerequisites_zaak() + self.zaken(archiefstatus="nog_te_archiveren") + self.resultaten() + self.rollen() + self.statussen() + self.zaakobjecten() + self.zaakeigenschappen() + self.zaakinformatieobjecten_kopppeling() + self.klantcontacten() + + def _create_valid_rsin(self): + found = False + valid_rsin = "" + while not found: + valid_rsin = randomizer.create_random_number(9) + found = self._validate_rsin(str(valid_rsin)) + return valid_rsin + + @staticmethod + def _validate_rsin(value): + if len(value) != 9 or not value.isdigit(): + return False + + total = 0 + for multiplier, char in enumerate(reversed(value), start=1): + if multiplier == 1: + total += -multiplier * int(char) + else: + total += multiplier * int(char) + if total % 11 != 0 or total == 0: + return False + return True + + @staticmethod + def _replace_with_internal_service_address(external_url, service): + parts = external_url.split("/") + url_builder = service + build = [] + for index, part in enumerate(parts): + if part == "api": + build = parts[index:] + for index, part in enumerate(build): + if index < len(build): + url_builder += "/" + url_builder += part + return url_builder + + def resultaten(self): + resultaatype_url = self.resultaattype_url + if self.internal_service_endpoints is not None: + resultaatype_url = self._replace_with_internal_service_address( + self.resultaattype_url, self.internal_service_endpoints.ztc + ) + + body = {"zaak": self.zaak_url, "resultaattype": resultaatype_url} + + response = self.client.zaken.create_resultaat(body) + self.resultaat_url = response.json()["url"] + + def zaakinformatieobjecten_kopppeling(self): + informatieobject_url = self.enkelvoudig_informatieobject_url + if self.internal_service_endpoints is not None: + informatieobject_url = self._replace_with_internal_service_address( + self.enkelvoudig_informatieobject_url, + self.internal_service_endpoints.drc, + ) + + body = { + "zaak": self.zaak_url, + "informatieobject": informatieobject_url, + "titel": "titel" + self.naam, + "beschrijving": "beschrijving" + self.naam, + } + + response = self.client.zaken.relate_informatieobject(body) + + if response.status_code == 201: + self.zaakinformatieobject_url = response.json()["url"] + + def statussen(self, datum_gezet="", close=True): + status_url = self.statustype_eind + if self.internal_service_endpoints is not None: + status_url = self._replace_with_internal_service_address( + self.statustype_eind, self.internal_service_endpoints.ztc + ) + if not close: + status_url = self.statustype_begin + if self.internal_service_endpoints is not None: + status_url = self._replace_with_internal_service_address( + self.statustype_begin, self.internal_service_endpoints.ztc + ) + + if datum_gezet == "": + # datetime.now() returns a 400 + datum_gezet = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") + + body = { + "zaak": self.zaak_url, + "statustype": status_url, + "datumStatusGezet": datum_gezet, + } + + response = self.client.zaken.create_status(body) + self.status = response.json()["url"] + return response + + def enkelvoudiginformatieobject(self, field="", value=""): + informatie_object_type = self.informatieobjecttype_url + if self.internal_service_endpoints is not None: + informatie_object_type = self._replace_with_internal_service_address( + self.informatieobjecttype_url, self.internal_service_endpoints.ztc + ) + body = { + "bronorganisatie": self.valid_resin, + "creatiedatum": self.creatie_datum, + "titel": "testobject", + "auteur": "testauteur", + "taal": "eng", + "inhoud": "c3RyaW5n", + "informatieobjecttype": informatie_object_type, + "bestandsomvang": 6, + } + + if field != "": + body[field] = value + + response = self.client.documenten.create_enkelvoudiginformatieobjecten(body) + self.enkelvoudig_informatieobject_url = response.json()["url"] + + def gebruiksrechten(self): + informatie_object = self.enkelvoudig_informatieobject_url + if self.internal_service_endpoints is not None: + informatie_object = self._replace_with_internal_service_address( + self.enkelvoudig_informatieobject_url, + self.internal_service_endpoints.drc, + ) + + start_datum = datetime.today().strftime("%Y-%m-%dT%H:%M:%S") + body = { + "informatieobject": informatie_object, + "startdatum": start_datum, + "omschrijvingVoorwaarden": "test " + self.naam, + } + self.client.documenten.create_gebruiksrechten(body) + + def zaken(self, archiefstatus="nog_te_archiveren"): + selectie_lijst_url = self.selectie_lijst_url + if self.internal_service_endpoints is not None: + selectie_lijst_url = self._replace_with_internal_service_address( + self.selectie_lijst_url, self.internal_service_endpoints.vrl + ) + + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + td = timedelta(days=30) + delta = datetime.utcnow() + td + einddatum = delta.strftime("%Y-%m-%d") + + td = timedelta(days=10) + delta = datetime.utcnow() + td + betaaldatum = delta.strftime("%Y-%m-%d") + + body = { + "bronorganisatie": self.valid_resin, + "omschrijving": "omschrijving: " + self.naam, + "toelichting": "toelichting: " + self.naam, + "registratiedatum": self.creatie_datum, + "verantwoordelijkeOrganisatie": self.valid_resin, + "zaaktype": zaaktype_url, + "startdatum": self.creatie_datum, + "einddatumGepland": einddatum, + "uiterlijkeEinddatumAfdoening": einddatum, + "publicatiedatum": self.creatie_datum, + "vertrouwelijkheidaanduiding": "openbaar", + "betalingsindicatie": "geheel", + "laatsteBetaalDatum": betaaldatum, + "zaakgeometrie": {"type": "Point", "coordinates": [53, 5]}, + "opschorting": {"indicatie": True, "reden": "string"}, + "selectielijstklasse": selectie_lijst_url, + "archiefstatus": archiefstatus, + } + + self.zaak = self.client.zaken.create_zaak(body) + self.zaak_url = self.zaak.json()["url"] + self.zaak_uuid = self.zaak.json()["uuid"] + + def setup_catalogus(self): + random_name = randomizer.create_random_string(25) + random_domein = randomizer.create_random_letter(5).upper() + + self.naam = random_name + + body = { + "domein": random_domein, + "rsin": self.valid_resin, + "contactpersoonBeheerNaam": "TestPersoon " + random_name, + "naam": random_name, + } + + self.catalogus = self.client.catalogus.create_catalogus(body) + self.catalogus_url = self.catalogus.json()["url"] + + def besluittype(self): + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + body = { + "catalogus": catalogus_url, + "omschrijving": "testbesluittype" + self.naam, + "zaaktypen": [], + "publicatieIndicatie": False, + "informatieobjecttypen": [], + "beginGeldigheid": self.geldigheid, + } + + response = self.client.catalogus.create_besluittype(body) + self.besluittype_url = response.json()["url"] + self.besluittype = response.json() + return response + + def besluittype_with_return(self, body): + response = self.client.catalogus.create_besluittype(body) + return response + + def besluittype_with_informatieobjecttype(self): + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + + omschrijving = "testbesluittype" + self.naam + + td = timedelta(days=10) + d = datetime.utcnow() - td + geldigheid = d.strftime("%Y-%m-%d") + iso = "P1Y0M0D" + + iot_omschrijving = self.informatieobject_type["omschrijving"] + body = { + "catalogus": catalogus_url, + "omschrijving": omschrijving, + "zaaktypen": [], + "reactietermijn": iso, + "publicatieIndicatie": False, + "informatieobjecttypen": [iot_omschrijving], + "beginGeldigheid": geldigheid, + } + + response = self.client.catalogus.create_besluittype(body) + self.besluittype_url = response.json()["url"] + self.besluit_type = response.json() + return response + + def informatieobjecttype(self, omschrijving=None): + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + + if omschrijving is None: + omschrijving = "testinformatieobjecttype" + self.naam + body = { + "catalogus": catalogus_url, + "omschrijving": omschrijving, + "vertrouwelijkheidaanduiding": "openbaar", + "informatieobjectcategorie": "informatieobjectcategorie" + self.naam, + "beginGeldigheid": self.geldigheid, + } + + response = self.client.catalogus.create_informatieobjecttype(body) + self.informatieobjecttype_url = response.json()["url"] + self.informatieobject_type = response.json() + + return response + + def deelzaaktype(self): + identificatie = randomizer.create_random_string(40) + + resultaten = self.client.referentie.get_resultaten().json() + for resultaat in resultaten["results"]: + if resultaat["procestermijn"] == "nihil": + self.procestype_url = resultaat["procesType"] + self.selectie_lijst_url = resultaat["url"] + break + + procestype_url = self.procestype_url + if self.internal_service_endpoints is not None: + procestype_url = self._replace_with_internal_service_address( + self.procestype_url, self.internal_service_endpoints.vrl + ) + + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + + besluittypen = [] + if self.besluit_type is not None: + besluittypen.append(self.besluit_type["omschrijving"]) + + body = { + "identificatie": identificatie, + "omschrijving": "testdeelzaaktype " + self.naam, + "verantwoordelijke": "verantwoordelijk" + self.naam, + "vertrouwelijkheidaanduiding": "openbaar", + "doel": "test doel", + "aanleiding": "test aanleiding", + "indicatieInternOfExtern": "extern", + "handelingInitiator": "indienen", + "onderwerp": "openbare ruimte", + "handelingBehandelaar": "behandelen", + "doorlooptijd": "P10D", + "opschortingEnAanhoudingMogelijk": False, + "verlengingMogelijk": True, + "publicatieIndicatie": False, + "productenOfDiensten": ["https://vng.nl/projecten/gemma-softwarecatalogus"], + "selectielijstProcestype": procestype_url, + "referentieproces": {"naam": "test", "link": ""}, + "catalogus": catalogus_url, + "informatieobjecttypen": [], + "besluittypen": besluittypen, + "gerelateerdeZaaktypen": [], + "beginGeldigheid": self.geldigheid, + "versiedatum": self.geldigheid, + "concept": True, + "verlengingstermijn": "P5D", + } + + response = self.client.catalogus.create_zaaktype(body) + self.deelzaak_type = response.json() + self.deelzaaktype_url = response.json()["url"] + return response + + def update_zaaktype_with_geldigheid(self, uuid, geldigheid): + body = { + "eindeGeldigheid": geldigheid, + } + response = self.client.catalogus.patch_zaaktype(uuid, body) + return response + + def update_besluittype_with_geldigheid(self, uuid, geldigheid): + body = { + "eindeGeldigheid": geldigheid, + } + response = self.client.catalogus.patch_besluittype(uuid, body) + return response + def zaaktype_with_return(self, identificatie, other_id=None): + if self.procestype_url is None: + resultaten = self.client.referentie.get_resultaten().json() + for resultaat in resultaten["results"]: + if resultaat["procestermijn"] == "nihil": + self.procestype_url = resultaat["procesType"] + self.selectie_lijst_url = resultaat["url"] + break + + procestype_url = self.procestype_url + if self.internal_service_endpoints is not None: + procestype_url = self._replace_with_internal_service_address( + self.procestype_url, self.internal_service_endpoints.vrl + ) + + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + + gerelateerd_zaaktype = { + "zaaktype": identificatie, + "aardRelatie": "vervolg", + "toelichting": f"gerealteerd: {identificatie}", + } + + new_id = randomizer.create_random_string(40) + td = timedelta(days=1) + d = datetime.utcnow() + td + geldigheid = d.strftime("%Y-%m-%d") + body = { + "identificatie": new_id, + "omschrijving": "thisisanothergeneratedtest " + self.naam, + "vertrouwelijkheidaanduiding": "openbaar", + "verantwoordelijke": "verantwoordelijk" + self.naam, + "doel": "test doel", + "aanleiding": "test aanleiding", + "indicatieInternOfExtern": "extern", + "handelingInitiator": "indienen", + "onderwerp": "openbare ruimte", + "handelingBehandelaar": "behandelen", + "doorlooptijd": "P10D", + "opschortingEnAanhoudingMogelijk": False, + "toelichting": "handmatige ophoging", + "verlengingMogelijk": True, + "publicatieIndicatie": False, + "productenOfDiensten": ["https://vng.nl/projecten/gemma-softwarecatalogus"], + "selectielijstProcestype": procestype_url, + "referentieproces": {"naam": "test", "link": ""}, + "deelzaaktypen": [], + "catalogus": catalogus_url, + "informatieobjecttypen": [], + "besluittypen": [], + "gerelateerdeZaaktypen": [], + "beginGeldigheid": geldigheid, + "versiedatum": geldigheid, + "concept": True, + "verlengingstermijn": "P5D", + } + if gerelateerd_zaaktype is not None: + body["gerelateerdeZaaktypen"] = [gerelateerd_zaaktype] + response = self.client.catalogus.create_zaaktype(body) + return response + + def zaaktype( + self, gerelateerd_zaaktype=None, add_deelzaak=True, add_besluittype=True + ): + identificatie = randomizer.create_random_string(40) + + if self.procestype_url is None: + resultaten = self.client.referentie.get_resultaten().json() + for resultaat in resultaten["results"]: + if resultaat["procestermijn"] == "nihil": + self.procestype_url = resultaat["procesType"] + self.selectie_lijst_url = resultaat["url"] + break + + procestype_url = self.procestype_url + if self.internal_service_endpoints is not None: + procestype_url = self._replace_with_internal_service_address( + self.procestype_url, self.internal_service_endpoints.vrl + ) + + catalogus_url = self.catalogus_url + if self.internal_service_endpoints is not None: + catalogus_url = self._replace_with_internal_service_address( + self.catalogus_url, self.internal_service_endpoints.ztc + ) + + besluitentypen = [] + if self.besluit_type is not None and add_besluittype: + besluitentypen.append(self.besluit_type["omschrijving"]) + + deelzaken = [] + if self.deelzaak_type is not None and add_deelzaak: + deelzaken.append(self.deelzaak_type["identificatie"]) + + td = timedelta(days=10) + delta = datetime.utcnow() - td + geldigheid = delta.strftime("%Y-%m-%d") + body = { + "identificatie": identificatie, + "omschrijving": "testzaaktype " + self.naam, + "vertrouwelijkheidaanduiding": "openbaar", + "verantwoordelijke": "verantwoordelijk" + self.naam, + "doel": "test doel", + "aanleiding": "test aanleiding", + "indicatieInternOfExtern": "extern", + "handelingInitiator": "indienen", + "onderwerp": "openbare ruimte", + "handelingBehandelaar": "behandelen", + "doorlooptijd": "P10D", + "opschortingEnAanhoudingMogelijk": False, + "verlengingMogelijk": True, + "publicatieIndicatie": False, + "productenOfDiensten": ["https://vng.nl/projecten/gemma-softwarecatalogus"], + "selectielijstProcestype": procestype_url, + "referentieproces": {"naam": "test", "link": ""}, + "deelzaaktypen": deelzaken, + "catalogus": catalogus_url, + "informatieobjecttypen": [], + "besluittypen": besluitentypen, + "gerelateerdeZaaktypen": [], + "beginGeldigheid": geldigheid, + "versiedatum": geldigheid, + "concept": True, + "verlengingstermijn": "P5D", + } + + if gerelateerd_zaaktype is not None: + body["gerelateerdeZaaktypen"] = gerelateerd_zaaktype + + response = self.client.catalogus.create_zaaktype(body) + self.zaaktype_url = response.json()["url"] + return response + + def zaaktype_list( + self, gerelateerd_zaaktype=False, add_deelzaaktype=False, add_besluittype=False + ): + if gerelateerd_zaaktype: + zaaktypen = [] + for zaaktype in self.zaaktypen_list: + body = { + "zaaktype": zaaktype["identificatie"], + "aardRelatie": "vervolg", + "toelichting": f"gerealteerd: {zaaktype['identificatie']}", + } + zaaktypen.append(body) + response = self.zaaktype( + gerelateerd_zaaktype=zaaktypen, + add_deelzaak=add_deelzaaktype, + add_besluittype=add_besluittype, + ) + self.zaaktypen_list.append(response.json()) + return response + response = self.zaaktype( + add_deelzaak=add_deelzaaktype, add_besluittype=add_besluittype + ) + self.zaaktypen_list.append(response.json()) + return response + + def zaaktype_informatie_relation(self): + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + informatieobjecttype_url = self.informatieobjecttype_url + if self.internal_service_endpoints is not None: + informatieobjecttype_url = self._replace_with_internal_service_address( + self.informatieobjecttype_url, self.internal_service_endpoints.ztc + ) + + body = { + "zaaktype": zaaktype_url, + "informatieobjecttype": informatieobjecttype_url, + "volgnummer": 1, + "richting": "inkomend", + } + return self.client.catalogus.create_zaaktype_informatieobjecttype_relation(body) + + def eigenschappen(self): + eigenschap_naam = randomizer.create_random_string(8) + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + body = { + "naam": "eigenschap " + eigenschap_naam, + "definitie": "for test", + "zaaktype": zaaktype_url, + "specificatie": { + "formaat": "tekst", + "lengte": "5", + "kardinaliteit": "1", + "waardenverzameling": ["test"], + }, + } + response = self.client.catalogus.create_eigenschap(body) + self.zaaktype_eigenschap_url = response.json()["url"] + return response + + def resultaattypen(self): + resultaattypeomschrijvingen = self.client.referentie.get_omschrijvingen().json() + self.resultaattypeomschrijving_url = resultaattypeomschrijvingen[0]["url"] + + selectie_lijst_url = self.selectie_lijst_url + if self.internal_service_endpoints is not None: + selectie_lijst_url = self._replace_with_internal_service_address( + self.selectie_lijst_url, self.internal_service_endpoints.vrl + ) + + resultaattypeomschrijving_url = self.resultaattypeomschrijving_url + if self.internal_service_endpoints is not None: + resultaattypeomschrijving_url = self._replace_with_internal_service_address( + self.resultaattypeomschrijving_url, self.internal_service_endpoints.vrl + ) + + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + body = { + "zaaktype": zaaktype_url, + "omschrijving": "Klaar", + "resultaattypeomschrijving": resultaattypeomschrijving_url, + "selectielijstklasse": selectie_lijst_url, + "brondatumArchiefprocedure": { + "afleidingswijze": "afgehandeld", + "procestermijn": None, + "datumkenmerk": "", + "einddatumBekend": False, + "objecttype": "", + "registratie": "", + }, + } + + resp = self.client.catalogus.create_resultaattype(body) + self.resultaattype = resp + self.resultaattype_url = resp.json()["url"] + + def statustype_begin_end(self): + omschrijvingen = ["Begin", "Einde"] + + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + for i, omschrijving in enumerate(omschrijvingen, 1): + body = { + "omschrijving": omschrijving, + "zaaktype": zaaktype_url, + "volgnummer": i, + } + response = self.client.catalogus.create_statustype(body).json() + if i < len(omschrijvingen): + self.statustype_begin = response["url"] + else: + self.statustype_eind = response["url"] + return + + def roltype(self): + zaaktype_url = self.zaaktype_url + if self.internal_service_endpoints is not None: + zaaktype_url = self._replace_with_internal_service_address( + self.zaaktype_url, self.internal_service_endpoints.ztc + ) + + body = { + "zaaktype": zaaktype_url, + "omschrijving": "testroltype", + "omschrijvingGeneriek": "adviseur", + } + + response = self.client.catalogus.create_roltype(body) + self.roltype_url = response.json()["url"] + + def rollen(self): + roltype_url = self.roltype_url + if self.internal_service_endpoints is not None: + roltype_url = self._replace_with_internal_service_address( + self.roltype_url, self.internal_service_endpoints.ztc + ) + + body = { + "zaak": self.zaak_url, + "betrokkene": "http://example.com/2d0815580af94ee0a15aa677aa646e1a", + "betrokkeneType": "natuurlijk_persoon", + "rolomschrijving": "behandelaar", + "roltoelichting": "testrol", + "roltype": roltype_url, + } + + response = self.client.zaken.create_rollen(body) + self.rol_url = response.json()["url"] + + def zaakeigenschappen(self): + zaaktype_eigenschap_url = self.zaaktype_eigenschap_url + if self.internal_service_endpoints is not None: + zaaktype_eigenschap_url = self._replace_with_internal_service_address( + self.zaaktype_eigenschap_url, self.internal_service_endpoints.ztc + ) + + body = { + "zaak": self.zaak_url, + "eigenschap": zaaktype_eigenschap_url, + "waarde": "test", + } + + response = self.client.zaken.create_zaakeigenschappen( + body=body, uuid=self.zaak_uuid + ) + self.zaak_eigenschap_url = response.json()["url"] + + def zaakobjecten(self): + body = { + "zaak": self.zaak_url, + "objectType": "pand", + "objectIdentificatie": {"identificatie": "test"}, + } + + response = self.client.zaken.create_zaakobjecten(body) + + def klantcontacten(self): + body = { + "zaak": self.zaak_url, + "datumtijd": datetime.today().strftime("%Y-%m-%dT%H:%M:%S"), + } + + response = self.client.zaken.create_klantcontacten(body) + + def publish_types(self): + if self.besluittype_url is not None: + self.client.catalogus.publish_type(self.besluittype_url) + + if self.informatieobjecttype_url is not None: + self.client.catalogus.publish_type(self.informatieobjecttype_url) + + if self.deelzaaktype_url is not None: + self.client.catalogus.publish_type(self.deelzaaktype_url) + + if self.zaaktype_url is not None: + self.client.catalogus.publish_type(self.zaaktype_url) diff --git a/requirements.txt b/requirements.txt index 653867a..090e536 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ behave==1.2.6 -certifi==2022.9.24 -charset-normalizer==2.1.1 +certifi==2022.12.7 +charset-normalizer==3.1.0 idna==3.4 parse==1.19.0 parse-type==0.6.0 -requests==2.28.1 +requests==2.28.2 six==1.16.0 -urllib3==1.26.12 +urllib3==1.26.14 diff --git a/steps/archiveren.py b/steps/archiveren.py new file mode 100644 index 0000000..eed0201 --- /dev/null +++ b/steps/archiveren.py @@ -0,0 +1,47 @@ +from behave import * + +use_step_matcher("re") + + +@step("dat deze zaak een begin status heeft") +def step_impl(context): + context.flow.statussen(close=False) + + +@step("deze zaak nog niet de eindstatus bereikt heeft") +def step_impl(context): + # zaak -> status -> statustype -> assert !eindstatus + # uuid = context.flow.zaak.json()["uuid"] + # resp = context.client.catalogus.search_statustype(uuid) + # assert resp.status_code == 200 + + # status van de zaak ophalen + + # assert resp.json()["eindstatus"] == None + assert True is True + + +@step("dat de archiefnominatie van de zaak nog niet bekend is") +def step_impl(context): + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + assert resp.json()["archiefnominatie"] == None + + +@step( + "voor alle aan deze zaak gerelateerde informatieobjecten de status (?P.+) heeft en indicatie_gebruiksrecht (?P.+)" +) +def step_impl(context, informatieobject_status, indicatie_gebruiksrecht): + """ + :type context: behave.runner.Context + :type informatieobject_status: str + :type indicatie_gebruiksrecht: str + """ + context.flow.zaakinformatieobjecten_kopppeling() + resp = context.client.zaken.search_zaakinformatieobject( + url=context.flow.zaakinformatieobject_url + ) + sut = resp.json() + print(sut) diff --git a/steps/catalogus.py b/steps/catalogus.py new file mode 100644 index 0000000..1adb280 --- /dev/null +++ b/steps/catalogus.py @@ -0,0 +1,264 @@ +from datetime import datetime + +from _datetime import timedelta +from behave import * + + +@step("de catalogus-api is beschikbaar") +def step_impl(context): + response = context.client.catalogus.check_available() + assert response.status_code == 200 + return + + +@step("de catalogus wordt gezocht met parameters") +def step_impl(context): + search_responses = [] + response = context.flow.catalogus.json() + for row in context.table: + query_param = {row["parameter"]: response[row["parameter"]]} + resp = context.client.catalogus.search_catalogus(query_arguments=query_param) + search_responses.append(resp) + context.search_responses = search_responses + + +@step("er een nieuwe valide catalogus aangemaakt wordt") +def step_impl(context): + context.flow.setup_catalogus() + context.response = context.flow.catalogus + return + + +@step("er een valide besluittype aangemaakt wordt") +def step_impl(context): + context.flow.besluittype() + return + + +@step("er een valide informatieobjecttype aangemaakt wordt") +def step_impl(context): + context.flow.informatieobjecttype() + return + + +@step("er een valide deelzaaktype aangemaakt wordt") +def step_impl(context): + context.flow.deelzaaktype() + return + + +@step("er een valide zaaktype aangemaakt wordt") +def step_impl(context): + context.flow.zaaktype() + return + + +@step("er een relatie wordt gelegd tussen het zaaktype en informatieobjecttype") +def step_impl(context): + context.flow.zaaktype_informatie_relation() + return + + +@step("er een valide eigenschap aangemaakt wordt") +def step_impl(context): + context.flow.eigenschappen() + return + + +@step("er een valide resultaattype aangemaakt wordt") +def step_impl(context): + context.flow.resultaattypen() + return + + +@step("er een valide statussen aangemaakt wordt") +def step_impl(context): + context.flow.statustype_begin_end() + return + + +@step("er een valide rol aangemaakt wordt") +def step_impl(context): + context.flow.roltype() + return + + +@step("de benodigde typen worden gepubliceerd") +def step_impl(context): + context.flow.publish_types() + return + + +@step("krijgt de gebruiker de catalogus terug met de juiste informatie") +def step_impl(context): + responses = context.search_responses + for response in responses: + assert response.status_code == 200 + + +@step( + "er een informatieobjecttype aangemaakt wordt met omschrijving {iot_omschrijving}" +) +def step_impl(context, iot_omschrijving): + context.flow.informatieobjecttype(iot_omschrijving) + + +@step("er een besluittype aangemaakt wordt met het informatieobjecttype") +def step_impl(context): + context.flow.besluittype_with_informatieobjecttype() + + +@step("er een zaaktype aangemaakt wordt") +def step_impl(context): + context.flow.zaaktype_list() + +@step("er een zaaktype aangemaakt wordt met identificatie en besluittype") +def step_impl(context): + context.flow.zaaktype_list(add_besluittype=True) + + +@step( + "er een valide zaaktypeinformatieobjecttype met zaaktype_url en het informatieobjecttype" +) +def step_impl(context): + context.flow.zaaktype_informatie_relation() + + +@step("er een zaaktype wordt aangemaakt met een gerelateerd zaaktype") +def step_impl(context): + context.flow.zaaktype_list(gerelateerd_zaaktype=True) + + +@step("er een zaaktype wordt aangemaakt met een deelzaaktype") +def step_impl(context): + context.flow.zaaktype_list(gerelateerd_zaaktype=False, add_deelzaaktype=True) + + +@step( + "het zaaktype met gerelateerd zaaktype opgevraagd wordt verwijst het gerelateerde zaaktype naar het eerste zaaktype" +) +def step_impl(context): + zaaktypen = context.flow.zaaktypen_list + for zaaktype in zaaktypen: + if zaaktype["gerelateerdeZaaktypen"] != []: + zktype = context.client.catalogus.retrieve_zaaktype(zaaktype["url"]) + z = zktype.json() + related_zaaktype = z["gerelateerdeZaaktypen"][0]["zaaktype"] + assert related_zaaktype == zaaktypen[0]["url"] + + +@step( + "er een nieuw concept versie zaaktype met zaaktypeidentificatie van het gerelateerde zaaktype wordt aangemaakt" +) +def step_impl(context): + first_zaaktype_id = context.flow.zaaktypen_list[0]["identificatie"] + resp = context.flow.zaaktype_with_return(identificatie=first_zaaktype_id) + assert resp.status_code == 201 + context.updated_zaaktype = resp.json() + + +@step("deze zaaktypen worden gepubliceerd") +def step_impl(context): + zaaktypen = context.flow.zaaktypen_list + for zaaktype in zaaktypen: + context.client.catalogus.publish_type(reference_url=zaaktype["url"]) + + +@step("het gerelateerde zaaktype een datum van vandaag krijgt") +def step_impl(context): + old_zaaktype_url = context.flow.zaaktypen_list[1]["url"] + old_zaaktype_id = old_zaaktype_url.split("/")[-1] + timestamp = datetime.utcnow().strftime("%Y-%m-%d") + context.flow.update_zaaktype_with_geldigheid( + uuid=old_zaaktype_id, geldigheid=timestamp + ) + + +@step("het nieuwe concept wordt gepubliceerd") +def step_impl(context): + zaaktype = context.updated_zaaktype + context.client.catalogus.publish_type(reference_url=zaaktype["url"]) + + +@step("het zaaktype opgevraagd word") +def step_impl(context): + zaaktypen = context.flow.zaaktypen_list + url = zaaktypen[0]["url"] + td = timedelta(days=5) + d = datetime.utcnow() + td + datum_geldigheid = d.strftime("%Y-%m-%d") + qp = {"datumGeldigheid": datum_geldigheid} + zaaktype_nieuw = context.client.catalogus.retrieve_zaaktype(url, query_arguments=qp) + delta = datetime.utcnow() - td + geldigheid = delta.strftime("%Y-%m-%d") + query_param = {"datumGeldigheid": geldigheid} + zaaktype_oud = context.client.catalogus.retrieve_zaaktype( + url, query_arguments=query_param + ) + + context.zaaktype_oud = zaaktype_oud + context.zaaktype_nieuw = zaaktype_nieuw + + +@step("moeten de besluittypen naar de juiste versie wijzen") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + zaaktype_oud = context.zaaktype_oud + zaaktype_nieuw = context.zaaktype_nieuw + assert zaaktype_nieuw.status_code == 200 + assert zaaktype_oud.status_code == 200 + + bto = context.client.catalogus.retrieve_catalogus_object(zaaktype_oud.json()['besluittypen'][0]) + btn = context.client.catalogus.retrieve_catalogus_object(zaaktype_nieuw.json()['besluittypen'][0]) + + assert bto.status_code == 200 + assert not bto.json()['concept'] + assert bto.json()["eindeGeldigheid"] != "" + assert btn.status_code == 200 + assert btn.json()['concept'] + assert btn.json()["eindeGeldigheid"] is None + + +@step("moeten de gerelateerdeZaaktype naar de juiste versie wijzen") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + zaaktype_oud = context.zaaktype_oud + zaaktype_nieuw = context.zaaktype_nieuw + assert zaaktype_nieuw.status_code == 200 + assert zaaktype_oud.status_code == 200 + assert zaaktype_nieuw.json()['gerelateerdeZaaktypen'] != [] + assert zaaktype_oud.json()['gerelateerdeZaaktypen'] != [] + +@step("er een nieuwe besluittype wordt aangemaakt door de reactietermijn omhoog te zetten") +def step_impl(context): + bt = context.client.catalogus.retrieve_catalogus_object(context.flow.besluittype_url) + body = bt.json() + td = timedelta(days=1) + d = datetime.utcnow() + td + datum_geldigheid = d.strftime("%Y-%m-%d") + new_reactietermijn = "P1Y1M10D" + body["reactietermijn"] = new_reactietermijn + body["beginGeldigheid"] = datum_geldigheid + del body["eindeGeldigheid"] + del body["concept"] + resp = context.flow.besluittype_with_return(body) + print(resp.json()) + + +@step("het besluittype gepubliceerd wordt") +def step_impl(context): + bt = context.client.catalogus.retrieve_catalogus_object(context.flow.besluittype_url) + context.client.catalogus.publish_type(bt.json()['url']) + + +@step("het besluittype een datum van vandaag krijgt") +def step_impl(context): + timestamp = datetime.utcnow().strftime("%Y-%m-%d") + uuid = context.flow.besluittype_url.split("/")[-1] + context.flow.update_besluittype_with_geldigheid( + uuid=uuid, geldigheid=timestamp + ) \ No newline at end of file diff --git a/steps/documenten.py b/steps/documenten.py new file mode 100644 index 0000000..e81a922 --- /dev/null +++ b/steps/documenten.py @@ -0,0 +1,23 @@ +from behave import * + + +@step("er een valide enkelvoudiginformatieobject aangemaakt wordt") +def step_impl(context): + context.flow.enkelvoudiginformatieobject() + return + + +@step("er valide gebruiksrechten worden aangemaakt") +def step_impl(context): + context.flow.gebruiksrechten() + return + + +@step("er een valide enkelvoudiginformatieobject aangemaakt wordt met {veld} {waarde}") +def step_impl(context, veld, waarde): + """ + :type context: behave.runner.Context + :type veld: str + :type waarde: str + """ + context.flow.enkelvoudiginformatieobject(field=veld, value=waarde) diff --git a/steps/generic.py b/steps/generic.py new file mode 100644 index 0000000..b2652f9 --- /dev/null +++ b/steps/generic.py @@ -0,0 +1,15 @@ +from behave import * + + +@step("er is een valide token gezet") +def step_impl(context): + context.client.catalogus.set_token(context.token) + context.client.documenten.set_token(context.token) + context.client.zaken.set_token(context.token) + return + + +@step("krijgt de gebruiker statuscode {status_code:d} terug") +def step_impl(context, status_code): + response = context.response + assert response.status_code == status_code diff --git a/steps/history.py b/steps/history.py new file mode 100644 index 0000000..e69de29 diff --git a/steps/zaak.py b/steps/zaak.py index 6691fd9..ebd647e 100644 --- a/steps/zaak.py +++ b/steps/zaak.py @@ -1,42 +1,264 @@ +from datetime import datetime, timedelta + from behave import * -from requests import request -@given("de zaken-api is beschikbaar") +@step("de zaken-api is beschikbaar") def step_impl(context): - response = request("GET", context.ztc_address) + response = context.client.zaken.check_available() assert response.status_code == 200 return -@when("zaken wordt gezocht met de volgende parameters") +@step("er is een zaak beschikbaar") +def step_impl(context): + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + +@step("er wordt een valide zaak aangemaakt") +def step_impl(context): + context.flow.zaken() + + +@step("zaken wordt gezocht met de volgende parameters") def step_impl(context): query_param = "" for row in context.table: query_param = f"?{row['naam']}={row['waarde']}" - url = f"{context.ztc_address}/zaken{query_param}" - payload = "" - headers = { - "Accept-Crs": "EPSG:4326", - "Content-Crs": "EPSG:4326", - "Authorization": f"Bearer {context.token}", - } - - response = request("GET", url, headers=headers, data=payload) - + response = context.client.zaken.search_zaak(params=query_param) context.response = response return -@then("heeft de response {number_of_zaken:d} zaak met de volgende gegevens") +@step("heeft de response {number_of_zaken:d} zaak met de volgende gegevens") def step_impl(context, number_of_zaken): response = context.response assert response.status_code == 200 result = response.json()["results"] assert len(result) == number_of_zaken for row in context.table: - print(row["waarde"]) - print(result[0].get(row["naam"])) assert result[0].get(row["naam"]) == row["waarde"] return + + +@step("er wordt een valide zaak aangemaakt met {archief_status}") +def step_impl(context, archief_status): + """ + :type context: behave.runner.Context + :type archief_status: str + """ + context.flow.zaken(archief_status) + + +@step("is er een zaak aangemaakt met statuscode {status_code:d} terug") +def step_impl(context, status_code): + """ + :type context: behave.runner.Context + """ + response = context.flow.zaak + assert response.status_code == status_code + + +@step("is de zaak terug te vinden") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + assert resp.json()["uuid"] == uuid + + +@step("dat een zaak bestaat") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + +@step("er een resultaat aan de zaak wordt toegevoegd met een resultaattype") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + context.flow.resultaten() + + +@step("er een eindstatus met de datum van vandaag aan de zaak wordt toegevoegd") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + today = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") + context.flow.statussen(close=True, datum_gezet=today) + + +@step("de zaak wordt heropend met een begin statustype") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + context.flow.statussen(close=False) + + +@step( + "staan einddatum op vandaag, archiefactiedatum op {archiefactiedatum:d} jaar in de toekomst en archiefnominatie op {archiefnominatie}" +) +def step_impl(context, archiefactiedatum, archiefnominatie): + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + einddatum = datetime.utcnow().strftime("%Y-%m-%d") + end_date_split = einddatum.split("-") + ten_years_from_now = int(end_date_split[0]) + archiefactiedatum + date_future = f"{ten_years_from_now}-{end_date_split[1]}-{end_date_split[2]}" + sut = resp.json() + assert date_future == sut["archiefactiedatum"] + assert einddatum == sut["einddatum"] + assert archiefnominatie == sut["archiefnominatie"] + + +@step("staan einddatum, archiefactiedatum en archiefnominatie op null") +def step_impl(context): + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + sut = resp.json() + assert sut["archiefactiedatum"] == None + assert sut["einddatum"] == None + assert sut["archiefnominatie"] == None + + +@step( + "dat het resultaattype archiefnominatie {archiefnominatie} en archiefactietermijn {archiefactietermijn} en archiefprocedure {archiefprocedure} heeft" +) +def step_impl(context, archiefnominatie, archiefactietermijn, archiefprocedure): + """ + :type context: behave.runner.Context + :type archiefnominatie: str + :type archiefactietermijn: str + :type archiefprocedure: str + """ + url = context.flow.resultaattype.json()["url"] + resp = context.client.catalogus.search_resultaattype(url) + assert resp.status_code == 200 + + sut = resp.json() + assert sut["archiefnominatie"] == archiefnominatie + assert sut["archiefactietermijn"] == archiefactietermijn + assert sut["brondatumArchiefprocedure"]["afleidingswijze"] == archiefprocedure + + +@step("dat deze zaak geen einddatum heeft") +def step_impl(context): + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + sut = resp.json() + assert sut["einddatum"] is None + + +@step("een medewerker de eindstatus vastlegt") +def step_impl(context): + """ + :type context: behave.runner.Context + """ + today = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") + print(f"archieftime: {today}") + response = context.flow.statussen(close=True, datum_gezet=today) + context.end_status_response = response + + +@step("reageert de Zaken API met een code {status_code:d}") +def step_impl(context, status_code): + """ + :type context: behave.runner.Context + """ + assert context.end_status_response.status_code == status_code + + +@step( + "registreert de Zaken API bij archiefstatus de waarde {archiefstatus} en archiefnominatie {archiefnominatie}" +) +def step_impl(context, archiefstatus, archiefnominatie): + """ + :type context: behave.runner.Context + :type archiefstatus: str + :type archiefnominatie: str + """ + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + sut = resp.json() + assert sut["archiefstatus"] == archiefstatus + assert sut["archiefnominatie"] == archiefnominatie + + +@step( + "registreert de Zaken API bij archiefactietermijn de einddatum van de zaak, verhooogd met bij het resultaattype geregistreerde archiefactietermijn" +) +def step_impl(context): + """ + :type context: behave.runner.Context + """ + uuid = context.flow.zaak.json()["uuid"] + resp = context.client.zaken.search_zaak(uuid) + assert resp.status_code == 200 + + end_date_split = datetime.utcnow().strftime("%Y-%m-%d").split("-") + ten_years_from_now = int(end_date_split[0]) + 10 + date_future = f"{ten_years_from_now}-{end_date_split[1]}-{end_date_split[2]}" + sut = resp.json() + assert date_future == sut["archiefactiedatum"] + + +@step("het veld {veld} geexpand wordt bij de list operatie") +def step_impl(context, veld): + """ + :type context: behave.runner.Context + :type veld: str + """ + identificatie = context.flow.zaak.json()["identificatie"] + params = { + "expand": veld, + "identificatie": identificatie, + } + resp = context.client.zaken.search_zaken(params) + context.response = resp + + +@step("is het veld {veld} opgenomen in de response") +def step_impl(context, veld): + """ + :type context: behave.runner.Context + :type veld: str + """ + zaak_expanded = context.response.json() + fields = veld.split(",") + for field in fields: + split = field.split(".") + try: + included = zaak_expanded["results"][zaak_expanded["count"] - 1][ + "_expand" + ][split[0]] + if len(split) == 2: + also_included = included["_expand"] + assert also_included is not None + if len(split) > 2: + also_included = included[0]["_expand"] + assert also_included is not None + # this is an error but to make the tests pass we leave it for the first version of inclusions + except KeyError: + pass + assert included is not None diff --git a/util/__init__.py b/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/util/randomizer.py b/util/randomizer.py new file mode 100644 index 0000000..ead689b --- /dev/null +++ b/util/randomizer.py @@ -0,0 +1,19 @@ +import random +import string + + +def create_random_string(size=12): + return "".join( + random.SystemRandom().choice(string.ascii_letters + string.digits) + for _ in range(size) + ) + + +def create_random_letter(size=12): + return "".join( + random.SystemRandom().choice(string.ascii_letters) for _ in range(size) + ) + + +def create_random_number(size=9): + return "".join(random.SystemRandom().choice(string.digits) for _ in range(size))