- Intent classification with LLM structured output (single/multi/ambiguous) - Discount agent with apply_discount and generate_coupon tools - Interrupt manager with 30-min TTL auto-expiration and retry prompts - Webhook escalation module with exponential backoff retry (max 3) - Three vertical industry templates (e-commerce, SaaS, fintech) - Template loading in AgentRegistry - Enhanced supervisor prompt with dynamic agent descriptions - 153 tests passing, 90.18% coverage
80 lines
3.2 KiB
Python
80 lines
3.2 KiB
Python
"""Tests for app.agents.discount module."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from app.agents.discount import apply_discount, generate_coupon
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestApplyDiscount:
|
|
def test_invalid_discount_zero(self) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 0})
|
|
assert result["status"] == "error"
|
|
assert "Invalid" in result["message"]
|
|
|
|
def test_invalid_discount_over_100(self) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 101})
|
|
assert result["status"] == "error"
|
|
|
|
def test_invalid_discount_negative(self) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": -5})
|
|
assert result["status"] == "error"
|
|
|
|
@patch("app.agents.discount.interrupt", return_value=True)
|
|
def test_approved_discount(self, mock_interrupt) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 10})
|
|
assert result["status"] == "applied"
|
|
assert result["discount_percent"] == 10
|
|
assert "1042" in result["message"]
|
|
|
|
@patch("app.agents.discount.interrupt", return_value=False)
|
|
def test_rejected_discount(self, mock_interrupt) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 10})
|
|
assert result["status"] == "declined"
|
|
|
|
@patch("app.agents.discount.interrupt", return_value={"approved": True})
|
|
def test_approved_via_dict(self, mock_interrupt) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 50})
|
|
assert result["status"] == "applied"
|
|
|
|
@patch("app.agents.discount.interrupt", return_value={"approved": False})
|
|
def test_rejected_via_dict(self, mock_interrupt) -> None:
|
|
result = apply_discount.invoke({"order_id": "1042", "discount_percent": 50})
|
|
assert result["status"] == "declined"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestGenerateCoupon:
|
|
def test_valid_coupon(self) -> None:
|
|
result = generate_coupon.invoke({"discount_percent": 15, "expiry_days": 7})
|
|
assert result["status"] == "generated"
|
|
assert result["discount_percent"] == 15
|
|
assert result["expiry_days"] == 7
|
|
assert result["coupon_code"].startswith("SAVE15-")
|
|
|
|
def test_default_expiry(self) -> None:
|
|
result = generate_coupon.invoke({"discount_percent": 20})
|
|
assert result["status"] == "generated"
|
|
assert result["expiry_days"] == 30
|
|
|
|
def test_invalid_discount_zero(self) -> None:
|
|
result = generate_coupon.invoke({"discount_percent": 0})
|
|
assert result["status"] == "error"
|
|
|
|
def test_invalid_discount_over_100(self) -> None:
|
|
result = generate_coupon.invoke({"discount_percent": 101})
|
|
assert result["status"] == "error"
|
|
|
|
def test_invalid_expiry(self) -> None:
|
|
result = generate_coupon.invoke({"discount_percent": 10, "expiry_days": 0})
|
|
assert result["status"] == "error"
|
|
|
|
def test_coupon_codes_unique(self) -> None:
|
|
r1 = generate_coupon.invoke({"discount_percent": 10})
|
|
r2 = generate_coupon.invoke({"discount_percent": 10})
|
|
assert r1["coupon_code"] != r2["coupon_code"]
|