File size: 10,655 Bytes
705812e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
"""Test the API with real examples to verify it's working."""

from __future__ import annotations

import json
import sys
import time
from datetime import datetime

import requests

BASE_URL = "https://LogicGoInfotechSpaces-duplicate-transaction-detection.hf.space"


def print_section(title: str):
    """Print a formatted section header."""
    print("\n" + "=" * 70)
    print(f"  {title}")
    print("=" * 70)


def test_health_endpoint():
    """Test the health endpoint."""
    print_section("TEST 1: Health Check Endpoint")
    
    try:
        response = requests.get(f"{BASE_URL}/health", timeout=10)
        print(f"URL: {BASE_URL}/health")
        print(f"Status Code: {response.status_code}")
        print(f"Response: {json.dumps(response.json(), indent=2)}")
        
        if response.status_code == 200:
            print("\n[SUCCESS] Health endpoint is working!")
            return True
        else:
            print(f"\n[ERROR] Unexpected status code: {response.status_code}")
            return False
    except Exception as e:
        print(f"\n[ERROR] Health check failed: {e}")
        return False


def test_suggestions_endpoint():
    """Test the suggestions endpoint with different parameters."""
    print_section("TEST 2: Suggestions Endpoint")
    
    # Test 1: Default limit
    print("\n--- Test 2.1: Get suggestions (default limit) ---")
    try:
        response = requests.get(f"{BASE_URL}/suggestions", timeout=60)
        print(f"URL: {BASE_URL}/suggestions")
        print(f"Status Code: {response.status_code}")
        
        if response.status_code == 200:
            suggestions = response.json()
            print(f"Total suggestions returned: {len(suggestions)}")
            
            if suggestions:
                print("\nFirst suggestion example:")
                first = suggestions[0]
                print(f"  - ID: {first.get('_id')}")
                print(f"  - Candidate IDs: {first.get('candidate_ids', [])[:3]}")
                print(f"  - Message: {first.get('message')}")
                print(f"  - Amount Delta: {first.get('details', {}).get('amount_delta_pct', 0):.2f}%")
                print(f"  - Time Delta: {first.get('details', {}).get('time_delta_minutes', 0):.2f} minutes")
                print(f"  - Merchant Match: {first.get('details', {}).get('merchant_match_rule')}")
                print(f"  - Generated At: {first.get('audit', {}).get('generated_at')}")
                print(f"  - Status: {first.get('status')}")
            else:
                print("  No suggestions found (scheduler may not have run yet)")
            
            print("\n[SUCCESS] Suggestions endpoint is working!")
            return True
        else:
            print(f"\n[ERROR] Unexpected status code: {response.status_code}")
            print(f"Response: {response.text[:200]}")
            return False
    except Exception as e:
        print(f"\n[ERROR] Suggestions request failed: {e}")
        return False


def test_suggestions_with_limit():
    """Test suggestions endpoint with custom limit."""
    print_section("TEST 3: Suggestions with Custom Limit")
    
    print("\n--- Test 3.1: Get 5 suggestions ---")
    try:
        response = requests.get(f"{BASE_URL}/suggestions", params={"limit": 5}, timeout=60)
        print(f"URL: {BASE_URL}/suggestions?limit=5")
        print(f"Status Code: {response.status_code}")
        
        if response.status_code == 200:
            suggestions = response.json()
            print(f"Suggestions returned: {len(suggestions)} (requested: 5)")
            
            if suggestions:
                print("\nSample suggestions summary:")
                for i, sug in enumerate(suggestions[:3], 1):
                    candidates = sug.get('candidate_ids', [])
                    print(f"  {i}. {len(candidates)} candidates, "
                          f"Amount delta: {sug.get('details', {}).get('amount_delta_pct', 0):.2f}%, "
                          f"Time delta: {sug.get('details', {}).get('time_delta_minutes', 0):.2f} min")
            
            print("\n[SUCCESS] Custom limit parameter working!")
            return True
        else:
            print(f"\n[ERROR] Unexpected status code: {response.status_code}")
            return False
    except Exception as e:
        print(f"\n[ERROR] Request failed: {e}")
        return False


def test_scheduler_activity():
    """Check if scheduler is generating new suggestions."""
    print_section("TEST 4: Scheduler Activity Check")
    
    print("\nChecking if scheduler is actively generating suggestions...")
    print("(This checks timestamps to see if suggestions are recent)")
    
    try:
        response = requests.get(f"{BASE_URL}/suggestions", params={"limit": 10}, timeout=60)
        if response.status_code == 200:
            suggestions = response.json()
            
            if suggestions:
                # Get the most recent suggestion
                most_recent = suggestions[0]  # They should be sorted by date
                generated_at_str = most_recent.get('audit', {}).get('generated_at')
                
                if generated_at_str:
                    try:
                        # Parse the timestamp
                        generated_at = datetime.fromisoformat(generated_at_str.replace('Z', '+00:00'))
                        now = datetime.utcnow()
                        age_minutes = (now - generated_at.replace(tzinfo=None)).total_seconds() / 60
                        
                        print(f"\nMost recent suggestion:")
                        print(f"  Generated at: {generated_at_str}")
                        print(f"  Age: {age_minutes:.1f} minutes ago")
                        
                        if age_minutes < 120:  # Less than 2 hours
                            print(f"\n[SUCCESS] Scheduler appears to be active! (Recent suggestions found)")
                        else:
                            print(f"\n[INFO] Most recent suggestion is {age_minutes:.1f} minutes old")
                            print("  (Scheduler may be running but no new duplicates detected)")
                    except Exception as e:
                        print(f"\n[INFO] Could not parse timestamp: {e}")
                
                # Count suggestions by status
                statuses = {}
                for sug in suggestions:
                    status = sug.get('status', 'unknown')
                    statuses[status] = statuses.get(status, 0) + 1
                
                print(f"\nSuggestion status breakdown:")
                for status, count in statuses.items():
                    print(f"  - {status}: {count}")
                
                return True
            else:
                print("\n[INFO] No suggestions found yet")
                print("  The scheduler may need more time to detect duplicates")
                return True
        else:
            print(f"\n[ERROR] Failed to get suggestions: {response.status_code}")
            return False
    except Exception as e:
        print(f"\n[ERROR] Check failed: {e}")
        return False


def test_api_response_format():
    """Verify the API response format matches expected schema."""
    print_section("TEST 5: API Response Format Validation")
    
    try:
        response = requests.get(f"{BASE_URL}/suggestions", params={"limit": 1}, timeout=60)
        if response.status_code == 200:
            suggestions = response.json()
            
            if suggestions:
                suggestion = suggestions[0]
                print("\nValidating response structure...")
                
                required_fields = ['_id', 'candidate_ids', 'message', 'details', 'audit', 'status']
                missing_fields = [field for field in required_fields if field not in suggestion]
                
                if missing_fields:
                    print(f"[ERROR] Missing required fields: {missing_fields}")
                    return False
                else:
                    print("[OK] All required fields present")
                
                # Validate details structure
                details = suggestion.get('details', {})
                detail_fields = ['amount_delta_pct', 'time_delta_minutes', 'merchant_match_rule']
                missing_details = [f for f in detail_fields if f not in details]
                
                if missing_details:
                    print(f"[WARN] Missing detail fields: {missing_details}")
                else:
                    print("[OK] Details structure valid")
                
                # Validate audit structure
                audit = suggestion.get('audit', {})
                if 'generated_by' in audit and 'generated_at' in audit:
                    print("[OK] Audit structure valid")
                else:
                    print("[WARN] Audit structure incomplete")
                
                print("\n[SUCCESS] Response format is valid!")
                return True
            else:
                print("[INFO] No suggestions to validate (format check skipped)")
                return True
        else:
            print(f"[ERROR] Failed to get response: {response.status_code}")
            return False
    except Exception as e:
        print(f"[ERROR] Validation failed: {e}")
        return False


def main():
    """Run all API tests."""
    print("\n" + "=" * 70)
    print("  API TESTING SUITE")
    print("  Testing: " + BASE_URL)
    print("=" * 70)
    
    results = []
    
    # Run all tests
    results.append(("Health Endpoint", test_health_endpoint()))
    results.append(("Suggestions Endpoint", test_suggestions_endpoint()))
    results.append(("Custom Limit Parameter", test_suggestions_with_limit()))
    results.append(("Scheduler Activity", test_scheduler_activity()))
    results.append(("Response Format", test_api_response_format()))
    
    # Summary
    print_section("TEST SUMMARY")
    
    passed = sum(1 for _, result in results if result)
    total = len(results)
    
    print("\nTest Results:")
    for test_name, result in results:
        status = "[PASS]" if result else "[FAIL]"
        print(f"  {status} {test_name}")
    
    print(f"\n{'=' * 70}")
    print(f"  Total: {passed}/{total} tests passed")
    print("=" * 70)
    
    if passed == total:
        print("\n[SUCCESS] All API tests passed! The API is working correctly.")
        return 0
    else:
        print(f"\n[WARNING] {total - passed} test(s) failed. Check the details above.")
        return 1


if __name__ == "__main__":
    sys.exit(main())