Refactor: reorganización completa del proyecto y documentación consolidada
Esta actualización reorganiza el proyecto de reverse engineering de la API de ADIF con los siguientes cambios: Estructura del proyecto: - Movida documentación principal a carpeta docs/ - Consolidados archivos markdown redundantes en CLAUDE.md (contexto completo del proyecto) - Organización de tests en carpeta tests/ con README explicativo - APK renombrado de base.apk a adif.apk para mayor claridad Archivos de código: - Movidos adif_auth.py y adif_client.py a la raíz (antes en api_testing_scripts/) - Eliminados scripts de testing obsoletos y scripts de Frida no utilizados - Nuevos tests detallados: test_endpoints_detailed.py y test_onepaths_with_real_trains.py Descubrimientos: - Documentados nuevos hallazgos en docs/NEW_DISCOVERIES.md - Actualización de onePaths funcionando con commercialNumber real (devuelve 200) - Extraídos 1587 códigos de estación en station_codes.txt Configuración: - Actualizado .gitignore con mejores patrones para Python e IDEs - Eliminados archivos temporales de depuración y logs
This commit is contained in:
160
tests/README.md
Normal file
160
tests/README.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Tests - ADIF API
|
||||
|
||||
Scripts de prueba para validar la funcionalidad de la API de ADIF.
|
||||
|
||||
## 🧪 Tests Activos
|
||||
|
||||
### test_endpoints_detailed.py
|
||||
Test exhaustivo de todos los endpoints con información de debug completa.
|
||||
|
||||
**Características**:
|
||||
- Muestra status codes, headers y respuesta JSON
|
||||
- Prueba múltiples variaciones de payload
|
||||
- Identifica errores 400, 401 y sus causas
|
||||
- Útil para debugging de nuevos endpoints
|
||||
|
||||
**Uso**:
|
||||
```bash
|
||||
python3 tests/test_endpoints_detailed.py
|
||||
```
|
||||
|
||||
**Salida esperada**:
|
||||
- Información detallada de cada petición
|
||||
- Análisis de errores con mensajes del servidor
|
||||
- Diferenciación entre errores de payload vs permisos
|
||||
|
||||
---
|
||||
|
||||
### test_onepaths_with_real_trains.py
|
||||
Test funcional que obtiene trenes reales y prueba el endpoint `onepaths`.
|
||||
|
||||
**Características**:
|
||||
- Consulta `departures` para obtener trenes circulando
|
||||
- Extrae `commercialNumber`, `launchingDate`, códigos de estación
|
||||
- Prueba `onepaths` con datos reales
|
||||
- Valida que el endpoint funciona correctamente
|
||||
|
||||
**Uso**:
|
||||
```bash
|
||||
python3 tests/test_onepaths_with_real_trains.py
|
||||
```
|
||||
|
||||
**Requisitos**:
|
||||
- Ejecutar durante el día (cuando hay trenes circulando)
|
||||
- Si se ejecuta de noche/madrugada puede no encontrar trenes
|
||||
|
||||
**Salida esperada**:
|
||||
```
|
||||
======================================================================
|
||||
PASO 1: Obteniendo trenes reales de Madrid Atocha
|
||||
======================================================================
|
||||
✅ Obtenidos 25 trenes
|
||||
|
||||
======================================================================
|
||||
PASO 2: Probando onePaths con trenes reales
|
||||
======================================================================
|
||||
✅ SUCCESS! onePaths funciona con datos reales
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Tests Archivados
|
||||
|
||||
La carpeta `archived/` contiene tests antiguos que fueron útiles durante el desarrollo pero ya no son necesarios:
|
||||
|
||||
- `test_all_endpoints.py` - Versión simple sin debug
|
||||
- `test_complete_bodies.py` - Pruebas de payloads completos
|
||||
- `test_corrected_api.py` / `test_corrected_api_v2.py` - Versiones anteriores
|
||||
- `test_real_auth.py` - Tests de autenticación básicos
|
||||
- `test_simple.py` - Test minimalista
|
||||
- `test_with_auth_headers.py` - Validación de headers
|
||||
- `test_without_auth.py` - Test sin autenticación
|
||||
- `debug_auth.py` - Debug del algoritmo HMAC
|
||||
|
||||
Estos tests se mantienen por si son útiles como referencia, pero los tests activos son más completos.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Estructura de un Test
|
||||
|
||||
### Template Básico
|
||||
|
||||
```python
|
||||
from adif_auth import AdifAuthenticator
|
||||
import requests
|
||||
import uuid
|
||||
|
||||
ACCESS_KEY = "and20210615"
|
||||
SECRET_KEY = "Jthjtr946RTt"
|
||||
|
||||
def test_endpoint():
|
||||
auth = AdifAuthenticator(access_key=ACCESS_KEY, secret_key=SECRET_KEY)
|
||||
|
||||
url = "https://circulacion.api.adif.es/portroyalmanager/secure/..."
|
||||
payload = {
|
||||
# Tu payload aquí
|
||||
}
|
||||
|
||||
user_id = str(uuid.uuid4())
|
||||
headers = auth.get_auth_headers("POST", url, payload, user_id=user_id)
|
||||
headers["User-key"] = auth.USER_KEY_CIRCULATION
|
||||
|
||||
response = requests.post(url, json=payload, headers=headers, timeout=10)
|
||||
|
||||
assert response.status_code == 200
|
||||
print(f"✅ Test passed: {response.json()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_endpoint()
|
||||
```
|
||||
|
||||
### Análisis de Status Codes
|
||||
|
||||
```python
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS - Endpoint funcional")
|
||||
data = response.json()
|
||||
|
||||
elif response.status_code == 204:
|
||||
print("⚠️ NO CONTENT - Autenticación correcta pero sin datos")
|
||||
|
||||
elif response.status_code == 400:
|
||||
print("❌ BAD REQUEST - Payload incorrecto")
|
||||
print(f"Error: {response.json()}")
|
||||
|
||||
elif response.status_code == 401:
|
||||
print("❌ UNAUTHORIZED - Sin permisos")
|
||||
print(f"Error: {response.json()}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Resultados Esperados
|
||||
|
||||
### Endpoints Funcionales (200)
|
||||
- `/departures/traffictype/`
|
||||
- `/arrivals/traffictype/`
|
||||
- `/onepaths/` (con commercialNumber real)
|
||||
- `/stationsobservations/`
|
||||
|
||||
### Endpoints Bloqueados (401)
|
||||
- `/betweenstations/traffictype/`
|
||||
- `/onestation/`
|
||||
- `/severalpaths/`
|
||||
- `/compositions/path/`
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips para Crear Nuevos Tests
|
||||
|
||||
1. **Usar `test_endpoints_detailed.py` como base** - Tiene buen manejo de errores
|
||||
2. **Validar timestamps** - Usar milisegundos, no segundos
|
||||
3. **Probar con datos reales** - Como hace `test_onepaths_with_real_trains.py`
|
||||
4. **Diferenciar errores**:
|
||||
- 400 = Payload incorrecto → Revisar campos
|
||||
- 401 = Sin permisos → Las claves no tienen acceso
|
||||
- 204 = Sin datos → Autenticación OK, pero respuesta vacía
|
||||
|
||||
---
|
||||
|
||||
**Última actualización**: 2025-12-05
|
||||
180
tests/test_api_authenticated.py
Normal file
180
tests/test_api_authenticated.py
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test de endpoints de Adif con autenticación HMAC-SHA256
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
# Agregar raíz del proyecto al path para importar adif_auth
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
import requests
|
||||
import json
|
||||
from adif_auth import AdifAuthenticator
|
||||
|
||||
# Claves extraídas con Frida
|
||||
ACCESS_KEY = "and20210615"
|
||||
SECRET_KEY = "Jthjtr946RTt"
|
||||
USER_ID = "0c8c32dce47f8512"
|
||||
|
||||
# Crear autenticador
|
||||
auth = AdifAuthenticator(ACCESS_KEY, SECRET_KEY, USER_ID)
|
||||
|
||||
def test_departures():
|
||||
"""Probar endpoint de salidas"""
|
||||
print("\n" + "="*70)
|
||||
print("TEST: Salidas de Madrid Atocha (Cercanías)")
|
||||
print("="*70)
|
||||
|
||||
host = "circulacion.api.adif.es"
|
||||
path = "/portroyalmanager/secure/circulationpaths/departures/traffictype/"
|
||||
url = f"https://{host}{path}"
|
||||
|
||||
payload = {
|
||||
"stationCode": "10200",
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "CERCANIAS"
|
||||
}
|
||||
|
||||
payload_str = json.dumps(payload)
|
||||
|
||||
# Firmar petición
|
||||
headers = auth.sign_request(
|
||||
method="POST",
|
||||
host=host,
|
||||
path=path,
|
||||
payload=payload_str
|
||||
)
|
||||
|
||||
print(f"\nURL: {url}")
|
||||
print(f"Payload: {payload_str}")
|
||||
print(f"\nHeaders:")
|
||||
for k, v in headers.items():
|
||||
if k == "Authorization":
|
||||
print(f" {k}: {v[:50]}...")
|
||||
else:
|
||||
print(f" {k}: {v}")
|
||||
|
||||
# Hacer petición
|
||||
try:
|
||||
response = requests.post(url, headers=headers, data=payload_str, timeout=10)
|
||||
print(f"\nStatus Code: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS!")
|
||||
data = response.json()
|
||||
print(f"\nRespuesta (preview):")
|
||||
print(json.dumps(data, indent=2, ensure_ascii=False)[:1000])
|
||||
else:
|
||||
print(f"❌ ERROR")
|
||||
print(f"Response: {response.text[:500]}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ EXCEPTION: {e}")
|
||||
|
||||
|
||||
def test_station_details():
|
||||
"""Probar endpoint de detalles de estación"""
|
||||
print("\n" + "="*70)
|
||||
print("TEST: Detalles de estación Madrid Atocha")
|
||||
print("="*70)
|
||||
|
||||
host = "estaciones.api.adif.es"
|
||||
path = "/portroyalmanager/secure/stations/onestation/"
|
||||
url = f"https://{host}{path}"
|
||||
|
||||
payload = {"stationCode": "10200"}
|
||||
payload_str = json.dumps(payload)
|
||||
|
||||
headers = auth.sign_request(
|
||||
method="POST",
|
||||
host=host,
|
||||
path=path,
|
||||
payload=payload_str
|
||||
)
|
||||
|
||||
print(f"\nURL: {url}")
|
||||
print(f"Payload: {payload_str}")
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, data=payload_str, timeout=10)
|
||||
print(f"\nStatus Code: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS!")
|
||||
data = response.json()
|
||||
print(f"\nRespuesta (preview):")
|
||||
print(json.dumps(data, indent=2, ensure_ascii=False)[:1000])
|
||||
else:
|
||||
print(f"❌ ERROR")
|
||||
print(f"Response: {response.text[:500]}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ EXCEPTION: {e}")
|
||||
|
||||
|
||||
def test_arrivals():
|
||||
"""Probar endpoint de llegadas"""
|
||||
print("\n" + "="*70)
|
||||
print("TEST: Llegadas a Madrid Atocha (Todos los tipos)")
|
||||
print("="*70)
|
||||
|
||||
host = "circulacion.api.adif.es"
|
||||
path = "/portroyalmanager/secure/circulationpaths/arrivals/traffictype/"
|
||||
url = f"https://{host}{path}"
|
||||
|
||||
payload = {
|
||||
"stationCode": "10200",
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "ALL"
|
||||
}
|
||||
|
||||
payload_str = json.dumps(payload)
|
||||
|
||||
headers = auth.sign_request(
|
||||
method="POST",
|
||||
host=host,
|
||||
path=path,
|
||||
payload=payload_str
|
||||
)
|
||||
|
||||
print(f"\nURL: {url}")
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, data=payload_str, timeout=10)
|
||||
print(f"\nStatus Code: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS!")
|
||||
data = response.json()
|
||||
print(f"\nRespuesta (preview):")
|
||||
print(json.dumps(data, indent=2, ensure_ascii=False)[:800])
|
||||
else:
|
||||
print(f"❌ ERROR")
|
||||
print(f"Response: {response.text[:500]}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ EXCEPTION: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n" + "="*70)
|
||||
print("PRUEBAS DE API ADIF CON AUTENTICACIÓN HMAC-SHA256")
|
||||
print("="*70)
|
||||
print(f"\nUsando claves:")
|
||||
print(f" ACCESS_KEY: {ACCESS_KEY}")
|
||||
print(f" SECRET_KEY: {SECRET_KEY}")
|
||||
print(f" USER_ID: {USER_ID}")
|
||||
|
||||
# Ejecutar tests
|
||||
test_departures()
|
||||
test_station_details()
|
||||
test_arrivals()
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("TESTS COMPLETADOS")
|
||||
print("="*70)
|
||||
204
tests/test_endpoints.py
Executable file
204
tests/test_endpoints.py
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script para probar diferentes endpoints de la API de Adif
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
# Agregar raíz del proyecto al path para importar adif_auth
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Headers descubiertos
|
||||
HEADERS_CIRCULATION = {
|
||||
"Content-Type": "application/json;charset=utf-8",
|
||||
"User-key": "f4ce9fbfa9d721e39b8984805901b5df"
|
||||
}
|
||||
|
||||
HEADERS_STATIONS = {
|
||||
"Content-Type": "application/json;charset=utf-8",
|
||||
"User-key": "0d021447a2fd2ac64553674d5a0c1a6f"
|
||||
}
|
||||
|
||||
HEADERS_AVISA = {
|
||||
"Content-Type": "application/json;charset=utf-8",
|
||||
"Authorization": "Basic YXZpc3RhX2NsaWVudF9hbmRyb2lkOjh5WzZKNyFmSjwhXypmYXE1NyNnOSohNElwa2MjWC1BTg=="
|
||||
}
|
||||
|
||||
# URLs base
|
||||
BASE_CIRCULATION = "https://circulacion.api.adif.es"
|
||||
BASE_STATIONS = "https://estaciones.api.adif.es"
|
||||
BASE_AVISA = "https://avisa.adif.es"
|
||||
|
||||
|
||||
def test_endpoint(name, method, url, headers, data=None):
|
||||
"""Probar un endpoint y mostrar resultado"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"TEST: {name}")
|
||||
print(f"{'='*60}")
|
||||
print(f"Method: {method}")
|
||||
print(f"URL: {url}")
|
||||
print(f"Headers: {json.dumps(headers, indent=2)}")
|
||||
|
||||
if data:
|
||||
print(f"Body: {json.dumps(data, indent=2)}")
|
||||
|
||||
try:
|
||||
if method == "GET":
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
elif method == "POST":
|
||||
response = requests.post(url, headers=headers, json=data, timeout=10)
|
||||
else:
|
||||
print(f"❌ Método {method} no soportado")
|
||||
return
|
||||
|
||||
print(f"\nStatus: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS")
|
||||
result = response.json()
|
||||
print(f"\nResponse Preview:")
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False)[:1000] + "...")
|
||||
else:
|
||||
print(f"❌ ERROR")
|
||||
print(f"Response: {response.text[:500]}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ EXCEPTION: {str(e)}")
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("PRUEBAS DE ENDPOINTS DE ADIF API")
|
||||
print("=" * 60)
|
||||
|
||||
# Test 1: Obtener salidas con diferentes formatos de body
|
||||
test_endpoint(
|
||||
"Salidas - Formato Simple",
|
||||
"POST",
|
||||
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/departures/traffictype/",
|
||||
HEADERS_CIRCULATION,
|
||||
{
|
||||
"stationCode": "10200",
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "CERCANIAS"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 2: Probar con State YES
|
||||
test_endpoint(
|
||||
"Salidas - State YES",
|
||||
"POST",
|
||||
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/departures/traffictype/",
|
||||
HEADERS_CIRCULATION,
|
||||
{
|
||||
"stationCode": "10200",
|
||||
"commercialService": "YES",
|
||||
"commercialStopType": "YES",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "ALL"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 3: Detalles de una ruta específica
|
||||
test_endpoint(
|
||||
"Detalles de Ruta",
|
||||
"POST",
|
||||
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
HEADERS_CIRCULATION,
|
||||
{
|
||||
"commercialNumber": "C1",
|
||||
"allControlPoints": False
|
||||
}
|
||||
)
|
||||
|
||||
# Test 4: Entre estaciones
|
||||
test_endpoint(
|
||||
"Entre Estaciones",
|
||||
"POST",
|
||||
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/betweenstations/traffictype/",
|
||||
HEADERS_CIRCULATION,
|
||||
{
|
||||
"originStationCode": "10200",
|
||||
"destinationStationCode": "10302",
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "ALL"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 5: Detalles de estación
|
||||
test_endpoint(
|
||||
"Detalles de Estación",
|
||||
"POST",
|
||||
f"{BASE_STATIONS}/portroyalmanager/secure/stations/onestation/",
|
||||
HEADERS_STATIONS,
|
||||
{
|
||||
"stationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 6: Observaciones de estación
|
||||
test_endpoint(
|
||||
"Observaciones de Estación",
|
||||
"POST",
|
||||
f"{BASE_STATIONS}/portroyalmanager/secure/stationsobservations/",
|
||||
HEADERS_STATIONS,
|
||||
{
|
||||
"stationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 7: Composición de tren
|
||||
test_endpoint(
|
||||
"Composición de Tren",
|
||||
"POST",
|
||||
f"{BASE_CIRCULATION}/portroyalmanager/secure/circulationpaths/compositions/path/",
|
||||
HEADERS_CIRCULATION,
|
||||
{
|
||||
"commercialNumber": "AVE 1001",
|
||||
"originStationCode": "10200",
|
||||
"destinationStationCode": "71801"
|
||||
}
|
||||
)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("RESUMEN")
|
||||
print("="*60)
|
||||
print("""
|
||||
Las pruebas han finalizado. Revisa los resultados arriba.
|
||||
|
||||
NOTAS:
|
||||
- Algunos endpoints pueden requerir códigos/números válidos
|
||||
- Los códigos de estación son numéricos (ej: 10200 para Madrid Atocha)
|
||||
- Los números comerciales varían según el tipo de tren
|
||||
- Algunos datos pueden no estar disponibles en tiempo real
|
||||
|
||||
CÓDIGOS DE ESTACIÓN COMUNES:
|
||||
- 10200: Madrid Puerta de Atocha
|
||||
- 10302: Madrid Chamartín
|
||||
- 71801: Barcelona Sants
|
||||
- 50000: Valencia Nord
|
||||
- 11401: Sevilla Santa Justa
|
||||
|
||||
TIPOS DE TRÁFICO:
|
||||
- CERCANIAS: Trenes de cercanías
|
||||
- MEDIA_DISTANCIA: Media distancia
|
||||
- LARGA_DISTANCIA: Larga distancia
|
||||
- ALL: Todos los tipos
|
||||
|
||||
ESTADOS:
|
||||
- YES: Solo servicios/paradas comerciales
|
||||
- NOT: Sin servicios/paradas comerciales
|
||||
- BOTH: Ambos tipos
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
182
tests/test_endpoints_detailed.py
Normal file
182
tests/test_endpoints_detailed.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Prueba detallada de endpoints con mensajes de error completos
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
# Agregar raíz del proyecto al path para importar adif_auth
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
import requests
|
||||
from adif_auth import AdifAuthenticator
|
||||
import uuid
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
import time
|
||||
|
||||
ACCESS_KEY = "and20210615"
|
||||
SECRET_KEY = "Jthjtr946RTt"
|
||||
|
||||
def test_endpoint_detailed(name, url, payload, use_stations_key=False):
|
||||
"""
|
||||
Prueba un endpoint y muestra información detallada
|
||||
"""
|
||||
auth = AdifAuthenticator(access_key=ACCESS_KEY, secret_key=SECRET_KEY)
|
||||
user_id = str(uuid.uuid4())
|
||||
|
||||
headers = auth.get_auth_headers("POST", url, payload, user_id=user_id)
|
||||
if use_stations_key:
|
||||
headers["User-key"] = auth.USER_KEY_STATIONS
|
||||
else:
|
||||
headers["User-key"] = auth.USER_KEY_CIRCULATION
|
||||
|
||||
print(f"\n{'='*70}")
|
||||
print(f"Testing: {name}")
|
||||
print(f"{'='*70}")
|
||||
print(f"URL: {url}")
|
||||
print(f"Payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=payload, headers=headers, timeout=10)
|
||||
print(f"\nStatus Code: {response.status_code}")
|
||||
print(f"Headers: {dict(response.headers)}")
|
||||
|
||||
try:
|
||||
response_json = response.json()
|
||||
print(f"Response Body: {json.dumps(response_json, indent=2, ensure_ascii=False)[:1000]}")
|
||||
except:
|
||||
print(f"Response Body (text): {response.text[:500]}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ FAILED - Status {response.status_code}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ ERROR: {e}")
|
||||
return False
|
||||
|
||||
# Obtener timestamps
|
||||
now = datetime.now()
|
||||
# Fecha actual al inicio del día en milisegundos
|
||||
today_start = int(datetime(now.year, now.month, now.day).timestamp() * 1000)
|
||||
# Fecha de mañana al inicio del día
|
||||
tomorrow_start = int((datetime(now.year, now.month, now.day) + timedelta(days=1)).timestamp() * 1000)
|
||||
|
||||
print(f"Testing con fechas:")
|
||||
print(f"Today (start): {today_start} = {datetime.fromtimestamp(today_start/1000)}")
|
||||
print(f"Tomorrow (start): {tomorrow_start} = {datetime.fromtimestamp(tomorrow_start/1000)}")
|
||||
|
||||
# Test betweenStations (401)
|
||||
test_endpoint_detailed(
|
||||
"BetweenStations",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpaths/betweenstations/traffictype/",
|
||||
{
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"originStationCode": "10200",
|
||||
"destinationStationCode": "71801",
|
||||
"page": {"pageNumber": 0},
|
||||
"trafficType": "ALL"
|
||||
}
|
||||
)
|
||||
|
||||
# Test onePaths con variaciones (400)
|
||||
print("\n\n" + "="*70)
|
||||
print("TESTING ONEPATHS CON DIFERENTES VARIACIONES")
|
||||
print("="*70)
|
||||
|
||||
# Variación 1: Con commercialNumber válido
|
||||
test_endpoint_detailed(
|
||||
"OnePaths - Con commercialNumber '03194'",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
{
|
||||
"allControlPoints": True,
|
||||
"commercialNumber": "03194",
|
||||
"destinationStationCode": "71801",
|
||||
"launchingDate": today_start,
|
||||
"originStationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Variación 2: Sin commercialNumber
|
||||
test_endpoint_detailed(
|
||||
"OnePaths - Sin commercialNumber (null)",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
{
|
||||
"allControlPoints": True,
|
||||
"commercialNumber": None,
|
||||
"destinationStationCode": "71801",
|
||||
"launchingDate": today_start,
|
||||
"originStationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Variación 3: Sin el campo commercialNumber completamente
|
||||
test_endpoint_detailed(
|
||||
"OnePaths - Sin campo commercialNumber",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
{
|
||||
"allControlPoints": True,
|
||||
"destinationStationCode": "71801",
|
||||
"launchingDate": today_start,
|
||||
"originStationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Variación 4: Solo con originStationCode (sin destination)
|
||||
test_endpoint_detailed(
|
||||
"OnePaths - Solo originStationCode",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
{
|
||||
"allControlPoints": True,
|
||||
"launchingDate": today_start,
|
||||
"originStationCode": "10200"
|
||||
}
|
||||
)
|
||||
|
||||
# Variación 5: Estructura mínima
|
||||
test_endpoint_detailed(
|
||||
"OnePaths - Estructura mínima",
|
||||
"https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/",
|
||||
{
|
||||
"commercialNumber": "03194",
|
||||
"launchingDate": today_start
|
||||
}
|
||||
)
|
||||
|
||||
# Test OneStation con onestation (401)
|
||||
test_endpoint_detailed(
|
||||
"OneStation",
|
||||
"https://estaciones.api.adif.es/portroyalmanager/secure/stations/onestation/",
|
||||
{
|
||||
"stationCode": "10200",
|
||||
"detailedInfo": {
|
||||
"extendedStationInfo": True,
|
||||
"stationActivities": True,
|
||||
"stationBanner": True,
|
||||
"stationCommercialServices": True,
|
||||
"stationInfo": True,
|
||||
"stationServices": True,
|
||||
"stationTransportServices": True
|
||||
}
|
||||
},
|
||||
use_stations_key=True
|
||||
)
|
||||
|
||||
# Variación: OneStation simple
|
||||
test_endpoint_detailed(
|
||||
"OneStation - Simple",
|
||||
"https://estaciones.api.adif.es/portroyalmanager/secure/stations/onestation/",
|
||||
{
|
||||
"stationCode": "10200"
|
||||
},
|
||||
use_stations_key=True
|
||||
)
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("PRUEBA COMPLETADA")
|
||||
print("="*70)
|
||||
126
tests/test_onepaths_with_real_trains.py
Executable file
126
tests/test_onepaths_with_real_trains.py
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Primero obtenemos trenes reales de departures, y luego probamos onePaths con esos números
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
# Agregar raíz del proyecto al path para importar adif_auth
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
import requests
|
||||
from adif_auth import AdifAuthenticator
|
||||
import uuid
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
ACCESS_KEY = "and20210615"
|
||||
SECRET_KEY = "Jthjtr946RTt"
|
||||
|
||||
auth = AdifAuthenticator(access_key=ACCESS_KEY, secret_key=SECRET_KEY)
|
||||
|
||||
# Paso 1: Obtener trenes reales de departures
|
||||
print("="*70)
|
||||
print("PASO 1: Obteniendo trenes reales de Madrid Atocha")
|
||||
print("="*70)
|
||||
|
||||
url = "https://circulacion.api.adif.es/portroyalmanager/secure/circulationpaths/departures/traffictype/"
|
||||
payload = {
|
||||
"commercialService": "BOTH",
|
||||
"commercialStopType": "BOTH",
|
||||
"page": {"pageNumber": 0},
|
||||
"stationCode": "10200", # Madrid Atocha
|
||||
"trafficType": "AVLDMD" # Alta Velocidad
|
||||
}
|
||||
|
||||
user_id = str(uuid.uuid4())
|
||||
headers = auth.get_auth_headers("POST", url, payload, user_id=user_id)
|
||||
headers["User-key"] = auth.USER_KEY_CIRCULATION
|
||||
|
||||
response = requests.post(url, json=payload, headers=headers, timeout=10)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"❌ Error obteniendo departures: {response.status_code}")
|
||||
print(response.text)
|
||||
exit(1)
|
||||
|
||||
data = response.json()
|
||||
trains = data.get('circulations', [])
|
||||
|
||||
print(f"✅ Obtenidos {len(trains)} trenes\n")
|
||||
|
||||
# Mostrar los primeros 5 trenes
|
||||
print("Primeros 5 trenes:")
|
||||
for i, train in enumerate(trains[:5]):
|
||||
commercial_number = train.get('commercialNumber')
|
||||
destination = train.get('destination', {})
|
||||
dest_name = destination.get('longName', 'Unknown')
|
||||
origin = train.get('origin', {})
|
||||
origin_name = origin.get('longName', 'Unknown')
|
||||
planned_time = train.get('plannedTime', 'Unknown')
|
||||
|
||||
print(f"\n{i+1}. Tren {commercial_number}")
|
||||
print(f" Origen: {origin_name}")
|
||||
print(f" Destino: {dest_name}")
|
||||
print(f" Hora salida: {planned_time}")
|
||||
|
||||
# Paso 2: Probar onePaths con trenes reales
|
||||
print("\n" + "="*70)
|
||||
print("PASO 2: Probando onePaths con trenes reales")
|
||||
print("="*70)
|
||||
|
||||
for i, train in enumerate(trains[:3]): # Probar los primeros 3
|
||||
commercial_number = train.get('commercialNumber')
|
||||
destination = train.get('destination', {})
|
||||
dest_code = destination.get('stationCode')
|
||||
origin = train.get('origin', {})
|
||||
origin_code = origin.get('stationCode')
|
||||
|
||||
# Obtener launchingDate del tren
|
||||
planned_time_str = train.get('plannedTime', '')
|
||||
# El plannedTime es algo como "08:30" - necesitamos convertirlo a timestamp
|
||||
now = datetime.now()
|
||||
today_start = int(datetime(now.year, now.month, now.day).timestamp() * 1000)
|
||||
|
||||
print(f"\n{'='*70}")
|
||||
print(f"Test {i+1}: Tren {commercial_number}")
|
||||
print(f"{'='*70}")
|
||||
|
||||
url_onepaths = "https://circulacion.api.adif.es/portroyalmanager/secure/circulationpathdetails/onepaths/"
|
||||
payload_onepaths = {
|
||||
"allControlPoints": True,
|
||||
"commercialNumber": commercial_number,
|
||||
"destinationStationCode": dest_code,
|
||||
"launchingDate": today_start,
|
||||
"originStationCode": origin_code
|
||||
}
|
||||
|
||||
print(f"Payload: {json.dumps(payload_onepaths, indent=2)}")
|
||||
|
||||
user_id = str(uuid.uuid4())
|
||||
headers = auth.get_auth_headers("POST", url_onepaths, payload_onepaths, user_id=user_id)
|
||||
headers["User-key"] = auth.USER_KEY_CIRCULATION
|
||||
|
||||
response = requests.post(url_onepaths, json=payload_onepaths, headers=headers, timeout=10)
|
||||
|
||||
print(f"\nStatus: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ SUCCESS!")
|
||||
try:
|
||||
data = response.json()
|
||||
print(f"Response: {json.dumps(data, indent=2, ensure_ascii=False)[:2000]}")
|
||||
except:
|
||||
print(f"Response text: {response.text[:500]}")
|
||||
elif response.status_code == 204:
|
||||
print("⚠️ 204 No Content - Autenticación correcta pero sin datos")
|
||||
else:
|
||||
print(f"❌ FAILED - Status {response.status_code}")
|
||||
try:
|
||||
print(f"Error: {response.json()}")
|
||||
except:
|
||||
print(f"Response text: {response.text}")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("PRUEBA COMPLETADA")
|
||||
print("="*70)
|
||||
Reference in New Issue
Block a user