File size: 3,223 Bytes
51e84d2
 
 
 
 
 
 
 
fc1dcbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# License: Apache-2.0 License
# Created by: Patrick Lumbantobing, VertoX-AI
# Copyright (c) 2026 VertoX-AI. All rights reserved.
#
# This work is licensed under the Apache-2.0 License.
# To view a copy of this license, visit
# https://www.apache.org/licenses/LICENSE-2.0

from __future__ import annotations

from pathlib import Path

import pytest

from speech_text_data_aligners.core.errors import ConfigurationError
from speech_text_data_aligners.runtime.artifacts import ArtifactPolicy, workspace


def test_workspace_never_retains_and_removes_temporary_path(tmp_path: Path) -> None:
    temp_root = tmp_path / "temp"
    with workspace(run_id="run", temporary_root=temp_root) as state:
        state.path.joinpath("detail.txt").write_text("detail", encoding="utf-8")
        active_path = state.path
        assert active_path.is_dir()
    assert not active_path.exists()
    assert state.retained_path is None


def test_workspace_always_retains_copy(tmp_path: Path) -> None:
    retention = tmp_path / "keep"
    with workspace(
        run_id="run", policy=ArtifactPolicy.ALWAYS, retention_root=retention
    ) as state:
        state.path.joinpath("detail.txt").write_text("detail", encoding="utf-8")
    assert state.retained_path == retention / "run"
    assert (retention / "run" / "detail.txt").read_text(encoding="utf-8") == "detail"


def test_workspace_on_failure_handles_marked_and_raised_failures(
    tmp_path: Path,
) -> None:
    retention = tmp_path / "keep"
    with workspace(
        run_id="marked", policy=ArtifactPolicy.ON_FAILURE, retention_root=retention
    ) as marked:
        marked.mark_failed()
    assert marked.retained_path == retention / "marked"

    with (
        pytest.raises(ValueError, match="boom"),
        workspace(
            run_id="raised", policy=ArtifactPolicy.ON_FAILURE, retention_root=retention
        ) as raised,
    ):
        raised.path.joinpath("evidence").write_text("x", encoding="utf-8")
        raise ValueError("boom")
    assert (retention / "raised" / "evidence").exists()


def test_workspace_on_failure_does_not_retain_success(tmp_path: Path) -> None:
    retention = tmp_path / "keep"
    with workspace(
        run_id="ok", policy=ArtifactPolicy.ON_FAILURE, retention_root=retention
    ) as state:
        assert state.path.exists()
    assert state.retained_path is None
    assert not retention.exists()


@pytest.mark.parametrize("run_id", ["", ".", "..", "a/b"])
def test_workspace_rejects_unsafe_ids(tmp_path: Path, run_id: str) -> None:
    with (
        pytest.raises(ConfigurationError),
        workspace(run_id=run_id, temporary_root=tmp_path),
    ):
        pass


def test_workspace_requires_retention_root() -> None:
    with (
        pytest.raises(ConfigurationError, match="retention_root"),
        workspace(run_id="run", policy=ArtifactPolicy.ALWAYS),
    ):
        pass


def test_workspace_refuses_to_overwrite_retained_directory(tmp_path: Path) -> None:
    retention = tmp_path / "keep"
    (retention / "run").mkdir(parents=True)
    with (
        pytest.raises(ConfigurationError, match="already exists"),
        workspace(run_id="run", policy=ArtifactPolicy.ALWAYS, retention_root=retention),
    ):
        pass