zapretgui/tests/test_profile_strategy_state_guards.py
loop-uh bc95026147
All checks were successful
Zapret source guards / validate (push) Successful in 4s
Дать пресетам постоянный uid в SQL-таблицах и перевести профили на uid
В settings.sqlite3 появились настоящие таблицы: presets (uid pid:<uuid4>,
UNIQUE(scope, file_name)), preset_remote_sources (FK с каскадом) и
profile_identities (порядок реестра фиксируется колонкой position — на
него опирается резолвер полных дублей). Привязка пресета к источнику
держится за uid: переименование меняет только file_name, удаление
убирает привязку каскадом. Старые JSON-секции мигрируются лениво.

Попутно исправлен баг: оценки стратегий и мета папок профилей ключевались
только legacy-ключами name:/sig: и молча отбрасывали uid-ключи, которыми
рантайм давно прошивает профили; uid теперь принимается везде, а legacy-
записи переносятся на uid при resolve идентичности.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 02:14:48 +03:00

176 lines
6.6 KiB
Python

from __future__ import annotations
import copy
import unittest
from unittest.mock import Mock, patch
from profile.strategy_state import ProfileStrategyState, ProfileStrategyStateStore
class ProfileStrategyStateGuardTests(unittest.TestCase):
def test_clear_strategy_state_skips_write_when_strategy_is_already_absent(self) -> None:
data = {
"version": 1,
"profiles": {
"name:Speedtest": {
"strategies": {
"other_strategy": {
"favorite": False,
"rating": "work",
"updated_at": "2026-05-31T00:00:00Z",
},
},
},
},
}
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
Mock(side_effect=AssertionError("absent strategy state must not be written")),
),
):
ProfileStrategyStateStore().clear_strategy_state("name:Speedtest", "tls_fake")
def test_set_strategy_state_skips_write_when_state_is_unchanged(self) -> None:
data = {
"version": 1,
"profiles": {
"name:Speedtest": {
"strategies": {
"tls_fake": {
"favorite": True,
"rating": "work",
"updated_at": "2026-05-31T00:00:00Z",
},
},
},
},
}
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
Mock(side_effect=AssertionError("unchanged strategy state must not be written")),
),
):
state = ProfileStrategyStateStore().set_strategy_state(
"name:Speedtest",
"tls_fake",
rating="work",
favorite=True,
)
self.assertEqual(state, ProfileStrategyState(rating="work", favorite=True))
if __name__ == "__main__":
unittest.main()
class ProfileStrategyStateUidMigrationTests(unittest.TestCase):
def test_uid_keys_are_accepted(self) -> None:
data = {"version": 1, "profiles": {}}
writes = []
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
side_effect=lambda value: writes.append(value) or value,
),
):
store = ProfileStrategyStateStore()
store.set_strategy_state("uid:abc123", "fake_tls", rating="work")
self.assertEqual(len(writes), 1)
self.assertIn("uid:abc123", writes[0]["profiles"])
def test_migrate_moves_legacy_rows_to_uid(self) -> None:
data = {
"version": 1,
"profiles": {
"name:YouTube": {
"strategies": {"fake_tls": {"favorite": True, "rating": "work", "updated_at": "2026-01-01T00:00:00Z"}},
},
"uid:kept": {
"strategies": {"other": {"favorite": False, "rating": "notwork", "updated_at": "2026-01-01T00:00:00Z"}},
},
},
}
writes = []
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
side_effect=lambda value: writes.append(value) or value,
),
):
store = ProfileStrategyStateStore()
changed = store.migrate_profile_keys({"name:YouTube": "uid:ytb", "name:Absent": "uid:none"})
self.assertTrue(changed)
profiles = writes[0]["profiles"]
self.assertNotIn("name:YouTube", profiles)
self.assertTrue(profiles["uid:ytb"]["strategies"]["fake_tls"]["favorite"])
self.assertIn("uid:kept", profiles)
def test_migrate_existing_uid_row_wins(self) -> None:
data = {
"version": 1,
"profiles": {
"name:YouTube": {"strategies": {"a": {"favorite": True, "rating": "work", "updated_at": "2026-01-01T00:00:00Z"}}},
"uid:ytb": {"strategies": {"b": {"favorite": False, "rating": "notwork", "updated_at": "2026-01-02T00:00:00Z"}}},
},
}
writes = []
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
side_effect=lambda value: writes.append(value) or value,
),
):
store = ProfileStrategyStateStore()
changed = store.migrate_profile_keys({"name:YouTube": "uid:ytb"})
self.assertTrue(changed)
profiles = writes[0]["profiles"]
self.assertNotIn("name:YouTube", profiles)
# Существующая uid-запись не перезаписана legacy-данными.
self.assertEqual(list(profiles["uid:ytb"]["strategies"].keys()), ["b"])
def test_migrate_noop_without_legacy_rows(self) -> None:
data = {"version": 1, "profiles": {"uid:only": {"strategies": {}}}}
writes = []
with (
patch(
"profile.strategy_state.settings_store.get_profile_strategy_state_settings",
side_effect=lambda: copy.deepcopy(data),
),
patch(
"profile.strategy_state.settings_store.set_profile_strategy_state_settings",
side_effect=lambda value: writes.append(value) or value,
),
):
store = ProfileStrategyStateStore()
changed = store.migrate_profile_keys({"name:Ghost": "uid:ghost"})
self.assertFalse(changed)
self.assertEqual(writes, [])