ci(test): включить проверку загрузки баз в общий профиль

This commit is contained in:
Denozordec committed 2026-10-14 15:33:30 +07:00
1 parent 4f6de4b08e
commit 61e6671685
10 files changed
+145 -9

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@
"test:auth": "tsx src/plugins/auth-path.test.ts && tsx src/lib/permissions.test.ts && tsx src/plugins/auth.smoke.test.ts && tsx src/plugins/auth.ospf-optimizer.test.ts",
"test:wireguard": "npx tsx src/services/wireguard-config.test.ts && npx tsx src/services/wireguard-ipv6.test.ts && npx tsx --test src/services/wireguard-import.test.ts src/services/wireguard-import-apply.test.ts src/services/wireguard-import-revision.test.ts src/services/wireguard-delete.test.ts && npx tsx src/routes/wireguard-import.test.ts",
"test:traffic-rate": "tsx src/services/traffic-rate.test.ts && tsx src/services/traffic-observation.test.ts && tsx src/services/traffic-freshness.test.ts && tsx src/services/traffic-live.test.ts && tsx src/services/traffic-observation-sql.test.ts && tsx src/services/traffic-history-sql.test.ts && tsx src/services/traffic-live-sql.test.ts && tsx src/services/traffic-volume-sql.test.ts && tsx src/services/traffic-binding-status.test.ts && tsx src/services/traffic-status-sql.test.ts && tsx src/services/traffic-gap.test.ts && tsx src/services/traffic-identity.test.ts && tsx src/services/traffic-membership.test.ts && tsx src/services/traffic-aggregate-peak.test.ts && tsx src/services/traffic-users-cache.test.ts && tsx src/services/traffic-collection-lock.test.ts && tsx src/services/traffic-concurrency-sql.test.ts",
"test:traffic-flow": "tsx src/routes/traffic-flow-query.test.ts && tsx src/services/traffic-flow-month.test.ts && tsx src/services/traffic-flow-parse.test.ts && tsx src/services/traffic-flow-ipv6-pipeline.test.ts && tsx src/services/traffic-flow-map-exporter.test.ts && tsx src/services/traffic-flow-ifaces.test.ts && tsx src/services/traffic-flow-ifindex.test.ts && tsx src/services/traffic-flow-dedup.test.ts && tsx src/services/traffic-flow-planes.test.ts && tsx src/services/traffic-flow-ip.test.ts && tsx src/services/traffic-flow-dest.test.ts && tsx src/services/traffic-flow-classify.test.ts && tsx src/services/traffic-flow-ripe.test.ts && tsx src/services/traffic-flow-brands.test.ts && tsx src/services/traffic-flow-ingest.test.ts && tsx src/services/traffic-flow-analytics.test.ts && tsx src/services/traffic-flow-map-hops.test.ts && tsx src/services/traffic-flow-purge.test.ts && tsx src/services/traffic-flow-geoip.test.ts && tsx src/services/traffic-flow-facts.test.ts && tsx src/services/traffic-flow-facts-filter.test.ts && tsx src/services/traffic-flow-facts-rebuild.test.ts && tsx src/services/statistics-aggregate.test.ts",
"test:traffic-flow": "tsx src/routes/traffic-flow-query.test.ts && tsx src/services/traffic-flow-month.test.ts && tsx src/services/traffic-flow-parse.test.ts && tsx src/services/traffic-flow-ipv6-pipeline.test.ts && tsx src/services/traffic-flow-map-exporter.test.ts && tsx src/services/traffic-flow-ifaces.test.ts && tsx src/services/traffic-flow-ifindex.test.ts && tsx src/services/traffic-flow-dedup.test.ts && tsx src/services/traffic-flow-planes.test.ts && tsx src/services/traffic-flow-ip.test.ts && tsx src/services/traffic-flow-dest.test.ts && tsx src/services/traffic-flow-classify.test.ts && tsx src/services/traffic-flow-ripe.test.ts && tsx src/services/traffic-flow-brands.test.ts && tsx src/services/traffic-flow-ingest.test.ts && tsx src/services/traffic-flow-analytics.test.ts && tsx src/services/traffic-flow-map-hops.test.ts && tsx src/services/traffic-flow-purge.test.ts && tsx src/services/geoip-download.test.ts && tsx src/services/traffic-flow-geoip.test.ts && tsx src/services/traffic-flow-facts.test.ts && tsx src/services/traffic-flow-facts-filter.test.ts && tsx src/services/traffic-flow-facts-rebuild.test.ts && tsx src/services/statistics-aggregate.test.ts",
"test:users": "tsx src/modules/users/iface-type.test.ts && tsx src/modules/users/bindings.test.ts && tsx src/modules/users/interface-inventory.test.ts && tsx src/routes/users-catalog.test.ts",
"test:pg": "tsx src/db/pg-pool.test.ts && tsx src/db/sql-bind.test.ts && tsx src/db/sqlite-json.test.ts && tsx src/db/traffic-flags.test.ts && tsx src/db/pg-schema.test.ts && tsx src/services/config-revisions.test.ts",
"test:recursive-routes": "tsx src/routes/recursive-routes.test.ts && tsx src/services/recursive-route-catalog.test.ts && tsx src/services/recursive-apply.test.ts",
@@ -0,0 +1,32 @@
#!/bin/bash
set -euo pipefail
umask 077
cd /opt/mmapp-test
mm245_db="mm_accept_166_$(date +%s%3N)"
mm245_pass="$(openssl rand -hex 24)"
mm245_role_created=false
mm245_db_created=false
cleanup245() {
docker rm mmapp-s3app245-owned >/dev/null 2>&1 || true
if $mm245_db_created; then docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "DROP DATABASE \"$mm245_db\" WITH (FORCE)"; fi
if $mm245_role_created; then docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "DROP ROLE \"$mm245_db\""; fi
remaining=$(docker exec mmapp-test-postgres psql -U mmapp -d mmapp -Atc "SELECT (SELECT count(*) FROM pg_database WHERE datname='$mm245_db')+(SELECT count(*) FROM pg_roles WHERE rolname='$mm245_db')")
[ "$remaining" = 0 ]
python3 - <<'PY'
import json,pathlib
p=pathlib.Path('/opt/mmapp-test/artifacts/traffic-flow245/traffic-flow245.json')
if p.exists():
r=json.loads(p.read_text());r['ownedDatabaseAndRoleRemoved']=True;p.write_text(json.dumps(r,indent=2)+'\n')
PY
printf 'OWNED_DATABASE_AND_ROLE_REMOVED\n'
unset mm245_pass
}
trap cleanup245 EXIT
[[ "$mm245_db" =~ ^mm_accept_166_[0-9]+$ ]]
existing=$(docker exec mmapp-test-postgres psql -U mmapp -d mmapp -Atc "SELECT (SELECT count(*) FROM pg_database WHERE datname='$mm245_db')+(SELECT count(*) FROM pg_roles WHERE rolname='$mm245_db')")
[ "$existing" = 0 ]
printf "CREATE ROLE \"%s\" LOGIN PASSWORD '%s' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS;\n" "$mm245_db" "$mm245_pass" | docker exec -i mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1
mm245_role_created=true
docker exec mmapp-test-postgres psql -U mmapp -d mmapp -v ON_ERROR_STOP=1 -c "CREATE DATABASE \"$mm245_db\" OWNER \"$mm245_db\""
mm245_db_created=true
docker run --name mmapp-s3app245-owned --network mmapp-test_default --cap-drop ALL --security-opt no-new-privileges -e "MMAPP_ORIGIN_BASELINE=${2:-false}" -e NODE_ENV=test -e "DATABASE_URL=postgres://$mm245_db:$mm245_pass@postgres:5432/$mm245_db" -e "MMAPP_OWN_SQL_DB=$mm245_db" -e "DATABASE_PATH=/tmp/$mm245_db/legacy.db" -e "GEOIP_DIR=/tmp/$mm245_db/geoip" -v /opt/mmapp-test/artifacts/traffic-flow245:/checks --entrypoint node "${1:-mmapp-test/backend:ux-geoip242-acceptance}" /checks/traffic-flow-regression.mjs
@@ -0,0 +1,27 @@
import fs from 'node:fs';
import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { createRequire } from 'node:module';
const pg = createRequire('/app/backend/package.json')('pg');
const database = process.env.MMAPP_OWN_SQL_DB; assert(/^mm_accept_166_\d+$/.test(database));
const url = new URL(process.env.DATABASE_URL); assert.equal(url.pathname, '/' + database); assert.equal(url.username, database);
const client = new pg.Client({ connectionString: url.toString() }); await client.connect();
const role = (await client.query('SELECT rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user')).rows[0]; assert(Object.values(role).every(v => v === false)); await client.end();
const pkg = JSON.parse(fs.readFileSync('/checks/package245.json'));
assert.equal(pkg.scripts['test:traffic-flow'].split('geoip-download.test.ts').length - 1, 1);
assert.equal(pkg.scripts['test:all'].split('npm run test:traffic-flow').length - 1, 1);
fs.writeFileSync('/app/backend/package.json', JSON.stringify(pkg, null, 2));
const report = { date: '2026-10-14', block: '12.5.245', scope: 'Changed traffic-flow profile only, source acceptance image + current npm command metadata + owned PostgreSQL', passed: false, newGeoipHttpTestIncludedOnce: true, testAllProfileIncludedOnce: true, productionImagesChanged: false };
try {
const started = Date.now();
const output = execFileSync('npm', ['--prefix', 'backend', 'run', 'test:traffic-flow'], { cwd: '/app', timeout: 180000, maxBuffer: 8 * 1024 ** 2, encoding: 'utf8', env: { ...process.env, NODE_ENV: 'test', DATABASE_PATH: '/tmp/' + database + '/legacy.db', GEOIP_DIR: '/tmp/' + database + '/geoip' }, stdio: ['ignore', 'pipe', 'pipe'] });
fs.writeFileSync('/checks/traffic-flow245-private.log', output, { mode: 0o600 });
assert(output.includes('GeoIP HTTP: whole-body timeout, declared/chunked limits,304 and recovery passed'));
report.durationMs = Date.now() - started;
report.unavailableSqlBranches = output.split('\n').filter(s => /\bskip(?:ped)?\b/i.test(s) && /PostgreSQL|owned|database|MMAPP_OWN|не пустая БД/i.test(s)).map(s => s.trim());
const expectedOptionalSkips = ['Monthly SQL: skip (requires an owned isolated database)', 'IPv6 UDP/worker/SQL: skip (requires an owned isolated database)'];
assert.deepEqual(report.unavailableSqlBranches, expectedOptionalSkips);
report.optionalSqlBranchesRequireTheirOwnDedicatedDatabase = true;
report.profileExitCode = 0; report.passed = true;
} catch (e) { report.failure = { name: e.name }; if (e.stdout || e.stderr) fs.writeFileSync('/checks/traffic-flow245-private.log', String(e.stdout ?? '') + '\n' + String(e.stderr ?? ''), { mode: 0o600 }); process.exitCode = 1; }
finally { fs.writeFileSync('/checks/traffic-flow245.json', JSON.stringify(report, null, 2) + '\n'); console.log(JSON.stringify(report)); }