Skip to content

Commit 22cdcb4

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 22cdcb4

2 files changed

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

0 commit comments

Comments
 (0)