Files
polygon/tests/test_converter.py

183 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Tests for from_stands.py — конвертер STANDS YAML → polygon config.
"""
import os
import tempfile
import pytest
import yaml
# Добавляем site/ в path для импорта from_stands
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "site"))
import from_stands
@pytest.fixture
def dummy_yaml():
"""Минимальный STANDS YAML для тестов."""
return {
"name": "dummy",
"service_id": 1,
"service_display_name": "Болванка",
"service_short_name": "dummy",
"lifecycle": {
"suspend_on_destroy_default": True,
"adopt_existing_on_create_default": False,
},
"operations": [
{
"name": "create",
"id": 18,
"kind": "instance",
"action": "create",
"params": [
{
"id": 242,
"code": "resourceRealm",
"data_type": "string",
"required": True,
"default": "dummy",
"value_list": ["dummy"],
},
{
"id": 198,
"code": "durationMs",
"data_type": "integer >= 0",
"required": True,
"default": "0",
},
],
},
{"name": "delete", "id": 71, "kind": "instance", "action": "delete"},
],
}
@pytest.fixture
def pg_yaml():
"""STANDS YAML с subresources для тестов."""
return {
"name": "postgres",
"service_id": 90,
"service_display_name": "PostgreSQL",
"service_short_name": "postgres",
"lifecycle": {
"suspend_on_destroy_default": True,
"adopt_existing_on_create_default": False,
},
"operations": [
{
"name": "create",
"id": 19,
"kind": "instance",
"action": "create",
"params": [
{
"id": 788,
"code": "clusterConfiguration",
"data_type": "map-fixed",
"required": True,
"sub_params": [
{"id": 106, "code": "replicas", "data_type": "integer > 0", "required": True, "default": "1"},
{"id": 107, "code": "disk", "data_type": "integer > 0", "required": True, "default": "10"},
],
},
],
},
{"name": "create_user", "id": 44, "kind": "subresource", "action": "create"},
{"name": "delete_user", "id": 45, "kind": "subresource", "action": "delete"},
{"name": "create_database", "id": 46, "kind": "subresource", "action": "create"},
{"name": "delete_database", "id": 47, "kind": "subresource", "action": "delete"},
],
}
class TestConvertService:
"""Тесты конвертации одного сервиса."""
def test_basic_fields(self, dummy_yaml):
"""Поля верхнего уровня переносятся 1:1."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
assert cfg["name"] == "dummy"
assert cfg["service_id"] == 1
assert cfg["service_display_name"] == "Болванка"
def test_lifecycle(self, dummy_yaml):
"""lifecycle конвертируется в camelCase."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
assert cfg["lifecycle"]["suspendOnDestroyDefault"] is True
assert cfg["lifecycle"]["adoptExistingOnCreateDefault"] is False
def test_operations_count(self, dummy_yaml):
"""Количество операций совпадает."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
assert len(cfg["operations"]) == 2
def test_html_unescape(self, dummy_yaml):
"""HTML entities раскодируются: > → >."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
cfs = {p["svcOperationCfsParamId"]: p for p in cfg["cfsParams"]}
assert cfs[198]["dataType"] == "integer >= 0"
assert ">" not in cfs[198]["dataType"]
def test_value_list(self, dummy_yaml):
"""valueList конвертируется."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
cfs = {p["svcOperationCfsParamId"]: p for p in cfg["cfsParams"]}
assert cfs[242]["valueList"] == ["dummy"]
def test_state_params_from_create(self, dummy_yaml):
"""stateParams генерируются из create-операции."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
assert cfg["stateParams"]["resourceRealm"] == "dummy"
assert cfg["stateParams"]["durationMs"] == "0"
def test_data_descriptor_from_sub_params(self, pg_yaml):
"""map-fixed/sub_params → dataDescriptor."""
cfg = from_stands.convert_service_from_dict(pg_yaml)
cfs = {p["svcOperationCfsParamId"]: p for p in cfg["cfsParams"]}
dd = cfs[788]["dataDescriptor"]
assert "replicas" in dd
assert "disk" in dd
assert dd["replicas"]["dataType"] == "integer > 0"
assert dd["replicas"]["defaultValue"] == "1"
def test_state_out_subresources(self, pg_yaml):
"""stateOut генерируется из subresource-операций."""
cfg = from_stands.convert_service_from_dict(pg_yaml)
assert "users" in cfg["stateOut"]
assert "databases" in cfg["stateOut"]
def test_cfs_params_by_op(self, dummy_yaml):
"""cfsParamsByOp связывает opId → список paramId."""
cfg = from_stands.convert_service_from_dict(dummy_yaml)
assert 18 in cfg["cfsParamsByOp"]
assert 242 in cfg["cfsParamsByOp"][18]
assert 198 in cfg["cfsParamsByOp"][18]
class TestFileRoundtrip:
"""Тесты записи/чтения YAML."""
def test_roundtrip(self, dummy_yaml):
"""Сгенерированный YAML можно записать и прочитать обратно."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
fname = f.name
try:
# Записать
with open(fname, "w") as f:
cfg = from_stands.convert_service_from_dict(dummy_yaml)
yaml.dump(cfg, f, allow_unicode=True, default_flow_style=False)
# Прочитать
with open(fname) as f:
loaded = yaml.safe_load(f)
assert loaded["name"] == "dummy"
assert len(loaded["cfsParams"]) == 2
finally:
os.unlink(fname)