From 94d35f3914515807e37ea749e29c516e42669ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 31 Jul 2026 22:32:00 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20code=20review=20#2=20=E2=80=94=20=5Fcfg.?= =?UTF-8?q?DELAY=20+=20VERSION=20=D0=B2=20config/loader=20+=20=D0=BC=D1=91?= =?UTF-8?q?=D1=80=D1=82=D0=B2=D1=8B=D0=B5=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 23 +++++++++++++++++++---- site/app.py | 5 +++-- site/config/loader.py | 11 +++++++++-- site/routes/mock_routes.py | 5 ++--- site/routes/operations_routes.py | 7 +++---- site/routes/root.py | 13 ++++++------- site/routes/run.py | 9 +++++---- site/state_machine.py | 2 +- 8 files changed, 48 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ae9cdff..47efd6a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# polygon v0.2.0 +# polygon v0.2.2 Эмулятор REST API облачной платформы Nubes для интеграционных тестов app-autotest. @@ -14,12 +14,27 @@ polygon/ │ ├── test_converter.py # 10 юнит-тестов from_stands.py │ └── test_state_machine.py # 9 юнит-тестов state_machine.py └── site/ - ├── app.py # Flask (17 эндпоинтов) + ├── app.py # Flask: только blueprint'ы + app.run() (57 строк) + ├── routes/ # 6 blueprint-файлов по доменам + │ ├── root.py # /health, / + │ ├── services_routes.py# /api/v1/svc/services + │ ├── instances_routes.py# /api/v1/svc/instances + │ ├── operations_routes.py# /api/v1/svc/instanceOperations/* + │ ├── run.py # /api/v1/svc/instanceOperations//run + │ └── mock_routes.py # /api/v1/svc/_mock/* ├── mock_state.py # MockState: instances, operations, op_params ├── state_machine.py # apply_effect() — мутация состояния - ├── config_loader.py # загрузка services/*.yaml + ├── config/ + │ └── loader.py # загрузка YAML + SERVICES/OPS_INDEX/DELAY/VERSION + ├── utils/ + │ ├── now.py # now() — UTC ISO с 'Z' + │ └── pluralize.py # pluralize() — плюрализация ├── from_stands.py # конвертер STANDS YAML → polygon config - └── services/ # 37 YAML-конфигов (сгенерированы) + ├── static/ + │ └── style.css # тёмная тема + ├── templates/ + │ └── index.html # Jinja2-шаблон + └── services/ # YAML-конфиги (сгенерированы from_stands.py) ``` ⛔ **Ровно 1 gunicorn-воркер.** Состояние в памяти, не shared. diff --git a/site/app.py b/site/app.py index 4fe6765..53921d7 100644 --- a/site/app.py +++ b/site/app.py @@ -1,5 +1,5 @@ """ -polygon v0.2.1 — Mock Nubes API. +polygon v0.2.2 — Mock Nubes API. Эмулятор REST API облачной платформы Nubes для интеграционных тестов. Blueprint'ы (каждый — отдельный файл в routes/): @@ -35,7 +35,8 @@ from routes.operations_routes import bp as operations_bp from routes.run import bp as run_bp from routes.mock_routes import bp as mock_bp -VERSION = "0.2.2" +# Версия — единый источник правды в config/loader.py +from config.loader import VERSION # Flask-приложение с Jinja2-шаблонами и статикой app = Flask(__name__, template_folder="templates", static_folder="static") diff --git a/site/config/loader.py b/site/config/loader.py index f4f55b2..7bc9420 100644 --- a/site/config/loader.py +++ b/site/config/loader.py @@ -2,10 +2,11 @@ config/loader.py — загрузка сервисов и глобальные конфигурационные переменные. Этот модуль загружает все YAML-конфиги сервисов при первом импорте и хранит их -как модульные переменные. Все routes/*.py импортируют SERVICES, OPS_INDEX, DELAY -отсюда — без дублирования загрузки и без циклических импортов. +как модульные переменные. Все routes/*.py импортируют SERVICES, OPS_INDEX, DELAY, +VERSION отсюда — без дублирования загрузки и без циклических импортов. Переменные модуля (вычисляются ОДИН раз при старте): + VERSION — str, версия полигона (единая для app.py и root.py) SERVICES — {service_id: service_def} все сервисы OPS_INDEX — {svcOperationId: service_def} поиск сервиса по ID операции DELAY — float, задержка операции из MOCK_OP_DELAY (по умолчанию 0.1) @@ -64,4 +65,10 @@ SERVICES, OPS_INDEX = _load_all() # Задержка операции в секундах (для синхронного sleep в /run). # Меняется на лету через POST /_mock/delay/ — см. mock_routes.py. +# ⛔ Импортировать ТОЛЬКО через `import config.loader as _cfg` и читать `_cfg.DELAY` — +# иначе float копируется по значению и не реагирует на изменение. DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1")) + +# Версия полигона — единый источник правды для app.py и routes/root.py. +# Меняется при КАЖДОМ изменении кода. +VERSION = "0.2.2" diff --git a/site/routes/mock_routes.py b/site/routes/mock_routes.py index 5ee2c7a..44aeb76 100644 --- a/site/routes/mock_routes.py +++ b/site/routes/mock_routes.py @@ -11,8 +11,7 @@ Blueprint "mock" с префиксом /api/v1/svc/_mock. from flask import Blueprint, jsonify import mock_state -from config.loader import SERVICES, DELAY as _DELAY -import config.loader as _cfg # для модификации модульной переменной DELAY +import config.loader as _cfg # для чтения/записи модульных переменных DELAY, SERVICES bp = Blueprint("mock", __name__, url_prefix="/api/v1/svc/_mock") @@ -73,7 +72,7 @@ def mock_services(): не дёргая реальный /api/v1/svc/services. """ result = {} - for svc_id, svc_def in SERVICES.items(): + for svc_id, svc_def in _cfg.SERVICES.items(): result[str(svc_id)] = { "name": svc_def.get("name", ""), "displayName": svc_def.get("service_display_name", ""), diff --git a/site/routes/operations_routes.py b/site/routes/operations_routes.py index ef82aa0..261502b 100644 --- a/site/routes/operations_routes.py +++ b/site/routes/operations_routes.py @@ -8,10 +8,9 @@ Blueprint "operations" с префиксом /api/v1/svc. POST /instanceOperationCfsParams — установить параметр GET /instanceOperations//validate-cfs — пустое тело, 200 -ВАЖНО: порядок маршрутов в蓝图 критичен. - /instanceOperations/default/ ДОЛЖЕН быть выше - /instanceOperations/ -Иначе Flask распарсит "default" как uid и уйдёт не в тот обработчик. +Порядок маршрутов: default/ (целое число) и (строка UUID) +различаются Flask/Werkzeug автоматически — конфликта нет, но default размещён +выше для ясности. """ from flask import Blueprint, jsonify, make_response, request diff --git a/site/routes/root.py b/site/routes/root.py index a03420c..9385875 100644 --- a/site/routes/root.py +++ b/site/routes/root.py @@ -8,11 +8,10 @@ Blueprint "root" регистрируется в app.py БЕЗ url_prefix. from flask import Blueprint, render_template import mock_state -from config.loader import SERVICES, DELAY -from utils.now import now as _now +import config.loader as _cfg -# Версия — показывается на HTML-странице и в healthcheck (опционально) -VERSION = "0.2.2" +# Версия — из config/loader.py (единый источник правды) +VERSION = _cfg.VERSION # Blueprint без префикса — роуты /health и / будут на корне домена bp = Blueprint("root", __name__) @@ -36,12 +35,12 @@ def index(): текущую задержку операций. Использует Jinja2-шаблон templates/index.html и внешний CSS из static/style.css. """ - svc_count = len(SERVICES) + svc_count = len(_cfg.SERVICES) inst_count = len(mock_state.state.instances) return render_template( "index.html", - version=VERSION, + version=_cfg.VERSION, svc_count=svc_count, inst_count=inst_count, - delay=DELAY, + delay=_cfg.DELAY, ) diff --git a/site/routes/run.py b/site/routes/run.py index 4a40c75..5aaf142 100644 --- a/site/routes/run.py +++ b/site/routes/run.py @@ -14,7 +14,7 @@ from flask import Blueprint, jsonify import mock_state import state_machine -from config.loader import SERVICES, DELAY +import config.loader as _cfg from utils.now import now as _now bp = Blueprint("run", __name__, url_prefix="/api/v1/svc") @@ -48,12 +48,13 @@ def run_operation(uid): op["dtStart"] = _now() # Эмулируем задержку выполнения (по умолчанию 0.1с) - if DELAY > 0: - time.sleep(DELAY) + # ⛔ _cfg.DELAY — модульная переменная, может меняться через /_mock/delay + if _cfg.DELAY > 0: + time.sleep(_cfg.DELAY) # Применить эффект операции к состоянию инстанса # (create → running+params, delete → удалить, modify → мерж params, ...) - state_machine.apply_effect(uid, mock_state.state, SERVICES) + state_machine.apply_effect(uid, mock_state.state, _cfg.SERVICES) # Фиксируем время завершения — операция выполнена успешно op["dtFinish"] = _now() diff --git a/site/state_machine.py b/site/state_machine.py index 4d134ce..171f438 100644 --- a/site/state_machine.py +++ b/site/state_machine.py @@ -29,7 +29,7 @@ def apply_effect(op_uid, mock_state, services): Args: op_uid — UUID операции mock_state — экземпляр MockState - services — {service_id: service_def} из config_loader + services — {service_id: service_def} из config/loader.py """ op = mock_state.operations.get(op_uid) if not op: