From 4273d4f1478181729c32e3c9dbd336d435cca789 Mon Sep 17 00:00:00 2001 From: Anna Shamray Date: Fri, 8 Mar 2024 18:02:36 +0100 Subject: [PATCH] :white_check_mark: [https://github.com/maykinmedia/django-setup-configuration/issues/1] test configuration steps --- src/objects/tests/commands/__init__.py | 0 .../commands/test_setup_configuration.py | 117 ++++++++++++++++++ src/objects/tests/config/__init__.py | 0 .../tests/config/test_demo_configuration.py | 73 +++++++++++ .../config/test_objecttypes_configuration.py | 82 ++++++++++++ .../tests/config/test_site_configuration.py | 66 ++++++++++ 6 files changed, 338 insertions(+) create mode 100644 src/objects/tests/commands/__init__.py create mode 100644 src/objects/tests/commands/test_setup_configuration.py create mode 100644 src/objects/tests/config/__init__.py create mode 100644 src/objects/tests/config/test_demo_configuration.py create mode 100644 src/objects/tests/config/test_objecttypes_configuration.py create mode 100644 src/objects/tests/config/test_site_configuration.py diff --git a/src/objects/tests/commands/__init__.py b/src/objects/tests/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/objects/tests/commands/test_setup_configuration.py b/src/objects/tests/commands/test_setup_configuration.py new file mode 100644 index 00000000..5a0d06e6 --- /dev/null +++ b/src/objects/tests/commands/test_setup_configuration.py @@ -0,0 +1,117 @@ +from io import StringIO + +from django.contrib.sites.models import Site +from django.core.management import CommandError, call_command +from django.test import TestCase, override_settings +from django.urls import reverse + +import requests_mock +from rest_framework import status +from zgw_consumers.models import Service + +from objects.config.demo import DemoUserStep +from objects.config.objecttypes import ObjecttypesStep +from objects.config.site import SiteConfigurationStep + +from ..utils import mock_service_oas_get + + +@override_settings( + OBJECTS_DOMAIN="objects.example.com", + OBJECTS_ORGANIZATION="ACME", + OBJECTTYPES_API_ROOT="https://objecttypes.example.com/api/v2/", + OBJECTTYPES_API_OAS="https://objecttypes.example.com/api/v2/schema/openapi.yaml", + OBJECTS_OBJECTTYPES_TOKEN="some-random-string", + DEMO_CONFIG_ENABLE=True, + DEMO_TOKEN="demo-random-string", + DEMO_PERSON="Demo", + DEMO_EMAIL="demo@demo.local", +) +class SetupConfigurationTests(TestCase): + def setUp(self): + super().setUp() + + self.addCleanup(Site.objects.clear_cache) + + @requests_mock.Mocker() + def test_setup_configuration(self, m): + stdout = StringIO() + # mocks + m.get("http://objects.example.com/", status_code=200) + m.get("http://objects.example.com/api/v2/objects", json=[]) + mock_service_oas_get( + m, "https://objecttypes.example.com/api/v2/", "objecttypes" + ) + m.get("https://objecttypes.example.com/api/v2/objecttypes", json={}) + + call_command("setup_configuration", stdout=stdout) + + with self.subTest("Command output"): + command_output = stdout.getvalue().splitlines() + expected_output = [ + f"Configuration will be set up with following steps: [{SiteConfigurationStep()}, " + f"{ObjecttypesStep()}, {DemoUserStep()}]", + f"Configuring {SiteConfigurationStep()}...", + f"{SiteConfigurationStep()} is successfully configured", + f"Configuring {ObjecttypesStep()}...", + f"{ObjecttypesStep()} is successfully configured", + f"Configuring {DemoUserStep()}...", + f"{DemoUserStep()} is successfully configured", + "Instance configuration completed.", + ] + + self.assertEqual(command_output, expected_output) + + with self.subTest("Site configured correctly"): + site = Site.objects.get_current() + self.assertEqual(site.domain, "objects.example.com") + self.assertEqual(site.name, "Objects ACME") + + with self.subTest("Objects can query Objecttypes API"): + client = Service.get_client("https://objecttypes.example.com/api/v2/") + self.assertIsNotNone(client) + + client.list("objecttype") + + list_call = m.last_request + self.assertEqual( + list_call.url, "https://objecttypes.example.com/api/v2/objecttypes" + ) + self.assertIn("Authorization", list_call.headers) + self.assertEqual( + list_call.headers["Authorization"], "Token some-random-string" + ) + + with self.subTest("Demo user configured correctly"): + response = self.client.get( + reverse("v2:object-list"), + HTTP_AUTHORIZATION="Token demo-random-string", + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + @requests_mock.Mocker() + def test_setup_configuration_selftest_fails(self, m): + m.get("http://objects.example.com/", status_code=500) + m.get("http://objects.example.com/api/v2/objects", status_code=200) + mock_service_oas_get( + m, "https://objecttypes.example.com/api/v2/", "objecttypes" + ) + m.get("https://objecttypes.example.com/api/v2/objecttypes", json={}) + + with self.assertRaisesMessage( + CommandError, + "Configuration test failed with errors: " + "Site Configuration: Could not access home page at 'http://objects.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) diff --git a/src/objects/tests/config/__init__.py b/src/objects/tests/config/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/objects/tests/config/test_demo_configuration.py b/src/objects/tests/config/test_demo_configuration.py new file mode 100644 index 00000000..5d9a2cce --- /dev/null +++ b/src/objects/tests/config/test_demo_configuration.py @@ -0,0 +1,73 @@ +from unittest.mock import patch + +from django.test import TestCase, override_settings + +import requests +import requests_mock +from django_setup_configuration.exceptions import SelfTestFailed + +from objects.config.demo import DemoUserStep +from objects.token.models import TokenAuth + + +@override_settings( + DEMO_TOKEN="demo-random-string", DEMO_PERSON="Demo", DEMO_EMAIL="demo@demo.local" +) +class DemoConfigurationTests(TestCase): + def test_configure(self): + configuration = DemoUserStep() + + configuration.configure() + + token_auth = TokenAuth.objects.get() + self.assertEqual(token_auth.token, "demo-random-string") + self.assertTrue(token_auth.is_superuser) + self.assertEqual(token_auth.contact_person, "Demo") + self.assertEqual(token_auth.email, "demo@demo.local") + + @requests_mock.Mocker() + @patch( + "objects.config.demo.build_absolute_url", + return_value="http://testserver/objects", + ) + def test_configuration_check_ok(self, m, *mocks): + configuration = DemoUserStep() + configuration.configure() + m.get("http://testserver/objects", json=[]) + + configuration.test_configuration() + + self.assertEqual(m.last_request.url, "http://testserver/objects") + self.assertEqual(m.last_request.method, "GET") + + @requests_mock.Mocker() + @patch( + "objects.config.demo.build_absolute_url", + return_value="http://testserver/objects", + ) + def test_configuration_check_failures(self, m, *mocks): + configuration = DemoUserStep() + 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/objects", **mock_config) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() + + def test_is_configured(self): + configuration = DemoUserStep() + + self.assertFalse(configuration.is_configured()) + + configuration.configure() + + self.assertTrue(configuration.is_configured()) diff --git a/src/objects/tests/config/test_objecttypes_configuration.py b/src/objects/tests/config/test_objecttypes_configuration.py new file mode 100644 index 00000000..95fee463 --- /dev/null +++ b/src/objects/tests/config/test_objecttypes_configuration.py @@ -0,0 +1,82 @@ +from unittest.mock import patch + +from django.test import TestCase, override_settings + +import requests +import requests_mock +from django_setup_configuration.exceptions import SelfTestFailed +from zgw_consumers.constants import AuthTypes +from zgw_consumers.models import Service + +from objects.config.objecttypes import ObjecttypesStep + +from ..utils import mock_service_oas_get + + +@override_settings( + OBJECTTYPES_API_ROOT="https://objecttypes.example.com/api/v2/", + OBJECTTYPES_API_OAS="https://objecttypes.example.com/api/v2/schema/openapi.yaml", + OBJECTS_OBJECTTYPES_TOKEN="some-random-string", +) +class ObjecttypesConfigurationTests(TestCase): + def test_configure(self): + configuration = ObjecttypesStep() + + configuration.configure() + + service = Service.objects.get( + api_root="https://objecttypes.example.com/api/v2/" + ) + self.assertEqual( + service.oas, "https://objecttypes.example.com/api/v2/schema/openapi.yaml" + ) + self.assertEqual(service.auth_type, AuthTypes.api_key) + self.assertEqual(service.header_key, "Authorization") + self.assertEqual(service.header_value, "Token some-random-string") + + @requests_mock.Mocker() + def test_selftest_ok(self, m): + configuration = ObjecttypesStep() + configuration.configure() + mock_service_oas_get( + m, "https://objecttypes.example.com/api/v2/", "objecttypes" + ) + m.get("https://objecttypes.example.com/api/v2/objecttypes", json={}) + + configuration.test_configuration() + + self.assertEqual( + m.last_request.url, "https://objecttypes.example.com/api/v2/objecttypes" + ) + + @requests_mock.Mocker() + def test_selftest_fail(self, m): + configuration = ObjecttypesStep() + configuration.configure() + mock_service_oas_get( + m, "https://objecttypes.example.com/api/v2/", "objecttypes" + ) + + 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( + "https://objecttypes.example.com/api/v2/objecttypes", **mock_config + ) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() + + def test_is_configured(self): + configuration = ObjecttypesStep() + self.assertFalse(configuration.is_configured()) + + configuration.configure() + + self.assertTrue(configuration.is_configured()) diff --git a/src/objects/tests/config/test_site_configuration.py b/src/objects/tests/config/test_site_configuration.py new file mode 100644 index 00000000..b6e47ecd --- /dev/null +++ b/src/objects/tests/config/test_site_configuration.py @@ -0,0 +1,66 @@ +from django.contrib.sites.models import Site +from django.test import TestCase, override_settings + +import requests +import requests_mock +from django_setup_configuration.exceptions import SelfTestFailed + +from objects.config.site import SiteConfigurationStep + + +@override_settings( + OBJECTS_DOMAIN="localhost:8000", + OBJECTS_ORGANIZATION="ACME", +) +class SiteConfigurationTests(TestCase): + def setUp(self): + super().setUp() + + self.addCleanup(Site.objects.clear_cache) + + def test_set_domain(self): + configuration = SiteConfigurationStep() + configuration.configure() + + site = Site.objects.get_current() + self.assertEqual(site.domain, "localhost:8000") + self.assertEqual(site.name, "Objects ACME") + + @requests_mock.Mocker() + def test_configuration_check_ok(self, m): + m.get("http://localhost:8000/", status_code=200) + configuration = SiteConfigurationStep() + configuration.configure() + + configuration.test_configuration() + + self.assertEqual(m.last_request.url, "http://localhost:8000/") + self.assertEqual(m.last_request.method, "GET") + + @requests_mock.Mocker() + def test_configuration_check_failures(self, m): + configuration = SiteConfigurationStep() + 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://localhost:8000/", **mock_config) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() + + def test_is_configured(self): + configuration = SiteConfigurationStep() + + self.assertFalse(configuration.is_configured()) + + configuration.configure() + + self.assertTrue(configuration.is_configured())