test_pan_verification.py•10.5 kB
"""Unit tests for PAN verification tool."""
import pytest
from unittest.mock import AsyncMock
from pydantic import ValidationError
from src.tools.pan_verification import PANVerificationTool
class TestPANVerificationTool:
"""Test suite for PAN verification tool."""
@pytest.mark.asyncio
async def test_successful_verification_all_match(
self, pan_verification_tool, valid_pan_request, mock_pan_verification_response
):
"""Test successful PAN verification with all fields matching."""
# Setup mock
pan_verification_tool.api_client.post = AsyncMock(
return_value=mock_pan_verification_response
)
# Execute
result = await pan_verification_tool.execute(valid_pan_request)
# Assert
assert result["pan"] == "ABCDE1234F"
assert result["status"] == "valid"
assert result["name_match"] is True
assert result["dob_match"] is True
assert result["aadhaar_seeding_status"] == "y"
assert "verified_at" in result
# Verify API was called correctly
pan_verification_tool.api_client.post.assert_called_once()
call_args = pan_verification_tool.api_client.post.call_args
assert call_args[1]["endpoint"] == "/kyc/pan/verify"
assert call_args[1]["data"]["pan"] == "ABCDE1234F"
@pytest.mark.asyncio
async def test_verification_name_mismatch(
self, pan_verification_tool, valid_pan_request, mock_responses
):
"""Test PAN verification with name mismatch."""
# Setup mock with name mismatch response
response = mock_responses["pan_verification"]["success_name_mismatch"]
pan_verification_tool.api_client.post = AsyncMock(return_value=response)
# Execute
result = await pan_verification_tool.execute(valid_pan_request)
# Assert
assert result["name_match"] is False
assert result["dob_match"] is True
assert result["status"] == "valid"
@pytest.mark.asyncio
async def test_verification_dob_mismatch(
self, pan_verification_tool, valid_pan_request, mock_responses
):
"""Test PAN verification with DOB mismatch."""
# Setup mock with DOB mismatch response
response = mock_responses["pan_verification"]["success_dob_mismatch"]
pan_verification_tool.api_client.post = AsyncMock(return_value=response)
# Execute
result = await pan_verification_tool.execute(valid_pan_request)
# Assert
assert result["name_match"] is True
assert result["dob_match"] is False
assert result["aadhaar_seeding_status"] == "n"
@pytest.mark.asyncio
async def test_verification_deceased_holder(
self, pan_verification_tool, valid_pan_request, mock_responses
):
"""Test PAN verification for deceased holder."""
# Setup mock with deceased holder response
response = mock_responses["pan_verification"]["success_deceased"]
pan_verification_tool.api_client.post = AsyncMock(return_value=response)
# Execute
result = await pan_verification_tool.execute(valid_pan_request)
# Assert
assert result["remarks"] == "Holder is Deceased"
assert result["aadhaar_seeding_status"] == "na"
@pytest.mark.asyncio
async def test_invalid_pan_format(self, pan_verification_tool):
"""Test validation error for invalid PAN format."""
invalid_request = {
"pan": "INVALID",
"name_as_per_pan": "John Doe",
"date_of_birth": "01/01/1990",
"consent": "Y",
"reason": "Test"
}
# Execute and assert
with pytest.raises(ValueError, match="Invalid input parameters"):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_lowercase_pan(self, pan_verification_tool):
"""Test validation error for lowercase PAN."""
invalid_request = {
"pan": "abcde1234f",
"name_as_per_pan": "John Doe",
"date_of_birth": "01/01/1990",
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_invalid_date_format(self, pan_verification_tool):
"""Test validation error for invalid date format."""
invalid_request = {
"pan": "ABCDE1234F",
"name_as_per_pan": "John Doe",
"date_of_birth": "1990-01-01", # Wrong format
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_missing_consent(self, pan_verification_tool):
"""Test validation error for missing consent."""
invalid_request = {
"pan": "ABCDE1234F",
"name_as_per_pan": "John Doe",
"date_of_birth": "01/01/1990",
"consent": "N", # Invalid consent
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_missing_required_field(self, pan_verification_tool):
"""Test validation error for missing required field."""
invalid_request = {
"pan": "ABCDE1234F",
"name_as_per_pan": "John Doe",
# Missing date_of_birth
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_api_error_handling(self, pan_verification_tool, valid_pan_request):
"""Test handling of API errors."""
# Setup mock to raise exception
pan_verification_tool.api_client.post = AsyncMock(
side_effect=Exception("API Error")
)
# Execute and assert
with pytest.raises(Exception, match="API Error"):
await pan_verification_tool.execute(valid_pan_request)
def test_get_name(self, pan_verification_tool):
"""Test tool name."""
assert pan_verification_tool.get_name() == "verify_pan"
def test_cache_key_generation(self, pan_verification_tool, valid_pan_request):
"""Test cache key generation."""
cache_key = pan_verification_tool.get_cache_key(valid_pan_request)
assert cache_key.startswith("pan_verify:")
assert len(cache_key) > len("pan_verify:")
# Same input should generate same key
cache_key2 = pan_verification_tool.get_cache_key(valid_pan_request)
assert cache_key == cache_key2
def test_cache_key_different_for_different_inputs(self, pan_verification_tool):
"""Test that different inputs generate different cache keys."""
request1 = {
"pan": "ABCDE1234F",
"name_as_per_pan": "John Doe",
"date_of_birth": "01/01/1990",
"consent": "Y",
"reason": "Test"
}
request2 = {
"pan": "XYZPQ5678R",
"name_as_per_pan": "Jane Smith",
"date_of_birth": "15/06/1985",
"consent": "Y",
"reason": "Test"
}
key1 = pan_verification_tool.get_cache_key(request1)
key2 = pan_verification_tool.get_cache_key(request2)
assert key1 != key2
def test_cache_ttl(self, pan_verification_tool):
"""Test cache TTL value."""
ttl = pan_verification_tool.get_cache_ttl()
assert ttl == 3600 # 1 hour
@pytest.mark.asyncio
async def test_empty_name(self, pan_verification_tool):
"""Test validation error for empty name."""
invalid_request = {
"pan": "ABCDE1234F",
"name_as_per_pan": "",
"date_of_birth": "01/01/1990",
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_empty_reason(self, pan_verification_tool):
"""Test validation error for empty reason."""
invalid_request = {
"pan": "ABCDE1234F",
"name_as_per_pan": "John Doe",
"date_of_birth": "01/01/1990",
"consent": "Y",
"reason": ""
}
with pytest.raises(ValueError):
await pan_verification_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_company_pan_verification(
self, pan_verification_tool, mock_responses
):
"""Test PAN verification for company PAN."""
request = {
"pan": "ABCCC1234F",
"name_as_per_pan": "ABC Company Ltd",
"date_of_birth": "01/01/2000",
"consent": "Y",
"reason": "Company verification"
}
response = mock_responses["pan_verification"]["success_company"]
pan_verification_tool.api_client.post = AsyncMock(return_value=response)
result = await pan_verification_tool.execute(request)
assert result["category"] == "company"
assert result["aadhaar_seeding_status"] == "na"
@pytest.mark.asyncio
async def test_lowercase_consent_accepted(
self, pan_verification_tool, valid_pan_request, mock_pan_verification_response
):
"""Test that lowercase 'y' is accepted for consent."""
valid_pan_request["consent"] = "y"
pan_verification_tool.api_client.post = AsyncMock(
return_value=mock_pan_verification_response
)
result = await pan_verification_tool.execute(valid_pan_request)
assert result["status"] == "valid"
@pytest.mark.asyncio
async def test_special_characters_in_name(
self, pan_verification_tool, valid_pan_request, mock_pan_verification_response
):
"""Test handling of special characters in name."""
valid_pan_request["name_as_per_pan"] = "O'Brien-Smith Jr."
pan_verification_tool.api_client.post = AsyncMock(
return_value=mock_pan_verification_response
)
result = await pan_verification_tool.execute(valid_pan_request)
assert result["status"] == "valid"