تخطَّ إلى المحتوى
kazma.
EN نجمة 6 ابدأ الآن

الاختبارات

  • pytest مع pytest-asyncio
  • التغطية مع pytest-cov
import pytest
from kazma_core.checkpoint import CheckpointManager
@pytest.fixture
async def manager(tmp_path):
m = CheckpointManager(db_path=str(tmp_path / "test.db"))
yield m
await m.close()
@pytest.mark.asyncio
async def test_save_and_load(manager):
state = {"agent_id": "test", "step": 1}
await manager.save(state)
loaded = await manager.load(agent_id="test")
assert loaded["step"] == 1
Terminal window
pytest
pytest --cov=kazma_core --cov-report=html
pytest -v

تُشغَّل مجموعتان اختباريتان مع كل التزام عبر pre-commit (انظر إعداد بيئة التطوير). كلتاهما تعتمد على AST فقط — لا تُقلعان التطبيق أبدًا، وتستغرقان معًا نحو ثماني ثوانٍ.

Terminal window
pytest tests/test_imports.py tests/test_static_gates.py -q

وُجدت لأن كل واحدة منهما تُغلق فئة عيوب اكتُشفت بالبحث النصي (grep) في الشجرة، لا باختبار فاشل:

البوابةما يُفشل البناء
test_every_product_module_importsوحدة لم تعد قابلة للاستيراد. وُلدت من حادثة crawl.py: خلّف حذفٌ استيرادًا معلّقًا، ونجح py_compile، فانكسر البحث في الإنتاج عند أول استخدام.
test_no_dangling_kazma_import_referencesمرجع استيراد kazma_* لا يحلّ إلى أي شيء — يلتقط الاستيرادات على مستوى الدوال التي يفوّتها اختبار الدخان.
test_no_blocking_db_driver_in_asyncاستدعاء sqlite3.connect متزامن داخل async def. يُثبِّت حلقة الأحداث التي تخدم أيضًا كل تدفقات SSE وWebSocket. أصلِحه بإسقاط async (يُمرِّر FastAPI المعالجات المتزامنة إلى threadpool) أو بالتغليف في asyncio.to_thread.
test_no_bare_create_taskنتيجة asyncio.create_task(...) مُهمَلة. تحتفظ الحلقة بمرجع ضعيف فقط، لذا قد تُجمَّع المهمّة كنفايات في منتصف تشغيلها — بصمت وبلا أثر رجعي (traceback). استخدم kazma_core.background.spawn_background.
test_every_registered_tool_has_a_tierأداة مسجّلة بلا مدخل في TOOL_TIERS. يرفض HITL افتراضيًا كل ما لا يستطيع تصنيفه، فأداة بلا طبقة ستطلب موافقة حتى على قراءة.
test_no_unfenced_web_tool_outputأداة ويب تعيد نصًا مؤلَّفًا من جهة بعيدة دون سياج «غير موثوق».

تحمل قائمة السماح في test_no_blocking_db_driver_in_async سلسلة سبب لكل إعفاء — أضف إعفاءً فقط مشفوعًا بشرح لماذا لا يمكن تفريغ الاستدعاء إلى خيط منفصل.

مجموعة اختبارات الانحدار لنتائج التدقيق الأمني

Section titled “مجموعة اختبارات الانحدار لنتائج التدقيق الأمني”

يحوي tests/test_audit_2026_08_29_regressions.py اختبارًا سلوكيًا واحدًا لكل نتيجة تدقيق تضمّنت سلوكًا قابلًا للاستغلال — كُتب كلٌّ منها ليفشل ضد الكود قبل الإصلاح. إذا لمست وسيط المصادقة، أو قناع الإعدادات، أو shell_exec، أو بوابة HITL، أو نطاق المستأجرين، فشغّله:

Terminal window
pytest tests/test_audit_2026_08_29_regressions.py -q

اختبار الوحدات التي أصبحت حزمًا

Section titled “اختبار الوحدات التي أصبحت حزمًا”

عدة وحدات «عملاقة» (god modules) سابقًا أصبحت الآن حزمًا خلف واجهات لم تتغير (routes_direct، sse_chat، i18n، tool_builtins). ولهذا تبعات على الاختبارات:

  • تأكيدات البحث في المصدر يجب أن تستخدم tests/_module_source.py. تقرأ module_source(path) ملف .py أو تسلسل حزمة كاملة في سلسلة واحدة، وmodule_exists(path) هي الحارس المطابق — فاستدعاء path.exists() المجرد يُرجع False لوحدة تحوّلت إلى حزمة، ما يحوّل التأكيد بصمت إلى عملية بلا أثر.
  • الرقع (monkeypatching) انتقل مع الكود. رُقّ عند النقطة التي تُعرَّف فيها (مثل kazma_ui.sse_chat._helpers)، لا على واجهة الحزمة — فرابطة from X import y في وحدة فرعية أخرى لن ترى رقعًا طُبِّق على فضاء أسماء الحزمة.