mcp-proxy-adapter 2.1.2__py3-none-any.whl → 2.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/METADATA +1 -1
  2. mcp_proxy_adapter-2.1.3.dist-info/RECORD +18 -0
  3. mcp_proxy_adapter-2.1.3.dist-info/top_level.txt +1 -0
  4. docs/README.md +0 -172
  5. docs/README_ru.md +0 -172
  6. docs/architecture.md +0 -251
  7. docs/architecture_ru.md +0 -343
  8. docs/command_development.md +0 -250
  9. docs/command_development_ru.md +0 -593
  10. docs/deployment.md +0 -251
  11. docs/deployment_ru.md +0 -1298
  12. docs/examples.md +0 -254
  13. docs/examples_ru.md +0 -401
  14. docs/mcp_proxy_adapter.md +0 -251
  15. docs/mcp_proxy_adapter_ru.md +0 -405
  16. docs/quickstart.md +0 -251
  17. docs/quickstart_ru.md +0 -397
  18. docs/testing.md +0 -255
  19. docs/testing_ru.md +0 -469
  20. docs/validation_ru.md +0 -287
  21. examples/analyze_config.py +0 -141
  22. examples/basic_integration.py +0 -161
  23. examples/docstring_and_schema_example.py +0 -60
  24. examples/extension_example.py +0 -60
  25. examples/help_best_practices.py +0 -67
  26. examples/help_usage.py +0 -64
  27. examples/mcp_proxy_client.py +0 -131
  28. examples/mcp_proxy_config.json +0 -175
  29. examples/openapi_server.py +0 -369
  30. examples/project_structure_example.py +0 -47
  31. examples/testing_example.py +0 -53
  32. mcp_proxy_adapter-2.1.2.dist-info/RECORD +0 -61
  33. mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +0 -5
  34. scripts/code_analyzer/code_analyzer.py +0 -328
  35. scripts/code_analyzer/register_commands.py +0 -446
  36. scripts/publish.py +0 -85
  37. tests/conftest.py +0 -12
  38. tests/test_adapter.py +0 -529
  39. tests/test_adapter_coverage.py +0 -274
  40. tests/test_basic_dispatcher.py +0 -169
  41. tests/test_command_registry.py +0 -328
  42. tests/test_examples.py +0 -32
  43. tests/test_mcp_proxy_adapter.py +0 -568
  44. tests/test_mcp_proxy_adapter_basic.py +0 -262
  45. tests/test_part1.py +0 -348
  46. tests/test_part2.py +0 -524
  47. tests/test_schema.py +0 -358
  48. tests/test_simple_adapter.py +0 -251
  49. {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/WHEEL +0 -0
  50. {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/licenses/LICENSE +0 -0
docs/testing_ru.md DELETED
@@ -1,469 +0,0 @@
1
- # Руководство по тестированию команд
2
-
3
- В этом руководстве описаны подходы и лучшие практики по тестированию команд, зарегистрированных в Command Registry.
4
-
5
- ## Почему важно тестировать команды
6
-
7
- Команды в Command Registry часто представляют собой ключевые бизнес-операции приложения. Их тестирование имеет следующие преимущества:
8
-
9
- 1. **Надёжность** - проверка работоспособности команд в различных условиях
10
- 2. **Документация** - тесты демонстрируют ожидаемое поведение команд
11
- 3. **Регрессия** - предотвращение появления регрессий при изменениях
12
- 4. **Рефакторинг** - возможность безопасно улучшать код команд
13
- 5. **Валидация** - проверка корректной обработки входных параметров и ошибок
14
-
15
- ## Уровни тестирования
16
-
17
- ### 1. Модульное тестирование (Unit Tests)
18
-
19
- Тестирование отдельных функций-команд в изоляции от других компонентов.
20
-
21
- ```python
22
- import pytest
23
- from myapp.commands.math_commands import add_numbers
24
-
25
- def test_add_numbers_basic():
26
- # Базовый сценарий
27
- result = add_numbers(5, 3)
28
- assert result == 8
29
-
30
- def test_add_numbers_negative():
31
- # Работа с отрицательными числами
32
- result = add_numbers(-5, 3)
33
- assert result == -2
34
-
35
- def test_add_numbers_zero():
36
- # Работа с нулями
37
- result = add_numbers(0, 0)
38
- assert result == 0
39
- ```
40
-
41
- ### 2. Интеграционное тестирование (Integration Tests)
42
-
43
- Тестирование команд с реальными зависимостями или их моками.
44
-
45
- ```python
46
- import pytest
47
- from unittest.mock import MagicMock, patch
48
- from myapp.commands.user_commands import get_user_data
49
-
50
- @pytest.fixture
51
- def mock_db():
52
- """Фикстура для создания мока базы данных."""
53
- mock = MagicMock()
54
- mock.users.find_one.return_value = {
55
- "id": "user123",
56
- "name": "Test User",
57
- "email": "test@example.com",
58
- "created_at": "2023-01-01T00:00:00Z"
59
- }
60
- return mock
61
-
62
- @patch("myapp.commands.user_commands.get_database")
63
- def test_get_user_data(get_database_mock, mock_db):
64
- # Настройка мока
65
- get_database_mock.return_value = mock_db
66
-
67
- # Вызов команды
68
- result = get_user_data("user123")
69
-
70
- # Проверки
71
- assert result["id"] == "user123"
72
- assert result["name"] == "Test User"
73
- assert "email" in result
74
-
75
- # Проверка вызова БД с правильными параметрами
76
- mock_db.users.find_one.assert_called_once_with({"id": "user123"})
77
- ```
78
-
79
- ### 3. Тестирование через Command Registry
80
-
81
- Тестирование команд через интерфейс Command Registry.
82
-
83
- ```python
84
- import pytest
85
- from command_registry import CommandRegistry
86
- from command_registry.dispatchers import CommandDispatcher
87
- from myapp.commands.math_commands import add_numbers, subtract_numbers
88
-
89
- @pytest.fixture
90
- def registry():
91
- """Фикстура для создания CommandRegistry с зарегистрированными командами."""
92
- registry = CommandRegistry(CommandDispatcher())
93
- registry.register_command("add", add_numbers)
94
- registry.register_command("subtract", subtract_numbers)
95
- return registry
96
-
97
- def test_registry_add_command(registry):
98
- # Выполнение команды через реестр
99
- result = registry.execute("add", {"a": 10, "b": 5})
100
- assert result == 15
101
-
102
- def test_registry_subtract_command(registry):
103
- # Выполнение команды через реестр
104
- result = registry.execute("subtract", {"a": 10, "b": 5})
105
- assert result == 5
106
-
107
- def test_command_not_found(registry):
108
- # Проверка обработки несуществующей команды
109
- with pytest.raises(ValueError, match="Command 'multiply' not found"):
110
- registry.execute("multiply", {"a": 10, "b": 5})
111
- ```
112
-
113
- ### 4. E2E тестирование через API
114
-
115
- Тестирование команд через внешние интерфейсы (REST, JSON-RPC и т.д.).
116
-
117
- ```python
118
- import pytest
119
- from fastapi.testclient import TestClient
120
- from myapp.main import app # FastAPI приложение с зарегистрированными командами
121
-
122
- client = TestClient(app)
123
-
124
- def test_add_numbers_api():
125
- response = client.post(
126
- "/api/commands/add",
127
- json={"a": 10, "b": 5}
128
- )
129
- assert response.status_code == 200
130
- assert response.json() == {"result": 15}
131
-
132
- def test_invalid_params_api():
133
- response = client.post(
134
- "/api/commands/add",
135
- json={"a": "not_a_number", "b": 5}
136
- )
137
- assert response.status_code == 400
138
- assert "error" in response.json()
139
- ```
140
-
141
- ## Тестирование с использованием параметризации
142
-
143
- Параметризация позволяет тестировать множество сценариев с разными входными данными и ожиданиями.
144
-
145
- ```python
146
- import pytest
147
- from myapp.commands.math_commands import calculate_total
148
-
149
- @pytest.mark.parametrize("prices, discount, expected", [
150
- ([10, 20, 30], 0, 60), # Без скидки
151
- ([10, 20, 30], 10, 54), # Скидка 10%
152
- ([100], 50, 50), # Скидка 50%
153
- ([], 10, 0), # Пустой список
154
- ])
155
- def test_calculate_total(prices, discount, expected):
156
- result = calculate_total(prices, discount)
157
- assert result == expected
158
-
159
- @pytest.mark.parametrize("invalid_discount", [-10, 110, "invalid"])
160
- def test_calculate_total_invalid_discount(invalid_discount):
161
- with pytest.raises(ValueError):
162
- calculate_total([10, 20], invalid_discount)
163
- ```
164
-
165
- ## Тестирование асинхронных команд
166
-
167
- Для тестирования асинхронных команд используйте pytest-asyncio.
168
-
169
- ```python
170
- import pytest
171
- import asyncio
172
- from unittest.mock import AsyncMock, patch
173
- from myapp.commands.async_commands import fetch_user_data
174
-
175
- @pytest.mark.asyncio
176
- @patch("myapp.commands.async_commands.get_async_database")
177
- async def test_fetch_user_data(mock_get_db):
178
- # Создаем асинхронный мок
179
- mock_db = AsyncMock()
180
- mock_db.users.find_one.return_value = {"id": "user123", "name": "Test User"}
181
- mock_get_db.return_value = mock_db
182
-
183
- # Вызываем асинхронную команду
184
- result = await fetch_user_data("user123")
185
-
186
- # Проверяем результат
187
- assert result["id"] == "user123"
188
- assert result["name"] == "Test User"
189
-
190
- # Проверяем, что мок был вызван с правильными параметрами
191
- mock_db.users.find_one.assert_called_once_with({"id": "user123"})
192
- ```
193
-
194
- ## Тестирование обработки ошибок
195
-
196
- ```python
197
- import pytest
198
- from myapp.commands.user_commands import get_user_data
199
- from myapp.exceptions import UserNotFoundError
200
-
201
- @patch("myapp.commands.user_commands.get_database")
202
- def test_get_user_data_not_found(mock_get_db):
203
- # Настраиваем мок для возврата None (пользователь не найден)
204
- db_mock = MagicMock()
205
- db_mock.users.find_one.return_value = None
206
- mock_get_db.return_value = db_mock
207
-
208
- # Проверяем, что команда вызывает ожидаемое исключение
209
- with pytest.raises(UserNotFoundError, match="User with id 'unknown_user' not found"):
210
- get_user_data("unknown_user")
211
- ```
212
-
213
- ## Тестирование валидации параметров
214
-
215
- ```python
216
- import pytest
217
- from myapp.commands.product_commands import update_product_price
218
-
219
- def test_update_product_price_negative():
220
- # Проверка на отрицательную цену
221
- with pytest.raises(ValueError, match="Price cannot be negative"):
222
- update_product_price("product123", -10.0)
223
-
224
- def test_update_product_price_invalid_id():
225
- # Проверка на пустой идентификатор продукта
226
- with pytest.raises(ValueError, match="Product ID cannot be empty"):
227
- update_product_price("", 10.0)
228
- ```
229
-
230
- ## Использование фикстур для общих случаев
231
-
232
- ```python
233
- import pytest
234
- from command_registry import CommandRegistry
235
- from command_registry.dispatchers import CommandDispatcher
236
- import myapp.commands as commands
237
-
238
- @pytest.fixture
239
- def registry():
240
- """Создает CommandRegistry со всеми зарегистрированными командами."""
241
- registry = CommandRegistry(CommandDispatcher())
242
- registry.scan_module(commands)
243
- return registry
244
-
245
- @pytest.fixture
246
- def mock_database():
247
- """Создает мок базы данных с тестовыми данными."""
248
- db = MagicMock()
249
- db.users.find_one.return_value = {"id": "user1", "name": "Test User"}
250
- db.products.find.return_value = [
251
- {"id": "prod1", "name": "Product 1", "price": 10.0},
252
- {"id": "prod2", "name": "Product 2", "price": 20.0}
253
- ]
254
- return db
255
-
256
- @pytest.fixture
257
- def app_client(registry):
258
- """Создает тестовый клиент для FastAPI с Command Registry."""
259
- from fastapi import FastAPI
260
- from command_registry.adapters import RESTAdapter
261
-
262
- app = FastAPI()
263
- adapter = RESTAdapter(registry)
264
- adapter.register_endpoints(app)
265
-
266
- from fastapi.testclient import TestClient
267
- return TestClient(app)
268
- ```
269
-
270
- ## Мокирование внешних зависимостей
271
-
272
- ```python
273
- import pytest
274
- from unittest.mock import patch, MagicMock
275
- import requests
276
- from myapp.commands.external_commands import fetch_external_data
277
-
278
- @patch("myapp.commands.external_commands.requests.get")
279
- def test_fetch_external_data(mock_get):
280
- # Настраиваем мок для requests.get
281
- mock_response = MagicMock()
282
- mock_response.status_code = 200
283
- mock_response.json.return_value = {"data": "test_data"}
284
- mock_get.return_value = mock_response
285
-
286
- # Вызываем команду
287
- result = fetch_external_data("https://api.example.com/data")
288
-
289
- # Проверяем результат
290
- assert result == {"data": "test_data"}
291
-
292
- # Проверяем, что запрос был отправлен по правильному URL
293
- mock_get.assert_called_once_with("https://api.example.com/data")
294
-
295
- @patch("myapp.commands.external_commands.requests.get")
296
- def test_fetch_external_data_error(mock_get):
297
- # Настраиваем мок для имитации ошибки
298
- mock_response = MagicMock()
299
- mock_response.status_code = 404
300
- mock_get.return_value = mock_response
301
-
302
- # Проверяем, что команда корректно обрабатывает ошибку
303
- with pytest.raises(ValueError, match="Failed to fetch data"):
304
- fetch_external_data("https://api.example.com/data")
305
- ```
306
-
307
- ## Тестирование полной интеграции с Command Registry
308
-
309
- ```python
310
- def test_full_registry_integration(registry):
311
- """
312
- Тестирует полную интеграцию с Command Registry, включая:
313
- - регистрацию команд
314
- - получение метаданных
315
- - выполнение команд
316
- - обработку ошибок
317
- """
318
- # Проверка регистрации
319
- commands = registry.get_valid_commands()
320
- assert "add_user" in commands
321
- assert "get_user" in commands
322
-
323
- # Проверка метаданных
324
- add_user_info = registry.get_command_info("add_user")
325
- assert add_user_info["description"] == "Создает нового пользователя"
326
- assert "name" in add_user_info["params"]
327
- assert add_user_info["params"]["name"]["required"] is True
328
-
329
- # Выполнение команды
330
- with patch("myapp.commands.user_commands.get_database") as mock_get_db:
331
- db_mock = MagicMock()
332
- mock_get_db.return_value = db_mock
333
- db_mock.users.insert_one.return_value.inserted_id = "new_user_id"
334
-
335
- result = registry.execute("add_user", {
336
- "name": "New User",
337
- "email": "new@example.com"
338
- })
339
-
340
- assert result["id"] == "new_user_id"
341
- assert result["name"] == "New User"
342
- db_mock.users.insert_one.assert_called_once()
343
-
344
- # Проверка обработки ошибок при выполнении
345
- with pytest.raises(ValueError):
346
- registry.execute("add_user", {
347
- "name": "", # Пустое имя должно вызвать ошибку валидации
348
- "email": "new@example.com"
349
- })
350
-
351
- # Проверка обработки несуществующей команды
352
- with pytest.raises(ValueError, match="Command 'non_existent' not found"):
353
- registry.execute("non_existent", {})
354
- ```
355
-
356
- ## Рекомендации по организации тестов
357
-
358
- 1. **Структура директорий** - зеркалируйте структуру исходного кода:
359
- ```
360
- src/
361
- commands/
362
- user_commands.py
363
- product_commands.py
364
- tests/
365
- commands/
366
- test_user_commands.py
367
- test_product_commands.py
368
- ```
369
-
370
- 2. **Именование** - используйте понятные имена тестов, отражающие проверяемую функциональность:
371
- ```python
372
- def test_add_user_creates_new_user_with_valid_data():
373
- # ...
374
-
375
- def test_add_user_raises_error_when_name_is_empty():
376
- # ...
377
- ```
378
-
379
- 3. **Документирование тестов** - добавляйте docstrings, поясняющие цель теста:
380
- ```python
381
- def test_calculate_total_applies_discount_correctly():
382
- """
383
- Проверяет, что команда calculate_total правильно применяет скидку к сумме.
384
- Должна вычесть процент скидки из общей суммы всех цен.
385
- """
386
- # ...
387
- ```
388
-
389
- ## Примеры тестирования распространенных сценариев
390
-
391
- ### Тестирование команды с транзакцией базы данных
392
-
393
- ```python
394
- import pytest
395
- from unittest.mock import MagicMock, patch
396
- from myapp.commands.order_commands import create_order
397
-
398
- @patch("myapp.commands.order_commands.get_database")
399
- def test_create_order_transaction(mock_get_db):
400
- # Настраиваем моки для базы данных и транзакции
401
- db_mock = MagicMock()
402
- transaction_mock = MagicMock()
403
- db_mock.begin_transaction.return_value = transaction_mock
404
- mock_get_db.return_value = db_mock
405
-
406
- # Выполняем команду
407
- result = create_order(
408
- user_id="user123",
409
- items=[
410
- {"product_id": "prod1", "quantity": 2},
411
- {"product_id": "prod2", "quantity": 1}
412
- ]
413
- )
414
-
415
- # Проверяем, что транзакция была начата и закоммичена
416
- db_mock.begin_transaction.assert_called_once()
417
- transaction_mock.commit.assert_called_once()
418
-
419
- # Проверяем, что не было отката транзакции
420
- transaction_mock.rollback.assert_not_called()
421
-
422
- @patch("myapp.commands.order_commands.get_database")
423
- def test_create_order_transaction_rollback(mock_get_db):
424
- # Настраиваем моки для имитации ошибки
425
- db_mock = MagicMock()
426
- transaction_mock = MagicMock()
427
- db_mock.begin_transaction.return_value = transaction_mock
428
- db_mock.orders.insert_one.side_effect = Exception("DB Error")
429
- mock_get_db.return_value = db_mock
430
-
431
- # Проверяем, что команда корректно обрабатывает ошибку
432
- with pytest.raises(Exception):
433
- create_order(
434
- user_id="user123",
435
- items=[{"product_id": "prod1", "quantity": 2}]
436
- )
437
-
438
- # Проверяем, что транзакция была начата и откачена
439
- db_mock.begin_transaction.assert_called_once()
440
- transaction_mock.rollback.assert_called_once()
441
- ```
442
-
443
- ### Тестирование логирования в командах
444
-
445
- ```python
446
- import pytest
447
- import logging
448
- from unittest.mock import patch
449
- from myapp.commands.user_commands import delete_user
450
-
451
- @patch("myapp.commands.user_commands.logger")
452
- @patch("myapp.commands.user_commands.get_database")
453
- def test_delete_user_logging(mock_get_db, mock_logger):
454
- # Настраиваем мок базы данных
455
- db_mock = MagicMock()
456
- db_mock.users.delete_one.return_value.deleted_count = 1
457
- mock_get_db.return_value = db_mock
458
-
459
- # Выполняем команду
460
- result = delete_user("user123")
461
-
462
- # Проверяем, что логи были созданы
463
- mock_logger.info.assert_any_call("Deleting user with ID: user123")
464
- mock_logger.info.assert_any_call("User user123 successfully deleted")
465
- ```
466
-
467
- ## Заключение
468
-
469
- Тестирование команд в Command Registry - важная часть обеспечения качества приложения. Используйте комбинацию модульных, интеграционных и E2E тестов для достижения максимального покрытия. Помните, что хорошие тесты не только проверяют правильную работу кода, но и документируют ожидаемое поведение системы.