diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ac5b69..6c0f361 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,7 @@ on: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: python-version: ["3.13"] @@ -39,8 +40,10 @@ jobs: uv run basedpyright - name: Run tests with coverage + env: + LANGSMITH_TRACING: "false" run: | - uv run pytest --cov=olive --cov=olive_client --cov-report=xml --cov-report=html --cov-report=term + uv run pytest -p no:anyio -p no:langsmith -v --cov=olive --cov=olive_client --cov-report=xml --cov-report=term - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 diff --git a/.gitignore b/.gitignore index 1ed1e4c..3a44589 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,6 @@ ehthumbs.db # Local environment variables .env.local .env.*.local + +# Temporal dev server database +.temporal.db diff --git a/olive/temporal/worker.py b/olive/temporal/worker.py index b88d4bd..6218e80 100644 --- a/olive/temporal/worker.py +++ b/olive/temporal/worker.py @@ -67,7 +67,11 @@ async def _get_client(self) -> Client: if tls_config is not None: connect_kwargs["tls"] = tls_config - # Temporal Cloud requires API key auth; use data plane address with tls. + # Temporal Cloud always requires TLS, even without mTLS client certs + if temporal_config.is_cloud and "tls" not in connect_kwargs: + connect_kwargs["tls"] = True + + # Temporal Cloud API key auth if temporal_config.is_cloud and temporal_config.cloud_api_key: connect_kwargs.setdefault("rpc_metadata", {}) connect_kwargs["rpc_metadata"]["authorization"] = f"Bearer {temporal_config.cloud_api_key}" diff --git a/tests/test_cli.py b/tests/test_cli.py index 6b409fe..76cbdad 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -19,7 +19,7 @@ start_temporal_dev_server, version, ) -from olive.config import OliveConfig +from olive.config import OliveConfig, TemporalConfig runner = CliRunner() @@ -83,9 +83,16 @@ def test_init_command(tmp_path): assert "Files already exist" in result.output +def _temporal_enabled_config(**overrides): + """Return an OliveConfig with temporal explicitly enabled.""" + temporal_kwargs = {"enabled": True, **overrides} + return OliveConfig(temporal=TemporalConfig(**temporal_kwargs)) + + def test_dev_command(): """Test dev command.""" with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), mock.patch("olive.cli.check_temporal_running", return_value=True), mock.patch("olive.cli.TemporalWorker") as mock_worker_class, mock.patch("uvicorn.run") as mock_uvicorn, @@ -109,6 +116,7 @@ def test_dev_command(): def test_dev_command_starts_temporal(): """Test dev command starts Temporal if not running.""" with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), mock.patch("olive.cli.check_temporal_running") as mock_check, mock.patch("olive.cli.start_temporal_dev_server") as mock_start, mock.patch("olive.cli.TemporalWorker") as mock_worker_class, @@ -135,6 +143,7 @@ def test_dev_command_starts_temporal(): def test_dev_command_temporal_timeout(): """Test dev command exits if Temporal doesn't start.""" with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), mock.patch("olive.cli.check_temporal_running", return_value=False), mock.patch("olive.cli.start_temporal_dev_server") as mock_start, mock.patch("time.sleep"), @@ -149,6 +158,7 @@ def test_dev_command_temporal_timeout(): def test_dev_command_cleanup(): """Test dev command cleanup on exit.""" with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), mock.patch("olive.cli.check_temporal_running") as mock_check, mock.patch("olive.cli.start_temporal_dev_server") as mock_start, mock.patch("olive.cli.TemporalWorker") as mock_worker_class, @@ -177,7 +187,11 @@ def test_dev_command_cleanup(): def test_serve_command(): """Test serve command.""" - with mock.patch("olive.cli.TemporalWorker") as mock_worker_class, mock.patch("uvicorn.run") as mock_uvicorn: + with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), + mock.patch("olive.cli.TemporalWorker") as mock_worker_class, + mock.patch("uvicorn.run") as mock_uvicorn, + ): mock_worker = mock.Mock() mock_worker_class.return_value = mock_worker @@ -201,7 +215,11 @@ def test_serve_command(): def test_serve_command_cleanup(): """Test serve command cleanup on exit.""" - with mock.patch("olive.cli.TemporalWorker") as mock_worker_class, mock.patch("uvicorn.run") as mock_uvicorn: + with ( + mock.patch("olive.cli.OliveConfig.from_file", return_value=_temporal_enabled_config()), + mock.patch("olive.cli.TemporalWorker") as mock_worker_class, + mock.patch("uvicorn.run") as mock_uvicorn, + ): mock_worker = mock.Mock() mock_worker_class.return_value = mock_worker @@ -345,7 +363,7 @@ def test_main_module(): # Run the script - result = subprocess.run([sys.executable, "-c", test_script], capture_output=True, text=True) + result = subprocess.run([sys.executable, "-c", test_script], capture_output=True, text=True, timeout=10) # Check result if result.returncode != 0: diff --git a/tests/test_init.py b/tests/test_init.py index d6c162f..3d9f055 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -9,7 +9,7 @@ def test_version(): """Test version is defined.""" - assert __version__ == "1.3.2" + assert __version__ == "1.4.2" def test_run_dev():