Skip to content

Commit fc70243

Browse files
test: remove hardcoded defaults from functional test config and add soak test
Env vars (ATHENA_HOST, OAUTH_AUTH_URL, OAUTH_AUDIENCE) now fall back to their SDK defaults when unset rather than overriding with stale hard-coded values. Adds proactive_refresh_threshold to CredentialHelper and a new classify_single soak test that validates hash-check classification success rate over 1000 iterations. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0b93a07 commit fc70243

2 files changed

Lines changed: 87 additions & 11 deletions

File tree

tests/functional/conftest.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,25 @@ async def credential_helper() -> CredentialHelper:
8080
client_id = os.environ["OAUTH_CLIENT_ID"]
8181
client_secret = os.environ["OAUTH_CLIENT_SECRET"]
8282
auth_url = os.getenv(
83-
"OAUTH_AUTH_URL", "https://crispthinking.auth0.com/oauth/token"
83+
"OAUTH_AUTH_URL"
8484
)
85-
audience = os.getenv("OAUTH_AUDIENCE", "crisp-athena-live")
85+
audience = os.getenv("OAUTH_AUDIENCE")
8686

8787
# Create credential helper
88-
return CredentialHelper(
89-
client_id=client_id,
90-
client_secret=client_secret,
91-
auth_url=auth_url,
92-
audience=audience,
93-
)
88+
kwargs: dict[str, str] = {
89+
"client_id": client_id,
90+
"client_secret": client_secret,
91+
}
92+
if auth_url:
93+
kwargs["auth_url"] = auth_url
94+
if audience:
95+
kwargs["audience"] = audience
9496

97+
return CredentialHelper(proactive_refresh_threshold=0.25, **kwargs)
9598

9699
def _load_options() -> AthenaOptions:
97100
_ = load_dotenv()
98-
host = os.getenv("ATHENA_HOST", "localhost")
101+
host = os.getenv("ATHENA_HOST")
99102

100103
deployment_id = f"functional-test-{uuid.uuid4()}"
101104
if len(deployment_id) > MAX_DEPLOYMENT_ID_LENGTH:
@@ -104,8 +107,7 @@ def _load_options() -> AthenaOptions:
104107
affiliate = os.environ["ATHENA_TEST_AFFILIATE"]
105108

106109
# Run classification with OAuth authentication
107-
return AthenaOptions(
108-
host=host,
110+
opts = AthenaOptions(
109111
resize_images=True,
110112
deployment_id=deployment_id,
111113
compress_images=True,
@@ -115,6 +117,11 @@ def _load_options() -> AthenaOptions:
115117
compression_quality=2,
116118
)
117119

120+
if host:
121+
opts.host = host
122+
123+
return opts
124+
118125

119126
@pytest.fixture
120127
def athena_options() -> AthenaOptions:
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import grpc
2+
import pytest
3+
4+
from common_utils.image_generation import create_test_image
5+
from resolver_athena_client.client.athena_client import AthenaClient
6+
from resolver_athena_client.client.athena_options import AthenaOptions
7+
from resolver_athena_client.client.channel import (
8+
CredentialHelper,
9+
create_channel_with_credentials,
10+
)
11+
from resolver_athena_client.client.models import ImageData
12+
13+
SOAK_ITERATIONS = 1000
14+
15+
16+
@pytest.mark.asyncio
17+
@pytest.mark.functional
18+
@pytest.mark.soak
19+
async def test_classify_single_hash_check_soak(
20+
athena_options: AthenaOptions, credential_helper: CredentialHelper
21+
) -> None:
22+
"""Soak test: repeatedly classify images and assert hash check result exists.
23+
24+
Sends ~1000 classify_single requests and asserts each response contains
25+
a KnownCSAM- hash check classification.
26+
"""
27+
28+
channel = await create_channel_with_credentials(
29+
athena_options.host, credential_helper
30+
)
31+
32+
async with AthenaClient(channel, athena_options) as client:
33+
successes = 0
34+
failures: list[str] = []
35+
36+
for i in range(SOAK_ITERATIONS):
37+
image_bytes = create_test_image()
38+
image_data = ImageData(image_bytes)
39+
40+
try:
41+
result = await client.classify_single(image_data)
42+
except grpc.aio.AioRpcError as e:
43+
failures.append(
44+
f"Iteration {i}: gRPC error {e.code()} - {e.details()}"
45+
)
46+
continue
47+
48+
if result.error.code:
49+
failures.append(
50+
f"Iteration {i}: error {result.error.code} - {result.error.message}"
51+
)
52+
continue
53+
54+
found_hash_check = any(
55+
c.label.startswith("KnownCSAM-")
56+
for c in result.classifications
57+
)
58+
if found_hash_check:
59+
successes += 1
60+
else:
61+
failures.append(
62+
f"Iteration {i}: no KnownCSAM- classification found"
63+
)
64+
65+
success_rate = successes / SOAK_ITERATIONS
66+
assert success_rate >= 0.95, (
67+
f"Hash check success rate {success_rate:.1%} is below 95%. "
68+
f"{len(failures)} failures:\n" + "\n".join(failures[:20])
69+
)

0 commit comments

Comments
 (0)