Skip to content

Commit d095a3d

Browse files
committed
feat(api tests): switch schemathesis invocation to harness-test; move auth header generation into get_schemathesis_command and remove TokenAuth hooks
1 parent 5c5b2d2 commit d095a3d

File tree

4 files changed

+68
-36
lines changed

4 files changed

+68
-36
lines changed

libraries/cloudharness-utils/cloudharness_utils/testing/api.py

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import os
2+
import logging
23

34
from ruamel.yaml import YAML
45

56
from cloudharness_model.models import ApiTestsConfig, ApplicationHarnessConfig
7+
from cloudharness.auth import get_token
68

79
yaml = YAML(typ='safe')
810

@@ -11,19 +13,67 @@ def get_api_filename(app_dir):
1113
return os.path.join(app_dir, "api", "openapi.yaml")
1214

1315

14-
def get_schemathesis_command(api_filename, app_config: ApplicationHarnessConfig, app_domain: str):
15-
# Make sure to set SCHEMATHESIS_HOOKS=cloudharness_test.apitest_init in environment to use the custom hooks
16-
return ["st", "run", api_filename, *get_schemathesis_params(app_config, app_domain)]
16+
def get_schemathesis_command(api_filename, app_config: ApplicationHarnessConfig, app_domain: str, app_env: dict | None = None):
17+
"""
18+
Build the schemathesis command for running API tests.
1719
20+
Extended to support runtime authentication header generation directly in the command instead of relying on hooks.
21+
"""
22+
return ["st", "run", api_filename, *get_schemathesis_params(app_config, app_domain, app_env)]
1823

19-
def get_schemathesis_params(app_config: ApplicationHarnessConfig, app_domain: str):
24+
25+
def _get_auth_headers(app_env: dict):
26+
"""Return list of CLI flags setting auth & headers based on environment.
27+
28+
Supported:
29+
- USERNAME/PASSWORD -> basic auth OR bearer token if token retrievable
30+
- API_KEY -> X-API-Key header
31+
- BEARER_TOKEN explicit -> Authorization header
32+
Priority order:
33+
1. Explicit BEARER_TOKEN
34+
2. USERNAME/PASSWORD -> try get_token (Keycloak) then fallback to --auth basic
35+
3. API_KEY header
36+
"""
37+
if not app_env:
38+
return []
39+
flags = []
40+
41+
bearer = app_env.get("BEARER_TOKEN")
42+
username = app_env.get("USERNAME")
43+
password = app_env.get("PASSWORD")
44+
api_key = app_env.get("API_KEY")
45+
46+
if bearer:
47+
flags += ["--header", f"Authorization: Bearer {bearer}"]
48+
elif username and password:
49+
# Attempt to retrieve token; if fails, fallback to basic auth
50+
try:
51+
token = get_token(username, password)
52+
if token:
53+
flags += ["--header", f"Authorization: Bearer {token}"]
54+
# also cookie header if needed by backend
55+
flags += ["--header", f"Cookie: kc-access={token}"]
56+
else:
57+
flags += ["--auth", f"{username}:{password}"]
58+
except Exception as e:
59+
logging.warning("Failed to retrieve bearer token; fallback to basic auth: %s", e)
60+
flags += ["--auth", f"{username}:{password}"]
61+
62+
if api_key:
63+
flags += ["--header", f"X-API-Key: {api_key}"]
64+
return flags
65+
66+
67+
def get_schemathesis_params(app_config: ApplicationHarnessConfig, app_domain: str, app_env: dict | None = None):
2068
params = ["--url", app_domain]
2169
api_config: ApiTestsConfig = app_config.test.api
2270
if api_config.checks:
2371
for c in api_config.checks:
2472
params += ["-c", c]
2573

26-
return [*params, *api_config.run_params]
74+
params.extend(api_config.run_params)
75+
params.extend(_get_auth_headers(app_env or {}))
76+
return params
2777

2878

2979
def get_urls_from_api_file(api_filename):

tools/cloudharness-test/cloudharness_test/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def run_api_tests(root_paths, helm_values: HarnessMainConfig, base_domain, inclu
6969

7070
if api_config.autotest:
7171
logging.info("Running auto api tests")
72-
cmd = get_schemathesis_command(api_filename, app_config, app_domain)
72+
cmd = get_schemathesis_command(api_filename, app_config, app_domain, app_env)
7373
logging.info("Running: %s", " ".join(cmd))
7474
result = subprocess.run(cmd,
7575
env=app_env, cwd=app_dir)

tools/cloudharness-test/cloudharness_test/apitest_init.py

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import schemathesis as st
55
from schemathesis.hooks import HookContext
66

7-
from cloudharness.auth import get_token
8-
97

108
if "APP_URL" or "APP_SCHEMA_FILE" in os.environ:
119
app_schema = os.environ.get("APP_SCHEMA_FILE", None)
@@ -45,31 +43,7 @@
4543
if not schema:
4644
raise Exception("Cannot setup API tests: No valid schema found. Check your deployment and configuration.")
4745

48-
if "USERNAME" in os.environ and "PASSWORD" in os.environ:
49-
logging.info("Setting token from username and password")
50-
51-
@st.auth()
52-
class TokenAuth:
53-
def get(self, case, ctx):
54-
username = os.environ["USERNAME"]
55-
password = os.environ["PASSWORD"]
56-
57-
return get_token(username, password)
58-
59-
def set(self, case, data, context):
60-
case.headers = case.headers or {}
61-
case.headers["Authorization"] = f"Bearer {data}"
62-
case.headers["Cookie"] = f"kc-access={data}"
63-
else:
64-
@st.auth()
65-
class TokenAuth:
66-
def get(self, case, ctx):
67-
return ""
68-
69-
def set(self, case, data, context):
70-
case.headers = case.headers or {}
71-
case.headers["Authorization"] = f"Bearer {data}"
72-
case.headers["Cookie"] = f"kc-access={data}"
46+
# Authentication headers are now passed directly via CLI flags; no auth hook required.
7347

7448
UNSAFE_VALUES = ("%", )
7549

tools/deployment-cli-tools/ch_cli_tools/codefresh.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,13 +450,21 @@ def codefresh_template_spec(template_path, **kwargs):
450450

451451

452452
def api_tests_commands(app_config: ApplicationHarnessConfig, run_custom_tests, api_url):
453+
"""Return commands to execute API tests for Codefresh pipeline.
454+
455+
Harness-test is now the unified entrypoint; it internally builds schemathesis command with headers.
456+
We invoke harness-test with -a flag targeting only API tests & include specific app.
457+
Custom pytest tests run separately inside the same container.
458+
"""
453459
api_config: ApiTestsConfig = app_config.test.api
454460
commands = []
461+
app_name = app_config.name
455462
if api_config.autotest:
456-
commands.append(" ".join(get_schemathesis_command(
457-
get_api_filename(""), app_config, api_url)))
463+
# harness-test requires values.yaml generated & domain; Codefresh sets environment accordingly.
464+
# We limit to the specific app using -i and run only api tests with -a
465+
commands.append(f"harness-test . -i {app_name} -a")
458466
if run_custom_tests:
459-
commands.append(f"pytest -v test/api")
467+
commands.append("pytest -v test/api")
460468
return commands
461469

462470

0 commit comments

Comments
 (0)