import pytest
import requests
import json
from unittest.mock import Mock, patch
class TestFraudAbuseFeedbackAPI:
"""Comprehensive test cases for the Fraud and Abuse Feedback API"""
BASE_URL = "https://api.example.com/v1/feedback/payment-status"
def setup_method(self):
"""Setup test data"""
self.valid_payload = {
"storeId": "store123",
"shoppingTripId": "trip-abc-123",
"totalAmount": {
"amount": 25.99,
"code": "USD"
},
"settledAmount": {
"amount": 25.99,
"code": "USD"
},
"paymentStatusTime": 1640995200
}
# SUCCESS SCENARIOS
@patch('requests.post')
def test_successful_payment_status_accepted(self, mock_post):
"""Test successful payment status report - Accepted"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"status": "Accepted",
"reasonCode": "PAYMENT_PROCESSED"
}
mock_post.return_value = mock_response
response = requests.post(self.BASE_URL, json=self.valid_payload)
assert response.status_code == 200
data = response.json()
assert data["status"] == "Accepted"
assert "reasonCode" in data
@patch('requests.post')
def test_successful_payment_status_rejected(self, mock_post):
"""Test successful payment status report - Rejected"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"status": "Rejected",
"reasonCode": "INSUFFICIENT_FUNDS"
}
mock_post.return_value = mock_response
response = requests.post(self.BASE_URL, json=self.valid_payload)
assert response.status_code == 200
data = response.json()
assert data["status"] == "Rejected"
assert data["reasonCode"] == "INSUFFICIENT_FUNDS"
@patch('requests.post')
def test_partial_payment_scenario(self, mock_post):
"""Test partial payment where settled amount < total amount"""
partial_payload = self.valid_payload.copy()
partial_payload["settledAmount"]["amount"] = 20.00
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"status": "Accepted",
"reasonCode": "PARTIAL_PAYMENT"
}
mock_post.return_value = mock_response
response = requests.post(self.BASE_URL, json=partial_payload)
assert response.status_code == 200
data = response.json()
assert data["status"] == "Accepted"
# VALIDATION TESTS
@patch('requests.post')
def test_valid_store_id_formats(self, mock_post):
"""Test various valid storeId formats"""
valid_store_ids = ["store123", "STORE_456", "store-789", "123ABC"]
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "OK"}
mock_post.return_value = mock_response
for store_id in valid_store_ids:
payload = self.valid_payload.copy()
payload["storeId"] = store_id
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
@patch('requests.post')
def test_valid_currency_codes(self, mock_post):
"""Test various valid currency codes"""
valid_currencies = ["USD", "EUR", "GBP", "CAD", "JPY"]
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "OK"}
mock_post.return_value = mock_response
for currency in valid_currencies:
payload = self.valid_payload.copy()
payload["totalAmount"]["code"] = currency
payload["settledAmount"]["code"] = currency
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
# ERROR SCENARIOS - 400 Bad Request
@patch('requests.post')
def test_missing_required_fields(self, mock_post):
"""Test missing required fields"""
required_fields = ["storeId", "shoppingTripId", "totalAmount", "settledAmount"]
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Missing required field"}
mock_post.return_value = mock_response
for field in required_fields:
payload = self.valid_payload.copy()
del payload[field]
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_invalid_store_id_format(self, mock_post):
"""Test invalid storeId formats"""
invalid_store_ids = ["", "store@123", "store 123", "a" * 256]
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Invalid storeId format"}
mock_post.return_value = mock_response
for store_id in invalid_store_ids:
payload = self.valid_payload.copy()
payload["storeId"] = store_id
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_invalid_shopping_trip_id(self, mock_post):
"""Test invalid shoppingTripId formats"""
invalid_trip_ids = ["", "trip@123", "trip 123", "a" * 256]
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Invalid shoppingTripId format"}
mock_post.return_value = mock_response
for trip_id in invalid_trip_ids:
payload = self.valid_payload.copy()
payload["shoppingTripId"] = trip_id
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_invalid_currency_code(self, mock_post):
"""Test invalid currency codes"""
invalid_currencies = ["", "US", "USDD", "us", "123"]
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Invalid currency code"}
mock_post.return_value = mock_response
for currency in invalid_currencies:
payload = self.valid_payload.copy()
payload["totalAmount"]["code"] = currency
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_negative_amounts(self, mock_post):
"""Test negative amounts"""
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Amount cannot be negative"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["totalAmount"]["amount"] = -10.00
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_unknown_shopping_trip(self, mock_post):
"""Test 400 UnknownShoppingTrip error"""
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "UnknownShoppingTrip"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["shoppingTripId"] = "nonexistent-trip-id"
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
assert "UnknownShoppingTrip" in response.json()["errorMsg"]
@patch('requests.post')
def test_bad_request_exception(self, mock_post):
"""Test 400 BadRequestException"""
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "BadRequestException"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["storeId"] = "invalid@store"
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
assert "BadRequestException" in response.json()["errorMsg"]
# ERROR SCENARIOS - 500 Server Error
@patch('requests.post')
def test_service_exception(self, mock_post):
"""Test 500 ServiceException"""
mock_response = Mock()
mock_response.status_code = 500
mock_response.json.return_value = {"errorMsg": "ServiceException"}
mock_post.return_value = mock_response
response = requests.post(self.BASE_URL, json=self.valid_payload)
assert response.status_code == 500
assert "ServiceException" in response.json()["errorMsg"]
# EDGE CASES
@patch('requests.post')
def test_zero_amounts(self, mock_post):
"""Test zero amounts"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "ZERO_AMOUNT"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["totalAmount"]["amount"] = 0
payload["settledAmount"]["amount"] = 0
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
@patch('requests.post')
def test_large_amounts(self, mock_post):
"""Test large amounts"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "LARGE_AMOUNT"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["totalAmount"]["amount"] = 999999.99
payload["settledAmount"]["amount"] = 999999.99
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
@patch('requests.post')
def test_mismatched_currencies(self, mock_post):
"""Test mismatched currencies between total and settled amounts"""
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Currency mismatch"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["totalAmount"]["code"] = "USD"
payload["settledAmount"]["code"] = "EUR"
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
@patch('requests.post')
def test_settled_greater_than_total(self, mock_post):
"""Test settled amount greater than total amount"""
mock_response = Mock()
mock_response.status_code = 400
mock_response.json.return_value = {"errorMsg": "Settled amount exceeds total"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["totalAmount"]["amount"] = 20.00
payload["settledAmount"]["amount"] = 25.00
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 400
# BOUNDARY TESTS
@patch('requests.post')
def test_max_length_store_id(self, mock_post):
"""Test maximum length storeId (255 characters)"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "OK"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["storeId"] = "a" * 255
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
@patch('requests.post')
def test_max_length_shopping_trip_id(self, mock_post):
"""Test maximum length shoppingTripId (255 characters)"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "Accepted", "reasonCode": "OK"}
mock_post.return_value = mock_response
payload = self.valid_payload.copy()
payload["shoppingTripId"] = "a" * 255
response = requests.post(self.BASE_URL, json=payload)
assert response.status_code == 200
if __name__ == "__main__":
pytest.main([__file__])