Files
2026-07-13 13:22:34 +08:00

334 lines
11 KiB
Python

import json
import pytest
from mlflow.claude_code.config import (
MLFLOW_TRACING_ENABLED,
get_env_var,
get_tracing_status,
load_claude_config,
save_claude_config,
setup_environment_config,
)
@pytest.fixture
def temp_settings_path(tmp_path):
"""Provide a temporary settings.json path for tests."""
return tmp_path / "settings.json"
def test_load_claude_config_valid_json(temp_settings_path):
config_data = {"tools": {"computer_20241022": {"name": "computer"}}}
with open(temp_settings_path, "w") as f:
json.dump(config_data, f)
result = load_claude_config(temp_settings_path)
assert result == config_data
def test_load_claude_config_missing_file(tmp_path):
non_existent_path = tmp_path / "non_existent.json"
result = load_claude_config(non_existent_path)
assert result == {}
def test_load_claude_config_invalid_json(temp_settings_path):
with open(temp_settings_path, "w") as f:
f.write("invalid json content")
result = load_claude_config(temp_settings_path)
assert result == {}
def test_save_claude_config_creates_file(temp_settings_path):
config_data = {"test": "value"}
save_claude_config(temp_settings_path, config_data)
assert temp_settings_path.exists()
saved_data = json.loads(temp_settings_path.read_text())
assert saved_data == config_data
def test_save_claude_config_creates_directory(tmp_path):
nested_path = tmp_path / "nested" / "dir" / "settings.json"
config_data = {"test": "value"}
save_claude_config(nested_path, config_data)
assert nested_path.exists()
saved_data = json.loads(nested_path.read_text())
assert saved_data == config_data
def test_get_env_var_from_os_environment_when_no_settings(tmp_path, monkeypatch):
monkeypatch.setenv(MLFLOW_TRACING_ENABLED, "test_os_value")
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "test_os_value"
def test_get_env_var_os_env_takes_precedence_over_settings(tmp_path, monkeypatch):
monkeypatch.setenv(MLFLOW_TRACING_ENABLED, "os_value")
config_data = {"env": {MLFLOW_TRACING_ENABLED: "settings_value"}}
claude_settings_path = tmp_path / ".claude" / "settings.json"
claude_settings_path.parent.mkdir(parents=True, exist_ok=True)
with open(claude_settings_path, "w") as f:
json.dump(config_data, f)
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "os_value"
def test_get_env_var_falls_back_to_os_env_when_not_in_settings(tmp_path, monkeypatch):
monkeypatch.setenv(MLFLOW_TRACING_ENABLED, "os_value")
config_data = {"env": {"OTHER_VAR": "other_value"}}
claude_settings_path = tmp_path / ".claude" / "settings.json"
claude_settings_path.parent.mkdir(parents=True, exist_ok=True)
with open(claude_settings_path, "w") as f:
json.dump(config_data, f)
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "os_value"
def test_get_env_var_from_settings_local_json(tmp_path, monkeypatch):
monkeypatch.delenv(MLFLOW_TRACING_ENABLED, raising=False)
config_data = {"env": {MLFLOW_TRACING_ENABLED: "local_value"}}
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
with open(claude_dir / "settings.local.json", "w") as f:
json.dump(config_data, f)
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "local_value"
def test_get_env_var_settings_local_overrides_settings(tmp_path, monkeypatch):
monkeypatch.delenv(MLFLOW_TRACING_ENABLED, raising=False)
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
with open(claude_dir / "settings.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "shared_value"}}, f)
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "local_value"}}, f)
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "local_value"
def test_get_env_var_falls_through_local_to_settings(tmp_path, monkeypatch):
monkeypatch.delenv("MLFLOW_TRACKING_URI", raising=False)
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
# local has ENABLED, shared has URI
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "true"}}, f)
with open(claude_dir / "settings.json", "w") as f:
json.dump({"env": {"MLFLOW_TRACKING_URI": "https://example.com"}}, f)
monkeypatch.chdir(tmp_path)
assert get_env_var(MLFLOW_TRACING_ENABLED, "default") == "true"
assert get_env_var("MLFLOW_TRACKING_URI", "default") == "https://example.com"
def test_get_env_var_os_env_takes_precedence_over_local(tmp_path, monkeypatch):
monkeypatch.setenv(MLFLOW_TRACING_ENABLED, "os_value")
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "local_value"}}, f)
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default")
assert result == "os_value"
def test_get_tracing_status_merges_local_and_shared(tmp_path):
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
settings_path = claude_dir / "settings.json"
# URI in shared, ENABLED in local
with open(settings_path, "w") as f:
json.dump({"env": {"MLFLOW_TRACKING_URI": "https://example.com"}}, f)
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "true"}}, f)
status = get_tracing_status(settings_path)
assert status.enabled is True
assert status.tracking_uri == "https://example.com"
def test_get_tracing_status_local_overrides_shared(tmp_path):
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
settings_path = claude_dir / "settings.json"
with open(settings_path, "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "true"}}, f)
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "false"}}, f)
status = get_tracing_status(settings_path)
assert status.enabled is False
def test_get_tracing_status_from_local_only(tmp_path):
claude_dir = tmp_path / ".claude"
claude_dir.mkdir(parents=True, exist_ok=True)
settings_path = claude_dir / "settings.json"
with open(claude_dir / "settings.local.json", "w") as f:
json.dump({"env": {MLFLOW_TRACING_ENABLED: "true"}}, f)
status = get_tracing_status(settings_path)
assert status.enabled is True
def test_get_env_var_default_when_not_found(tmp_path, monkeypatch):
# Ensure OS env var is not set
monkeypatch.delenv(MLFLOW_TRACING_ENABLED, raising=False)
# Create empty settings file in .claude directory
claude_settings_path = tmp_path / ".claude" / "settings.json"
claude_settings_path.parent.mkdir(parents=True, exist_ok=True)
with open(claude_settings_path, "w") as f:
json.dump({}, f)
# Change to temp directory so .claude/settings.json is found
monkeypatch.chdir(tmp_path)
result = get_env_var(MLFLOW_TRACING_ENABLED, "default_value")
assert result == "default_value"
def test_get_tracing_status_enabled(temp_settings_path):
# Create settings with tracing enabled
config_data = {"env": {MLFLOW_TRACING_ENABLED: "true"}}
with open(temp_settings_path, "w") as f:
json.dump(config_data, f)
status = get_tracing_status(temp_settings_path)
assert status.enabled is True
assert hasattr(status, "tracking_uri")
def test_get_tracing_status_disabled(temp_settings_path):
# Create settings with tracing disabled
config_data = {"env": {MLFLOW_TRACING_ENABLED: "false"}}
with open(temp_settings_path, "w") as f:
json.dump(config_data, f)
status = get_tracing_status(temp_settings_path)
assert status.enabled is False
def test_get_tracing_status_no_config(tmp_path):
non_existent_path = tmp_path / "missing.json"
status = get_tracing_status(non_existent_path)
assert status.enabled is False
assert status.reason == "No configuration found"
def test_setup_environment_config_new_file(temp_settings_path):
tracking_uri = "test://localhost"
experiment_id = "123"
setup_environment_config(temp_settings_path, tracking_uri, experiment_id)
# Verify file was created
assert temp_settings_path.exists()
# Verify configuration contents
config = json.loads(temp_settings_path.read_text())
env_vars = config["env"]
assert env_vars[MLFLOW_TRACING_ENABLED] == "true"
assert env_vars["MLFLOW_TRACKING_URI"] == tracking_uri
assert env_vars["MLFLOW_EXPERIMENT_ID"] == experiment_id
def test_setup_environment_config_experiment_id_precedence(temp_settings_path):
# Create existing config with different experiment ID
existing_config = {
"env": {
MLFLOW_TRACING_ENABLED: "true",
"MLFLOW_EXPERIMENT_ID": "old_id",
"MLFLOW_TRACKING_URI": "old_uri",
}
}
with open(temp_settings_path, "w") as f:
json.dump(existing_config, f)
new_tracking_uri = "new://localhost"
new_experiment_id = "new_id"
setup_environment_config(temp_settings_path, new_tracking_uri, new_experiment_id)
# Verify configuration was updated
config = json.loads(temp_settings_path.read_text())
env_vars = config["env"]
assert env_vars[MLFLOW_TRACING_ENABLED] == "true"
assert env_vars["MLFLOW_TRACKING_URI"] == new_tracking_uri
assert env_vars["MLFLOW_EXPERIMENT_ID"] == new_experiment_id
def test_setup_environment_config_defaults_to_current_tracking_uri_and_default_experiment(
temp_settings_path, monkeypatch
):
monkeypatch.delenv("MLFLOW_TRACKING_URI", raising=False)
monkeypatch.delenv("MLFLOW_EXPERIMENT_ID", raising=False)
monkeypatch.delenv("MLFLOW_EXPERIMENT_NAME", raising=False)
monkeypatch.setattr("mlflow.get_tracking_uri", lambda: "file:///tmp/mlruns")
setup_environment_config(temp_settings_path)
config = json.loads(temp_settings_path.read_text())
env_vars = config["env"]
assert env_vars["MLFLOW_TRACKING_URI"] == "file:///tmp/mlruns"
assert env_vars["MLFLOW_EXPERIMENT_ID"] == "0"
def test_setup_environment_config_resolves_experiment_name_to_id(temp_settings_path, monkeypatch):
class DummyExperiment:
experiment_id = "456"
class DummyClient:
def __init__(self, tracking_uri):
assert tracking_uri == "http://localhost:5000"
def get_experiment_by_name(self, name):
assert name == "my-exp"
return DummyExperiment()
def create_experiment(self, name):
raise AssertionError("create_experiment should not be called when experiment exists")
monkeypatch.setattr("mlflow.tracking.client.MlflowClient", DummyClient)
setup_environment_config(
temp_settings_path,
tracking_uri="http://localhost:5000",
experiment_name="my-exp",
)
config = json.loads(temp_settings_path.read_text())
env_vars = config["env"]
assert env_vars["MLFLOW_TRACKING_URI"] == "http://localhost:5000"
assert env_vars["MLFLOW_EXPERIMENT_ID"] == "456"
assert env_vars["MLFLOW_EXPERIMENT_NAME"] == "my-exp"