Spaces:
Sleeping
Sleeping
| """Tests for the ace.tracing wrapper.""" | |
| from __future__ import annotations | |
| import os | |
| from unittest.mock import patch | |
| import pytest | |
| class TestConfigure: | |
| """Tests for ace.tracing.configure().""" | |
| def test_configure_sets_tracking_uri_and_token(self) -> None: | |
| with patch.dict(os.environ, {}, clear=False): | |
| from kayba_tracing._wrapper import configure | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| configure(api_key="kb-test-key") | |
| mock_mlflow.set_tracking_uri.assert_called_once_with( | |
| "https://use.kayba.ai/api/mlflow" | |
| ) | |
| assert os.environ["MLFLOW_TRACKING_TOKEN"] == "kb-test-key" | |
| def test_configure_custom_base_url(self) -> None: | |
| with patch.dict(os.environ, {}, clear=False): | |
| from kayba_tracing._wrapper import configure | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| configure( | |
| api_key="kb-test-key", | |
| base_url="https://custom.example.com", | |
| ) | |
| mock_mlflow.set_tracking_uri.assert_called_once_with( | |
| "https://custom.example.com/api/mlflow" | |
| ) | |
| def test_configure_strips_trailing_slash(self) -> None: | |
| with patch.dict(os.environ, {}, clear=False): | |
| from kayba_tracing._wrapper import configure | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| configure( | |
| api_key="kb-test-key", | |
| base_url="https://custom.example.com/", | |
| ) | |
| mock_mlflow.set_tracking_uri.assert_called_once_with( | |
| "https://custom.example.com/api/mlflow" | |
| ) | |
| def test_configure_reads_api_key_from_env(self) -> None: | |
| with patch.dict(os.environ, {"KAYBA_API_KEY": "kb-env-key"}, clear=False): | |
| from kayba_tracing._wrapper import configure | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| configure() | |
| assert os.environ["MLFLOW_TRACKING_TOKEN"] == "kb-env-key" | |
| def test_configure_reads_base_url_from_env(self) -> None: | |
| with patch.dict( | |
| os.environ, | |
| { | |
| "KAYBA_API_KEY": "kb-key", | |
| "KAYBA_API_URL": "https://env.example.com", | |
| }, | |
| clear=False, | |
| ): | |
| from kayba_tracing._wrapper import configure | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| configure() | |
| mock_mlflow.set_tracking_uri.assert_called_once_with( | |
| "https://env.example.com/api/mlflow" | |
| ) | |
| def test_configure_raises_without_api_key(self) -> None: | |
| with patch.dict(os.environ, {"KAYBA_API_KEY": ""}, clear=False): | |
| from kayba_tracing._wrapper import configure | |
| with pytest.raises(ValueError, match="No API key provided"): | |
| configure() | |
| def test_experiment_is_alias_for_folder(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| with patch.dict(os.environ, {}, clear=False): | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| w.configure(api_key="kb-key", experiment="my-project") | |
| assert w._folder == "my-project" | |
| def test_folder_takes_precedence_over_experiment(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| with patch.dict(os.environ, {}, clear=False): | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| w.configure( | |
| api_key="kb-key", | |
| experiment="from-experiment", | |
| folder="from-folder", | |
| ) | |
| assert w._folder == "from-folder" | |
| def test_configure_sets_folder(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| with patch.dict(os.environ, {}, clear=False): | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| w.configure(api_key="kb-key", folder="my-folder") | |
| assert w._folder == "my-folder" | |
| def test_configure_clears_folder_when_none(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| with patch.dict(os.environ, {}, clear=False): | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| w.configure(api_key="kb-key", folder="old") | |
| w.configure(api_key="kb-key") | |
| assert w._folder is None | |
| class TestSanitizeFolder: | |
| """Tests for folder name sanitization.""" | |
| def test_strips_html_tags(self) -> None: | |
| from kayba_tracing._wrapper import _sanitize_folder | |
| assert _sanitize_folder('<script>alert("xss")</script>') == "alertxss" | |
| def test_strips_control_characters(self) -> None: | |
| from kayba_tracing._wrapper import _sanitize_folder | |
| assert _sanitize_folder("folder\x00\x1f\nname") == "foldername" | |
| def test_allows_safe_characters(self) -> None: | |
| from kayba_tracing._wrapper import _sanitize_folder | |
| assert _sanitize_folder("my-folder/sub_dir 2.0") == "my-folder/sub_dir 2.0" | |
| def test_truncates_long_names(self) -> None: | |
| from kayba_tracing._wrapper import _sanitize_folder | |
| assert len(_sanitize_folder("a" * 500)) == 256 | |
| def test_strips_sql_injection_chars(self) -> None: | |
| from kayba_tracing._wrapper import _sanitize_folder | |
| assert _sanitize_folder("folder'; DROP TABLE--") == "folder DROP TABLE--" | |
| def test_configure_sanitizes_folder(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| with patch.dict(os.environ, {}, clear=False): | |
| with patch("kayba_tracing._wrapper.mlflow"): | |
| w.configure(api_key="kb-key", folder='<img onerror="xss">') | |
| # Entire input is an HTML tag, stripped to empty string | |
| assert w._folder is None | |
| def test_set_folder_sanitizes(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w.set_folder("<b>bold</b>") | |
| assert w.get_folder() == "bold" | |
| class TestFolder: | |
| """Tests for set_folder / get_folder.""" | |
| def test_set_and_get_folder(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w.set_folder("production") | |
| assert w.get_folder() == "production" | |
| def test_clear_folder(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w.set_folder("production") | |
| w.set_folder(None) | |
| assert w.get_folder() is None | |
| def test_inject_folder_tag(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w._folder = "my-folder" | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| w._inject_folder_tag() | |
| mock_mlflow.update_current_trace.assert_called_once_with( | |
| tags={"kayba.folder": "my-folder"} | |
| ) | |
| def test_inject_folder_tag_noop_when_none(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w._folder = None | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| w._inject_folder_tag() | |
| mock_mlflow.update_current_trace.assert_not_called() | |
| class TestTraceDecorator: | |
| """Tests for the trace decorator wrapper.""" | |
| def test_trace_wraps_function(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w._folder = "test-folder" | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| # Make mlflow.trace return a passthrough decorator | |
| mock_mlflow.trace.side_effect = lambda fn=None, **kw: ( | |
| fn if fn is not None else (lambda f: f) | |
| ) | |
| def my_func(x: int) -> int: | |
| return x + 1 | |
| result = my_func(5) | |
| assert result == 6 | |
| mock_mlflow.update_current_trace.assert_called_with( | |
| tags={"kayba.folder": "test-folder"} | |
| ) | |
| def test_trace_with_params(self) -> None: | |
| import kayba_tracing._wrapper as w | |
| w._folder = None | |
| with patch("kayba_tracing._wrapper.mlflow") as mock_mlflow: | |
| mock_mlflow.trace.return_value = lambda fn: fn | |
| def my_func() -> str: | |
| return "ok" | |
| result = my_func() | |
| assert result == "ok" | |
| mock_mlflow.trace.assert_called_once_with(name="custom", span_type="LLM") | |
| # No folder set, so no tag injection | |
| mock_mlflow.update_current_trace.assert_not_called() | |
| class TestReExports: | |
| """Verify utility re-exports.""" | |
| def test_enable_calls_mlflow(self) -> None: | |
| from kayba_tracing._wrapper import enable | |
| with patch("kayba_tracing._wrapper.mlflow.tracing.enable") as mock: | |
| enable() | |
| mock.assert_called_once() | |
| def test_disable_calls_mlflow(self) -> None: | |
| from kayba_tracing._wrapper import disable | |
| with patch("kayba_tracing._wrapper.mlflow.tracing.disable") as mock: | |
| disable() | |
| mock.assert_called_once() | |
| class TestPackageInit: | |
| """Verify the public __init__ exports.""" | |
| def test_all_exports(self) -> None: | |
| import ace.tracing | |
| expected = { | |
| "configure", | |
| "disable", | |
| "enable", | |
| "get_folder", | |
| "get_trace", | |
| "search_traces", | |
| "set_folder", | |
| "start_span", | |
| "trace", | |
| } | |
| assert set(ace.tracing.__all__) == expected | |