2026-09-08 03:43:49 +02:00
|
|
|
# retoor <retoor@molodetz.nl>
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from devplacepy.database import get_table, init_db
|
|
|
|
|
from devplacepy.services.containers import store
|
|
|
|
|
from devplacepy.utils import generate_uid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
|
def _init_db_containers_store():
|
|
|
|
|
init_db()
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _make_instance(project_uid, deleted_at=None):
|
|
|
|
|
uid = generate_uid()
|
|
|
|
|
get_table("instances").insert(
|
|
|
|
|
{
|
|
|
|
|
"uid": uid,
|
|
|
|
|
"project_uid": project_uid,
|
|
|
|
|
"deleted_at": deleted_at,
|
|
|
|
|
"deleted_by": None,
|
|
|
|
|
"name": f"inst-{uid[:8]}",
|
|
|
|
|
"status": "running",
|
|
|
|
|
"desired_state": "running",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
return uid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_gc_workspaces_removes_directories_with_no_live_instance(
|
|
|
|
|
local_db, tmp_path, monkeypatch
|
|
|
|
|
):
|
|
|
|
|
monkeypatch.setattr("devplacepy.config.CONTAINER_WORKSPACES_DIR", tmp_path)
|
|
|
|
|
active_project = "gcws-active-project"
|
|
|
|
|
orphan_project = "gcws-orphan-project"
|
|
|
|
|
(tmp_path / active_project).mkdir()
|
|
|
|
|
(tmp_path / orphan_project).mkdir()
|
2026-09-08 05:07:31 +02:00
|
|
|
(tmp_path / orphan_project / "leftover.bin").write_bytes(b"x" * 42)
|
2026-09-08 03:43:49 +02:00
|
|
|
_make_instance(active_project)
|
|
|
|
|
|
2026-09-08 05:07:31 +02:00
|
|
|
removed, freed = store.gc_workspaces()
|
2026-09-08 03:43:49 +02:00
|
|
|
|
|
|
|
|
assert removed == 1
|
2026-09-08 05:07:31 +02:00
|
|
|
assert freed == 42
|
2026-09-08 03:43:49 +02:00
|
|
|
assert (tmp_path / active_project).exists()
|
|
|
|
|
assert not (tmp_path / orphan_project).exists()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_gc_workspaces_ignores_soft_deleted_instances(local_db, tmp_path, monkeypatch):
|
|
|
|
|
monkeypatch.setattr("devplacepy.config.CONTAINER_WORKSPACES_DIR", tmp_path)
|
|
|
|
|
project = "gcws-soft-deleted-project"
|
|
|
|
|
(tmp_path / project).mkdir()
|
|
|
|
|
_make_instance(project, deleted_at="2020-01-01T00:00:00+00:00")
|
|
|
|
|
|
2026-09-08 05:07:31 +02:00
|
|
|
removed, freed = store.gc_workspaces()
|
2026-09-08 03:43:49 +02:00
|
|
|
|
|
|
|
|
assert removed == 1
|
2026-09-08 05:07:31 +02:00
|
|
|
assert freed == 0
|
2026-09-08 03:43:49 +02:00
|
|
|
assert not (tmp_path / project).exists()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_gc_workspaces_dry_run_changes_nothing(local_db, tmp_path, monkeypatch):
|
|
|
|
|
monkeypatch.setattr("devplacepy.config.CONTAINER_WORKSPACES_DIR", tmp_path)
|
|
|
|
|
orphan_project = "gcws-dry-run-project"
|
|
|
|
|
(tmp_path / orphan_project).mkdir()
|
2026-09-08 05:07:31 +02:00
|
|
|
(tmp_path / orphan_project / "leftover.bin").write_bytes(b"y" * 7)
|
2026-09-08 03:43:49 +02:00
|
|
|
|
2026-09-08 05:07:31 +02:00
|
|
|
removed, freed = store.gc_workspaces(dry_run=True)
|
2026-09-08 03:43:49 +02:00
|
|
|
|
|
|
|
|
assert removed == 1
|
2026-09-08 05:07:31 +02:00
|
|
|
assert freed == 7
|
2026-09-08 03:43:49 +02:00
|
|
|
assert (tmp_path / orphan_project).exists()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_gc_workspaces_missing_base_dir_is_a_noop(local_db, tmp_path, monkeypatch):
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
"devplacepy.config.CONTAINER_WORKSPACES_DIR", tmp_path / "does-not-exist"
|
|
|
|
|
)
|
2026-09-08 05:07:31 +02:00
|
|
|
assert store.gc_workspaces() == (0, 0)
|