Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sqlmesh/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,8 @@ def invalidate_environment(self, name: str, sync: bool = False) -> None:
be deleted asynchronously by the janitor process.
"""
name = Environment.sanitize_name(name)
if self.state_sync.get_environment(name) is None:
raise SQLMeshError(f"Environment '{name}' does not exist.")
self.state_sync.invalidate_environment(name)
if sync:
self._cleanup_environments(name=name)
Expand Down
14 changes: 14 additions & 0 deletions tests/core/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,20 @@ def test_invalidate_environment_no_sync_skips_cleanup(sushi_context, mocker: Moc
state_sync_mock.delete_expired_environments.assert_not_called()


def test_invalidate_environment_nonexistent_raises(sushi_context, mocker: MockerFixture) -> None:
"""Invalidating an environment that does not exist should error instead of
reporting success, so a mistyped name is caught rather than silently accepted."""
state_sync_mock = mocker.patch.object(
type(sushi_context), "state_sync", new_callable=mocker.PropertyMock
).return_value
state_sync_mock.get_environment.return_value = None

with pytest.raises(SQLMeshError, match="Environment 'doesnotexist' does not exist"):
sushi_context.invalidate_environment("doesnotexist")

state_sync_mock.invalidate_environment.assert_not_called()


@pytest.mark.slow
def test_plan_default_end(sushi_context_pre_scheduling: Context):
prod_plan_builder = sushi_context_pre_scheduling.plan_builder("prod")
Expand Down