File size: 4,148 Bytes
0f9caed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""Testy SettingsManager — validace, persistence, klasifikace polí."""


def test_defaults_from_env(settings_module, monkeypatch):
    monkeypatch.setenv("MODEL_PRIMARY", "org/env-model")
    monkeypatch.setenv("MAX_STEPS", "42")
    s = settings_module.Settings()
    assert s.model == "org/env-model"
    assert s.max_steps == 42
    assert s.tensor_parallel_size == 4
    assert s.gpu_memory_utilization == 0.92


def test_update_instant_field(settings_module):
    mgr = settings_module.SettingsManager()
    applied, reload_needed, errors = mgr.update({"max_steps": "40"})
    assert applied == {"max_steps": 40}
    assert reload_needed is False
    assert errors == {}
    assert mgr.get().max_steps == 40
    assert mgr.revision == 1


def test_update_engine_field_flags_reload(settings_module):
    mgr = settings_module.SettingsManager()
    applied, reload_needed, errors = mgr.update({"model": "org/new-model"})
    assert applied == {"model": "org/new-model"}
    assert reload_needed is True
    assert errors == {}


def test_no_change_no_revision_bump(settings_module):
    mgr = settings_module.SettingsManager()
    current = mgr.get().max_steps
    applied, reload_needed, _ = mgr.update({"max_steps": current})
    assert applied == {}
    assert reload_needed is False
    assert mgr.revision == 0


def test_validation_errors(settings_module):
    mgr = settings_module.SettingsManager()
    applied, _, errors = mgr.update({
        "gpu_memory_utilization": "1.5",
        "tensor_parallel_size": "16",
        "agent_mode": "dual",
        "runner_url": "ftp://spatne",
        "neexistujici_pole": "x",
        "max_output_tokens": "abc",
    })
    assert applied == {}
    assert set(errors) == {"gpu_memory_utilization", "tensor_parallel_size",
                           "agent_mode", "runner_url", "neexistujici_pole",
                           "max_output_tokens"}


def test_bool_and_float_coercion(settings_module):
    mgr = settings_module.SettingsManager()
    applied, reload_needed, errors = mgr.update({
        "enforce_eager": "true",
        "temperature": "0.7",
        "enable_prefix_caching": False,
    })
    assert errors == {}
    assert applied["enforce_eager"] is True
    assert applied["temperature"] == 0.7
    assert applied["enable_prefix_caching"] is False
    assert reload_needed is True  # oba bool patří mezi engine pole


def test_persistence_roundtrip(settings_module, env):
    mgr = settings_module.SettingsManager()
    mgr.update({"model": "org/persisted", "max_steps": 55})
    # nový manager se stejnou cestou načte uložené hodnoty
    mgr2 = settings_module.SettingsManager(path=mgr.path)
    assert mgr2.get().model == "org/persisted"
    assert mgr2.get().max_steps == 55


def test_masking_secrets(settings_module):
    mgr = settings_module.SettingsManager()
    mgr.update({"runner_token": "super-secret"})
    data = mgr.as_dict()
    assert data["runner_token"] == "********"
    # maskovaná hodnota poslaná zpět z UI nesmí přepsat skutečný token
    applied, _, _ = mgr.update({"runner_token": "********"})
    assert applied == {}
    assert mgr.get().runner_token == "super-secret"


def test_download_dir_validation(settings_module):
    mgr = settings_module.SettingsManager()
    # relativní cesta => chyba
    applied, _, errors = mgr.update({"download_dir": "relativni/cesta"})
    assert applied == {} and "download_dir" in errors
    # absolutní cesta => OK, jde o enginové pole (reload)
    applied, reload_needed, errors = mgr.update({"download_dir": "/data/models/"})
    assert errors == {}
    assert applied == {"download_dir": "/data/models"}  # trailing / oříznut
    assert reload_needed is True
    # prázdné = auto => OK
    applied, _, errors = mgr.update({"download_dir": ""})
    assert errors == {} and applied == {"download_dir": ""}


def test_corrupted_persist_file_ignored(settings_module, env):
    path = env["tmp"] / "settings.json"
    path.write_text("{ rozbité json ", encoding="utf-8")
    mgr = settings_module.SettingsManager(path=path)
    assert mgr.get().tensor_parallel_size == 4  # defaulty přežily