Skip to content

Commit f47d53f

Browse files
author
Jakub Smolar
authored
Merge pull request #573 from averevki/dns-healthchecks-tests
Add DNSPolicy health check tests
2 parents d2d194c + 98bfe91 commit f47d53f

File tree

7 files changed

+253
-1
lines changed

7 files changed

+253
-1
lines changed

testsuite/kuadrant/policy/dns.py

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Module for DNSPolicy related classes"""
22

33
from dataclasses import dataclass
4-
from typing import Optional
4+
from typing import Optional, Literal
55

66
from testsuite.gateway import Referencable
7+
from testsuite.kubernetes import KubernetesObject
78
from testsuite.kubernetes.client import KubernetesClient
89
from testsuite.kuadrant.policy import Policy
910
from testsuite.utils import asdict, check_condition
@@ -31,6 +32,33 @@ class LoadBalancing:
3132
weight: Optional[int] = None
3233

3334

35+
@dataclass
36+
class AdditionalHeadersRef:
37+
"""Object representing DNSPolicy additionalHeadersRef field"""
38+
39+
name: str
40+
41+
42+
@dataclass
43+
class HealthCheck: # pylint: disable=invalid-name
44+
"""Object representing DNSPolicy health check specification"""
45+
46+
additionalHeadersRef: Optional[AdditionalHeadersRef] = None
47+
path: Optional[str] = None
48+
failureThreshold: Optional[int] = None
49+
interval: Optional[str] = None
50+
port: Optional[int] = None
51+
protocol: Literal["HTTP", "HTTPS"] = "HTTP"
52+
53+
54+
class DNSHealthCheckProbe(KubernetesObject):
55+
"""DNSHealthCheckProbe object"""
56+
57+
def is_healthy(self) -> bool:
58+
"""Returns True if DNSHealthCheckProbe endpoint is healthy"""
59+
return self.refresh().model.status.healthy
60+
61+
3462
class DNSPolicy(Policy):
3563
"""DNSPolicy object"""
3664

@@ -61,6 +89,16 @@ def create_instance(
6189

6290
return cls(model, context=cluster.context)
6391

92+
def set_health_check(self, health_check: HealthCheck):
93+
"""Sets health check for DNSPolicy"""
94+
self.model["spec"]["healthCheck"] = asdict(health_check)
95+
96+
def get_dns_health_probe(self) -> DNSHealthCheckProbe:
97+
"""Returns DNSHealthCheckProbe object for the created DNSPolicy"""
98+
with self.context:
99+
dns_probe = self.get_owned("dnsrecords.kuadrant.io")[0].get_owned("DNSHealthCheckProbe")[0]
100+
return DNSHealthCheckProbe(dns_probe.model, context=self.context)
101+
64102
def wait_for_full_enforced(self, timelimit=300):
65103
"""Wait for a Policy to be fully Enforced with increased timelimit for DNSPolicy"""
66104
super().wait_for_full_enforced(timelimit=timelimit)

testsuite/tests/singlecluster/gateway/dnspolicy/health_check/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Conftest for DNSPolicy health checks"""
2+
3+
import pytest
4+
5+
from testsuite.gateway import Hostname, TLSGatewayListener
6+
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
7+
8+
9+
@pytest.fixture(scope="module")
10+
def subdomain(blame):
11+
"""Subdomain name that will be added to HTTPRoute"""
12+
return blame("hostname")
13+
14+
15+
@pytest.fixture(scope="module")
16+
def hostname(gateway, exposer, subdomain) -> Hostname:
17+
"""Exposed Hostname object"""
18+
return exposer.expose_hostname(subdomain, gateway)
19+
20+
21+
@pytest.fixture(scope="module")
22+
def gateway(request, cluster, blame, base_domain, module_label, subdomain):
23+
"""Returns ready gateway"""
24+
gateway_name = blame("gw")
25+
gw = KuadrantGateway.create_instance(
26+
cluster,
27+
gateway_name,
28+
{"app": module_label},
29+
)
30+
gw.add_listener(TLSGatewayListener(hostname=f"{subdomain}.{base_domain}", gateway_name=gateway_name))
31+
request.addfinalizer(gw.delete)
32+
gw.commit()
33+
gw.wait_for_ready()
34+
return gw
35+
36+
37+
@pytest.fixture(scope="module")
38+
def dns_policy(dns_policy, health_check):
39+
"""Add health check to DNSPolicy"""
40+
dns_policy.set_health_check(health_check)
41+
return dns_policy
42+
43+
44+
@pytest.fixture(scope="module")
45+
def dns_health_probe(dns_policy):
46+
"""Return DNSHealthCheckProbe object for created DNSPolicy"""
47+
return dns_policy.get_dns_health_probe()
48+
49+
50+
@pytest.fixture(scope="module", autouse=True)
51+
def commit(request, route, tls_policy, dns_policy): # pylint: disable=unused-argument
52+
"""Commits dnspolicy"""
53+
for component in [tls_policy, dns_policy]:
54+
request.addfinalizer(component.delete)
55+
component.commit()
56+
component.wait_for_ready()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Tests for DNSPolicy health checks - healthy endpoint"""
2+
3+
import pytest
4+
5+
from testsuite.kuadrant.policy.dns import HealthCheck
6+
7+
pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]
8+
9+
10+
@pytest.fixture(scope="module")
11+
def health_check():
12+
"""Returns healthy endpoint specification for DNSPolicy health check"""
13+
return HealthCheck(
14+
path="/get",
15+
interval="5s",
16+
protocol="HTTPS",
17+
port=443,
18+
)
19+
20+
21+
def test_healthy_endpoint(dns_health_probe, client, auth):
22+
"""Test healthy endpoint check"""
23+
assert dns_health_probe.is_healthy()
24+
25+
response = client.get("/get", auth=auth)
26+
assert response.status_code == 200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Tests for DNSPolicy health checks with HTTP only endpoint - healthy endpoint"""
2+
3+
import pytest
4+
5+
from testsuite.gateway import GatewayListener
6+
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
7+
from testsuite.kuadrant.policy.dns import HealthCheck
8+
9+
pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]
10+
11+
12+
@pytest.fixture(scope="module")
13+
def health_check():
14+
"""Returns healthy endpoint specification for DNSPolicy health check"""
15+
return HealthCheck(
16+
path="/get",
17+
interval="5s",
18+
protocol="HTTP",
19+
port=80,
20+
)
21+
22+
23+
@pytest.fixture(scope="module")
24+
def gateway(request, cluster, blame, base_domain, module_label, subdomain):
25+
"""Create gateway without TLS enabled"""
26+
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": module_label})
27+
gw.add_listener(GatewayListener(hostname=f"{subdomain}.{base_domain}"))
28+
request.addfinalizer(gw.delete)
29+
gw.commit()
30+
gw.wait_for_ready()
31+
return gw
32+
33+
34+
@pytest.fixture(scope="module", autouse=True)
35+
def commit(request, route, dns_policy): # pylint: disable=unused-argument
36+
"""Commits dnspolicy only"""
37+
request.addfinalizer(dns_policy.delete)
38+
dns_policy.commit()
39+
dns_policy.wait_for_ready()
40+
41+
42+
def test_healthy_endpoint_http(dns_health_probe, client):
43+
"""Test healthy endpoint check without TLS enabled"""
44+
assert dns_health_probe.is_healthy()
45+
46+
response = client.get("/get")
47+
assert response.status_code == 200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Tests for DNSPolicy health checks - healthy endpoint"""
2+
3+
import pytest
4+
5+
from testsuite.kuadrant.policy import has_condition
6+
from testsuite.kuadrant.policy.dns import HealthCheck, has_record_condition
7+
8+
pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]
9+
10+
11+
@pytest.fixture(scope="module")
12+
def health_check():
13+
"""Returns healthy endpoint specification for DNSPolicy health check"""
14+
return HealthCheck(
15+
path="/get",
16+
interval="5s",
17+
protocol="HTTPS",
18+
port=443,
19+
)
20+
21+
22+
def test_remove_endpoint(backend, dns_policy, dns_health_probe, client, auth):
23+
"""Scale backend replicas to 0 and back to 1, and check if DNSPolicy will remove the unhealthy endpoint"""
24+
assert dns_health_probe.is_healthy()
25+
response = client.get("/get", auth=auth)
26+
assert response.status_code == 200
27+
28+
backend.deployment.self_selector().scale(0)
29+
assert dns_policy.wait_until(has_condition("SubResourcesHealthy", "False"), timelimit=120)
30+
assert dns_policy.wait_until(
31+
has_record_condition("Healthy", "False", "HealthChecksFailed", "Not healthy addresses:")
32+
)
33+
34+
assert not dns_health_probe.is_healthy()
35+
response = client.get("/get", auth=auth)
36+
assert response.status_code == 503
37+
38+
backend.deployment.self_selector().scale(1)
39+
assert dns_policy.wait_until(has_condition("SubResourcesHealthy", "True"), timelimit=120)
40+
41+
assert dns_health_probe.is_healthy()
42+
response = client.get("/get", auth=auth)
43+
assert response.status_code == 200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Tests for DNSPolicy health checks - unhealthy endpoint"""
2+
3+
import pytest
4+
5+
from testsuite.kuadrant.policy import has_condition
6+
from testsuite.kuadrant.policy.dns import HealthCheck, has_record_condition
7+
8+
pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]
9+
10+
11+
@pytest.fixture(scope="module")
12+
def health_check():
13+
"""Returns unhealthy endpoint specification for DNSPolicy health check"""
14+
return HealthCheck(
15+
path="/unknown-endpoint",
16+
interval="5s",
17+
protocol="HTTPS",
18+
port=443,
19+
)
20+
21+
22+
@pytest.fixture(scope="module", autouse=True)
23+
def commit(request, route, tls_policy, dns_policy): # pylint: disable=unused-argument
24+
"""Commits tlspolicy and dnspolicy without waiting for dnspolicy to be enforced"""
25+
request.addfinalizer(tls_policy.delete)
26+
tls_policy.commit()
27+
tls_policy.wait_for_ready()
28+
29+
request.addfinalizer(dns_policy.delete)
30+
dns_policy.commit()
31+
32+
33+
def test_unhealthy_endpoint(dns_policy, dns_health_probe, client, auth):
34+
"""Test unhealthy endpoint check"""
35+
assert not dns_health_probe.is_healthy()
36+
response = client.get("/get", auth=auth)
37+
assert response.has_dns_error()
38+
39+
assert dns_policy.wait_until(has_condition("Enforced", "False"))
40+
assert dns_policy.wait_until(
41+
has_record_condition("Ready", "False", "HealthChecksFailed", "Not publishing unhealthy records")
42+
)

0 commit comments

Comments
 (0)