test_pan_aadhaar_link.py•10.5 kB
"""Unit tests for PAN-Aadhaar link status tool."""
import pytest
from unittest.mock import AsyncMock
from src.tools.pan_aadhaar_link import PANAadhaarLinkTool
class TestPANAadhaarLinkTool:
"""Test suite for PAN-Aadhaar link status tool."""
@pytest.mark.asyncio
async def test_successful_linked_status(
self, pan_aadhaar_tool, valid_pan_aadhaar_request, mock_pan_aadhaar_response
):
"""Test successful check when PAN and Aadhaar are linked."""
# Setup mock
pan_aadhaar_tool.api_client.post = AsyncMock(
return_value=mock_pan_aadhaar_response
)
# Execute
result = await pan_aadhaar_tool.execute(valid_pan_aadhaar_request)
# Assert
assert result["linked"] is True
assert result["status"] == "y"
assert result["message"] == "PAN and Aadhaar are linked"
assert "checked_at" in result
# Verify API was called correctly
pan_aadhaar_tool.api_client.post.assert_called_once()
call_args = pan_aadhaar_tool.api_client.post.call_args
assert call_args[1]["endpoint"] == "/kyc/pan-aadhaar/status"
assert call_args[1]["data"]["pan"] == "ABCPE1234F"
@pytest.mark.asyncio
async def test_not_linked_status(
self, pan_aadhaar_tool, valid_pan_aadhaar_request, mock_responses
):
"""Test successful check when PAN and Aadhaar are not linked."""
# Setup mock with not linked response
response = mock_responses["pan_aadhaar_link"]["not_linked"]
pan_aadhaar_tool.api_client.post = AsyncMock(return_value=response)
# Execute
result = await pan_aadhaar_tool.execute(valid_pan_aadhaar_request)
# Assert
assert result["linked"] is False
assert result["status"] == "n"
assert result["message"] == "PAN and Aadhaar are not linked"
@pytest.mark.asyncio
async def test_invalid_aadhaar_format(self, pan_aadhaar_tool):
"""Test validation error for invalid Aadhaar format."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "12345", # Too short
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError, match="Invalid input parameters"):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_aadhaar_with_letters(self, pan_aadhaar_tool):
"""Test validation error for Aadhaar with letters."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "12345678901A",
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_non_individual_pan(self, pan_aadhaar_tool):
"""Test validation error for non-individual PAN (4th character not 'P')."""
invalid_request = {
"pan": "ABCCE1234F", # 4th character is 'C', not 'P'
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError, match="Only individual PAN cards"):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_invalid_pan_format(self, pan_aadhaar_tool):
"""Test validation error for invalid PAN format."""
invalid_request = {
"pan": "INVALID",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_missing_consent(self, pan_aadhaar_tool):
"""Test validation error for missing consent."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "N", # Invalid consent
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_missing_required_field(self, pan_aadhaar_tool):
"""Test validation error for missing required field."""
invalid_request = {
"pan": "ABCPE1234F",
# Missing aadhaar_number
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_empty_reason(self, pan_aadhaar_tool):
"""Test validation error for empty reason."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": ""
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_api_error_handling(
self, pan_aadhaar_tool, valid_pan_aadhaar_request
):
"""Test handling of API errors."""
# Setup mock to raise exception
pan_aadhaar_tool.api_client.post = AsyncMock(
side_effect=Exception("API Error")
)
# Execute and assert
with pytest.raises(Exception, match="API Error"):
await pan_aadhaar_tool.execute(valid_pan_aadhaar_request)
def test_get_name(self, pan_aadhaar_tool):
"""Test tool name."""
assert pan_aadhaar_tool.get_name() == "check_pan_aadhaar_link"
def test_cache_key_generation(
self, pan_aadhaar_tool, valid_pan_aadhaar_request
):
"""Test cache key generation."""
cache_key = pan_aadhaar_tool.get_cache_key(valid_pan_aadhaar_request)
assert cache_key.startswith("pan_aadhaar:")
assert len(cache_key) > len("pan_aadhaar:")
# Same input should generate same key
cache_key2 = pan_aadhaar_tool.get_cache_key(valid_pan_aadhaar_request)
assert cache_key == cache_key2
def test_cache_key_different_for_different_inputs(self, pan_aadhaar_tool):
"""Test that different inputs generate different cache keys."""
request1 = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Test"
}
request2 = {
"pan": "XYZPQ5678R",
"aadhaar_number": "987654321098",
"consent": "Y",
"reason": "Test"
}
key1 = pan_aadhaar_tool.get_cache_key(request1)
key2 = pan_aadhaar_tool.get_cache_key(request2)
assert key1 != key2
def test_cache_ttl(self, pan_aadhaar_tool):
"""Test cache TTL value."""
ttl = pan_aadhaar_tool.get_cache_ttl()
assert ttl == 7200 # 2 hours
@pytest.mark.asyncio
async def test_lowercase_consent_accepted(
self, pan_aadhaar_tool, valid_pan_aadhaar_request, mock_pan_aadhaar_response
):
"""Test that lowercase 'y' is accepted for consent."""
valid_pan_aadhaar_request["consent"] = "y"
pan_aadhaar_tool.api_client.post = AsyncMock(
return_value=mock_pan_aadhaar_response
)
result = await pan_aadhaar_tool.execute(valid_pan_aadhaar_request)
assert result["linked"] is True
@pytest.mark.asyncio
async def test_aadhaar_too_long(self, pan_aadhaar_tool):
"""Test validation error for Aadhaar number that's too long."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "1234567890123", # 13 digits
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_aadhaar_too_short(self, pan_aadhaar_tool):
"""Test validation error for Aadhaar number that's too short."""
invalid_request = {
"pan": "ABCPE1234F",
"aadhaar_number": "12345678901", # 11 digits
"consent": "Y",
"reason": "Test"
}
with pytest.raises(ValueError):
await pan_aadhaar_tool.execute(invalid_request)
@pytest.mark.asyncio
async def test_multiple_individual_pan_formats(
self, pan_aadhaar_tool, mock_pan_aadhaar_response
):
"""Test that various individual PAN formats are accepted."""
valid_pans = ["ABCPE1234F", "XYZPQ5678R", "LMNPA9012S"]
pan_aadhaar_tool.api_client.post = AsyncMock(
return_value=mock_pan_aadhaar_response
)
for pan in valid_pans:
request = {
"pan": pan,
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Test"
}
result = await pan_aadhaar_tool.execute(request)
assert result["linked"] is True
@pytest.mark.asyncio
async def test_cache_key_includes_both_identifiers(self, pan_aadhaar_tool):
"""Test that cache key is based on both PAN and Aadhaar."""
request1 = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Test"
}
request2 = {
"pan": "ABCPE1234F",
"aadhaar_number": "987654321098", # Different Aadhaar
"consent": "Y",
"reason": "Test"
}
key1 = pan_aadhaar_tool.get_cache_key(request1)
key2 = pan_aadhaar_tool.get_cache_key(request2)
# Different Aadhaar should result in different cache key
assert key1 != key2
@pytest.mark.asyncio
async def test_reason_not_affecting_cache_key(self, pan_aadhaar_tool):
"""Test that reason field doesn't affect cache key."""
request1 = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Reason 1"
}
request2 = {
"pan": "ABCPE1234F",
"aadhaar_number": "123456789012",
"consent": "Y",
"reason": "Reason 2" # Different reason
}
key1 = pan_aadhaar_tool.get_cache_key(request1)
key2 = pan_aadhaar_tool.get_cache_key(request2)
# Same PAN and Aadhaar should result in same cache key
assert key1 == key2