This commit is contained in:
devRaGonSa
2026-06-05 16:57:25 +02:00
commit 0da8338ba8
310 changed files with 45849 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
$ErrorActionPreference = "Stop"
Write-Host "Historical UI regression validation"
function Assert-Contains {
param(
[string] $Content,
[string] $Pattern,
[string] $Message
)
if ($Content -notmatch [regex]::Escape($Pattern)) {
throw $Message
}
}
function Assert-NotContains {
param(
[string] $Content,
[string] $Pattern,
[string] $Message
)
if ($Content -match [regex]::Escape($Pattern)) {
throw $Message
}
}
function Get-VisibleText {
param([string] $Html)
return ($Html -replace "<script[\s\S]*?</script>", " " `
-replace "<style[\s\S]*?</style>", " " `
-replace "<[^>]+>", " ")
}
$historicoHtml = Get-Content -Raw "frontend/historico.html"
$historicoPartidaHtml = Get-Content -Raw "frontend/historico-partida.html"
$historicoJs = Get-Content -Raw "frontend/assets/js/historico.js"
$historicoPartidaJs = Get-Content -Raw "frontend/assets/js/historico-partida.js"
$visibleHistoricalText = "$(Get-VisibleText $historicoHtml) $(Get-VisibleText $historicoPartidaHtml)"
Assert-NotContains $historicoHtml 'data-server-slug="comunidad-hispana-03"' `
"Comunidad Hispana #03 selector was reintroduced."
Assert-NotContains $historicoHtml "MVP mensual V1" `
"MVP mensual V1 block was reintroduced in visible historical HTML."
Assert-NotContains $historicoHtml "MVP mensual V2" `
"MVP mensual V2 block was reintroduced in visible historical HTML."
Assert-NotContains $historicoHtml "Comparativa V1 vs V2" `
"Comparativa V1 vs V2 block was reintroduced in visible historical HTML."
Assert-NotContains $historicoHtml "Elo/MMR" `
"Elo/MMR public block was reintroduced in visible historical HTML."
Assert-NotContains $visibleHistoricalText "snapshot" `
"Public snapshot wording was reintroduced in visible historical text."
Assert-NotContains $historicoJs "Ver partida" `
"Recent match cards must not expose the external scoreboard action label."
Assert-Contains $historicoJs "Ver detalles" `
"Recent match cards no longer include the internal detail fallback label."
Assert-NotContains $historicoJs "item.match_url || item.source_url" `
"Recent match cards must not trust legacy source_url fallback."
Assert-Contains $historicoPartidaJs "Ver en Scoreboard" `
"Match detail page no longer includes the external scoreboard action label."
Assert-Contains $historicoPartidaJs 'rel="noopener noreferrer"' `
"External scoreboard links must keep rel noopener noreferrer."
Assert-Contains $historicoPartidaJs 'target="_blank"' `
"External scoreboard links must open in a new tab."
$backendCheck = @'
import sys
sys.path.insert(0, "backend")
from app.config import get_historical_data_source_kind
from app.routes import resolve_get_payload
status, payload = resolve_get_payload("/health")
if status is None or payload.get("status") != "ok":
raise SystemExit("/health did not resolve to an ok payload.")
if payload.get("historical_data_source") != "rcon":
raise SystemExit("/health no longer reports RCON-first historical source.")
if get_historical_data_source_kind() != "rcon":
raise SystemExit("Configured historical source is no longer rcon.")
detail_status, detail_payload = resolve_get_payload(
"/api/historical/matches/detail?server=comunidad-hispana-01&match=regression-check"
)
if detail_status is None or detail_payload.get("status") != "ok":
raise SystemExit("Match detail endpoint did not resolve successfully.")
if detail_payload.get("data", {}).get("context") != "historical-match-detail":
raise SystemExit("Match detail endpoint context changed unexpectedly.")
'@
$backendCheck | python -
Write-Host "Historical UI regression validation passed."

View File

@@ -0,0 +1,123 @@
$ErrorActionPreference = "Stop"
Write-Host "HLL Vietnam RCON data pipeline validation"
function Invoke-Step {
param(
[Parameter(Mandatory = $true)][string]$Name,
[Parameter(Mandatory = $true)][scriptblock]$Command
)
Write-Host ""
Write-Host "== $Name =="
& $Command
}
function Test-PythonModule {
param([Parameter(Mandatory = $true)][string]$ModuleName)
$check = "import importlib.util; raise SystemExit(0 if importlib.util.find_spec('$ModuleName') else 1)"
python -c $check *> $null
return $LASTEXITCODE -eq 0
}
Invoke-Step "Compile backend application modules" {
python -m compileall backend/app
}
$previousPythonPath = $env:PYTHONPATH
$env:PYTHONPATH = if ($previousPythonPath) { "backend;$previousPythonPath" } else { "backend" }
try {
if (Test-PythonModule "pytest") {
Invoke-Step "Run RCON parser, storage and materialization tests with pytest" {
python -m pytest `
backend/tests/test_rcon_admin_log_parser.py `
backend/tests/test_rcon_admin_log_storage.py `
backend/tests/test_rcon_materialization_pipeline.py `
backend/tests/test_scoreboard_match_links.py
}
}
else {
Write-Host ""
Write-Host "pytest is not installed; running offline fallback checks for RCON parser/storage and unittest suites."
Invoke-Step "Run RCON parser and storage fallback checks" {
$fallbackChecks = @'
from pathlib import Path
import tempfile
from backend.tests import test_rcon_admin_log_parser as parser_tests
from backend.tests import test_rcon_admin_log_storage as storage_tests
parser_tests.test_parse_match_start()
parser_tests.test_parse_match_end()
parser_tests.test_parse_kill()
parser_tests.test_parse_team_switch()
parser_tests.test_parse_connected()
parser_tests.test_parse_disconnected()
parser_tests.test_parse_chat()
parser_tests.test_parse_kick()
parser_tests.test_parse_message_profile()
parser_tests.test_parse_player_profile_snapshot_spanish_sections()
parser_tests.test_non_profile_message_does_not_parse_as_profile_snapshot()
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_initialize_rcon_admin_log_storage_creates_event_table(Path(tmp))
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_persist_rcon_admin_log_entries_inserts_then_reports_duplicates(Path(tmp))
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_profile_message_snapshots_are_materialized_and_deduped(Path(tmp))
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_non_profile_messages_do_not_create_profile_snapshots(Path(tmp))
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_canonical_message_dedupes_changing_relative_prefixes(Path(tmp))
with tempfile.TemporaryDirectory() as tmp:
storage_tests.test_list_rcon_admin_log_event_counts_groups_by_target_and_event_type(Path(tmp))
print("RCON parser and storage fallback checks passed.")
'@
$fallbackChecks | python -
}
Invoke-Step "Run RCON materialization unittest suite" {
python -m unittest backend.tests.test_rcon_materialization_pipeline
}
Invoke-Step "Run RCON scoreboard link unittest suite" {
python -m unittest backend.tests.test_scoreboard_match_links
}
}
}
finally {
$env:PYTHONPATH = $previousPythonPath
}
Invoke-Step "Optional Docker backend smoke check" {
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
Write-Host "Skipping Docker smoke check: docker command is not available."
return
}
docker compose ps --services --filter "status=running" *> $null
if ($LASTEXITCODE -ne 0) {
Write-Host "Skipping Docker smoke check: docker compose is not available or no compose project is active."
return
}
$runningServices = docker compose ps --services --filter "status=running"
if ($runningServices -notcontains "backend") {
Write-Host "Skipping backend endpoint smoke check: backend service is not running."
return
}
$health = Invoke-WebRequest "http://localhost:8000/health" -UseBasicParsing
if ($health.StatusCode -lt 200 -or $health.StatusCode -ge 300) {
throw "Backend health smoke check failed with status $($health.StatusCode)."
}
Write-Host "Backend health smoke check passed."
}
Write-Host ""
Write-Host "Skipping real RCON checks: this validation is designed to run without RCON credentials."
Write-Host "RCON data pipeline validation passed."
exit 0