Skip to content

Commit

Permalink
Merge pull request Kuadrant#387 from pehala/affected_by
Browse files Browse the repository at this point in the history
Add affected by status tests
  • Loading branch information
pehala authored May 27, 2024
2 parents e07642c + 0ceeb26 commit f29c0eb
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 47 deletions.
15 changes: 15 additions & 0 deletions testsuite/gateway/gateway_api/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from testsuite.gateway import Gateway
from testsuite.openshift.client import OpenShiftClient
from testsuite.openshift import OpenShiftObject
from testsuite.policy import Policy
from testsuite.utils import check_condition


class KuadrantGateway(OpenShiftObject, Gateway):
Expand Down Expand Up @@ -81,6 +83,19 @@ def wait_for_ready(self, timeout: int = 10 * 60):
assert success, "Gateway didn't get ready in time"
self.refresh()

def is_affected_by(self, policy: Policy) -> bool:
"""Returns True, if affected by status is found within the object for the specific policy"""
for condition in self.model.status.conditions:
if check_condition(
condition,
f"kuadrant.io/{policy.kind(lowercase=False)}Affected",
"True",
"Accepted",
f"Object affected by {policy.kind(lowercase=False)} {policy.namespace()}/{policy.name()}",
):
return True
return False

def get_tls_cert(self):
if "tls" not in self.model.spec.listeners[0]:
return None
Expand Down
18 changes: 17 additions & 1 deletion testsuite/gateway/gateway_api/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from testsuite.gateway import Gateway, GatewayRoute, PathMatch, MatchType, RouteMatch
from testsuite.openshift.client import OpenShiftClient
from testsuite.openshift import OpenShiftObject, modify
from testsuite.utils import asdict
from testsuite.policy import Policy
from testsuite.utils import asdict, check_condition

if typing.TYPE_CHECKING:
from testsuite.backend import Backend
Expand Down Expand Up @@ -43,6 +44,21 @@ def create_instance(

return cls(model, context=openshift.context)

def is_affected_by(self, policy: Policy):
"""Returns True, if affected by status is found within the object for the specific policy"""
for condition_set in self.model.status.parents:
if condition_set.controllerName == "kuadrant.io/policy-controller":
for condition in condition_set.conditions:
if check_condition(
condition,
f"kuadrant.io/{policy.kind(lowercase=False)}Affected",
"True",
"Accepted",
f"Object affected by {policy.kind(lowercase=False)} {policy.namespace()}/{policy.name()}",
):
return True
return False

@property
def reference(self):
return {
Expand Down
19 changes: 19 additions & 0 deletions testsuite/policy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Contains Base class for policies"""

import openshift_client as oc

from testsuite.openshift import OpenShiftObject
from testsuite.utils import has_condition


class Policy(OpenShiftObject):
"""Base class with common functionality for all policies"""

def wait_for_ready(self):
"""Wait for a Policy to be Enforced"""
with oc.timeout(90):
success, _, _ = self.self_selector().until_all(
success_func=has_condition("Enforced", "True"),
tolerate_failures=5,
)
assert success, f"{self.kind()} did not get ready in time"
19 changes: 4 additions & 15 deletions testsuite/policy/authorization/auth_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

from typing import Dict, TYPE_CHECKING

import openshift_client as oc

from testsuite.utils import asdict, has_condition
from testsuite.gateway import Referencable
from testsuite.openshift.client import OpenShiftClient
from testsuite.openshift import modify
from testsuite.openshift.client import OpenShiftClient
from testsuite.utils import asdict
from .auth_config import AuthConfig
from .. import Policy

if TYPE_CHECKING:
from . import Rule


class AuthPolicy(AuthConfig):
class AuthPolicy(AuthConfig, Policy):
"""AuthPolicy object, it serves as Kuadrants AuthConfig"""

@property
Expand Down Expand Up @@ -47,13 +46,3 @@ def add_rule(self, when: list["Rule"]):
"""Add rule for the skip of entire AuthPolicy"""
self.model.spec.setdefault("when", [])
self.model.spec["when"].extend([asdict(x) for x in when])

def wait_for_ready(self):
"""Waits until AuthPolicy object reports ready status"""
with oc.timeout(90):
success, _, _ = self.self_selector().until_all(
success_func=has_condition("Enforced", "True"),
tolerate_failures=5,
)
assert success, f"{self.kind()} did not get ready in time"
self.refresh()
16 changes: 2 additions & 14 deletions testsuite/policy/dns_policy.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
"""Module for DNSPolicy related classes"""

import openshift_client as oc

from testsuite.gateway import Referencable
from testsuite.openshift import OpenShiftObject
from testsuite.openshift.client import OpenShiftClient
from testsuite.utils import has_condition
from testsuite.policy import Policy


class DNSPolicy(OpenShiftObject):
class DNSPolicy(Policy):
"""DNSPolicy object"""

@classmethod
Expand All @@ -29,12 +26,3 @@ def create_instance(
}

return cls(model, context=openshift.context)

def wait_for_ready(self):
"""Wait for DNSPolicy to be Enforced"""
with oc.timeout(90):
success, _, _ = self.self_selector().until_all(
success_func=has_condition("Enforced", "True"),
tolerate_failures=5,
)
assert success, f"{self.kind()} did not get ready in time"
13 changes: 7 additions & 6 deletions testsuite/policy/rate_limit_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
from dataclasses import dataclass
from typing import Iterable, Literal, Optional, List

import openshift_client as oc
from openshift_client import timeout

from testsuite.policy.authorization import Rule
from testsuite.utils import asdict, has_condition
from testsuite.gateway import Referencable, RouteMatch
from testsuite.openshift import modify
from testsuite.openshift.client import OpenShiftClient
from testsuite.openshift import OpenShiftObject, modify
from testsuite.policy import Policy
from testsuite.policy.authorization import Rule
from testsuite.utils import asdict, has_condition


@dataclass
Expand Down Expand Up @@ -39,7 +40,7 @@ def __init__(self, *matches: RouteMatch, hostnames: Optional[List[str]] = None):
self.hostnames = hostnames


class RateLimitPolicy(OpenShiftObject):
class RateLimitPolicy(Policy):
"""RateLimitPolicy (or RLP for short) object, used for applying rate limiting rules to a Gateway/HTTPRoute"""

@classmethod
Expand Down Expand Up @@ -80,7 +81,7 @@ def add_limit(

def wait_for_ready(self):
"""Wait for RLP to be enforced"""
with oc.timeout(90):
with timeout(90):
success, _, _ = self.self_selector().until_all(
success_func=has_condition("Enforced", "True"),
tolerate_failures=5,
Expand Down
4 changes: 2 additions & 2 deletions testsuite/policy/tls_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

from testsuite.gateway import Referencable
from testsuite.openshift.client import OpenShiftClient
from testsuite.openshift import OpenShiftObject
from testsuite.policy import Policy
from testsuite.utils import has_condition


class TLSPolicy(OpenShiftObject):
class TLSPolicy(Policy):
"""TLSPolicy object"""

@classmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Tests that affected by status is applied correctly to the HTTPRoute and Gateway"""

import pytest

pytestmark = [pytest.mark.kuadrant_only]


def test_route_status(route, rate_limit, authorization):
"""Tests affected by status for HTTPRoute"""
route.refresh()
assert route.is_affected_by(rate_limit)
assert route.is_affected_by(authorization)

rate_limit.delete()
assert not route.wait_until(lambda obj: obj.is_affected_by(rate_limit))

authorization.delete()
assert not route.wait_until(lambda obj: obj.is_affected_by(authorization))


def test_gateway_status(gateway, dns_policy, tls_policy):
"""Tests affected by status for Gateway"""
gateway.refresh()
assert gateway.is_affected_by(dns_policy)
assert gateway.is_affected_by(tls_policy)

dns_policy.delete()
assert not gateway.wait_until(lambda obj: obj.is_affected_by(dns_policy))

tls_policy.delete()
assert not gateway.wait_until(lambda obj: obj.is_affected_by(tls_policy))
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from testsuite.gateway import CustomReference
from testsuite.policy.tls_policy import TLSPolicy
from testsuite.utils import has_condition
from . import dns_policy

pytestmark = [pytest.mark.kuadrant_only]
Expand Down Expand Up @@ -33,6 +32,6 @@ def test_no_gw(request, create_cr, hub_openshift, blame, module_label, cluster_i
request.addfinalizer(policy.delete)
policy.commit()

assert policy.wait_until(
has_condition("Accepted", "False", "TargetNotFound", "target does-not-exist was not found"), timelimit=20
assert policy.wait_for_condition(
"Accepted", "False", "TargetNotFound", "target does-not-exist was not found", timelimit=20
), f"Policy did not reach expected status, instead it was: {policy.refresh().model.status.conditions}"
19 changes: 13 additions & 6 deletions testsuite/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,24 @@ def _asdict_recurse(obj):
return result


def check_condition(condition, condition_type, status, reason=None, message=None):
"""Checks if condition matches expectation, won't check message and reason if they are None"""
if ( # pylint: disable=too-many-boolean-expressions
condition.type == condition_type
and condition.status == status
and (message is None or message in condition.message)
and (reason is None or reason == condition.reason)
):
return True
return False


def has_condition(condition_type, status="True", reason=None, message=None):
"""Returns function, that returns True if the Kubernetes object has a specific value"""

def _check(obj):
for condition in obj.model.status.conditions:
if ( # pylint: disable=too-many-boolean-expressions
condition.type == condition_type
and condition.status == status
and (message is None or message in condition.message)
and (reason is None or reason == condition.reason)
):
if check_condition(condition, condition_type, status, reason, message):
return True
return False

Expand Down

0 comments on commit f29c0eb

Please sign in to comment.