Skip to content

Commit

Permalink
✅ [#200] Add/fix tests for setup config steps
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenbal committed Dec 6, 2024
1 parent f48ba98 commit 1f6fc00
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 242 deletions.
37 changes: 37 additions & 0 deletions src/nrc/tests/commands/files/setup_config_full.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
zgw_consumers_config_enable: True
zgw_consumers:
services:
- identifier: autorisaties-api
label: Objecttypen API test
api_root: http://localhost:8001/autorisaties/api/v1/
api_type: ac
auth_type: zgw
client_id: open-notificaties
secret: oPMsHCEuoP9Qh8vP06D7
user_id: open-notificaties
user_representation: Open Notificaties Demodam

autorisaties_api_config_enable: True
autorisaties_api:
# Configure Open Notificaties to make use of Open Zaak's Autorisaties API
authorizations_api_service_identifier: autorisaties-api

vng_api_common_credentials_config_enable: True
vng_api_common_credentials:
items:
# Credentials for Open Zaak to be able to make requests to Open Notificaties
- identifier: open-zaak
secret: G2LIVfXal1J93puQkV3O

notifications_config_enable: True
notifications_config:
# No notifications_api_service necessary, because Open Notificaties doesn't send
# notifications to itself
notification_delivery_max_retries: 5
notification_delivery_retry_backoff: 3
notification_delivery_retry_backoff_max: 30

site_config_enable: True
site_config:
domain: opennotificaties.local:8000
organization: Demodam
109 changes: 48 additions & 61 deletions src/nrc/tests/commands/test_setup_configuration.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
import uuid
from io import StringIO
from pathlib import Path

from django.contrib.sites.models import Site
from django.core.management import CommandError, call_command
from django.test import TestCase, override_settings
from django.core.management import call_command
from django.test import TestCase
from django.urls import reverse

import requests
import requests_mock
from jwt import decode
from notifications_api_common.contrib.setup_configuration.steps import (
NotificationConfigurationStep,
)
from notifications_api_common.models import NotificationsConfig
from rest_framework import status
from vng_api_common.authorizations.models import AuthorizationsConfig
from vng_api_common.authorizations.utils import generate_jwt
from vng_api_common.contrib.setup_configuration.steps import JWTSecretsConfigurationStep
from zgw_consumers.contrib.setup_configuration.steps import ServiceConfigurationStep

from nrc.config.authorization import AuthorizationStep, OpenZaakAuthStep
from nrc.config.notification_retry import NotificationRetryConfigurationStep
from nrc.config.authorization import AuthorizationStep
from nrc.config.site import SiteConfigurationStep

CONFIG_FILE_PATH = Path("src/nrc/tests/commands/files/setup_config_full.yaml").resolve()


@override_settings(
SITES_CONFIG_ENABLE=True,
OPENNOTIFICATIES_DOMAIN="open-notificaties.example.com",
OPENNOTIFICATIES_ORGANIZATION="ACME",
AUTHORIZATION_CONFIG_ENABLE=True,
AUTORISATIES_API_ROOT="https://oz.example.com/autorisaties/api/v1/",
NOTIF_OPENZAAK_CLIENT_ID="notif-client-id",
NOTIF_OPENZAAK_SECRET="notif-secret",
OPENZAAK_NOTIF_CONFIG_ENABLE=True,
OPENZAAK_NOTIF_CLIENT_ID="oz-client-id",
OPENZAAK_NOTIF_SECRET="oz-secret",
NOTIFICATION_RETRY_CONFIG_ENABLE=True,
)
class SetupConfigurationTests(TestCase):
maxDiff = None

Expand All @@ -44,15 +38,15 @@ def test_setup_configuration(self, m):
stdout = StringIO()
# mocks
_uuid = uuid.uuid4()
m.get("http://open-notificaties.example.com/", status_code=200)
m.get("http://open-notificaties.example.com/api/v1/kanaal", json=[])
m.get("http://opennotificaties.local:8000/", status_code=200)
m.get("http://opennotificaties.local:8000/api/v1/kanaal", json=[])
m.get(
"https://oz.example.com/autorisaties/api/v1/applicaties",
"http://localhost:8001/autorisaties/api/v1/applicaties",
json={
"count": 1,
"results": [
{
"url": f"https://oz.example.com/autorisaties/api/v1/applicaties/{_uuid}",
"url": f"http://localhost:8001/autorisaties/api/v1/applicaties/{_uuid}",
"clientIds": ["oz-client-id"],
"label": "OZ for ON",
"heeftAlleAutorisaties": True,
Expand All @@ -62,31 +56,34 @@ def test_setup_configuration(self, m):
},
)

call_command("setup_configuration", stdout=stdout, no_color=True)
call_command(
"setup_configuration",
yaml_file=CONFIG_FILE_PATH,
stdout=stdout,
no_color=True,
)

with self.subTest("Command output"):
command_output = stdout.getvalue().splitlines()
expected_output = [
f"Configuration will be set up with following steps: [{SiteConfigurationStep()}, "
f"{AuthorizationStep()}, {OpenZaakAuthStep()}, {NotificationRetryConfigurationStep()}]",
f"Configuring {SiteConfigurationStep()}...",
f"{SiteConfigurationStep()} is successfully configured",
f"Configuring {AuthorizationStep()}...",
f"{AuthorizationStep()} is successfully configured",
f"Configuring {OpenZaakAuthStep()}...",
f"{OpenZaakAuthStep()} is successfully configured",
f"Configuring {NotificationRetryConfigurationStep()}...",
f"{NotificationRetryConfigurationStep()} is successfully configured",
f"Loading config settings from {CONFIG_FILE_PATH}",
"The following steps are configured:",
f"{ServiceConfigurationStep()}",
f"{JWTSecretsConfigurationStep()}",
f"{AuthorizationStep()}",
f"{NotificationConfigurationStep()}",
f"{SiteConfigurationStep()}",
"Executing steps...",
f"Successfully executed step: {ServiceConfigurationStep()}",
f"Successfully executed step: {JWTSecretsConfigurationStep()}",
f"Successfully executed step: {AuthorizationStep()}",
f"Successfully executed step: {NotificationConfigurationStep()}",
f"Successfully executed step: {SiteConfigurationStep()}",
"Instance configuration completed.",
]

self.assertEqual(command_output, expected_output)

with self.subTest("Site configured correctly"):
site = Site.objects.get_current()
self.assertEqual(site.domain, "open-notificaties.example.com")
self.assertEqual(site.name, "Open Notificaties ACME")

with self.subTest("Authorization API client configured correctly"):
ac_client = AuthorizationsConfig.get_client()
self.assertIsNotNone(ac_client)
Expand All @@ -96,17 +93,17 @@ def test_setup_configuration(self, m):
create_call = m.last_request
self.assertEqual(
create_call.url,
"https://oz.example.com/autorisaties/api/v1/applicaties",
"http://localhost:8001/autorisaties/api/v1/applicaties",
)
self.assertIn("Authorization", create_call.headers)

header_jwt = create_call.headers["Authorization"].split(" ")[1]
decoded_jwt = decode(header_jwt, options={"verify_signature": False})

self.assertEqual(decoded_jwt["client_id"], "notif-client-id")
self.assertEqual(decoded_jwt["client_id"], "open-notificaties")

with self.subTest("Open Zaak can query Notification API"):
token = generate_jwt("oz-client-id", "oz-secret", "", "")
token = generate_jwt("open-zaak", "G2LIVfXal1J93puQkV3O", "", "")

response = self.client.get(
reverse("kanaal-list", kwargs={"version": 1}),
Expand All @@ -115,24 +112,14 @@ def test_setup_configuration(self, m):

self.assertEqual(response.status_code, status.HTTP_200_OK)

@requests_mock.Mocker()
def test_setup_configuration_selftest_fails(self, m):
m.get("http://open-notificaties.example.com/", exc=requests.ConnectionError)
m.get("http://open-notificaties.example.com/api/v1/kanaal", json=[])
m.get("https://oz.example.com/autorisaties/api/v1/applicaties", json=[])
with self.subTest("Notifications configured correctly"):
config = NotificationsConfig.get_solo()
self.assertEqual(config.notifications_api_service, None)
self.assertEqual(config.notification_delivery_max_retries, 5)
self.assertEqual(config.notification_delivery_retry_backoff, 3)
self.assertEqual(config.notification_delivery_retry_backoff_max, 30)

with self.assertRaisesMessage(
CommandError,
"Could not access home page at 'http://open-notificaties.example.com/'",
):
call_command("setup_configuration")

@requests_mock.Mocker()
def test_setup_configuration_without_selftest(self, m):
stdout = StringIO()

call_command("setup_configuration", no_selftest=True, stdout=stdout)
command_output = stdout.getvalue()

self.assertEqual(len(m.request_history), 0)
self.assertTrue("Selftest is skipped" in command_output)
with self.subTest("Site configured correctly"):
site = Site.objects.get_current()
self.assertEqual(site.domain, "opennotificaties.local:8000")
self.assertEqual(site.name, "Open Notificaties Demodam")
3 changes: 3 additions & 0 deletions src/nrc/tests/config/files/setup_config_auth_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
autorisaties_api_config_enable: True
autorisaties_api:
authorizations_api_service_identifier: autorisaties-api
4 changes: 4 additions & 0 deletions src/nrc/tests/config/files/setup_config_sites.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
site_config_enable: True
site_config:
domain: opennotificaties.local:8000
organization: Demodam
145 changes: 37 additions & 108 deletions src/nrc/tests/config/test_authorization_configuration.py
Original file line number Diff line number Diff line change
@@ -1,129 +1,58 @@
from unittest.mock import patch
from django.test import TestCase

from django.test import TestCase, override_settings

import requests
import requests_mock
from django_setup_configuration.exceptions import SelfTestFailed
from django_setup_configuration.test_utils import execute_single_step
from vng_api_common.authorizations.models import AuthorizationsConfig, ComponentTypes
from vng_api_common.models import JWTSecret

from nrc.config.authorization import AuthorizationStep, OpenZaakAuthStep
from zgw_consumers.test.factories import ServiceFactory

from nrc.config.authorization import AuthorizationStep

@override_settings(
AUTORISATIES_API_ROOT="https://oz.example.com/autorisaties/api/v1/",
NOTIF_OPENZAAK_CLIENT_ID="notif-client-id",
NOTIF_OPENZAAK_SECRET="notif-secret",
)
class AuthorizationConfigurationTests(TestCase):
def test_configure(self):
configuration = AuthorizationStep()
CONFIG_FILE_PATH = "src/nrc/tests/config/files/setup_config_auth_config.yaml"

configuration.configure()

config = AuthorizationsConfig.get_solo()
service = config.authorizations_api_service
class AuthorizationConfigurationTests(TestCase):
@classmethod
def setUpTestData(cls):
super().setUpTestData()

self.assertEqual(config.component, ComponentTypes.nrc)
self.assertEqual(
service.api_root, "https://oz.example.com/autorisaties/api/v1/"
cls.service = ServiceFactory.create(
slug="autorisaties-api",
api_root="http://openzaak.local/autorisaties/api/v1/",
)

self.assertEqual(service.client_id, "notif-client-id")
self.assertEqual(service.secret, "notif-secret")
def test_execute_configuration_step_success(self):
execute_single_step(AuthorizationStep, yaml_source=CONFIG_FILE_PATH)

@requests_mock.Mocker()
def test_selftest_ok(self, m):
configuration = AuthorizationStep()
configuration.configure()

m.get("https://oz.example.com/autorisaties/api/v1/applicaties", json=[])
config = AuthorizationsConfig.get_solo()

configuration.test_configuration()
self.assertEqual(config.component, ComponentTypes.nrc)
self.assertEqual(config.authorizations_api_service, self.service)

self.assertEqual(
m.last_request.url, "https://oz.example.com/autorisaties/api/v1/applicaties"
)
def test_execute_configuration_step_update_existing(self):
config = AuthorizationsConfig.get_solo()
config.component = ComponentTypes.zrc
config.authorizations_api_service = ServiceFactory.create(slug="other-api")
config.save()

@requests_mock.Mocker()
def test_selftest_fail(self, m):
configuration = AuthorizationStep()
configuration.configure()
execute_single_step(AuthorizationStep, yaml_source=CONFIG_FILE_PATH)

m.get("https://oz.example.com/autorisaties/api/v1/applicaties", status_code=403)
config = AuthorizationsConfig.get_solo()
service = config.authorizations_api_service

with self.assertRaises(SelfTestFailed):
configuration.test_configuration()
self.assertEqual(config.component, ComponentTypes.nrc)
self.assertEqual(service, self.service)

self.assertEqual(
m.last_request.url, "https://oz.example.com/autorisaties/api/v1/applicaties"
)
def test_execute_configuration_step_idempotent(self):
def make_assertions():
config = AuthorizationsConfig.get_solo()
service = config.authorizations_api_service

def test_is_configured(self):
configuration = AuthorizationStep()
self.assertFalse(configuration.is_configured())

configuration.configure()

self.assertTrue(configuration.is_configured())


@override_settings(
OPENZAAK_NOTIF_CLIENT_ID="oz-client-id",
OPENZAAK_NOTIF_SECRET="oz-secret",
)
class OpenZaakConfigurationTests(TestCase):
def test_configure(self):
configuration = OpenZaakAuthStep()

configuration.configure()

jwt_secret = JWTSecret.objects.get(identifier="oz-client-id")
self.assertEqual(jwt_secret.secret, "oz-secret")

@requests_mock.Mocker()
@patch(
"nrc.config.authorization.build_absolute_url",
return_value="http://testserver/kanaal",
)
def test_selftest_ok(self, m, *mocks):
configuration = OpenZaakAuthStep()
configuration.configure()
m.get("http://testserver/kanaal", json=[])

configuration.test_configuration()

self.assertEqual(m.last_request.url, "http://testserver/kanaal")
self.assertEqual(m.last_request.method, "GET")

@requests_mock.Mocker()
@patch(
"nrc.config.authorization.build_absolute_url",
return_value="http://testserver/kanaal",
)
def test_selftest_fail(self, m, *mocks):
configuration = OpenZaakAuthStep()
configuration.configure()

mock_kwargs = (
{"exc": requests.ConnectTimeout},
{"exc": requests.ConnectionError},
{"status_code": 404},
{"status_code": 403},
{"status_code": 500},
)
for mock_config in mock_kwargs:
with self.subTest(mock=mock_config):
m.get("http://testserver/kanaal", **mock_config)
self.assertEqual(config.component, ComponentTypes.nrc)
self.assertEqual(service, self.service)

with self.assertRaises(SelfTestFailed):
configuration.test_configuration()
execute_single_step(AuthorizationStep, yaml_source=CONFIG_FILE_PATH)

def test_is_configured(self):
configuration = OpenZaakAuthStep()
self.assertFalse(configuration.is_configured())
make_assertions()

configuration.configure()
execute_single_step(AuthorizationStep, yaml_source=CONFIG_FILE_PATH)

self.assertTrue(configuration.is_configured())
make_assertions()
Loading

0 comments on commit 1f6fc00

Please sign in to comment.