feat: implementar Fases 3, 4 y 5 del roadmap (Planificacion Avanzada, Historial de Corridas y Copia Local Duplicada)

This commit is contained in:
Carlos Tello
2026-08-15 00:58:05 -03:00
parent 2c2cfeb867
commit 929f9affd7
11 changed files with 677 additions and 57 deletions
+81 -1
View File
@@ -4,7 +4,7 @@ import platform
import ctypes
import tempfile
from pathlib import Path
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta
from app.core.database import init_db, AsyncSessionLocal
from app.models.models import Client, BackupJob, BackupFile
@@ -12,6 +12,7 @@ from app.api.jobs import purge_orphans
from app.schemas.schemas import PurgeOrphansRequest
from app.core.config import settings
from agent.scanner import DirectoryScanner
from agent.service import is_job_due
def set_windows_attributes(filepath: Path, hidden: bool = False, system: bool = False, readonly: bool = False):
if platform.system() != "Windows":
@@ -222,3 +223,82 @@ async def test_replica_mode_purge_orphans():
assert db_files[0].is_active == True
assert db_files[2].is_active == True
assert (Path(settings.STORAGE_ROOT) / db_files[0].relative_path).exists()
def test_is_job_due_advanced():
# 1. Traditional intervals
# Last run was 50 mins ago (3000s)
last_run_iso = (datetime.now(timezone.utc) - timedelta(minutes=50)).isoformat()
assert is_job_due("hourly", last_run_iso) == False
# Last run was 70 mins ago (4200s)
last_run_iso = (datetime.now(timezone.utc) - timedelta(minutes=70)).isoformat()
assert is_job_due("hourly", last_run_iso) == True
# 2. Calendar schedule match
# Let's test a simple day:
# If the scheduled time occurred in the window, it is due.
five_mins_ago = datetime.now(timezone.utc) - timedelta(minutes=5)
day_name = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"][five_mins_ago.weekday()]
time_str = five_mins_ago.strftime("%H:%M")
sched_str = f"{day_name} {time_str}"
last_run = (five_mins_ago - timedelta(hours=1)).strftime("%Y-%m-%d %H:%M:%S")
assert is_job_due(sched_str, last_run) == True
# 3. Cron schedule match
# Cron format: minute hour day month weekday (0-6 starting Sunday)
cron_weekday = (five_mins_ago.weekday() + 1) % 7
cron_str = f"{five_mins_ago.minute} {five_mins_ago.hour} * * {cron_weekday}"
assert is_job_due(cron_str, last_run) == True
@pytest.mark.asyncio
async def test_job_runs_api_telemetry():
"""
Tests the creation, execution tracking, and completion endpoints of job runs.
"""
async with AsyncSessionLocal() as db:
# 1. Setup client and job
client = Client(
client_code="CLIENT-R-01",
name="Runs Test Machine",
status="ONLINE",
storage_used_bytes=0,
storage_quota_bytes=100000
)
db.add(client)
await db.flush()
job = BackupJob(
job_code="JOB-R-01",
client_id=client.id,
name="Runs Test Job",
source_path="C:\\RunsSource"
)
db.add(job)
await db.commit()
# 2. Simulate runs endpoints inside backend
from app.api.jobs import start_job_run, complete_job_run
from app.schemas.schemas import JobRunStartRequest, JobRunCompleteRequest
start_req = JobRunStartRequest(client_id=client.id)
run_res = await start_job_run(job_id=job.id, payload=start_req, db=db, current_client=client)
assert run_res.status == "RUNNING"
assert run_res.job_id == job.id
# Complete the run
complete_req = JobRunCompleteRequest(
status="SUCCESS",
files_scanned=10,
files_copied=3,
files_skipped=7,
errors_count=0,
bytes_transferred=50000
)
completed_res = await complete_job_run(job_id=job.id, run_id=run_res.id, payload=complete_req, db=db, current_client=client)
assert completed_res.status == "SUCCESS"
assert completed_res.files_scanned == 10
assert completed_res.files_copied == 3
assert completed_res.files_skipped == 7
assert completed_res.errors_count == 0
assert completed_res.bytes_transferred == 50000