Parent: Unit tests creation for CD001 #27
Description
Add a full unit test suite for the agent tools layer — vendor management, invoice operations, and fraud detection.
Tests follow the established pattern with:
- Title
- Basically question
- Steps
- Expected Results
- Impact
Bug-exposing tests are included for each confirmed production defect.
📁 Test Files
tests/unit/tools/test_vendor.py
TestGetVendorDetails
| Test ID |
Title |
| test_vnd_get_001 |
get_vendor_details returns vendor as dictionary |
| test_vnd_get_002 |
get_vendor_details raises ValueError when vendor not found |
| test_vnd_get_003 |
get_vendor_details enforces namespace isolation |
| test_vnd_get_004 |
Database session leaks when vendor is not found |
| test_vnd_get_005 |
get_vendor_details rejects vendor_id=0 (lower boundary) |
| test_vnd_get_006 |
get_vendor_details rejects negative vendor_id |
TestGetVendorContactInfo
| Test ID |
Title |
| test_vnd_contact_001 |
get_vendor_contact_info returns limited contact fields |
| test_vnd_contact_002 |
get_vendor_contact_info raises ValueError when vendor not found |
| test_vnd_contact_003 |
get_vendor_contact_info prevents cross-namespace access |
| test_vnd_contact_004 |
get_vendor_contact_info rejects vendor_id=0 |
| test_vnd_contact_005 |
get_vendor_contact_info rejects negative vendor_id |
| test_vnd_contact_006 |
get_vendor_contact_info omits all bank and TIN fields |
TestUpdateVendorStatus
| Test ID |
Title |
| test_vnd_upd_001 |
update_vendor_status persists new status |
| test_vnd_upd_002 |
update_vendor_status captures status, trust_level, and risk_level |
| test_vnd_upd_003 |
update_vendor_status appends notes instead of overwriting |
| test_vnd_upd_004 |
update_vendor_status raises ValueError when vendor not found |
| test_vnd_upd_005 |
update_vendor_status enforces namespace isolation |
| test_vnd_upd_006 |
update_vendor_status does not validate status against allowed values |
| test_vnd_upd_007 |
update_vendor_status does not validate trust_level |
| test_vnd_upd_008 |
None agent_notes produces literal "None" string in notes field |
| test_vnd_upd_009 |
update_vendor_status does not validate risk_level |
| test_vnd_upd_010 |
update_vendor_status rejects vendor_id=0 |
| test_vnd_upd_011 |
update_vendor_status rejects negative vendor_id |
| test_vnd_upd_status_invalid_rejected |
update_vendor_status rejects invalid status values |
| test_vnd_upd_trust_level_invalid_rejected |
update_vendor_status rejects invalid trust_level values |
| test_vnd_upd_risk_level_invalid_rejected |
update_vendor_status rejects invalid risk_level values |
TestUpdateVendorAgentNotes
| Test ID |
Title |
| test_vnd_notes_001 |
update_vendor_agent_notes appends without overwriting |
| test_vnd_notes_002 |
update_vendor_agent_notes raises ValueError when vendor not found |
| test_vnd_notes_003 |
Repeated calls preserve all prior entries |
| test_vnd_notes_004 |
None agent_notes produces literal "None" string |
| test_vnd_notes_005 |
update_vendor_agent_notes rejects vendor_id=0 |
| test_vnd_notes_006 |
update_vendor_agent_notes rejects negative vendor_id |
| test_vnd_notes_007 |
Does not reject whitespace-only notes |
| test_vnd_notes_008 |
No maximum length limit on notes |
| test_vnd_notes_009 |
Does not reject newline-only notes |
| test_vnd_notes_010 |
Does not reject tab-only notes |
| test_vnd_notes_011 |
Accepts injected agent prefix in notes (defect) |
| test_vnd_notes_012 |
Accepts notes at the 10,000-character boundary |
| test_vnd_notes_013 |
Accepts notes well within the 10,000-character limit |
| test_vnd_notes_isolation |
update_vendor_agent_notes enforces namespace isolation |
tests/unit/tools/test_invoice.py
TestGetInvoiceDetails
| Test ID |
Title |
| test_inv_get_001 |
get_invoice_details returns invoice as dictionary |
| test_inv_get_002 |
get_invoice_details raises ValueError when invoice not found |
| test_inv_get_003 |
get_invoice_details enforces namespace isolation |
| test_inv_get_004 |
Database session leaks when invoice is not found |
| test_inv_get_005 |
get_invoice_details handles zero-amount invoices |
| test_inv_get_006 |
get_invoice_details does not validate amount sign |
| test_inv_get_007 |
get_invoice_details rejects invoice_id=0 |
| test_inv_get_008 |
get_invoice_details rejects negative invoice_id |
| test_inv_get_009 |
get_invoice_details handles 1e15 amount without overflow |
TestUpdateInvoiceStatus
| Test ID |
Title |
| test_inv_upd_001 |
update_invoice_status persists new status |
| test_inv_upd_002 |
update_invoice_status appends notes instead of overwriting |
| test_inv_upd_003 |
update_invoice_status raises ValueError when invoice not found |
| test_inv_upd_004 |
update_invoice_status enforces namespace isolation |
| test_inv_upd_005 |
update_invoice_status does not validate status against allowed values |
| test_inv_upd_006 |
None agent_notes produces literal "None" string |
| test_inv_upd_007 |
update_invoice_status rejects invoice_id=0 |
| test_inv_upd_008 |
update_invoice_status rejects negative invoice_id |
| test_inv_upd_009 |
Does not reject empty string status |
| test_inv_upd_010 |
Does not enforce case on status |
| test_inv_upd_011 |
Does not strip whitespace from status |
| test_inv_upd_012 |
Does not reject None status |
| test_inv_upd_013 |
Does not reject leading whitespace in status |
| test_inv_upd_014 |
Does not enforce lowercase on status |
TestUpdateInvoiceAgentNotes
| Test ID |
Title |
| test_inv_notes_001 |
update_invoice_agent_notes appends without overwriting |
| test_inv_notes_002 |
update_invoice_agent_notes raises ValueError when invoice not found |
| test_inv_notes_003 |
Repeated calls preserve all prior entries |
| test_inv_notes_004 |
None agent_notes produces literal "None" string |
| test_inv_notes_005 |
update_invoice_agent_notes rejects invoice_id=0 |
| test_inv_notes_006 |
update_invoice_agent_notes rejects negative invoice_id |
| test_inv_notes_007 |
Does not reject whitespace-only notes |
| test_inv_notes_008 |
No maximum length limit on notes |
| test_inv_notes_009 |
Does not reject newline-only notes |
| test_inv_notes_010 |
Does not reject tab-only notes |
| test_inv_notes_011 |
Does not sanitize injected [Fraud Agent] prefix |
| test_inv_notes_012 |
Accepts notes at the 10,000-character boundary |
| test_inv_notes_013 |
Accepts notes well within the 10,000-character limit |
tests/unit/tools/test_fraud.py
TestGetVendorRiskProfile
| Test ID |
Title |
| test_fraud_risk_001 |
get_vendor_risk_profile returns complete risk profile |
| test_fraud_risk_002 |
get_vendor_risk_profile groups invoice counts by status |
| test_fraud_risk_003 |
get_vendor_risk_profile raises ValueError when vendor not found |
| test_fraud_risk_004 |
get_vendor_risk_profile prevents cross-namespace access |
| test_fraud_risk_005 |
Database session leaks when vendor is not found |
| test_fraud_risk_006 |
get_vendor_risk_profile handles vendor with no invoices |
| test_fraud_risk_007 |
get_vendor_risk_profile sums negative amounts without validation |
| test_fraud_risk_008 |
get_vendor_risk_profile rejects vendor_id=0 |
| test_fraud_risk_009 |
get_vendor_risk_profile rejects negative vendor_id |
| test_fraud_risk_010 |
get_vendor_risk_profile sums 1e15 amounts without overflow |
TestGetVendorInvoices
| Test ID |
Title |
| test_fraud_inv_001 |
get_vendor_invoices returns all vendor invoices as list |
| test_fraud_inv_002 |
get_vendor_invoices returns [] for vendor with no invoices |
| test_fraud_inv_003 |
get_vendor_invoices silently returns [] for non-existent vendor (defect) |
| test_fraud_inv_004 |
get_vendor_invoices prevents cross-namespace access |
TestUpdateVendorRisk
| Test ID |
Title |
| test_fraud_upd_001 |
update_vendor_risk persists new risk_level |
| test_fraud_upd_002 |
update_vendor_risk adds [Fraud Agent] prefix to notes |
| test_fraud_upd_003 |
update_vendor_risk raises ValueError when vendor not found |
| test_fraud_upd_004 |
update_vendor_risk prevents cross-namespace updates |
| test_fraud_upd_005 |
update_vendor_risk does not validate risk_level |
| test_fraud_upd_006 |
None agent_notes produces "[Fraud Agent] None" |
| test_fraud_upd_007 |
flag_invoice_for_review does not reject negative amount invoices |
| test_fraud_upd_008 |
Does not reject empty string risk_level |
| test_fraud_upd_009 |
Does not enforce case on risk_level |
| test_fraud_upd_010 |
Does not strip whitespace from risk_level |
| test_fraud_upd_011 |
Does not reject None risk_level |
| test_fraud_upd_012 |
Does not reject leading whitespace in risk_level |
| test_fraud_upd_013 |
Does not enforce lowercase on risk_level |
TestFlagInvoiceForReview
| Test ID |
Title |
| test_fraud_flag_001 |
flag_invoice_for_review writes flag_reason into agent_notes |
| test_fraud_flag_002 |
flag_invoice_for_review sets status to rejected when action is reject |
| test_fraud_flag_003 |
flag_invoice_for_review leaves approved invoices unchanged |
| test_fraud_flag_004 |
flag_invoice_for_review raises ValueError when invoice not found |
| test_fraud_flag_005 |
flag_invoice_for_review does not validate recommended_action |
| test_fraud_flag_006 |
reject action on processing invoice leaves status unchanged |
| test_fraud_flag_007 |
flag_invoice_for_review rejects invoice_id=0 |
| test_fraud_flag_008 |
flag_invoice_for_review rejects negative invoice_id |
| test_fraud_flag_009 |
Does not reject empty recommended_action |
| test_fraud_flag_010 |
Does not enforce case on recommended_action |
| test_fraud_flag_011 |
Does not auto-reject paid invoices |
| test_fraud_flag_012 |
Does not reject empty flag_reason |
| test_fraud_flag_013 |
Does not reject None flag_reason |
| test_fraud_flag_014 |
Does not reject whitespace-only flag_reason |
| test_fraud_flag_015 |
No maximum length limit on flag_reason |
| test_fraud_flag_016 |
Does not sanitize [Fraud Agent] prefix in flag_reason |
| test_fraud_flag_017 |
Does not reject None recommended_action |
| test_fraud_flag_018 |
Does not reject leading whitespace in recommended_action |
TestUpdateFraudAgentNotes
| Test ID |
Title |
| test_fraud_notes_001 |
update_fraud_agent_notes adds [Fraud Agent] prefix and appends |
| test_fraud_notes_002 |
update_fraud_agent_notes raises ValueError when vendor not found |
| test_fraud_notes_003 |
None notes produces "[Fraud Agent] None" (defect) |
| test_fraud_notes_004 |
update_fraud_agent_notes rejects vendor_id=0 |
| test_fraud_notes_005 |
update_fraud_agent_notes rejects negative vendor_id |
| test_fraud_notes_006 |
Does not reject whitespace-only notes |
| test_fraud_notes_007 |
No maximum length limit on notes |
| test_fraud_notes_008 |
Does not reject newline-only notes |
| test_fraud_notes_009 |
Does not reject tab-only notes |
| test_fraud_notes_010 |
Does not sanitize injected [Fraud Agent] prefix |
| test_fraud_notes_011 |
Accepts notes at the 10,000-character boundary |
| test_fraud_notes_012 |
Accepts notes well within the 10,000-character limit |
✅ Notes
- Covers vendor, invoice, and fraud domains
- Includes edge cases, validation gaps, and known defects
- Designed for LLM/AI agent testing + backend validation
Parent: Unit tests creation for CD001 #27
Description
Add a full unit test suite for the agent tools layer — vendor management, invoice operations, and fraud detection.
Tests follow the established pattern with:
Bug-exposing tests are included for each confirmed production defect.
📁 Test Files
tests/unit/tools/test_vendor.py
TestGetVendorDetails
TestGetVendorContactInfo
TestUpdateVendorStatus
TestUpdateVendorAgentNotes
tests/unit/tools/test_invoice.py
TestGetInvoiceDetails
TestUpdateInvoiceStatus
TestUpdateInvoiceAgentNotes
tests/unit/tools/test_fraud.py
TestGetVendorRiskProfile
TestGetVendorInvoices
TestUpdateVendorRisk
TestFlagInvoiceForReview
TestUpdateFraudAgentNotes
✅ Notes