合并门禁:将R3门禁能力集成至一期综合验收
- 将QA数据库配置对齐至隔离库 railwaysystem_integrated_qa_20260916
This commit is contained in:
1 parent
307c9cd172
commit
63f463d094
11 files changed
+714
-4
No files matched your search
@@ -219,6 +219,23 @@ public class DbAssertionChecker {
|
||||
return map;
|
||||
}
|
||||
|
||||
private static String resolveDbUrl() {
|
||||
try {
|
||||
File yml = new File("RuoYi-Vue/ruoyi-admin/src/main/resources/application-druid.yml");
|
||||
if (!yml.exists()) {
|
||||
yml = new File("../RuoYi-Vue/ruoyi-admin/src/main/resources/application-druid.yml");
|
||||
}
|
||||
if (yml.exists()) {
|
||||
for (String line : Files.readAllLines(yml.toPath())) {
|
||||
if (line.trim().startsWith("url:")) {
|
||||
return line.trim().substring("url:".length()).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return "jdbc:kingbase8://127.0.0.1:4321/railwaysystem_integrated_qa_20260916?currentSchema=public,sys_catalog&useUnicode=true&characterEncoding=utf8";
|
||||
}
|
||||
|
||||
private static String resolveDbPassword() {
|
||||
String env = System.getenv("DB_PASSWORD");
|
||||
if (env != null && !env.isEmpty()) {
|
||||
@@ -257,7 +274,7 @@ public class DbAssertionChecker {
|
||||
}
|
||||
|
||||
private static void executeDependentsCleanup(String resourcesPath) {
|
||||
String dbUrl = "jdbc:kingbase8://127.0.0.1:4321/training?currentSchema=public,sys_catalog&useUnicode=true&characterEncoding=utf8";
|
||||
String dbUrl = resolveDbUrl();
|
||||
String dbUser = "kingbase";
|
||||
String dbPassword = resolveDbPassword();
|
||||
|
||||
@@ -280,7 +297,7 @@ public class DbAssertionChecker {
|
||||
}
|
||||
|
||||
private static void executeExactIdCleanup(String resourcesPath) {
|
||||
String dbUrl = "jdbc:kingbase8://127.0.0.1:4321/training?currentSchema=public,sys_catalog&useUnicode=true&characterEncoding=utf8";
|
||||
String dbUrl = resolveDbUrl();
|
||||
String dbUser = "kingbase";
|
||||
String dbPassword = resolveDbPassword();
|
||||
|
||||
@@ -349,7 +366,7 @@ public class DbAssertionChecker {
|
||||
}
|
||||
|
||||
private static void disableStudent(String studentId) {
|
||||
String dbUrl = "jdbc:kingbase8://127.0.0.1:4321/training?currentSchema=public,sys_catalog&useUnicode=true&characterEncoding=utf8";
|
||||
String dbUrl = resolveDbUrl();
|
||||
String dbUser = "kingbase";
|
||||
String dbPassword = resolveDbPassword();
|
||||
try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword)) {
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
package scripts.qa;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
public class IntegratedQaBootstrapAndValidation {
|
||||
|
||||
private static final String TARGET_DB = "railwaysystem_integrated_qa_20260916";
|
||||
private static final String TEMPLATE_DB = "training";
|
||||
private static final String MAINTENANCE_DB_URL = "jdbc:kingbase8://127.0.0.1:4321/kingbase?useUnicode=true&characterEncoding=utf8";
|
||||
private static final String QA_DB_URL = "jdbc:kingbase8://127.0.0.1:4321/" + TARGET_DB + "?useUnicode=true&characterEncoding=utf8¤tSchema=public,sys_catalog";
|
||||
private static final String USER = "kingbase";
|
||||
|
||||
public static void main(String[] args) {
|
||||
String password = resolveDbPassword();
|
||||
|
||||
try {
|
||||
Class.forName("com.kingbase8.Driver");
|
||||
|
||||
// 1. Re-create QA Database from template training
|
||||
System.out.println("=== 1. DATABASE PROVISIONING ===");
|
||||
try (Connection conn = DriverManager.getConnection(MAINTENANCE_DB_URL, USER, password)) {
|
||||
try (Statement st = conn.createStatement()) {
|
||||
// Disconnect any active connections to TARGET_DB
|
||||
st.execute("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '" + TARGET_DB + "' AND pid <> pg_backend_pid()");
|
||||
st.execute("DROP DATABASE IF EXISTS " + TARGET_DB);
|
||||
System.out.println("Dropped existing " + TARGET_DB);
|
||||
st.execute("CREATE DATABASE " + TARGET_DB + " TEMPLATE " + TEMPLATE_DB);
|
||||
System.out.println("Created " + TARGET_DB + " from TEMPLATE " + TEMPLATE_DB + " successfully.");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. DB Identity Gate & Clean Business State
|
||||
System.out.println("\n=== 2. DB IDENTITY GATE & CLEAN BUSINESS STATE ===");
|
||||
Map<String, Integer> initialBusinessCounts = new LinkedHashMap<>();
|
||||
try (Connection conn = DriverManager.getConnection(QA_DB_URL, USER, password)) {
|
||||
try (Statement st = conn.createStatement();
|
||||
ResultSet rs = st.executeQuery("SELECT current_database(), current_user, inet_server_addr(), inet_server_port()")) {
|
||||
if (rs.next()) {
|
||||
System.out.println("CURRENT_DATABASE: " + rs.getString(1));
|
||||
System.out.println("CURRENT_USER: " + rs.getString(2));
|
||||
System.out.println("SERVER_ADDR: " + rs.getString(3));
|
||||
System.out.println("SERVER_PORT: " + rs.getString(4));
|
||||
System.out.println("DB_ENVIRONMENT: ISOLATED_QA");
|
||||
}
|
||||
}
|
||||
|
||||
// Drop legacy backup tables
|
||||
try (Statement st = conn.createStatement()) {
|
||||
List<String> bakTables = new ArrayList<>();
|
||||
try (ResultSet rs = st.executeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE 'bak_v1_%'")) {
|
||||
while (rs.next()) bakTables.add(rs.getString(1));
|
||||
}
|
||||
for (String bak : bakTables) {
|
||||
st.execute("DROP TABLE IF EXISTS " + bak + " CASCADE");
|
||||
}
|
||||
System.out.println("Dropped " + bakTables.size() + " legacy backup tables (bak_v1_*).");
|
||||
}
|
||||
|
||||
// Truncate all business demo tables in dependency order
|
||||
String[] businessTables = new String[]{
|
||||
"train_student_checkin",
|
||||
"train_class_report",
|
||||
"train_student_score",
|
||||
"train_student_portrait",
|
||||
"train_study_duration",
|
||||
"train_accommodation",
|
||||
"train_external_operation",
|
||||
"train_external_resource_mapping",
|
||||
"train_dorm_auth",
|
||||
"train_lesson",
|
||||
"train_plan_course",
|
||||
"train_enrollment",
|
||||
"train_score_item",
|
||||
"train_course_resource",
|
||||
"train_resource",
|
||||
"train_course",
|
||||
"train_class_plan",
|
||||
"train_dormitory_info",
|
||||
"train_classroom_info",
|
||||
"train_training_site",
|
||||
"train_electronic_board",
|
||||
"train_student",
|
||||
"train_teacher",
|
||||
"sys_logininfor",
|
||||
"sys_oper_log",
|
||||
"sys_job_log",
|
||||
"gen_table_column",
|
||||
"gen_table",
|
||||
"app_config"
|
||||
};
|
||||
|
||||
try (Statement st = conn.createStatement()) {
|
||||
for (String table : businessTables) {
|
||||
try {
|
||||
st.execute("TRUNCATE TABLE " + table + " CASCADE");
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
st.execute("DELETE FROM " + table);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Clean table " + table + " warning: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Business tables truncated successfully.");
|
||||
}
|
||||
|
||||
// Clean sys_user to keep only system accounts (admin, ry)
|
||||
try (Statement st = conn.createStatement()) {
|
||||
st.execute("DELETE FROM sys_user_role WHERE user_id NOT IN (SELECT user_id FROM sys_user WHERE user_name IN ('admin', 'ry'))");
|
||||
st.execute("DELETE FROM sys_user_post WHERE user_id NOT IN (SELECT user_id FROM sys_user WHERE user_name IN ('admin', 'ry'))");
|
||||
st.execute("DELETE FROM sys_user WHERE user_name NOT IN ('admin', 'ry')");
|
||||
System.out.println("sys_user cleaned: only admin/ry retained.");
|
||||
}
|
||||
|
||||
// Verify and record initial business counts
|
||||
System.out.println("\n--- INITIAL BUSINESS DATA COUNTS ---");
|
||||
try (Statement st = conn.createStatement()) {
|
||||
for (String table : businessTables) {
|
||||
try (ResultSet rs = st.executeQuery("SELECT count(*) FROM " + table)) {
|
||||
if (rs.next()) {
|
||||
int c = rs.getInt(1);
|
||||
initialBusinessCounts.put(table, c);
|
||||
System.out.println(String.format("%-35s : %d", table, c));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(String.format("%-35s : TABLE_NOT_EXIST_YET", table));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Migration First Run & Second Run
|
||||
System.out.println("\n=== 3. MIGRATION EXECUTION & IDEMPOTENCY ===");
|
||||
String[] migrationFiles = new String[]{
|
||||
"RuoYi-Vue/sql/system/kingbase/006_accommodation_history_constraint.sql",
|
||||
"RuoYi-Vue/sql/system/kingbase/008_external_resource_operation.sql",
|
||||
"RuoYi-Vue/sql/system/kingbase/009_dorm_authorization_orchestration.sql",
|
||||
"RuoYi-Vue/sql/system/kingbase/010_dms_access_management_permissions.sql"
|
||||
};
|
||||
|
||||
// FIRST RUN
|
||||
System.out.println("--- FIRST RUN ---");
|
||||
boolean firstRunAllPass = true;
|
||||
try (Connection conn = DriverManager.getConnection(QA_DB_URL, USER, password)) {
|
||||
for (String path : migrationFiles) {
|
||||
boolean pass = executeSqlScript(conn, path);
|
||||
System.out.println("Migration " + new File(path).getName() + " FIRST_RUN: " + (pass ? "PASS" : "FAIL"));
|
||||
if (!pass) firstRunAllPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
// SECOND RUN (IDEMPOTENCY TEST)
|
||||
System.out.println("\n--- SECOND RUN (IDEMPOTENCY TEST) ---");
|
||||
boolean secondRunAllPass = true;
|
||||
try (Connection conn = DriverManager.getConnection(QA_DB_URL, USER, password)) {
|
||||
for (String path : migrationFiles) {
|
||||
boolean pass = executeSqlScript(conn, path);
|
||||
System.out.println("Migration " + new File(path).getName() + " SECOND_RUN: " + (pass ? "PASS" : "FAIL"));
|
||||
if (!pass) secondRunAllPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("MIGRATION_FIRST_RUN = " + (firstRunAllPass ? "PASS" : "FAIL"));
|
||||
System.out.println("MIGRATION_SECOND_RUN = " + (secondRunAllPass ? "PASS" : "FAIL"));
|
||||
System.out.println("MIGRATION_IDEMPOTENT = " + (firstRunAllPass && secondRunAllPass ? "PASS" : "FAIL"));
|
||||
|
||||
// 4. Schema Validation
|
||||
System.out.println("\n=== 4. SCHEMA VALIDATION ===");
|
||||
try (Connection conn = DriverManager.getConnection(QA_DB_URL, USER, password)) {
|
||||
// Check required tables
|
||||
String[] requiredTables = new String[]{
|
||||
"train_class_plan",
|
||||
"train_course",
|
||||
"train_enrollment",
|
||||
"train_lesson",
|
||||
"train_student_checkin",
|
||||
"train_accommodation",
|
||||
"train_dorm_auth",
|
||||
"train_external_resource_mapping",
|
||||
"train_external_operation"
|
||||
};
|
||||
|
||||
for (String t : requiredTables) {
|
||||
try (Statement st = conn.createStatement();
|
||||
ResultSet rs = st.executeQuery("SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '" + t + "'")) {
|
||||
boolean ok = rs.next();
|
||||
System.out.println("TABLE " + t + " EXISTS: " + (ok ? "YES" : "NO"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check constraints & indexes
|
||||
checkIndexOrConstraint(conn, "train_accommodation", "uq_accommodation_enroll_active", "Active accommodation partial unique index");
|
||||
checkIndexOrConstraint(conn, "train_external_resource_mapping", "uq_ext_res_map_active_room", "Active room mapping partial unique index");
|
||||
checkIndexOrConstraint(conn, "train_external_resource_mapping", "uq_ext_res_map_active_ext_res", "Active external res partial unique index");
|
||||
checkIndexOrConstraint(conn, "train_external_operation", "uq_ext_op_idempotency", "External op idempotency unique index");
|
||||
checkIndexOrConstraint(conn, "train_dorm_auth", "idx_dorm_auth_status", "Dorm auth status index");
|
||||
checkIndexOrConstraint(conn, "train_dorm_auth", "idx_dorm_auth_latest_op", "Dorm auth latest op index");
|
||||
|
||||
// Check RBAC roles
|
||||
System.out.println("\n--- RBAC ROLES CHECK ---");
|
||||
try (Statement st = conn.createStatement();
|
||||
ResultSet rs = st.executeQuery("SELECT role_id, role_name, role_key, status FROM sys_role WHERE role_key IN ('admin', 'train_admin', 'train_teacher', 'train_student')")) {
|
||||
while (rs.next()) {
|
||||
System.out.println("ROLE: " + rs.getString("role_key") + " (" + rs.getString("role_name") + ") status=" + rs.getString("status"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check DMS Permissions in sys_menu
|
||||
System.out.println("\n--- DMS PERMISSIONS IN SYS_MENU ---");
|
||||
try (Statement st = conn.createStatement();
|
||||
ResultSet rs = st.executeQuery("SELECT menu_id, menu_name, perms FROM sys_menu WHERE perms IN ('train:access:query', 'train:access:manage', 'train:access:reconcile')")) {
|
||||
while (rs.next()) {
|
||||
System.out.println("MENU: " + rs.getString("perms") + " - " + rs.getString("menu_name"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check Orphan counts
|
||||
System.out.println("\n--- ORPHAN COUNTS CHECK ---");
|
||||
int totalOrphans = 0;
|
||||
String[] orphanChecks = new String[]{
|
||||
"SELECT count(*) FROM train_enrollment e WHERE NOT EXISTS (SELECT 1 FROM train_student s WHERE s.s_id = e.student_id)",
|
||||
"SELECT count(*) FROM train_enrollment e WHERE NOT EXISTS (SELECT 1 FROM train_class_plan p WHERE p.plan_id = e.plan_id)",
|
||||
"SELECT count(*) FROM train_lesson l WHERE NOT EXISTS (SELECT 1 FROM train_plan_course pc WHERE pc.plan_course_id = l.plan_course_id)",
|
||||
"SELECT count(*) FROM train_accommodation a WHERE NOT EXISTS (SELECT 1 FROM train_enrollment e WHERE e.enrollment_id = a.enrollment_id)",
|
||||
"SELECT count(*) FROM train_student_checkin c WHERE NOT EXISTS (SELECT 1 FROM train_enrollment e WHERE e.enrollment_id = c.enrollment_id)",
|
||||
"SELECT count(*) FROM train_dorm_auth d WHERE NOT EXISTS (SELECT 1 FROM train_accommodation a WHERE a.accommodation_id = d.accommodation_id)",
|
||||
"SELECT count(*) FROM train_external_operation o WHERE NOT EXISTS (SELECT 1 FROM train_dorm_auth d WHERE d.auth_id = o.door_auth_id)"
|
||||
};
|
||||
|
||||
for (String q : orphanChecks) {
|
||||
try (Statement st = conn.createStatement();
|
||||
ResultSet rs = st.executeQuery(q)) {
|
||||
if (rs.next()) {
|
||||
totalOrphans += rs.getInt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("ORPHAN_COUNT = " + totalOrphans);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Execution failed: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean executeSqlScript(Connection conn, String path) {
|
||||
try {
|
||||
File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
System.err.println("Script not found: " + path);
|
||||
return false;
|
||||
}
|
||||
String content = new String(Files.readAllBytes(f.toPath()));
|
||||
|
||||
// For DO $$ ... $$; block
|
||||
if (content.contains("DO $$")) {
|
||||
try (Statement st = conn.createStatement()) {
|
||||
st.execute(content);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Split by semicolon, accounting for BEGIN/COMMIT
|
||||
String[] stmts = content.split(";");
|
||||
try (Statement st = conn.createStatement()) {
|
||||
for (String s : stmts) {
|
||||
String trimmed = s.trim();
|
||||
if (!trimmed.isEmpty() && !trimmed.startsWith("--")) {
|
||||
st.execute(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.err.println("Script execution failed on " + path + ": " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIndexOrConstraint(Connection conn, String table, String name, String desc) {
|
||||
try (Statement st = conn.createStatement()) {
|
||||
boolean found = false;
|
||||
// check constraint
|
||||
try (ResultSet rs = st.executeQuery("SELECT 1 FROM pg_constraint c JOIN pg_class t ON c.conrelid = t.oid WHERE t.relname = '" + table + "' AND c.conname = '" + name + "'")) {
|
||||
if (rs.next()) found = true;
|
||||
}
|
||||
if (!found) {
|
||||
// check index
|
||||
try (ResultSet rs = st.executeQuery("SELECT 1 FROM pg_class c JOIN pg_index i ON c.oid = i.indexrelid JOIN pg_class t ON i.indrelid = t.oid WHERE t.relname = '" + table + "' AND c.relname = '" + name + "'")) {
|
||||
if (rs.next()) found = true;
|
||||
}
|
||||
}
|
||||
System.out.println("CONSTRAINT/INDEX " + name + " (" + desc + ") ON " + table + ": " + (found ? "PASS" : "FAIL"));
|
||||
} catch (Exception e) {
|
||||
System.out.println("CONSTRAINT/INDEX " + name + " ERROR: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static String resolveDbPassword() {
|
||||
String env = System.getenv("DB_PASSWORD");
|
||||
if (env != null && !env.isEmpty()) return env;
|
||||
try {
|
||||
File yml = new File("RuoYi-Vue/ruoyi-admin/src/main/resources/application-druid.yml");
|
||||
if (!yml.exists()) {
|
||||
yml = new File("../RuoYi-Vue/ruoyi-admin/src/main/resources/application-druid.yml");
|
||||
}
|
||||
if (yml.exists()) {
|
||||
for (String line : Files.readAllLines(yml.toPath())) {
|
||||
if (line.trim().startsWith("password:")) {
|
||||
return line.trim().substring("password:".length()).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return "123456";
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user