Skip to content

Commit 7eebf6a

Browse files
author
Jakub Smolar
authored
Merge pull request #599 from trepel/identical-hostname-test-updates
Update 'identical hostname' tests since the behavior has changed
2 parents c8ad03a + 430cc7a commit 7eebf6a

14 files changed

+334
-426
lines changed

testsuite/tests/singlecluster/identical_hostnames/auth/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Conftest for "identical hostname" tests"""
2+
3+
import pytest
4+
5+
6+
@pytest.fixture(scope="module")
7+
def authorization(authorization):
8+
"""1st 'allow-all' Authorization object"""
9+
authorization.authorization.add_opa_policy("rego", "allow = true")
10+
return authorization
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""
2+
There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to AuthPolicy
3+
https://github.com/Kuadrant/kuadrant-operator/blob/c8d083808daff46772254e223407c849b55020a7/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames
4+
(second topology mentioned there)
5+
This test validates that it has been properly fixed, i.e. both AuthPolicies are fully and successfully enforced.
6+
"""
7+
8+
import pytest
9+
10+
from testsuite.kuadrant.policy import has_condition
11+
from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy
12+
13+
pytestmark = [pytest.mark.kuadrant_only]
14+
15+
16+
@pytest.fixture(scope="module")
17+
def authorization2(gateway, blame, cluster, label):
18+
"""2nd 'deny-all' Authorization object"""
19+
auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), gateway, labels={"testRun": label})
20+
auth_policy.authorization.add_opa_policy("rego", "allow = false")
21+
return auth_policy
22+
23+
24+
@pytest.fixture(scope="module", autouse=True)
25+
def commit(request, authorization, authorization2):
26+
"""Ensure Authorizations are created"""
27+
for auth in [authorization, authorization2]:
28+
if auth is not None:
29+
request.addfinalizer(auth.delete)
30+
auth.commit()
31+
auth.wait_for_accepted()
32+
33+
authorization.wait_for_ready()
34+
35+
# At this point the 'route2' has not been created yet so authorization2 is completely overridden by authorization1
36+
assert authorization2.wait_until(has_condition("Enforced", "False", "Overridden")), (
37+
f"'deny-all' AuthPolicy did not reach expected record status, instead it was: "
38+
f"{authorization2.model.status.condition}"
39+
)
40+
41+
42+
def test_identical_hostnames_auth_on_gw_and_route(client, authorization, authorization2):
43+
"""
44+
Tests that Gateway-attached AuthPolicy affects on 'route2' even if both 'route' and 'route2' declare identical
45+
hostname and there is another AuthPolicy already successfully enforced on 'route'.
46+
Setup:
47+
- Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2'
48+
- 'allow-all' AuthPolicy enforced on the '/anything/route1' HTTPRoute
49+
- 'deny-all' AuthPolicy (created after 'allow-all' AuthPolicy) enforced on the Gateway
50+
Test:
51+
- Send a request via 'route' and assert that response status code is 200 OK
52+
- Send a request via 'route2' and assert that response status code is 403 Forbidden
53+
- Delete the 'allow-all' AuthPolicy
54+
- Send a request via both routes
55+
- Assert that both response status codes are 403 (Forbidden)
56+
"""
57+
58+
# Verify that the GW-level 'deny-all' AuthPolicy is now only partially enforced ('route2' only). It is overridden
59+
# for 'route1' by HTTPRoute-level 'allow-all' AuthPolicy
60+
authorization2.wait_for_partial_enforced()
61+
62+
# Access via 'route' is allowed due to 'allow-all' AuthPolicy
63+
response = client.get("/anything/route1/get")
64+
assert response.status_code == 200
65+
66+
# 'deny-all' Gateway AuthPolicy affects route2
67+
response = client.get("/anything/route2/get")
68+
assert response.status_code == 403
69+
70+
# Deletion of 'allow-all' AuthPolicy should make the 'deny-all' Gateway AuthPolicy enforced on both routes
71+
authorization.delete()
72+
authorization2.wait_for_ready()
73+
74+
response = client.get("/anything/route1/get")
75+
assert response.status_code == 403
76+
77+
response = client.get("/anything/route2/get")
78+
assert response.status_code == 403
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
There used to be a limitation if using two HTTPRoutes declaring the same hostname related to AuthPolicy:
3+
https://github.com/Kuadrant/kuadrant-operator/blob/c8d083808daff46772254e223407c849b55020a7/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames
4+
(the first topology mentioned there)
5+
This test validates that it has been properly fixed, i.e. both AuthPolicies are fully and successfully enforced.
6+
"""
7+
8+
import pytest
9+
10+
from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy
11+
12+
pytestmark = [pytest.mark.kuadrant_only]
13+
14+
15+
@pytest.fixture(scope="module")
16+
def authorization2(route2, blame, cluster, label):
17+
"""2nd 'deny-all' Authorization object"""
18+
auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), route2, labels={"testRun": label})
19+
auth_policy.authorization.add_opa_policy("rego", "allow = false")
20+
return auth_policy
21+
22+
23+
@pytest.fixture(scope="module", autouse=True)
24+
def commit(request, authorization, authorization2):
25+
"""Ensure Authorizations are created"""
26+
for auth in [authorization, authorization2]:
27+
if auth is not None:
28+
request.addfinalizer(auth.delete)
29+
auth.commit()
30+
auth.wait_for_ready()
31+
32+
33+
def test_identical_hostnames_auth_on_routes(client, authorization):
34+
"""
35+
Validate that 2nd AuthPolicy is fully enforced on 'route2' declaring identical hostname as 'route' when another
36+
AuthPolicy already successfully enforced on 'route'.
37+
Setup:
38+
- Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2'
39+
- 'allow-all' AuthPolicy enforced on the '/anything/route1' HTTPRoute
40+
- 'deny-all' AuthPolicy (created after 'allow-all' AuthPolicy) enforced on the '/anything/route2' HTTPRoute
41+
Test:
42+
- Send a request via 'route' and assert that response status code is 200 OK
43+
- Send a request via 'route2' and assert that response status code is 403 Forbidden
44+
- Delete the 'allow-all' AuthPolicy
45+
- Send a request via both routes
46+
- Assert that access via 'route' is still 200 (OK), deletion of 'allow-all' Authpolicy should have no effect
47+
- Assert that access via 'route2' is still 403 (Forbidden)
48+
"""
49+
50+
response = client.get("/anything/route1/get")
51+
assert response.status_code == 200
52+
53+
response = client.get("/anything/route2/get")
54+
assert response.status_code == 403
55+
56+
# Deletion of 'allow-all' AuthPolicy
57+
authorization.delete()
58+
59+
# Access via 'route' is still allowed because 'deny-all' AuthPolicy is not enforced on this route
60+
response = client.get("/anything/route1/get")
61+
assert response.status_code == 200
62+
63+
# Access via 'route2' is still not allowed due to 'deny-all' AuthPolicy being enforced on 'route2'
64+
response = client.get("/anything/route2/get")
65+
assert response.status_code == 403

testsuite/tests/singlecluster/identical_hostnames/rlp/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Conftest for "identical hostname" tests"""
2+
3+
import pytest
4+
5+
from testsuite.kuadrant.policy.rate_limit import Limit
6+
7+
8+
@pytest.fixture(scope="module")
9+
def rate_limit(rate_limit):
10+
"""Add limit to 1st RateLimitPolicy allowing 1 request per 10 seconds (a.k.a. '1rp10s' RateLimitPolicy)"""
11+
rate_limit.add_limit("1rp10s", [Limit(1, "10s")])
12+
return rate_limit
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to RLP.
3+
https://github.com/Kuadrant/kuadrant-operator/blob/3b8e313d552090c52d8aadca95f6952f42a03192/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames
4+
(second topology mentioned there)
5+
This test validates that it has been properly fixed, i.e. both RateLimitPolicies (RLPs) are successfully enforced.
6+
"""
7+
8+
from time import sleep
9+
import pytest
10+
11+
from testsuite.kuadrant.policy import has_condition
12+
from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit
13+
14+
pytestmark = [pytest.mark.kuadrant_only]
15+
16+
LIMIT = Limit(2, "10s")
17+
18+
19+
@pytest.fixture(scope="module")
20+
def rate_limit2(gateway, blame, cluster, label):
21+
"""2nd RateLimitPolicy object allowing 2 requests per 10 seconds (a.k.a. '2rp10s')"""
22+
rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10s"), gateway, labels={"testRun": label})
23+
rlp.add_limit("2rp10s", [LIMIT])
24+
return rlp
25+
26+
27+
@pytest.fixture(scope="module", autouse=True)
28+
def commit(request, rate_limit, rate_limit2):
29+
"""Ensure RLPs are created"""
30+
for rlp in [rate_limit, rate_limit2]:
31+
if rlp is not None:
32+
request.addfinalizer(rlp.delete)
33+
rlp.commit()
34+
rlp.wait_for_accepted()
35+
36+
rate_limit.wait_for_ready()
37+
38+
# At this point the 'route2' has not been created yet so rate_limit2 is completely overridden by rate_limit
39+
assert rate_limit2.wait_until(
40+
has_condition("Enforced", "False", "Overridden")
41+
), f"'2pr10s' RLP did not reach expected record status, instead it was: {rate_limit2.model.status.condition}"
42+
43+
44+
def test_identical_hostnames_rlp_on_gw_and_route(client, rate_limit, rate_limit2):
45+
"""
46+
Tests that Gateway-attached RateLimitPolicy is enforced on 'route2' if both 'route' and 'route2' declare
47+
identical hostname and there is another RateLimitPolicy already successfully enforced on 'route'.
48+
Setup:
49+
- Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2'
50+
- '1rp10s' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute
51+
- '2rp10s' RateLimitPolicy (created after '1pr10s' RateLimitPolicy) enforced on the Gateway
52+
Test:
53+
- Send requests via 'route' and assert that 429 is returned after one 200 OK
54+
- Send a request via 'route2' and assert that 429 is returned after two 200s
55+
- Delete the '1rp10s' RateLimitPolicy
56+
- Send a request via both routes
57+
- Assert that on both routes the 429s are returned after two 200s
58+
"""
59+
# At this point route2 exists so the '2rp10s' RLP should not be overridden, should be partially enforced instead
60+
rate_limit2.wait_for_partial_enforced()
61+
62+
# Access via 'route' is limited due to '1rp10s' RateLimitPolicy
63+
response = client.get("/anything/route1/get")
64+
assert response.status_code == 200
65+
response = client.get("/anything/route1/get")
66+
assert response.status_code == 429
67+
68+
# Access via 'route2' is limited due to '2rp10s' Gateway RateLimitPolicy
69+
responses = client.get_many("/anything/route2/get", LIMIT.limit)
70+
responses.assert_all(status_code=200)
71+
response = client.get("/anything/route2/get")
72+
assert response.status_code == 429
73+
74+
# Deletion of '1rp10s' RateLimitPolicy should make both routes rate-limited by '2pr10s' RLP.
75+
# '2pr10s' RLP should get fully enforced (was: partially enforced)
76+
rate_limit.delete()
77+
rate_limit2.wait_for_ready()
78+
79+
# Wait for 15 seconds to make sure counter is reset
80+
sleep(15)
81+
82+
responses = client.get_many("/anything/route1/get", LIMIT.limit)
83+
responses.assert_all(status_code=200)
84+
response = client.get("/anything/route1/get")
85+
assert response.status_code == 429
86+
87+
responses = client.get_many("/anything/route2/get", LIMIT.limit)
88+
responses.assert_all(status_code=200)
89+
response = client.get("/anything/route2/get")
90+
assert response.status_code == 429
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"""
2+
There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to RLP.
3+
https://github.com/Kuadrant/kuadrant-operator/blob/3b8e313d552090c52d8aadca95f6952f42a03192/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames
4+
(the first topology mentioned there)
5+
This test validates that it has been properly fixed, i.e. both RateLimitPolicies (RLPs) are successfully enforced.
6+
"""
7+
8+
from time import sleep
9+
import pytest
10+
11+
from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit
12+
13+
14+
pytestmark = [pytest.mark.kuadrant_only]
15+
16+
LIMIT = Limit(2, "10s")
17+
18+
19+
@pytest.fixture(scope="module")
20+
def rate_limit2(route2, blame, cluster, label):
21+
"""2nd RateLimitPolicy allowing 2 requests per 10 seconds (a.k.a. '2rp10s' RateLimitPolicy)"""
22+
rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10s"), route2, labels={"testRun": label})
23+
rlp.add_limit("2rp10m", [LIMIT])
24+
return rlp
25+
26+
27+
@pytest.fixture(scope="module", autouse=True)
28+
def commit(request, rate_limit, rate_limit2):
29+
"""Ensure Authorizations are created"""
30+
for rlp in [rate_limit, rate_limit2]:
31+
if rlp is not None:
32+
request.addfinalizer(rlp.delete)
33+
rlp.commit()
34+
rlp.wait_for_ready()
35+
36+
37+
def test_identical_hostnames_rlp_on_routes(client, rate_limit2):
38+
"""
39+
Validates that 1st RateLimitPolicy is still enforced on 'route' declaring identical hostname as 'route2' if another
40+
RateLimitPolicy got successfully enforced on 'route2' in the interim.
41+
Setup:
42+
- Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2'
43+
- '1rp10m' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute
44+
- '2rp10m' RateLimitPolicy (created after '1rp10s' RateLimitPolicy) enforced on the '/anything/route2' HTTPRoute
45+
Test:
46+
- Send a request via 'route' and assert that no 429s (Too Many Requests) are returned
47+
- Send a request via 'route2' and assert that no 429s (Too Many Requests) are returned
48+
- Delete the '2rp10s' RateLimitPolicy
49+
- Send a request via both routes
50+
- Assert that 429 is returned after single 200 (OK) for route1
51+
- Assert that there are no 429s for 'route2'
52+
"""
53+
# Access via 'route' is limited due to '1rp10s' RateLimitPolicy
54+
# despite it reporting being successfully enforced
55+
response = client.get("/anything/route1/get")
56+
assert response.status_code == 200
57+
response = client.get("/anything/route1/get")
58+
assert response.status_code == 429
59+
60+
# Access via 'route2' is limited due to '2rp10s' RateLimitPolicy
61+
responses = client.get_many("/anything/route2/get", LIMIT.limit)
62+
responses.assert_all(status_code=200)
63+
response = client.get("/anything/route2/get")
64+
assert response.status_code == 429
65+
66+
# Deletion of '2rp10m' RateLimitPolicy
67+
rate_limit2.delete()
68+
69+
# Access via 'route' should now be still limited via '1rp10s' RateLimitPolicy
70+
# Wait for 15s to make sure the counter is reset
71+
sleep(15)
72+
response = client.get("/anything/route1/get")
73+
assert response.status_code == 200
74+
response = client.get("/anything/route1/get")
75+
assert response.status_code == 429
76+
77+
# Access via 'route2' is now not limited at all
78+
responses = client.get_many("/anything/route2/get", LIMIT.limit + 1)
79+
responses.assert_all(status_code=200)

0 commit comments

Comments
 (0)