523 lines
14 KiB
Markdown
523 lines
14 KiB
Markdown
# Local Testing Without Docker
|
|
|
|
This guide shows how to test the ACH processing system locally without Docker or SFTP server.
|
|
|
|
## Option 1: Direct File Testing (Simplest)
|
|
|
|
This approach tests the core processing logic by using local files directly.
|
|
|
|
### 1. Setup Test Files
|
|
|
|
```bash
|
|
# Create local test directories
|
|
mkdir -p test_files/HDFC/NACH
|
|
mkdir -p test_files/ICICI/NACH
|
|
|
|
# Copy sample ACH file
|
|
cp ACH_99944_19012026103217_001.txt test_files/HDFC/NACH/
|
|
cp ACH_99944_19012026103217_001.txt test_files/ICICI/NACH/ACH_12345_05122025102947_001.txt
|
|
```
|
|
|
|
### 2. Create Local Testing Script
|
|
|
|
Create `test_local.py`:
|
|
|
|
```bash
|
|
cat > test_local.py << 'EOF'
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Local testing script - test core processing without SFTP/Database.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
from pathlib import Path
|
|
|
|
# Test data mapper
|
|
print("\n" + "="*80)
|
|
print("TEST 1: Data Mapper")
|
|
print("="*80)
|
|
|
|
from processors.data_mapper import DataMapper
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
# Test date conversion
|
|
d = DataMapper.convert_date('19/01/26')
|
|
assert d == date(2026, 1, 19), f"Expected 2026-01-19, got {d}"
|
|
print("✓ Date conversion: '19/01/26' → 2026-01-19")
|
|
|
|
# Test TXNIND
|
|
assert DataMapper.calculate_txnind('100.50') == 'CR'
|
|
assert DataMapper.calculate_txnind('-50.00') == 'DR'
|
|
print("✓ TXNIND calculation: 100.50 → CR, -50.00 → DR")
|
|
|
|
# Test amount
|
|
amt = DataMapper.convert_amount('-100.50')
|
|
assert amt == Decimal('100.50')
|
|
print("✓ Amount conversion: -100.50 → 100.50 (absolute)")
|
|
|
|
# Test transaction mapping
|
|
from ach_parser import ACHParser
|
|
parser = ACHParser('ACH_99944_19012026103217_001.txt')
|
|
transactions, metadata, summary = parser.parse()
|
|
print(f"✓ ACH Parser: Extracted {len(transactions)} transactions")
|
|
|
|
mapped = DataMapper.map_transaction(transactions[0], 'HDFC')
|
|
print(f"✓ Transaction mapping: Single transaction mapped to DB format")
|
|
|
|
all_mapped = DataMapper.map_transactions(transactions, 'HDFC')
|
|
print(f"✓ Batch mapping: {len(all_mapped)} transactions mapped")
|
|
|
|
# Test file monitor
|
|
print("\n" + "="*80)
|
|
print("TEST 2: File Monitor")
|
|
print("="*80)
|
|
|
|
from sftp.file_monitor import FileMonitor
|
|
|
|
# Test filename parsing
|
|
filename = 'ACH_99944_05122025102947_001.txt'
|
|
parsed = FileMonitor.parse_filename(filename)
|
|
assert parsed['branch'] == '99944'
|
|
assert parsed['day'] == '05'
|
|
assert parsed['month'] == '12'
|
|
assert parsed['year'] == '2025'
|
|
print(f"✓ Filename parsing: {filename}")
|
|
print(f" Branch: {parsed['branch']}")
|
|
print(f" Timestamp: {parsed['timestamp']}")
|
|
|
|
# Test filename validation
|
|
invalid = 'invalid_file.txt'
|
|
parsed = FileMonitor.parse_filename(invalid)
|
|
assert parsed == {}
|
|
print(f"✓ Invalid filename rejected: {invalid}")
|
|
|
|
# Test local file discovery
|
|
print("\n" + "="*80)
|
|
print("TEST 3: Local File Discovery")
|
|
print("="*80)
|
|
|
|
# Find ACH files locally
|
|
test_dir = Path('test_files')
|
|
if test_dir.exists():
|
|
ach_files = list(test_dir.glob('**/ACH_*.txt'))
|
|
print(f"✓ Found {len(ach_files)} test ACH files locally:")
|
|
for f in ach_files:
|
|
print(f" - {f.relative_to(test_dir)}")
|
|
|
|
# Test configuration
|
|
print("\n" + "="*80)
|
|
print("TEST 4: Configuration")
|
|
print("="*80)
|
|
|
|
from config import get_config
|
|
cfg = get_config()
|
|
print(f"✓ Bank codes: {cfg.bank_codes}")
|
|
print(f"✓ Poll interval: {cfg.poll_interval_minutes} minutes")
|
|
print(f"✓ Batch size: {cfg.batch_size}")
|
|
|
|
# Summary
|
|
print("\n" + "="*80)
|
|
print("ALL TESTS PASSED ✓")
|
|
print("="*80)
|
|
print("\nCore processing logic is working correctly.")
|
|
print("Ready for database and SFTP integration testing.")
|
|
print("\nNext steps:")
|
|
print("1. Install Oracle Instant Client (for DB testing)")
|
|
print("2. Create database tables")
|
|
print("3. Configure .env with actual credentials")
|
|
print("4. Test with actual SFTP server")
|
|
print("5. Deploy to production")
|
|
EOF
|
|
|
|
python test_local.py
|
|
```
|
|
|
|
### 3. Run the Test
|
|
|
|
```bash
|
|
python test_local.py
|
|
```
|
|
|
|
Expected output:
|
|
```
|
|
================================================================================
|
|
TEST 1: Data Mapper
|
|
================================================================================
|
|
✓ Date conversion: '19/01/26' → 2026-01-19
|
|
✓ TXNIND calculation: 100.50 → CR, -50.00 → DR
|
|
✓ Amount conversion: -100.50 → 100.50 (absolute)
|
|
✓ ACH Parser: Extracted 178 transactions
|
|
✓ Transaction mapping: Single transaction mapped to DB format
|
|
✓ Batch mapping: 178 transactions mapped
|
|
|
|
================================================================================
|
|
TEST 2: File Monitor
|
|
================================================================================
|
|
✓ Filename parsing: ACH_99944_05122025102947_001.txt
|
|
Branch: 99944
|
|
Timestamp: 05/12/2025 10:29:47
|
|
✓ Invalid filename rejected: invalid_file.txt
|
|
|
|
================================================================================
|
|
TEST 3: Local File Discovery
|
|
================================================================================
|
|
✓ Found 2 test ACH files locally:
|
|
- HDFC/NACH/ACH_99944_19012026103217_001.txt
|
|
- ICICI/NACH/ACH_12345_05122025102947_001.txt
|
|
|
|
================================================================================
|
|
TEST 4: Configuration
|
|
================================================================================
|
|
✓ Bank codes: ['HDFC', 'ICICI', 'SBI', 'AXIS', 'PNB']
|
|
✓ Poll interval: 1 minutes
|
|
✓ Batch size: 100
|
|
|
|
================================================================================
|
|
ALL TESTS PASSED ✓
|
|
================================================================================
|
|
```
|
|
|
|
---
|
|
|
|
## Option 2: Python Mock SFTP Server (Local)
|
|
|
|
If you want to test SFTP locally without Docker, use the included mock SFTP server.
|
|
|
|
### 1. Start Mock SFTP Server
|
|
|
|
```bash
|
|
# Start the server in one terminal
|
|
python tests/mock_sftp_server.py
|
|
```
|
|
|
|
Expected output:
|
|
```
|
|
================================================================================
|
|
Mock SFTP Server for Testing
|
|
================================================================================
|
|
✓ Created ./sftp_data/HDFC/NACH
|
|
✓ Created ./sftp_data/ICICI/NACH
|
|
✓ Created ./sftp_data/SBI/NACH
|
|
|
|
Starting mock SFTP server...
|
|
[INFO] Mock SFTP server listening on 127.0.0.1:2222
|
|
[INFO] SFTP root: /home/asif/projects/ach_ui_dbtl_file_based/sftp_data
|
|
[INFO] Username: ipks, Password: ipks_password
|
|
|
|
================================================================================
|
|
Server running. Press CTRL+C to stop.
|
|
|
|
To test connection:
|
|
sftp -P 2222 ipks@127.0.0.1
|
|
Password: ipks_password
|
|
|
|
To use with application:
|
|
SFTP_HOST=127.0.0.1
|
|
SFTP_PORT=2222
|
|
SFTP_USERNAME=ipks
|
|
SFTP_PASSWORD=ipks_password
|
|
================================================================================
|
|
```
|
|
|
|
### 2. Test SFTP Connection (in another terminal)
|
|
|
|
```bash
|
|
# Test connection
|
|
sftp -P 2222 ipks@127.0.0.1
|
|
# Password: ipks_password
|
|
|
|
# Commands to try:
|
|
sftp> ls
|
|
sftp> cd HDFC/NACH
|
|
sftp> ls
|
|
sftp> put ACH_99944_19012026103217_001.txt
|
|
sftp> quit
|
|
```
|
|
|
|
### 3. Configure for Testing
|
|
|
|
Edit `.env`:
|
|
|
|
```bash
|
|
SFTP_HOST=127.0.0.1
|
|
SFTP_PORT=2222
|
|
SFTP_USERNAME=ipks
|
|
SFTP_PASSWORD=ipks_password
|
|
SFTP_BASE_PATH=/home/ipks/IPKS_FILES/REPORTS
|
|
POLL_INTERVAL_MINUTES=1
|
|
BANK_CODES=HDFC,ICICI,SBI
|
|
```
|
|
|
|
### 4. Copy Test Files to Mock SFTP
|
|
|
|
```bash
|
|
mkdir -p sftp_data/HDFC/NACH
|
|
cp ACH_99944_19012026103217_001.txt sftp_data/HDFC/NACH/
|
|
```
|
|
|
|
### 5. Run Application
|
|
|
|
In another terminal:
|
|
|
|
```bash
|
|
source venv/bin/activate
|
|
python main.py
|
|
```
|
|
|
|
Note: This will try to connect to the database. Without a real database, it will fail, but you can see SFTP operations working.
|
|
|
|
---
|
|
|
|
## Option 3: Unit Tests Only
|
|
|
|
Test without SFTP or Database - just the logic.
|
|
|
|
```bash
|
|
# Run unit tests
|
|
pytest tests/ -v
|
|
|
|
# Output:
|
|
# tests/test_data_mapper.py::TestDataMapper::test_convert_date_valid PASSED
|
|
# tests/test_data_mapper.py::TestDataMapper::test_calculate_txnind_credit PASSED
|
|
# tests/test_data_mapper.py::TestDataMapper::test_convert_amount PASSED
|
|
# tests/test_data_mapper.py::TestDataMapper::test_map_transaction PASSED
|
|
# tests/test_file_monitor.py::TestFileMonitor::test_parse_filename_valid PASSED
|
|
# ...
|
|
```
|
|
|
|
---
|
|
|
|
## Option 4: Database-Only Testing (Local SQLite for testing)
|
|
|
|
Test database logic without Oracle. Use SQLite for testing first.
|
|
|
|
### 1. Create Test Database Module
|
|
|
|
Create `tests/test_with_sqlite.py`:
|
|
|
|
```bash
|
|
cat > tests/test_with_sqlite.py << 'EOF'
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Test database operations with SQLite (no Oracle required).
|
|
"""
|
|
|
|
import sqlite3
|
|
import tempfile
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
print("\n" + "="*80)
|
|
print("SQLite Database Testing")
|
|
print("="*80)
|
|
|
|
# Create temporary database
|
|
temp_db = tempfile.mktemp(suffix='.db')
|
|
conn = sqlite3.connect(temp_db)
|
|
cursor = conn.cursor()
|
|
|
|
print(f"✓ Created test database: {temp_db}")
|
|
|
|
# Create test tables
|
|
cursor.execute("""
|
|
CREATE TABLE ach_api_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
narration TEXT,
|
|
status TEXT,
|
|
bankcode TEXT,
|
|
jrnl_id TEXT,
|
|
tran_date DATE,
|
|
cbs_acct TEXT,
|
|
tran_amt DECIMAL(15, 2),
|
|
TXNIND TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
cursor.execute("""
|
|
CREATE TABLE ach_processed_files (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
filename TEXT UNIQUE NOT NULL,
|
|
bankcode TEXT,
|
|
file_path TEXT,
|
|
processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
transaction_count INTEGER,
|
|
status TEXT DEFAULT 'SUCCESS',
|
|
error_message TEXT
|
|
)
|
|
""")
|
|
|
|
conn.commit()
|
|
print("✓ Created tables: ach_api_log, ach_processed_files")
|
|
|
|
# Test data insertion
|
|
test_data = [
|
|
('Test Remark 1', '23-DEP-PROCESSED', 'HDFC', '001', '2026-01-19', '1001', 100.50, 'CR'),
|
|
('Test Remark 2', '23-DEP-PROCESSED', 'HDFC', '002', '2026-01-19', '1002', 50.00, 'CR'),
|
|
('Test Remark 3', '23-DEP-PROCESSED', 'ICICI', '003', '2026-01-20', '2001', 75.75, 'CR'),
|
|
]
|
|
|
|
insert_sql = """
|
|
INSERT INTO ach_api_log (narration, status, bankcode, jrnl_id, tran_date, cbs_acct, tran_amt, TXNIND)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
"""
|
|
|
|
cursor.executemany(insert_sql, test_data)
|
|
conn.commit()
|
|
print(f"✓ Inserted {len(test_data)} test transactions")
|
|
|
|
# Query test
|
|
cursor.execute("SELECT COUNT(*) FROM ach_api_log")
|
|
count = cursor.fetchone()[0]
|
|
assert count == 3, f"Expected 3 records, got {count}"
|
|
print(f"✓ Query test: Found {count} transactions")
|
|
|
|
cursor.execute("SELECT * FROM ach_api_log WHERE bankcode = 'HDFC'")
|
|
hdfc_records = cursor.fetchall()
|
|
assert len(hdfc_records) == 2, f"Expected 2 HDFC records, got {len(hdfc_records)}"
|
|
print(f"✓ Bank filter: Found {len(hdfc_records)} HDFC transactions")
|
|
|
|
# Test processed files tracking
|
|
file_data = ('ACH_99944_19012026103217_001.txt', 'HDFC', '/path/to/file', 3, 'SUCCESS', None)
|
|
cursor.execute("""
|
|
INSERT INTO ach_processed_files (filename, bankcode, file_path, transaction_count, status, error_message)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
""", file_data)
|
|
conn.commit()
|
|
print("✓ File tracking: Marked file as processed")
|
|
|
|
# Test duplicate detection
|
|
cursor.execute("SELECT COUNT(*) FROM ach_processed_files WHERE filename = 'ACH_99944_19012026103217_001.txt'")
|
|
dup_count = cursor.fetchone()[0]
|
|
assert dup_count == 1, "Duplicate detection failed"
|
|
print("✓ Duplicate detection: Working correctly")
|
|
|
|
# Test transaction with rollback
|
|
cursor.execute("BEGIN TRANSACTION")
|
|
cursor.execute("""
|
|
INSERT INTO ach_api_log (narration, status, bankcode, jrnl_id, tran_date, cbs_acct, tran_amt, TXNIND)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
""", ('Rollback Test', '23-DEP-PROCESSED', 'SBI', '099', '2026-01-20', '9001', 999.99, 'CR'))
|
|
cursor.execute("ROLLBACK")
|
|
conn.commit()
|
|
|
|
cursor.execute("SELECT COUNT(*) FROM ach_api_log WHERE narration = 'Rollback Test'")
|
|
rb_count = cursor.fetchone()[0]
|
|
assert rb_count == 0, "Rollback did not work"
|
|
print("✓ Transaction safety: Rollback works correctly")
|
|
|
|
# Summary
|
|
print("\n" + "="*80)
|
|
print("DATABASE TESTS PASSED ✓")
|
|
print("="*80)
|
|
print("\nSQLite testing confirms:")
|
|
print(" ✓ Table structure works")
|
|
print(" ✓ Data insertion works")
|
|
print(" ✓ Queries work")
|
|
print(" ✓ Duplicate detection works")
|
|
print(" ✓ Transactions work")
|
|
print("\nReady for Oracle integration.")
|
|
|
|
# Cleanup
|
|
cursor.close()
|
|
conn.close()
|
|
Path(temp_db).unlink()
|
|
print(f"\n✓ Cleaned up test database")
|
|
EOF
|
|
|
|
python tests/test_with_sqlite.py
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Summary
|
|
|
|
### Without Docker/SFTP/Database:
|
|
```bash
|
|
python test_local.py # Tests data mapper, file monitor, config
|
|
pytest tests/ -v # Unit tests
|
|
```
|
|
|
|
### With Local Mock SFTP (Optional):
|
|
```bash
|
|
# Terminal 1
|
|
python tests/mock_sftp_server.py
|
|
|
|
# Terminal 2
|
|
python main.py # Will test SFTP but fail on DB
|
|
```
|
|
|
|
### With SQLite Database (Optional):
|
|
```bash
|
|
python tests/test_with_sqlite.py # Tests database logic
|
|
```
|
|
|
|
---
|
|
|
|
## What Gets Tested in Each Scenario
|
|
|
|
| Scenario | Data Mapper | File Monitor | SFTP | Database | Full Pipeline |
|
|
|----------|:-----------:|:------------:|:----:|:--------:|:-------------:|
|
|
| Option 1 (Local) | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
| Option 2 (SFTP) | ✓ | ✓ | ✓ | ✗ | ✗ |
|
|
| Option 3 (Unit) | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
| Option 4 (SQLite) | ✓ | ✓ | ✗ | ✓ | ✗ |
|
|
| Full (With Oracle) | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
|
|
---
|
|
|
|
## Recommended Testing Path
|
|
|
|
1. **Start**: `python test_local.py` (verify core logic)
|
|
2. **Unit Tests**: `pytest tests/ -v` (verify edge cases)
|
|
3. **SFTP**: `python tests/mock_sftp_server.py` (verify file operations)
|
|
4. **Database**: Setup Oracle & test with real database
|
|
5. **Full Pipeline**: Deploy and monitor in production
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### ImportError: No module named 'paramiko'
|
|
Mock SFTP server requires paramiko. Install it:
|
|
```bash
|
|
pip install paramiko cryptography
|
|
```
|
|
|
|
### "Address already in use" on port 2222
|
|
Either:
|
|
- Change port in mock_sftp_server.py
|
|
- Kill previous server process
|
|
- Wait a minute for socket to reset
|
|
|
|
### Test files not found
|
|
Make sure test_files directory exists:
|
|
```bash
|
|
mkdir -p test_files/HDFC/NACH test_files/ICICI/NACH
|
|
cp ACH_99944_19012026103217_001.txt test_files/HDFC/NACH/
|
|
```
|
|
|
|
### Permission Denied errors
|
|
Ensure directory permissions are correct:
|
|
```bash
|
|
chmod -R 755 test_files/
|
|
chmod -R 755 sftp_data/
|
|
```
|
|
|
|
---
|
|
|
|
## Next Steps After Testing
|
|
|
|
Once core logic is verified locally:
|
|
|
|
1. Install Oracle Instant Client
|
|
2. Create database tables
|
|
3. Update .env with real credentials
|
|
4. Test with actual SFTP server
|
|
5. Deploy to production
|
|
|
|
See SETUP.md for detailed Oracle setup instructions.
|