Files
Investidor-V2/tools/portal-audit-territory-coverage.php
T
nala 6ddafc95ba
tests / ci (push) Canceled after 0s
oportunidades 4
2026-10-10 07:03:59 +02:00

84 lines
4.8 KiB
PHP

<?php
// Exercise the real public API over the restored active catalogue. No migration or active connection.
use App\Services\InvestmentGeography;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RateLimiter;
$root = dirname(__DIR__);
$proof = json_decode(file_get_contents($root.'/storage/app/private/investmoz-v2/opportunity-resources-backup-proof.json'), true, 512, JSON_THROW_ON_ERROR);
$target = $proof['restored_target'];
if (! ($proof['restore_verified'] ?? false) || ! preg_match('/^desk_restore_\d{8}_\d{6}_test$/D', $target['database']) || (int) $target['port'] !== 55441) {
throw new RuntimeException('Verified restored QA target required');
}
foreach (['APP_ENV' => 'testing', 'APP_DEBUG' => 'false', 'APP_KEY' => 'base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '55441', 'DB_DATABASE' => $target['database'],
'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => '', 'CACHE_STORE' => 'array', 'SESSION_DRIVER' => 'array', 'QUEUE_CONNECTION' => 'sync'] as $key => $value) {
putenv($key.'='.$value);
$_ENV[$key] = $_SERVER[$key] = $value;
}
require $root.'/vendor/autoload.php';
$app = require $root.'/bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$kernel->bootstrap();
$identity = DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port');
if ($identity->database !== $target['database'] || (int) $identity->port !== 55441) {
throw new RuntimeException('Non-QA database rejected');
}
// Enumerating the whole catalogue is a QA coverage run, independent of rate-limit acceptance.
RateLimiter::for('api', fn () => Limit::none());
$expected = app(InvestmentGeography::class)->publicReferences()->whereIn('location_type', ['province', 'district', 'admin_post', 'locality'])
->get(['id', 'parent_id', 'location_type']);
$counts = [];
$results = [];
$seen = [];
foreach (['province' => null, 'district' => 'province', 'admin_post' => 'district', 'locality' => 'admin_post'] as $type => $parentType) {
$parents = $parentType === null ? [null] : $expected->where('location_type', $parentType)->pluck('id')->all();
foreach ($parents as $parent) {
$page = 1;
$actual = [];
do {
$uri = '/api/v1/investment/territory-options?'.http_build_query(['type' => $type, 'parent_id' => $parent, 'page' => $page]);
$request = Request::create($uri, 'GET', [], [], [], ['HTTP_ACCEPT' => 'application/json']);
$response = $kernel->handle($request);
if ($response->getStatusCode() !== 200) {
throw new RuntimeException('Catalogue API failed: '.$uri.' HTTP '.$response->getStatusCode());
}
$body = json_decode($response->getContent(), true, 512, JSON_THROW_ON_ERROR);
foreach ($body['data'] as $item) {
if ($item['location_type'] !== $type || ($parent !== null && $item['parent_id'] !== $parent)) {
throw new RuntimeException('Hierarchy mismatch');
}
$actual[] = $item['id'];
$seen[$item['id']] = true;
}
$kernel->terminate($request, $response);
$results[] = ['type' => $type, 'parent_id' => $parent, 'page' => $page, 'http' => 200, 'rows' => count($body['data'])];
$page++;
} while ($body['next_page_url'] !== null);
$wanted = $expected->where('location_type', $type);
if ($parent !== null) {
$wanted = $wanted->where('parent_id', $parent);
}
$wanted = $wanted->pluck('id')->sort()->values()->all();
sort($actual);
if ($wanted !== $actual) {
throw new RuntimeException('API omissions/duplicates at '.$type.' '.$parent);
}
}
$counts[$type] = $expected->where('location_type', $type)->count();
}
if (count($seen) !== $expected->count()) {
throw new RuntimeException('Unreachable catalogue references');
}
$result = ['captured_at' => gmdate('c'), 'target' => $identity, 'source' => 'Verified active backup restored in QA', 'counts' => $counts,
'references_expected' => $expected->count(), 'references_recovered' => count($seen), 'api_requests' => count($results), 'checks' => $results,
'visual_verified' => false, 'all_consumers_accepted' => false, 'geometry_rows' => DB::table('geo_geometries')->count(),
'rate_limit_scope' => 'Excluded only in QA bulk catalogue enumeration; access/rate behavior covered separately', 'active_writes' => 0];
file_put_contents($root.'/storage/app/private/investmoz-v2/portal-audit/territory-catalogue-coverage.json', json_encode($result, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
unset($result['checks']);
echo json_encode($result, JSON_THROW_ON_ERROR).PHP_EOL;