Files
Investidor-V2/tools/test-mne-integrity.php
nala 1106509116
tests / ci (push) Canceled after 0s
vrsao 2
2026-10-08 14:02:01 +02:00

83 lines
3.5 KiB
PHP

<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
require __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$db = DB::connection();
if (! $app->environment('testing') || $db->getDatabaseName() !== 'portal_services_test' || (string) $db->getConfig('port') !== '55441') {
throw new RuntimeException('Isolated QA required');
}
if ($db->selectOne("SELECT count(*) AS n FROM pg_namespace WHERE nspname='mne'")->n) {
throw new RuntimeException('QA schema mne must be absent');
}
$run = function (string $file) use ($db): void {
$sql = file_get_contents(base_path('migrations/'.$file));
$sql = preg_replace('/^BEGIN;\s*$/m', '', $sql);
$db->unprepared(preg_replace('/COMMIT;\s*$/', '', $sql));
};
$indexes = fn () => (int) $db->selectOne("SELECT count(*) AS n FROM pg_indexes WHERE schemaname='mne'")->n;
$db->beginTransaction();
try {
$run('001_mne_schema.sql');
$run('002_mne_existing_territories.sql');
$before = $indexes();
$run('003_mne_integrity.sql');
$after = $indexes();
$missing = $db->selectOne(<<<'SQL'
SELECT count(*) AS n FROM pg_constraint c
JOIN pg_namespace n ON n.oid=c.connamespace
WHERE n.nspname='mne' AND c.contype='f' AND NOT EXISTS (
SELECT 1 FROM pg_index i JOIN pg_class ix ON ix.oid=i.indexrelid
JOIN pg_am am ON am.oid=ix.relam
WHERE i.indrelid=c.conrelid AND i.indisvalid AND i.indisready
AND i.indpred IS NULL AND am.amname='btree' AND i.indnkeyatts >= cardinality(c.conkey)
AND ARRAY(SELECT x FROM unnest(i.indkey::smallint[]) WITH ORDINALITY u(x,p)
WHERE p <= cardinality(c.conkey) ORDER BY p)=c.conkey
)
SQL);
if ((int) $missing->n !== 0) {
throw new RuntimeException('Foreign keys without index coverage');
}
$run('003_mne_integrity.sql');
if ($indexes() !== $after) {
throw new RuntimeException('Duplicate indexes');
}
$db->insert("INSERT INTO mne.audit_events(action,subject_type,subject_id,correlation_id) VALUES ('qa','synthetic',gen_random_uuid(),gen_random_uuid())");
$rejections = 0;
foreach (['audit_events', 'business_status_history', 'document_versions', 'negotiation_events'] as $table) {
foreach (["UPDATE mne.$table SET id=id", "DELETE FROM mne.$table", "TRUNCATE mne.$table"] as $sql) {
$db->statement('SAVEPOINT mutation');
$rejected = false;
try {
$db->unprepared($sql);
} catch (QueryException $e) {
$rejected = $e->getCode() === '23514';
}
$db->statement('ROLLBACK TO SAVEPOINT mutation');
if (! $rejected) {
throw new RuntimeException('Mutation was not rejected by evidence guard');
}
$rejections++;
}
}
$run('003_mne_integrity_down.sql');
if ($indexes() !== $before) {
throw new RuntimeException('DOWN changed original indexes');
}
$db->delete('DELETE FROM mne.audit_events');
$run('003_mne_integrity.sql');
if ($indexes() !== $after) {
throw new RuntimeException('Reapply failed');
}
echo json_encode(['passed' => true, 'original_indexes' => $before, 'added_indexes' => $after - $before, 'mutation_rejections' => $rejections, 'idempotency_and_down' => true]).PHP_EOL;
} finally {
$db->rollBack();
}
if ($db->selectOne("SELECT count(*) AS n FROM pg_namespace WHERE nspname='mne'")->n) {
throw new RuntimeException('QA cleanup failed');
}