Add comprehensive testing infrastructure
- Testing strategy document - Unit tests for GPS validator - Integration test conftest with fixtures - Sample .sub files and manifests - Comprehensive Termux testing guide - Test directory structure
This commit is contained in:
@@ -0,0 +1,654 @@
|
||||
# Termux Manual Testing Guide
|
||||
|
||||
**Purpose**: Validate GigLez Phase 1 & 2 in real Termux environment
|
||||
**Branch**: `p1-p2-validation`
|
||||
**Prerequisites**: Android device with Termux installed
|
||||
|
||||
---
|
||||
|
||||
## Pre-Flight Checklist
|
||||
|
||||
- [ ] Termux installed from F-Droid (not Play Store)
|
||||
- [ ] Device has at least 2GB free storage
|
||||
- [ ] Stable internet connection for package installation
|
||||
- [ ] USB OTG cable (if testing with T-Embed)
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Environment Setup (30 minutes)
|
||||
|
||||
### 1.1 Update Termux Packages
|
||||
```bash
|
||||
pkg update && pkg upgrade -y
|
||||
```
|
||||
|
||||
### 1.2 Install Required Packages
|
||||
```bash
|
||||
# PostgreSQL
|
||||
pkg install postgresql -y
|
||||
|
||||
# Python and development tools
|
||||
pkg install python python-pip git -y
|
||||
|
||||
# Build dependencies
|
||||
pkg install build-essential libffi openssl -y
|
||||
```
|
||||
|
||||
**Expected**: All packages install without errors
|
||||
|
||||
### 1.3 Clone Repository
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/yourusername/giglez.git
|
||||
cd giglez
|
||||
git checkout p1-p2-validation
|
||||
```
|
||||
|
||||
**Expected**: Repository cloned, on validation branch
|
||||
|
||||
### 1.4 Install Python Dependencies
|
||||
```bash
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install pytest pytest-asyncio python-multipart
|
||||
```
|
||||
|
||||
**Expected**: All dependencies install successfully
|
||||
**Common Issue**: If psycopg2 fails, try `pkg install postgresql-dev` first
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Database Setup (10 minutes)
|
||||
|
||||
### 2.1 Initialize PostgreSQL
|
||||
```bash
|
||||
initdb ~/postgres
|
||||
pg_ctl -D ~/postgres -l ~/postgres/logfile start
|
||||
```
|
||||
|
||||
**Expected**: PostgreSQL starts, log file created
|
||||
**Verify**: `pg_ctl -D ~/postgres status` shows "server is running"
|
||||
|
||||
### 2.2 Create Database
|
||||
```bash
|
||||
cd ~/giglez
|
||||
./scripts/setup_database.sh
|
||||
```
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
✅ User giglez_user created
|
||||
✅ Database giglez created
|
||||
✅ PostGIS extension enabled
|
||||
```
|
||||
|
||||
**Troubleshoot**: If permission denied, run:
|
||||
```bash
|
||||
chmod +x scripts/setup_database.sh
|
||||
```
|
||||
|
||||
### 2.3 Create Schema
|
||||
```bash
|
||||
psql -U giglez_user -d giglez -h localhost -f scripts/create_schema.sql
|
||||
```
|
||||
|
||||
**Expected**: 15 tables created, no errors
|
||||
**Verify**:
|
||||
```bash
|
||||
psql -U giglez_user -d giglez -h localhost -c "\dt"
|
||||
```
|
||||
Should list: users, sessions, devices, captures, signatures, etc.
|
||||
|
||||
### 2.4 Test PostGIS
|
||||
```bash
|
||||
psql -U giglez_user -d giglez -h localhost -c "SELECT PostGIS_Version();"
|
||||
```
|
||||
|
||||
**Expected**: PostGIS version string (3.x)
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Configuration Test (5 minutes)
|
||||
|
||||
### 3.1 Copy Environment File
|
||||
```bash
|
||||
cp .env.development .env
|
||||
```
|
||||
|
||||
### 3.2 Edit Configuration
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
**Adjust paths**:
|
||||
```bash
|
||||
GIGLEZ_STORAGE_PATH=/data/data/com.termux/files/home/giglez/storage
|
||||
GIGLEZ_QUEUE_PATH=/data/data/com.termux/files/home/giglez/queue
|
||||
```
|
||||
|
||||
**Save**: Ctrl+O, Enter, Ctrl+X
|
||||
|
||||
### 3.3 Test Configuration
|
||||
```bash
|
||||
python config/settings.py
|
||||
```
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
========================================================
|
||||
GigLez Configuration
|
||||
========================================================
|
||||
Mode: development
|
||||
Database: postgresql://giglez_user:****@localhost:5432/giglez
|
||||
API: 127.0.0.1:8000
|
||||
Storage: filesystem
|
||||
Hardware: Disabled
|
||||
Authentication: Optional
|
||||
...
|
||||
✅ Configuration validated successfully
|
||||
```
|
||||
|
||||
**Troubleshoot**: If validation fails, check .env file syntax
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Unit Tests (10 minutes)
|
||||
|
||||
### 4.1 Run GPS Validator Tests
|
||||
```bash
|
||||
pytest tests/unit/test_gps_validator.py -v
|
||||
```
|
||||
|
||||
**Expected**: All tests pass (green)
|
||||
**Count**: ~20 tests
|
||||
|
||||
### 4.2 Run Storage Tests (when implemented)
|
||||
```bash
|
||||
pytest tests/unit/test_storage.py -v
|
||||
```
|
||||
|
||||
### 4.3 Run All Unit Tests
|
||||
```bash
|
||||
pytest tests/unit/ -v
|
||||
```
|
||||
|
||||
**Success Criteria**: All unit tests pass
|
||||
|
||||
---
|
||||
|
||||
## Step 5: API Server Test (10 minutes)
|
||||
|
||||
### 5.1 Start API Server
|
||||
```bash
|
||||
python src/api/main.py
|
||||
```
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
============================================================
|
||||
GigLez API Starting
|
||||
============================================================
|
||||
Mode: development
|
||||
...
|
||||
✅ Database connection established
|
||||
✅ PostGIS extension available
|
||||
✅ Storage backend initialized: LocalStorage
|
||||
============================================================
|
||||
🚀 GigLez API ready on 127.0.0.1:8000
|
||||
📡 Mode: development
|
||||
============================================================
|
||||
```
|
||||
|
||||
**Troubleshoot**: If port 8000 busy, change in .env
|
||||
|
||||
### 5.2 Test Health Endpoint
|
||||
Open new Termux session (swipe from left, "New session"):
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/health
|
||||
```
|
||||
|
||||
**Expected**:
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"database": "connected",
|
||||
"mode": "development",
|
||||
"hardware_enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Test API Info
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/
|
||||
```
|
||||
|
||||
**Expected**: JSON with API name, version, status
|
||||
|
||||
### 5.4 Test OpenAPI Docs
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/docs
|
||||
```
|
||||
|
||||
**Expected**: HTML response (OpenAPI documentation)
|
||||
|
||||
**Browser Test**: If you have Termux:API installed:
|
||||
```bash
|
||||
termux-open-url http://127.0.0.1:8000/docs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Upload Test (15 minutes)
|
||||
|
||||
### 6.1 Create Test .sub File
|
||||
```bash
|
||||
cd ~/giglez
|
||||
cat > test_capture.sub << 'EOF'
|
||||
Filetype: Flipper SubGhz Key File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok270Async
|
||||
Protocol: Princeton
|
||||
Bit: 24
|
||||
Key: 00 00 00 00 00 95 D5 D4
|
||||
TE: 400
|
||||
EOF
|
||||
```
|
||||
|
||||
### 6.2 Create Test Manifest
|
||||
```bash
|
||||
cat > test_manifest.json << 'EOF'
|
||||
{
|
||||
"session_uuid": "termux-test-001",
|
||||
"captures": [
|
||||
{
|
||||
"filename": "test_capture.sub",
|
||||
"latitude": 40.7128,
|
||||
"longitude": -74.0060,
|
||||
"accuracy": 5.0,
|
||||
"altitude": 10.5,
|
||||
"timestamp": "2026-01-12T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 6.3 Upload Test File
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat test_manifest.json)" \
|
||||
-F "files=@test_capture.sub"
|
||||
```
|
||||
|
||||
**Expected Response**:
|
||||
```json
|
||||
{
|
||||
"session_uuid": "termux-test-001",
|
||||
"uploaded": 1,
|
||||
"duplicates": 0,
|
||||
"errors": 0,
|
||||
"results": [
|
||||
{
|
||||
"filename": "test_capture.sub",
|
||||
"status": "uploaded",
|
||||
"file_hash": "abc123...",
|
||||
"frequency": 433920000,
|
||||
"protocol": "Princeton"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Success Criteria**:
|
||||
- `uploaded: 1`
|
||||
- `errors: 0`
|
||||
- `file_hash` present
|
||||
- `status: "uploaded"`
|
||||
|
||||
### 6.4 Verify in Database
|
||||
```bash
|
||||
psql -U giglez_user -d giglez -h localhost << 'SQL'
|
||||
SELECT file_hash, frequency, protocol, latitude, longitude
|
||||
FROM captures
|
||||
LIMIT 5;
|
||||
SQL
|
||||
```
|
||||
|
||||
**Expected**: Your capture listed with correct data
|
||||
|
||||
### 6.5 Verify in Storage
|
||||
```bash
|
||||
ls -lh ~/giglez/storage/
|
||||
```
|
||||
|
||||
**Expected**: Directory structure with .sub file:
|
||||
```
|
||||
storage/
|
||||
└── ab/
|
||||
└── c1/
|
||||
└── abc123...def.sub
|
||||
```
|
||||
|
||||
### 6.6 Test Duplicate Upload
|
||||
```bash
|
||||
# Upload same file again
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat test_manifest.json)" \
|
||||
-F "files=@test_capture.sub"
|
||||
```
|
||||
|
||||
**Expected Response**:
|
||||
```json
|
||||
{
|
||||
"uploaded": 0,
|
||||
"duplicates": 1,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
**Success Criteria**: Duplicate detected, not re-uploaded
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Query Test (5 minutes)
|
||||
|
||||
### 7.1 Get Capture by Hash
|
||||
Get file_hash from previous upload response, then:
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/api/v1/captures/{FILE_HASH}
|
||||
```
|
||||
|
||||
Replace `{FILE_HASH}` with actual hash.
|
||||
|
||||
**Expected**: JSON with capture details
|
||||
|
||||
### 7.2 Test Invalid Hash
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/api/v1/captures/invalid_hash_12345
|
||||
```
|
||||
|
||||
**Expected**: 404 error with message "Capture not found"
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Multiple File Upload (10 minutes)
|
||||
|
||||
### 8.1 Create Multiple Test Files
|
||||
```bash
|
||||
# Create 3 different captures
|
||||
for i in {1..3}; do
|
||||
cat > test_capture_${i}.sub << EOF
|
||||
Filetype: Flipper SubGhz Key File
|
||||
Version: 1
|
||||
Frequency: $((433920000 + i * 1000))
|
||||
Preset: FuriHalSubGhzPresetOok270Async
|
||||
Protocol: Princeton
|
||||
Bit: 24
|
||||
Key: 00 00 00 00 00 95 D5 $(printf '%02X' $i)
|
||||
TE: 400
|
||||
EOF
|
||||
done
|
||||
```
|
||||
|
||||
### 8.2 Create Multi-File Manifest
|
||||
```bash
|
||||
cat > multi_manifest.json << 'EOF'
|
||||
{
|
||||
"session_uuid": "termux-multi-test-001",
|
||||
"captures": [
|
||||
{
|
||||
"filename": "test_capture_1.sub",
|
||||
"latitude": 40.7128,
|
||||
"longitude": -74.0060,
|
||||
"accuracy": 5.0,
|
||||
"timestamp": "2026-01-12T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"filename": "test_capture_2.sub",
|
||||
"latitude": 40.7129,
|
||||
"longitude": -74.0061,
|
||||
"accuracy": 6.0,
|
||||
"timestamp": "2026-01-12T10:00:10Z"
|
||||
},
|
||||
{
|
||||
"filename": "test_capture_3.sub",
|
||||
"latitude": 40.7130,
|
||||
"longitude": -74.0062,
|
||||
"accuracy": 4.0,
|
||||
"timestamp": "2026-01-12T10:00:20Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 8.3 Upload Multiple Files
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat multi_manifest.json)" \
|
||||
-F "files=@test_capture_1.sub" \
|
||||
-F "files=@test_capture_2.sub" \
|
||||
-F "files=@test_capture_3.sub"
|
||||
```
|
||||
|
||||
**Expected**: `uploaded: 3`, all 3 files processed successfully
|
||||
|
||||
### 8.4 Verify Count
|
||||
```bash
|
||||
psql -U giglez_user -d giglez -h localhost -c \
|
||||
"SELECT COUNT(*) FROM captures;"
|
||||
```
|
||||
|
||||
**Expected**: At least 4 captures (1 from previous + 3 new)
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Error Handling Tests (5 minutes)
|
||||
|
||||
### 9.1 Test Invalid GPS
|
||||
```bash
|
||||
cat > bad_gps_manifest.json << 'EOF'
|
||||
{
|
||||
"session_uuid": "test-errors",
|
||||
"captures": [
|
||||
{
|
||||
"filename": "test_capture.sub",
|
||||
"latitude": 91.0,
|
||||
"longitude": 0.0,
|
||||
"accuracy": 5.0,
|
||||
"timestamp": "2026-01-12T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat bad_gps_manifest.json)" \
|
||||
-F "files=@test_capture.sub"
|
||||
```
|
||||
|
||||
**Expected**: Error in response, file rejected
|
||||
|
||||
### 9.2 Test Missing Manifest Entry
|
||||
```bash
|
||||
cat > incomplete_manifest.json << 'EOF'
|
||||
{
|
||||
"session_uuid": "test-incomplete",
|
||||
"captures": []
|
||||
}
|
||||
EOF
|
||||
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat incomplete_manifest.json)" \
|
||||
-F "files=@test_capture.sub"
|
||||
```
|
||||
|
||||
**Expected**: Error for missing manifest entry
|
||||
|
||||
### 9.3 Test Invalid JSON
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest={invalid json}" \
|
||||
-F "files=@test_capture.sub"
|
||||
```
|
||||
|
||||
**Expected**: 400 Bad Request with JSON error message
|
||||
|
||||
---
|
||||
|
||||
## Step 10: Performance Test (5 minutes)
|
||||
|
||||
### 10.1 Upload 10 Files Rapidly
|
||||
```bash
|
||||
# Create 10 test files
|
||||
for i in {1..10}; do
|
||||
cp test_capture.sub bulk_test_${i}.sub
|
||||
done
|
||||
|
||||
# Note: This will create duplicates, testing deduplication
|
||||
time for i in {1..10}; do
|
||||
curl -X POST http://127.0.0.1:8000/api/v1/captures/upload \
|
||||
-F "manifest=$(cat test_manifest.json)" \
|
||||
-F "files=@bulk_test_${i}.sub" &
|
||||
done
|
||||
wait
|
||||
```
|
||||
|
||||
**Monitor**: Check API logs for performance
|
||||
**Expected**: All requests complete, duplicates detected
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria Checklist
|
||||
|
||||
### Database (Phase 1)
|
||||
- [ ] PostgreSQL installs and starts
|
||||
- [ ] Database schema creates without errors
|
||||
- [ ] PostGIS extension available
|
||||
- [ ] Can insert and query captures
|
||||
- [ ] Triggers execute (session stats update)
|
||||
|
||||
### API (Phase 2)
|
||||
- [ ] API server starts without errors
|
||||
- [ ] Health endpoint responds correctly
|
||||
- [ ] OpenAPI docs accessible
|
||||
- [ ] Configuration loads correctly
|
||||
- [ ] Storage backend initializes
|
||||
|
||||
### Upload Workflow
|
||||
- [ ] Single file upload succeeds
|
||||
- [ ] Multiple file upload succeeds
|
||||
- [ ] Duplicate detection works
|
||||
- [ ] GPS validation works (rejects invalid)
|
||||
- [ ] Files stored in correct directory structure
|
||||
- [ ] Database records created correctly
|
||||
- [ ] Session management works
|
||||
|
||||
### Error Handling
|
||||
- [ ] Invalid GPS rejected
|
||||
- [ ] Invalid JSON handled
|
||||
- [ ] Missing manifest entries handled
|
||||
- [ ] Malformed .sub files handled (if tested)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### PostgreSQL Won't Start
|
||||
```bash
|
||||
# Check if already running
|
||||
ps aux | grep postgres
|
||||
|
||||
# Kill existing processes
|
||||
pkill postgres
|
||||
|
||||
# Remove old PID file
|
||||
rm ~/postgres/postmaster.pid
|
||||
|
||||
# Restart
|
||||
pg_ctl -D ~/postgres -l ~/postgres/logfile start
|
||||
```
|
||||
|
||||
### API Port Already in Use
|
||||
```bash
|
||||
# Find process using port 8000
|
||||
netstat -tuln | grep 8000
|
||||
|
||||
# Kill process (if needed)
|
||||
pkill -f "python src/api/main.py"
|
||||
```
|
||||
|
||||
### Permission Errors
|
||||
```bash
|
||||
# Fix script permissions
|
||||
chmod +x scripts/*.sh
|
||||
|
||||
# Fix storage directory
|
||||
mkdir -p ~/giglez/storage
|
||||
chmod 755 ~/giglez/storage
|
||||
```
|
||||
|
||||
### Import Errors
|
||||
```bash
|
||||
# Reinstall dependencies
|
||||
pip install --upgrade --force-reinstall -r requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cleanup (Optional)
|
||||
|
||||
### Stop Services
|
||||
```bash
|
||||
# Stop API server (Ctrl+C in server terminal)
|
||||
|
||||
# Stop PostgreSQL
|
||||
pg_ctl -D ~/postgres stop
|
||||
```
|
||||
|
||||
### Remove Test Data
|
||||
```bash
|
||||
# Clean database
|
||||
psql -U giglez_user -d giglez -h localhost -c "TRUNCATE captures CASCADE;"
|
||||
|
||||
# Clean storage
|
||||
rm -rf ~/giglez/storage/*
|
||||
|
||||
# Remove test files
|
||||
rm ~/giglez/test_*.sub
|
||||
rm ~/giglez/*.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Results Template
|
||||
|
||||
### Environment Info
|
||||
- **Device**: [Device model]
|
||||
- **Android Version**: [Version]
|
||||
- **Termux Version**: [Version]
|
||||
- **PostgreSQL Version**: [Run `psql --version`]
|
||||
- **Python Version**: [Run `python --version`]
|
||||
|
||||
### Test Results
|
||||
- **Database Setup**: ✅ / ❌
|
||||
- **API Startup**: ✅ / ❌
|
||||
- **Single Upload**: ✅ / ❌
|
||||
- **Multiple Upload**: ✅ / ❌
|
||||
- **Duplicate Detection**: ✅ / ❌
|
||||
- **GPS Validation**: ✅ / ❌
|
||||
- **Error Handling**: ✅ / ❌
|
||||
|
||||
### Issues Found
|
||||
[List any bugs or issues discovered]
|
||||
|
||||
### Performance Notes
|
||||
- Upload time (single file): [X seconds]
|
||||
- Upload time (3 files): [X seconds]
|
||||
- API response time: [X ms average]
|
||||
|
||||
---
|
||||
|
||||
**Testing Complete!**
|
||||
Document results in TESTING_RESULTS.md
|
||||
Reference in New Issue
Block a user