**Documentation:** - Added docs/geofence-testing.md with comprehensive test guide - Includes all test scripts, manual testing procedures - Troubleshooting section for common issues - Cleanup instructions **Configuration:** - Updated admin user email to joachim.hummel@gmail.com - Restored MQTT_BROKER_URL to mosquitto (Docker setup) - Fixed test-mqtt-geofence.js to use admin credentials **Test Results:** ✅ Database & Logic Test - Working perfectly ✅ Email Notification Test - Email sent successfully ✅ MQTT Integration - Server connects, receives messages ⚠️ Full chain test - Works but duplicate detection prevents retests **What's Working:** - Geofence creation and management via API - Distance calculations (Haversine formula) - Enter/Exit event generation with state tracking - SMTP email delivery with React Email templates - MQTT subscriber integration **Ready for Production:** The geofencing MVP is fully functional and ready for real-world testing with OwnTracks devices sending unique location updates. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
279 lines
7.0 KiB
Markdown
279 lines
7.0 KiB
Markdown
# Geofence Testing Guide
|
||
|
||
This document describes how to test the geofencing functionality.
|
||
|
||
## Prerequisites
|
||
|
||
- Database initialized: `npm run db:init`
|
||
- SMTP configured in `.env` or admin panel
|
||
- MQTT broker running (for full integration test)
|
||
|
||
## Test Scripts
|
||
|
||
### 1. Database & Logic Test
|
||
|
||
Tests geofence core functionality without MQTT or emails.
|
||
|
||
```bash
|
||
npm run test:geofence
|
||
```
|
||
|
||
**What it does:**
|
||
- Creates a test geofence in Frankfurt (50.1109, 8.6821)
|
||
- Simulates 4 location updates (Outside → Inside → Inside → Outside)
|
||
- Generates Enter and Exit events
|
||
- Shows event history
|
||
|
||
**Expected output:**
|
||
```
|
||
✓ Created geofence (ID: ...)
|
||
📌 Processing location "Outside (Start)"...
|
||
📏 Distance from center: 1158m (OUTSIDE)
|
||
ℹ No event (no state change)
|
||
|
||
📌 Processing location "Inside (Enter)"...
|
||
📏 Distance from center: 0m (INSIDE)
|
||
🔔 Generated ENTER event (ID: 1)
|
||
|
||
📌 Processing location "Inside (Stay)"...
|
||
📏 Distance from center: 73m (INSIDE)
|
||
ℹ No event (no state change)
|
||
|
||
📌 Processing location "Outside (Exit)"...
|
||
📏 Distance from center: 1158m (OUTSIDE)
|
||
🔔 Generated EXIT event (ID: 2)
|
||
|
||
Total events generated: 2
|
||
```
|
||
|
||
### 2. Email Notification Test
|
||
|
||
Tests SMTP connection and email delivery without MQTT.
|
||
|
||
```bash
|
||
npm run test:geofence:email
|
||
```
|
||
|
||
**What it does:**
|
||
- Connects to SMTP server
|
||
- Sends a test geofence notification email
|
||
- Validates email template rendering
|
||
|
||
**Expected output:**
|
||
```
|
||
✓ SMTP connection successful!
|
||
✓ Email prepared
|
||
✅ Email sent successfully!
|
||
|
||
Message ID: <...>
|
||
Check your inbox at: joachim.hummel@gmail.com
|
||
```
|
||
|
||
**Email you should receive:**
|
||
- Subject: "Device A hat Test Zone betreten"
|
||
- Formatted HTML with geofence details
|
||
- Time, position, distance from center
|
||
|
||
### 3. Full MQTT Integration Test
|
||
|
||
Tests the complete flow: MQTT → Location → Geofence → Email.
|
||
|
||
**Requirements:**
|
||
- MQTT broker must be accessible
|
||
- Admin credentials in `.env` (MQTT_ADMIN_USERNAME, MQTT_ADMIN_PASSWORD)
|
||
|
||
```bash
|
||
npm run test:geofence:mqtt
|
||
```
|
||
|
||
**What it does:**
|
||
- Creates a test geofence
|
||
- Connects to MQTT broker
|
||
- Publishes 4 OwnTracks location messages
|
||
- Triggers geofence events
|
||
- Results in email notifications (if dev server is running)
|
||
|
||
**Expected output:**
|
||
```
|
||
✓ Created test geofence: "MQTT Integration Test Zone"
|
||
✓ Connected to MQTT broker
|
||
📡 Publishing location: Outside (Start)
|
||
✓ Published
|
||
📡 Publishing location: Inside (Enter - should trigger EMAIL)
|
||
✓ Published
|
||
...
|
||
✅ Published 4 MQTT location messages
|
||
✅ Expected: 2 email notifications (Enter + Exit)
|
||
```
|
||
|
||
## Manual Testing with OwnTracks
|
||
|
||
### Setup
|
||
|
||
1. Create a geofence via API or script
|
||
2. Configure OwnTracks app with your MQTT credentials
|
||
3. Move device in/out of geofence zone
|
||
|
||
### Create Geofence Manually
|
||
|
||
```bash
|
||
# Get session cookie from browser (login first)
|
||
curl -X POST http://localhost:3000/api/geofences \
|
||
-H "Content-Type: application/json" \
|
||
-H "Cookie: authjs.session-token=YOUR_COOKIE" \
|
||
-d '{
|
||
"name": "My Test Zone",
|
||
"center_latitude": 50.1109,
|
||
"center_longitude": 8.6821,
|
||
"radius_meters": 500,
|
||
"device_id": "12",
|
||
"color": "#10b981"
|
||
}'
|
||
```
|
||
|
||
### Send Test MQTT Message
|
||
|
||
```bash
|
||
# ENTER geofence (inside the zone)
|
||
mosquitto_pub -h localhost -p 1883 \
|
||
-u admin -P 'YOUR_ADMIN_PASSWORD' \
|
||
-t "owntracks/user/12" \
|
||
-m '{"_type":"location","tid":"12","lat":50.1109,"lon":8.6821,"tst":'"$(date +%s)"',"batt":85,"vel":0}'
|
||
|
||
# Wait 5 seconds, then EXIT geofence (outside the zone)
|
||
mosquitto_pub -h localhost -p 1883 \
|
||
-u admin -P 'YOUR_ADMIN_PASSWORD' \
|
||
-t "owntracks/user/12" \
|
||
-m '{"_type":"location","tid":"12","lat":50.1200,"lon":8.6900,"tst":'"$(date +%s)"',"batt":84,"vel":5}'
|
||
```
|
||
|
||
**Expected:**
|
||
- Dev server logs show: `✓ Location saved: 12 at (...)`
|
||
- Geofence events logged: `[Geofence] Detected 1 event(s) for device 12`
|
||
- Email notification sent to owner
|
||
|
||
## Verify Results
|
||
|
||
### Check Events in Database
|
||
|
||
```bash
|
||
sqlite3 data/database.sqlite "
|
||
SELECT
|
||
id,
|
||
event_type,
|
||
timestamp,
|
||
CAST(distance_from_center AS INTEGER) as distance,
|
||
CASE notification_sent
|
||
WHEN 0 THEN 'Pending'
|
||
WHEN 1 THEN 'Sent'
|
||
WHEN 2 THEN 'Failed'
|
||
END as notification
|
||
FROM GeofenceEvent
|
||
ORDER BY id DESC
|
||
LIMIT 10
|
||
"
|
||
```
|
||
|
||
### Check Geofences
|
||
|
||
```bash
|
||
sqlite3 data/database.sqlite "
|
||
SELECT
|
||
id,
|
||
name,
|
||
device_id,
|
||
radius_meters,
|
||
is_active
|
||
FROM Geofence
|
||
"
|
||
```
|
||
|
||
### View Events via API
|
||
|
||
```bash
|
||
curl http://localhost:3000/api/geofences \
|
||
-H "Cookie: authjs.session-token=YOUR_COOKIE"
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
### No Events Generated
|
||
|
||
**Problem:** Location updates don't trigger events.
|
||
|
||
**Possible causes:**
|
||
1. **Duplicate location** - The unique index prevents duplicate locations
|
||
- Solution: Send locations with unique timestamps and coordinates
|
||
2. **Geofence inactive** - Check `is_active = 1` in database
|
||
3. **Wrong device** - Geofence is for different device
|
||
4. **MQTT subscriber not running** - Start dev server: `npm run dev`
|
||
|
||
### Email Not Received
|
||
|
||
**Problem:** Events are created but no email arrives.
|
||
|
||
**Check:**
|
||
1. **SMTP configuration** - Test with `npm run test:geofence:email`
|
||
2. **User email** - Check owner has email in database:
|
||
```bash
|
||
sqlite3 data/database.sqlite "SELECT id, username, email FROM User"
|
||
```
|
||
3. **Notification status** - Check `notification_sent` in GeofenceEvent table
|
||
4. **Spam folder** - Check your spam/junk folder
|
||
|
||
### MQTT Connection Failed
|
||
|
||
**Problem:** `MQTT connection error: ECONNREFUSED` or `Not authorized`
|
||
|
||
**Solutions:**
|
||
1. **Check broker URL** - Verify `MQTT_BROKER_URL` in `.env`
|
||
2. **Check credentials** - Verify `MQTT_ADMIN_USERNAME` and `MQTT_ADMIN_PASSWORD`
|
||
3. **Broker running** - Check: `nc -zv localhost 1883`
|
||
4. **Firewall** - Ensure port 1883 is open
|
||
|
||
## Cleanup
|
||
|
||
### Delete Test Geofences
|
||
|
||
```bash
|
||
# List all geofences
|
||
sqlite3 data/database.sqlite "SELECT id, name FROM Geofence"
|
||
|
||
# Delete specific geofence (CASCADE deletes events and status)
|
||
sqlite3 data/database.sqlite "DELETE FROM Geofence WHERE id = 'GEOFENCE_ID'"
|
||
|
||
# Or via API
|
||
curl -X DELETE http://localhost:3000/api/geofences/GEOFENCE_ID \
|
||
-H "Cookie: authjs.session-token=YOUR_COOKIE"
|
||
```
|
||
|
||
### Delete Old Events
|
||
|
||
```bash
|
||
# Delete events older than 30 days
|
||
sqlite3 data/database.sqlite "
|
||
DELETE FROM GeofenceEvent
|
||
WHERE timestamp < datetime('now', '-30 days')
|
||
"
|
||
```
|
||
|
||
## Next Steps
|
||
|
||
After successful testing:
|
||
|
||
1. **Deploy to production** - Ensure SMTP and MQTT are configured
|
||
2. **Create frontend UI** - Visual geofence editor on map (not yet implemented)
|
||
3. **Configure real devices** - Set up OwnTracks on mobile devices
|
||
4. **Monitor notifications** - Check GeofenceEvent table regularly
|
||
|
||
## Test Summary
|
||
|
||
| Test | What it validates | Duration |
|
||
|------|------------------|----------|
|
||
| `npm run test:geofence` | Database, logic, calculations | ~1 second |
|
||
| `npm run test:geofence:email` | SMTP, email templates | ~3 seconds |
|
||
| `npm run test:geofence:mqtt` | Full integration chain | ~10 seconds |
|
||
| Manual OwnTracks test | Real-world usage | Varies |
|
||
|
||
All tests are **non-destructive** and create test data that can be easily cleaned up.
|