Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion testsuite/kuadrant/policy/dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import backoff
import openshift_client as oc

Comment thread
fabikova marked this conversation as resolved.
from testsuite.gateway import Referencable
from testsuite.kubernetes import KubernetesObject
from testsuite.kubernetes.client import KubernetesClient
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
Tests the DNS Endpoint Provider aggregation logic.

Verifies that endpoints from multiple Source DNSRecords are correctly merged into
a single Destination DNSRecord (Zone) and successfully resolved via the upstream provider.
"""

import pytest
import dns.resolver
from testsuite.kuadrant.policy.dns import DNSRecord, DNSRecordEndpoint
from testsuite.kubernetes.secret import Secret

SOURCE_IP1 = "91.16.35.100"
SOURCE_IP2 = "172.6.13.223"

pytestmark = [pytest.mark.dnspolicy]


@pytest.fixture(scope="module")
def endpoint_provider_secret(request, cluster, module_label, blame):
"""Creates a fresh endpoint provider secret in the test namespace"""
secret_data = {
"ENDPOINT_GVR": "kuadrant.io/v1alpha1.dnsrecords",
"ENDPOINT_ZONE_RECORD_LABEL": "kuadrant.io/zone-record=true",
}

secret = Secret.create_instance(
cluster,
blame("endpoint-creds"),
secret_data,
secret_type="kuadrant.io/endpoint",
labels={"app": module_label},
)

request.addfinalizer(secret.delete)
secret.commit()
return secret.name()


@pytest.fixture(scope="module")
def destination_dnsrecord(cluster, blame, hostname, dns_provider_secret, module_label):
"""Destination Record acting as the Zone"""
record = DNSRecord.create_instance(
cluster=cluster,
name=blame("dest-zone"),
root_host=hostname.hostname,
delegate=False,
provider_ref_name=dns_provider_secret,
labels={"app": module_label, "kuadrant.io/zone-record": "true"},
)
return record


@pytest.fixture(scope="module")
def source_dnsrecords(cluster, blame, hostname, endpoint_provider_secret, module_label):
"""Source Records acting as endpoint feeders"""
dns_name_1 = f"src1.{hostname.hostname}"
dns_name_2 = f"src2.{hostname.hostname}"

source1 = DNSRecord.create_instance(
cluster=cluster,
name=blame("src-1"),
root_host=hostname.hostname,
endpoints=[DNSRecordEndpoint(dnsName=dns_name_1, recordType="A", recordTTL=60, targets=[SOURCE_IP1])],
delegate=False,
provider_ref_name=endpoint_provider_secret,
labels={"app": module_label},
)

source2 = DNSRecord.create_instance(
cluster=cluster,
name=blame("src-2"),
root_host=hostname.hostname,
endpoints=[DNSRecordEndpoint(dnsName=dns_name_2, recordType="A", recordTTL=60, targets=[SOURCE_IP2])],
delegate=False,
provider_ref_name=endpoint_provider_secret,
labels={"app": module_label},
)

return [source1, source2]


@pytest.fixture(scope="module", autouse=True)
def commit(request, destination_dnsrecord, source_dnsrecords):
"""Commits the DNSRecords to the cluster and handles cleanup"""
all_records = [destination_dnsrecord] + source_dnsrecords

for record in all_records:
request.addfinalizer(record.delete)
record.commit()
record.wait_for_ready()


def test_records_accessible(hostname):
"""Verify that endpoints are merged and accessible via DNS"""
src1_answers = dns.resolver.resolve(f"src1.{hostname.hostname}")
src2_answers = dns.resolver.resolve(f"src2.{hostname.hostname}")

assert len(src1_answers) == 1
assert len(src2_answers) == 1

assert src1_answers[0].address == SOURCE_IP1
assert src2_answers[0].address == SOURCE_IP2
Comment on lines +94 to +103

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid one-shot DNS lookups for this e2e assertion path.

The test performs a single resolve per hostname (Lines 96-97). External DNS propagation is eventually consistent, so this can cause intermittent failures even when records are correct. Add a bounded wait/poll step (or reuse the DNSRecord wait helper introduced in this PR) before final equality assertions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@testsuite/tests/singlecluster/gateway/dnspolicy/dns_records/test_dns_endpoint_provider.py`
around lines 94 - 103, The test_records_accessible(hostname) currently does
one-shot DNS resolves for src1.{hostname.hostname} and src2.{hostname.hostname}
(src1_answers, src2_answers) which can flake; change it to poll with a bounded
timeout/retry loop (or call the existing DNSRecord wait helper) until the
answers stabilize before doing the final assertions. Specifically, replace the
direct dns.resolver.resolve calls with a retry loop that re-resolves both
hostnames, sleeps between attempts, and exits early when each query returns an A
record whose address equals SOURCE_IP1 and SOURCE_IP2 respectively (or when
timeout is reached), then run the len(...) and address equality asserts.

Loading