Skip to content

Commit f402418

Browse files
committed
Fix 6 pre-existing test failures + 2 anti-patterns (REMYX-75)
Three groups of issues addressed in one PR. Group A — tests/api/test_dataset.py (3 failures) Function signatures drifted (delete_dataset + download_dataset gained a required `dataset_type` arg) without test updates. Also a mock-payload-shape mismatch (`list_datasets` reads from "message", not "datasets") and a long-broken `mock.called_once_with(...)` assertion that always trivially passed (should be `mock.assert_called_once_with(...)`). Fixed: updated test signatures, mock payloads, and assertion style. Group B — tests/api/test_recommendations.py header-threading (2 failures) Root cause: `HEADERS` in remyxai/api/__init__.py is built at *module import time* from $REMYXAI_API_KEY. The autouse fixture in each test file sets the env var *per-test*, which is too late — the module was already imported with an empty token. Tests asserted `len(auth) > len("Bearer ")` and failed because the module-level HEADERS was `{"Authorization": "Bearer "}` (no token). Fixed: added tests/conftest.py that sets `REMYXAI_API_KEY` at collection time (before any test module imports remyxai.api), so HEADERS is built with a non-empty Bearer token. Also updated tests/integration/test_recommendations_live.py's skipif to also skip when the env var is a `test-` placeholder (so the new conftest doesn't accidentally trigger live API calls). Group C — click commands silently exit 0 on errors (1 failure) list_models, summarize_model, deploy_model, dataset all wrapped their handlers in `try/except` that called `click.echo(...)` and let the function fall through — exit code stayed 0 even when an exception was raised. test_deploy_model_invalid_action asserted `exit_code != 0` and failed for this reason. Same anti-pattern in the other three commands (not tested but contractually wrong). Fixed: replaced silent except with `raise click.ClickException(...)` in all four commands. Click renders the message with an "Error: " prefix and exits 1. Test update: assertion now matches the new "deploying model failed" message rather than "Error deploying model". Verification: pytest now reports 106 passed / 15 skipped / 0 failures (15 skipped = the live integration tests, which is by design).
1 parent 1f9fdab commit f402418

5 files changed

Lines changed: 59 additions & 20 deletions

File tree

remyxai/cli/commands.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def list_models():
4242
try:
4343
handle_model_action({"subaction": "list"})
4444
except Exception as e:
45-
click.echo(f"Error listing models: {e}")
45+
raise click.ClickException(f"listing models failed: {e}")
4646

4747

4848
@cli.command()
@@ -52,7 +52,7 @@ def summarize_model(model_name):
5252
try:
5353
handle_model_action({"subaction": "summarize", "model_name": model_name})
5454
except Exception as e:
55-
click.echo(f"Error summarizing model: {e}")
55+
raise click.ClickException(f"summarizing model failed: {e}")
5656

5757

5858
@cli.command()
@@ -63,7 +63,7 @@ def deploy_model(model_name, action):
6363
try:
6464
handle_deployment_action({"model_name": model_name, "action": action})
6565
except Exception as e:
66-
click.echo(f"Error deploying model: {e}")
66+
raise click.ClickException(f"deploying model failed: {e}")
6767

6868

6969
@cli.command()
@@ -74,7 +74,7 @@ def dataset(action, dataset_name=None):
7474
try:
7575
handle_dataset_action({"action": action, "dataset_name": dataset_name})
7676
except Exception as e:
77-
click.echo(f"Error managing dataset: {e}")
77+
raise click.ClickException(f"dataset action failed: {e}")
7878

7979

8080
@cli.group()

tests/api/test_dataset.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,45 @@
1-
from remyxai.api.datasets import list_datasets, delete_dataset, download_dataset
21
from unittest.mock import patch
3-
from remyxai.api.datasets import BASE_URL
2+
3+
from remyxai.api.datasets import BASE_URL, delete_dataset, download_dataset, list_datasets
4+
45

56
@patch("remyxai.api.datasets.requests.get")
67
def test_list_datasets(mock_get):
8+
"""list_datasets reads from the response's 'message' field."""
79
mock_get.return_value.status_code = 200
8-
mock_get.return_value.json.return_value = {"datasets": ["dataset1", "dataset2"]}
10+
mock_get.return_value.json.return_value = {"message": ["dataset1", "dataset2"]}
11+
912
datasets = list_datasets()
13+
1014
assert isinstance(datasets, list)
11-
assert len(datasets) > 0
15+
assert datasets == ["dataset1", "dataset2"]
16+
1217

1318
@patch("remyxai.api.datasets.requests.delete")
1419
def test_delete_dataset(mock_delete):
20+
"""delete_dataset requires (dataset_type, dataset_name)."""
1521
mock_delete.return_value.status_code = 200
1622
mock_delete.return_value.json.return_value = {"message": "Dataset deleted successfully"}
17-
dataset_name = "test_dataset"
18-
delete_dataset(dataset_name)
19-
assert mock_delete.called_once_with(f"{BASE_URL}/datasets/delete/{dataset_name}")
23+
24+
result = delete_dataset("eval", "test_dataset")
25+
26+
assert result == "Dataset deleted successfully"
27+
args, _ = mock_delete.call_args
28+
assert args[0] == f"{BASE_URL}/datasets/delete/eval/test_dataset"
29+
2030

2131
@patch("remyxai.api.datasets.requests.get")
2232
def test_download_dataset(mock_get):
33+
"""download_dataset requires (dataset_type, dataset_name); returns an error
34+
when no presigned_url is in the response (avoids touching the network)."""
2335
mock_get.return_value.status_code = 200
24-
mock_get.return_value.json.return_value = {"url": "https://example.com/dataset.zip"}
25-
dataset_name = "test_dataset"
26-
download_dataset(dataset_name)
27-
assert mock_get.called_once_with(f"{BASE_URL}/datasets/download/{dataset_name}")
28-
36+
mock_get.return_value.json.return_value = {"presigned_url": ""}
2937

38+
result = download_dataset("eval", "test_dataset")
3039

40+
# With an empty presigned URL the function returns an explicit error dict
41+
# rather than attempting a download. Keep the test hermetic.
42+
assert isinstance(result, dict)
43+
assert "error" in result
44+
args, _ = mock_get.call_args
45+
assert args[0] == f"{BASE_URL}/datasets/download/eval/test_dataset"

tests/cli/test_commands.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,13 @@ def test_deploy_model_down(mock_handle_deployment_action):
5454

5555

5656
def test_deploy_model_invalid_action():
57+
"""Invalid action must surface as an error with a non-zero exit code.
58+
59+
The command uses `click.ClickException`, which prefixes the message
60+
with `Error: ` and exits 1. This is the contract this test enforces.
61+
"""
5762
runner = CliRunner()
5863
result = runner.invoke(cli, ["deploy-model", "model_name", "invalid_action"])
5964

60-
assert "Error deploying model" in result.output
65+
assert "deploying model failed" in result.output
6166
assert result.exit_code != 0

tests/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Shared pytest setup.
2+
3+
Sets `REMYXAI_API_KEY` before any test module imports `remyxai.api`,
4+
so the module-level `HEADERS` dict (built at import time in
5+
`remyxai/api/__init__.py`) has a non-empty Bearer token. Per-test
6+
autouse fixtures elsewhere can't fix this on their own because they
7+
run after collection-time imports.
8+
"""
9+
import os
10+
11+
os.environ.setdefault("REMYXAI_API_KEY", "test-key-collection-time")

tests/integration/test_recommendations_live.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,18 @@
2020
import pytest
2121

2222
# ─── skip entire module if no API key ────────────────────────────────────────
23-
23+
#
24+
# Skips when the env var is missing OR is a unit-test placeholder. The
25+
# tests/conftest.py sets `REMYXAI_API_KEY=test-...` at collection time so
26+
# the module-level HEADERS in remyxai/api/__init__.py is built with a
27+
# non-empty Bearer token (required for the unit-test header-threading
28+
# assertions). Live integration tests against engine.remyx.ai only run
29+
# when the env var is a real, non-test key.
30+
31+
_API_KEY = os.environ.get("REMYXAI_API_KEY", "")
2432
pytestmark = pytest.mark.skipif(
25-
not os.environ.get("REMYXAI_API_KEY"),
26-
reason="REMYXAI_API_KEY not set — skipping live integration tests",
33+
not _API_KEY or _API_KEY.startswith("test-"),
34+
reason="REMYXAI_API_KEY not set (or is a unit-test placeholder) — skipping live integration tests",
2735
)
2836

2937

0 commit comments

Comments
 (0)