diff --git a/testsuite/openshift/__init__.py b/testsuite/openshift/__init__.py index 66a210f3..f079a90d 100644 --- a/testsuite/openshift/__init__.py +++ b/testsuite/openshift/__init__.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from typing import Optional, Literal -from openshift_client import APIObject, timeout +from openshift_client import APIObject, timeout, OpenShiftPythonException from testsuite.lifecycle import LifecycleObject @@ -32,6 +32,17 @@ def delete(self, ignore_not_found=True, cmd_args=None): self.committed = False return deleted + def wait_until(self, test_function, timelimit=90): + """Waits until the test function succeeds for this object""" + try: + with timeout(timelimit): + success, _, _ = self.self_selector().until_all( + success_func=lambda obj: test_function(self.__class__(obj.model)) + ) + return success + except OpenShiftPythonException: + return False + def modify(func): """Wraps method of a subclass of OpenShiftObject to use modify_and_apply when the object diff --git a/testsuite/tests/mgc/reconciliation/__init__.py b/testsuite/tests/mgc/reconciliation/__init__.py new file mode 100644 index 00000000..57516944 --- /dev/null +++ b/testsuite/tests/mgc/reconciliation/__init__.py @@ -0,0 +1,8 @@ +"""Module containing tests for Reconciliation of MGC policies""" + +from testsuite.policy.dns_policy import DNSPolicy + + +def dns_policy(openshift, name, parent, issuer, labels: dict[str, str] = None): # pylint: disable=unused-argument + """DNSPolicy constructor that ignores issues""" + return DNSPolicy.create_instance(openshift, name, parent, labels=labels) diff --git a/testsuite/tests/mgc/reconciliation/test_gw_doesnt_exist.py b/testsuite/tests/mgc/reconciliation/test_gw_doesnt_exist.py new file mode 100644 index 00000000..5c025e37 --- /dev/null +++ b/testsuite/tests/mgc/reconciliation/test_gw_doesnt_exist.py @@ -0,0 +1,40 @@ +"""Tests that DNSPolicy/TLSPolicy is rejected if the Gateway does not exist at all""" + +import pytest + +from testsuite.gateway import CustomReference +from testsuite.policy.tls_policy import TLSPolicy +from testsuite.tests.mgc.reconciliation import dns_policy + +pytestmark = [pytest.mark.mgc] + + +@pytest.mark.parametrize( + "create_cr", [pytest.param(dns_policy, id="DNSPolicy"), pytest.param(TLSPolicy.create_instance, id="TLSPolicy")] +) +@pytest.mark.issue("https://github.com/Kuadrant/multicluster-gateway-controller/issues/361") +def test_no_gw(request, create_cr, hub_openshift, blame, module_label, cluster_issuer): + """Tests that policy is rejected if the Gateway does not exist at all""" + + def target_not_found(policy): + for condition in policy.model.status.conditions: + if ( + condition.type == "Ready" + and condition.status == "False" + and 'Gateway.gateway.networking.k8s.io "does-not-exist" not found' in condition.message + and condition.reason == "TargetNotFound" + ): + return True + return False + + policy = create_cr( + hub_openshift, + blame("resource"), + CustomReference(group="gateway.networking.k8s.io", kind="Gateway", name="does-not-exist"), + cluster_issuer, + labels={"app": module_label}, + ) + request.addfinalizer(policy.delete) + policy.commit() + + assert policy.wait_until(target_not_found), "Policy did not reach expected status" diff --git a/testsuite/tests/mgc/reconciliation/test_invalid_issuer_reference.py b/testsuite/tests/mgc/reconciliation/test_invalid_issuer_reference.py new file mode 100644 index 00000000..36923338 --- /dev/null +++ b/testsuite/tests/mgc/reconciliation/test_invalid_issuer_reference.py @@ -0,0 +1,75 @@ +"""Tests that TLSPolicy is rejected if the issuer is invalid""" + +import pytest +from openshift_client import selector + +from testsuite.gateway import CustomReference +from testsuite.policy.tls_policy import TLSPolicy + +pytestmark = [pytest.mark.mgc] + + +@pytest.fixture(scope="module") +def base_domain(hub_openshift): + """Returns preconfigured base domain""" + zone = selector("managedzone/aws-mz", static_context=hub_openshift.context).object() + return zone.model["spec"]["domainName"] + + +def test_wrong_issuer_type(request, hub_gateway, hub_openshift, blame, module_label): + """Tests that TLSPolicy is rejected if issuer does not have a correct type""" + + def wrong_issuer_type(policy): + for condition in policy.model.status.conditions: + if ( + condition.type == "Ready" + and condition.status == "False" + and 'invalid value "Gateway" for issuerRef.kind. Must be empty, "Issuer" or "ClusterIssuer"' + in condition.message + and condition.reason == "ReconciliationError" + ): + return True + return False + + policy = TLSPolicy.create_instance( + hub_openshift, + blame("resource"), + hub_gateway, + hub_gateway, + labels={"app": module_label}, + ) + request.addfinalizer(policy.delete) + policy.commit() + + assert policy.wait_until(wrong_issuer_type), "Policy did not reach expected status" + + +def test_non_existing_issuer(request, hub_gateway, hub_openshift, blame, module_label): + """Tests that TLSPolicy is rejected if issuer does not exist""" + + def wrong_issuer(policy): + for condition in policy.model.status.conditions: + if ( + condition.type == "Ready" + and condition.status == "False" + and 'ClusterIssuer.cert-manager.io "does-not-exist" not found' in condition.message + and condition.reason == "ReconciliationError" + ): + return True + return False + + policy = TLSPolicy.create_instance( + hub_openshift, + blame("resource"), + hub_gateway, + CustomReference( + group="cert-manager.io", + kind="ClusterIssuer", + name="does-not-exist", + ), + labels={"app": module_label}, + ) + request.addfinalizer(policy.delete) + policy.commit() + + assert policy.wait_until(wrong_issuer), "Policy did not reach expected status" diff --git a/testsuite/tests/mgc/reconciliation/test_same_target.py b/testsuite/tests/mgc/reconciliation/test_same_target.py new file mode 100644 index 00000000..37ab5f88 --- /dev/null +++ b/testsuite/tests/mgc/reconciliation/test_same_target.py @@ -0,0 +1,55 @@ +"""Tests that DNSPolicy/TLSPolicy is rejected when the Gateway already has a policy of the same kind""" + +import pytest +from openshift_client import selector + +from testsuite.policy.tls_policy import TLSPolicy +from testsuite.tests.mgc.reconciliation import dns_policy + +pytestmark = [pytest.mark.mgc] + + +@pytest.fixture(scope="module") +def base_domain(hub_openshift): + """Returns preconfigured base domain""" + zone = selector("managedzone/aws-mz", static_context=hub_openshift.context).object() + return zone.model["spec"]["domainName"] + + +@pytest.mark.parametrize( + "create_cr", [pytest.param(dns_policy, id="DNSPolicy"), pytest.param(TLSPolicy.create_instance, id="TLSPolicy")] +) +def test_two_policies_one_gw(request, create_cr, hub_gateway, client, blame, module_label, cluster_issuer): + """Tests that policy is rejected when the Gateway already has a DNSPolicy""" + + def two_dns_policies_error(policy): + for condition in policy.model.status.conditions: + if ( + condition.type == "Ready" + and condition.status == "False" + and condition.reason == "ReconciliationError" + and "is already referenced by policy" in condition.message + ): + return True + return False + + # test that it works before the policy + response = client.get("get") + assert response.status_code == 200, "Original DNSPolicy does not work" + + policy = create_cr( + hub_gateway.openshift, + blame("dns2"), + hub_gateway, + cluster_issuer, + labels={"app": module_label}, + ) + request.addfinalizer(policy.delete) + policy.commit() + + # Wait for expected status + assert policy.wait_until(two_dns_policies_error), "Policy did not reach expected status" + + # Test that the original policy still works + response = client.get("get") + assert response.status_code == 200