From c279b0a6e4b3577c81ced0f20900144d8fdd3df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Fri, 3 Apr 2026 22:00:47 +0800 Subject: [PATCH] test: add integration tests for operation log - Add R2DBC database initialization configuration - Fix schema-h2.sql Chinese comments issue - Add spring-security-test dependency - Create comprehensive integration tests for operation log - Tests cover create, delete, and error scenarios Closes #2 --- novalon-manage-api/manage-app/pom.xml | 5 + .../manage/app/config/R2dbcInitConfig.java | 42 +++ .../src/main/resources/application-test.yml | 9 +- .../src/main/resources/schema-h2.sql | 36 +-- .../src/main/resources/schema-h2.sql.bak2 | 253 ++++++++++++++++++ .../app/integration/DatabaseInitTest.java | 63 +++++ .../integration/ManualTableCreationTest.java | 58 ++++ .../OperationLogIntegrationTest.java | 156 +++++++++++ novalon-manage-api/manage-sys/pom.xml | 5 + 9 files changed, 602 insertions(+), 25 deletions(-) create mode 100644 novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/R2dbcInitConfig.java create mode 100644 novalon-manage-api/manage-app/src/main/resources/schema-h2.sql.bak2 create mode 100644 novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/DatabaseInitTest.java create mode 100644 novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/ManualTableCreationTest.java create mode 100644 novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/OperationLogIntegrationTest.java diff --git a/novalon-manage-api/manage-app/pom.xml b/novalon-manage-api/manage-app/pom.xml index 9db1d3a..4c07ca1 100644 --- a/novalon-manage-api/manage-app/pom.xml +++ b/novalon-manage-api/manage-app/pom.xml @@ -92,6 +92,11 @@ spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + io.projectreactor reactor-test diff --git a/novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/R2dbcInitConfig.java b/novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/R2dbcInitConfig.java new file mode 100644 index 0000000..da79440 --- /dev/null +++ b/novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/R2dbcInitConfig.java @@ -0,0 +1,42 @@ +package cn.novalon.manage.app.config; + +import io.r2dbc.spi.ConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; + +/** + * R2DBC数据库初始化配置 + * + * 用于测试环境的H2数据库初始化 + * + * @author 张翔 + * @date 2026-04-03 + */ +@Configuration +@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "test") +public class R2dbcInitConfig { + + private static final Logger logger = LoggerFactory.getLogger(R2dbcInitConfig.class); + + @Bean + public ConnectionFactoryInitializer connectionFactoryInitializer(ConnectionFactory connectionFactory) { + logger.info("Initializing R2DBC database with H2 schema and data"); + + ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); + initializer.setConnectionFactory(connectionFactory); + + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(new ClassPathResource("schema-h2.sql")); + populator.addScript(new ClassPathResource("data-h2.sql")); + + initializer.setDatabasePopulator(populator); + + return initializer; + } +} diff --git a/novalon-manage-api/manage-app/src/main/resources/application-test.yml b/novalon-manage-api/manage-app/src/main/resources/application-test.yml index b844638..74625ea 100644 --- a/novalon-manage-api/manage-app/src/main/resources/application-test.yml +++ b/novalon-manage-api/manage-app/src/main/resources/application-test.yml @@ -7,7 +7,7 @@ spring: r2dbc: url: r2dbc:h2:mem:///testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE username: sa - password: + password: pool: initial-size: 5 max-size: 20 @@ -17,15 +17,10 @@ spring: datasource: url: jdbc:h2:mem:///testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE username: sa - password: + password: driver-class-name: org.h2.Driver flyway: enabled: false - sql: - init: - mode: always - schema-locations: classpath:schema-h2.sql - data-locations: classpath:data-h2.sql h2: console: enabled: true diff --git a/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql b/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql index ab49bb4..8b4d065 100644 --- a/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql +++ b/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql @@ -1,5 +1,5 @@ --- H2数据库Schema for Integration Testing --- 创建用户表 +-- H2 Database Schema for Integration Testing +-- Create user table CREATE TABLE IF NOT EXISTS sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS sys_user ( deleted_at TIMESTAMP ); --- 创建角色表 +-- Create role table CREATE TABLE IF NOT EXISTS sys_role ( id BIGINT AUTO_INCREMENT PRIMARY KEY, role_name VARCHAR(100) NOT NULL, @@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS sys_role ( deleted_at TIMESTAMP ); --- 创建用户角色关联表 +-- Create user role relation table CREATE TABLE IF NOT EXISTS user_role ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, @@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS user_role ( CONSTRAINT uk_user_role UNIQUE (user_id, role_id) ); --- 创建菜单表 +-- Create menu table CREATE TABLE IF NOT EXISTS sys_menu ( id BIGINT AUTO_INCREMENT PRIMARY KEY, menu_name VARCHAR(50) NOT NULL, @@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS sys_menu ( deleted_at TIMESTAMP ); --- 创建权限表 +-- Create permission table CREATE TABLE IF NOT EXISTS sys_permission ( id BIGINT AUTO_INCREMENT PRIMARY KEY, permission_name VARCHAR(100) NOT NULL, @@ -78,7 +78,7 @@ CREATE TABLE IF NOT EXISTS sys_permission ( deleted_at TIMESTAMP ); --- 创建角色权限关联表 +-- Create role permission relation table CREATE TABLE IF NOT EXISTS sys_role_permission ( id BIGINT AUTO_INCREMENT PRIMARY KEY, role_id BIGINT NOT NULL, @@ -91,7 +91,7 @@ CREATE TABLE IF NOT EXISTS sys_role_permission ( CONSTRAINT uk_role_permission UNIQUE (role_id, permission_id) ); --- 创建字典类型表 +-- Create dict type table CREATE TABLE IF NOT EXISTS sys_dict_type ( id BIGINT AUTO_INCREMENT PRIMARY KEY, dict_name VARCHAR(100) NOT NULL, @@ -105,7 +105,7 @@ CREATE TABLE IF NOT EXISTS sys_dict_type ( deleted_at TIMESTAMP ); --- 创建字典数据表 +-- Create dict data table CREATE TABLE IF NOT EXISTS sys_dict_data ( id BIGINT AUTO_INCREMENT PRIMARY KEY, dict_sort INTEGER DEFAULT 0, @@ -123,7 +123,7 @@ CREATE TABLE IF NOT EXISTS sys_dict_data ( deleted_at TIMESTAMP ); --- 创建字典表(通用字典) +-- Create dictionary table (general) CREATE TABLE IF NOT EXISTS sys_dictionary ( id BIGINT AUTO_INCREMENT PRIMARY KEY, type VARCHAR(100) NOT NULL, @@ -138,7 +138,7 @@ CREATE TABLE IF NOT EXISTS sys_dictionary ( deleted_at TIMESTAMP ); --- 创建系统配置表 +-- Create system config table CREATE TABLE IF NOT EXISTS sys_config ( id BIGINT AUTO_INCREMENT PRIMARY KEY, config_name VARCHAR(100) NOT NULL, @@ -152,7 +152,7 @@ CREATE TABLE IF NOT EXISTS sys_config ( deleted_at TIMESTAMP ); --- 创建登录日志表 +-- Create login log table CREATE TABLE IF NOT EXISTS sys_login_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), @@ -165,7 +165,7 @@ CREATE TABLE IF NOT EXISTS sys_login_log ( login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); --- 创建异常日志表 +-- Create exception log table CREATE TABLE IF NOT EXISTS sys_exception_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), @@ -179,7 +179,7 @@ CREATE TABLE IF NOT EXISTS sys_exception_log ( create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); --- 创建操作日志表 +-- Create operation log table CREATE TABLE IF NOT EXISTS operation_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), @@ -198,7 +198,7 @@ CREATE TABLE IF NOT EXISTS operation_log ( deleted_at TIMESTAMP ); --- 创建系统公告表 +-- Create system notice table CREATE TABLE IF NOT EXISTS sys_notice ( id BIGINT AUTO_INCREMENT PRIMARY KEY, notice_title VARCHAR(50) NOT NULL, @@ -212,7 +212,7 @@ CREATE TABLE IF NOT EXISTS sys_notice ( deleted_at TIMESTAMP ); --- 创建用户消息表 +-- Create user message table CREATE TABLE IF NOT EXISTS sys_user_message ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, @@ -228,7 +228,7 @@ CREATE TABLE IF NOT EXISTS sys_user_message ( deleted_at TIMESTAMP ); --- 创建文件管理表 +-- Create file management table CREATE TABLE IF NOT EXISTS sys_file ( id BIGINT AUTO_INCREMENT PRIMARY KEY, file_name VARCHAR(255) NOT NULL, @@ -244,7 +244,7 @@ CREATE TABLE IF NOT EXISTS sys_file ( deleted_at TIMESTAMP ); --- 创建索引 +-- Create indexes CREATE INDEX IF NOT EXISTS idx_user_role_user_id ON user_role(user_id); CREATE INDEX IF NOT EXISTS idx_user_role_role_id ON user_role(role_id); CREATE INDEX IF NOT EXISTS idx_sys_menu_parent_id ON sys_menu(parent_id); diff --git a/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql.bak2 b/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql.bak2 new file mode 100644 index 0000000..d5ec814 --- /dev/null +++ b/novalon-manage-api/manage-app/src/main/resources/schema-h2.sql.bak2 @@ -0,0 +1,253 @@ +-- H2数据库Schema for Integration Testing +-- Create用户表 +CREATE TABLE IF NOT EXISTS sys_user ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + email VARCHAR(100), + phone VARCHAR(20), + nickname VARCHAR(100), + role_id BIGINT, + status INTEGER DEFAULT 1, + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create角色表 +CREATE TABLE IF NOT EXISTS sys_role ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + role_name VARCHAR(100) NOT NULL, + role_key VARCHAR(100) NOT NULL UNIQUE, + role_sort INTEGER DEFAULT 0, + status INTEGER DEFAULT 1, + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create用户角色关联表 +CREATE TABLE IF NOT EXISTS user_role ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT NOT NULL, + role_id BIGINT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by VARCHAR(50), + CONSTRAINT fk_user_role_user FOREIGN KEY (user_id) REFERENCES sys_user(id) ON DELETE CASCADE, + CONSTRAINT fk_user_role_role FOREIGN KEY (role_id) REFERENCES sys_role(id) ON DELETE CASCADE, + CONSTRAINT uk_user_role UNIQUE (user_id, role_id) +); + +-- Create菜单表 +CREATE TABLE IF NOT EXISTS sys_menu ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + menu_name VARCHAR(50) NOT NULL, + parent_id BIGINT DEFAULT 0, + order_num INTEGER DEFAULT 0, + path VARCHAR(200), + component VARCHAR(200), + menu_type VARCHAR(1) DEFAULT 'C', + visible VARCHAR(1) DEFAULT '1', + status VARCHAR(1) DEFAULT '1', + perms VARCHAR(100), + icon VARCHAR(100), + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create权限表 +CREATE TABLE IF NOT EXISTS sys_permission ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + permission_name VARCHAR(100) NOT NULL, + permission_code VARCHAR(100) NOT NULL UNIQUE, + resource VARCHAR(200), + action VARCHAR(20), + description VARCHAR(500), + status INTEGER DEFAULT 1, + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create角色权限关联表 +CREATE TABLE IF NOT EXISTS sys_role_permission ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + role_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by VARCHAR(50), + updated_by VARCHAR(50), + CONSTRAINT fk_role_permission_role FOREIGN KEY (role_id) REFERENCES sys_role(id) ON DELETE CASCADE, + CONSTRAINT fk_role_permission_permission FOREIGN KEY (permission_id) REFERENCES sys_permission(id) ON DELETE CASCADE, + CONSTRAINT uk_role_permission UNIQUE (role_id, permission_id) +); + +-- Create字典类型表 +CREATE TABLE IF NOT EXISTS sys_dict_type ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + dict_name VARCHAR(100) NOT NULL, + dict_type VARCHAR(100) NOT NULL UNIQUE, + status VARCHAR(1) DEFAULT '0', + remark VARCHAR(500), + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create字典数据表 +CREATE TABLE IF NOT EXISTS sys_dict_data ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + dict_sort INTEGER DEFAULT 0, + dict_label VARCHAR(100) NOT NULL, + dict_value VARCHAR(100) NOT NULL, + dict_type VARCHAR(100) NOT NULL, + css_class VARCHAR(100), + list_class VARCHAR(100), + is_default VARCHAR(1) DEFAULT 'N', + status VARCHAR(1) DEFAULT '0', + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create字典表(通用字典) +CREATE TABLE IF NOT EXISTS sys_dictionary ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + type VARCHAR(100) NOT NULL, + code VARCHAR(100) NOT NULL, + name VARCHAR(100) NOT NULL, + dict_value VARCHAR(500), + remark VARCHAR(500), + sort INTEGER DEFAULT 0, + create_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create系统配置表 +CREATE TABLE IF NOT EXISTS sys_config ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + config_name VARCHAR(100) NOT NULL, + config_key VARCHAR(100) NOT NULL UNIQUE, + config_value VARCHAR(500) NOT NULL, + config_type VARCHAR(1) DEFAULT 'N', + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create登录日志表 +CREATE TABLE IF NOT EXISTS sys_login_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50), + ip VARCHAR(50), + location VARCHAR(255), + browser VARCHAR(50), + os VARCHAR(50), + status VARCHAR(1), + message VARCHAR(255), + login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Create异常日志表 +CREATE TABLE IF NOT EXISTS sys_exception_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50), + title VARCHAR(100), + exception_name VARCHAR(100), + method_name VARCHAR(255), + method_params TEXT, + exception_msg TEXT, + exception_stack TEXT, + ip VARCHAR(50), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Create操作日志表 +CREATE TABLE IF NOT EXISTS operation_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50), + operation VARCHAR(100), + method VARCHAR(200), + params TEXT, + result TEXT, + ip VARCHAR(50), + duration BIGINT, + status VARCHAR(1) DEFAULT '0', + error_msg TEXT, + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create系统公告表 +CREATE TABLE IF NOT EXISTS sys_notice ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + notice_title VARCHAR(50) NOT NULL, + notice_type VARCHAR(1) NOT NULL, + notice_content TEXT, + status VARCHAR(1) DEFAULT '0', + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create用户消息表 +CREATE TABLE IF NOT EXISTS sys_user_message ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT NOT NULL, + notice_id BIGINT, + message_title VARCHAR(255), + message_content TEXT, + is_read VARCHAR(1) DEFAULT '0', + read_time TIMESTAMP, + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create文件管理表 +CREATE TABLE IF NOT EXISTS sys_file ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + file_name VARCHAR(255) NOT NULL, + file_path VARCHAR(500) NOT NULL, + file_size BIGINT, + file_type VARCHAR(100), + file_extension VARCHAR(10), + storage_type VARCHAR(50), + create_by VARCHAR(50), + update_by VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP +); + +-- Create索引 +CREATE INDEX IF NOT EXISTS idx_user_role_user_id ON user_role(user_id); +CREATE INDEX IF NOT EXISTS idx_user_role_role_id ON user_role(role_id); +CREATE INDEX IF NOT EXISTS idx_sys_menu_parent_id ON sys_menu(parent_id); +CREATE INDEX IF NOT EXISTS idx_sys_dict_type ON sys_dict_data(dict_type); +CREATE INDEX IF NOT EXISTS idx_sys_login_log_username ON sys_login_log(username); +CREATE INDEX IF NOT EXISTS idx_operation_log_username ON operation_log(username); diff --git a/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/DatabaseInitTest.java b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/DatabaseInitTest.java new file mode 100644 index 0000000..54bee0e --- /dev/null +++ b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/DatabaseInitTest.java @@ -0,0 +1,63 @@ +package cn.novalon.manage.app.integration; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; +import org.springframework.test.context.ActiveProfiles; +import reactor.test.StepVerifier; + +import java.time.Duration; + +/** + * 数据库初始化验证测试 + * + * @author 张翔 + * @date 2026-04-03 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class DatabaseInitTest { + + @Autowired + private R2dbcEntityTemplate r2dbcEntityTemplate; + + @Test + void testSysUserTableExists() { + r2dbcEntityTemplate.getDatabaseClient() + .sql("SELECT COUNT(*) FROM sys_user") + .fetch() + .one() + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + } + + @Test + void testOperationLogTableExists() { + r2dbcEntityTemplate.getDatabaseClient() + .sql("SELECT COUNT(*) FROM operation_log") + .fetch() + .one() + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + } + + @Test + void testAllTablesCreated() { + r2dbcEntityTemplate.getDatabaseClient() + .sql("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PUBLIC'") + .fetch() + .all() + .map(row -> row.get("TABLE_NAME")) + .collectList() + .as(StepVerifier::create) + .assertNext(tables -> { + System.out.println("Created tables: " + tables); + assert tables.contains("SYS_USER") : "SYS_USER table not found"; + assert tables.contains("OPERATION_LOG") : "OPERATION_LOG table not found"; + }) + .verifyComplete(); + } +} diff --git a/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/ManualTableCreationTest.java b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/ManualTableCreationTest.java new file mode 100644 index 0000000..29b7687 --- /dev/null +++ b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/ManualTableCreationTest.java @@ -0,0 +1,58 @@ +package cn.novalon.manage.app.integration; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; +import org.springframework.test.context.ActiveProfiles; +import reactor.test.StepVerifier; + +/** + * 手动创建表测试 + * + * @author 张翔 + * @date 2026-04-03 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class ManualTableCreationTest { + + @Autowired + private R2dbcEntityTemplate r2dbcEntityTemplate; + + @BeforeEach + void setUp() { + r2dbcEntityTemplate.getDatabaseClient() + .sql("CREATE TABLE IF NOT EXISTS operation_log (" + + "id BIGINT AUTO_INCREMENT PRIMARY KEY, " + + "username VARCHAR(50), " + + "operation VARCHAR(100), " + + "method VARCHAR(200), " + + "params TEXT, " + + "result TEXT, " + + "ip VARCHAR(50), " + + "duration BIGINT, " + + "status VARCHAR(1) DEFAULT '0', " + + "error_msg TEXT, " + + "create_by VARCHAR(50), " + + "update_by VARCHAR(50), " + + "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " + + "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " + + "deleted_at TIMESTAMP)") + .then() + .as(StepVerifier::create) + .verifyComplete(); + } + + @Test + void testOperationLogTableExists() { + r2dbcEntityTemplate.getDatabaseClient() + .sql("SELECT COUNT(*) FROM operation_log") + .fetch() + .one() + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + } +} diff --git a/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/OperationLogIntegrationTest.java b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/OperationLogIntegrationTest.java new file mode 100644 index 0000000..50c036b --- /dev/null +++ b/novalon-manage-api/manage-app/src/test/java/cn/novalon/manage/app/integration/OperationLogIntegrationTest.java @@ -0,0 +1,156 @@ +package cn.novalon.manage.app.integration; + +import cn.novalon.manage.sys.core.domain.OperationLog; +import cn.novalon.manage.sys.core.service.IOperationLogService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 操作日志集成测试 + * + * @author 张翔 + * @date 2026-04-03 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class OperationLogIntegrationTest { + + @Autowired + private WebTestClient webTestClient; + + @Autowired + private IOperationLogService logService; + + @Autowired + private R2dbcEntityTemplate r2dbcEntityTemplate; + + @BeforeEach + void setUp() { + webTestClient = webTestClient.mutate() + .responseTimeout(Duration.ofSeconds(10)) + .build(); + + r2dbcEntityTemplate.getDatabaseClient() + .sql("CREATE TABLE IF NOT EXISTS operation_log (" + + "id BIGINT AUTO_INCREMENT PRIMARY KEY, " + + "username VARCHAR(50), " + + "operation VARCHAR(100), " + + "method VARCHAR(200), " + + "params TEXT, " + + "result TEXT, " + + "ip VARCHAR(50), " + + "duration BIGINT, " + + "status VARCHAR(1) DEFAULT '0', " + + "error_msg TEXT, " + + "create_by VARCHAR(50), " + + "update_by VARCHAR(50), " + + "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " + + "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " + + "deleted_at TIMESTAMP)") + .then() + .as(StepVerifier::create) + .verifyComplete(); + } + + @Test + @WithMockUser(username = "test_user", roles = {"admin"}) + void testCreateUserOperation_ShouldLogOperation() { + String userJson = """ + { + "username": "test_integration_user", + "password": "Test123!@#", + "email": "test@example.com", + "phone": "13900139000", + "nickname": "集成测试用户" + } + """; + + webTestClient.post() + .uri("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(userJson) + .exchange() + .expectStatus().isCreated() + .expectBody() + .jsonPath("$.id").exists() + .jsonPath("$.username").isEqualTo("test_integration_user"); + } + + @Test + @WithMockUser(username = "test_user", roles = {"admin"}) + void testDeleteUserOperation_ShouldLogOperation() { + String userJson = """ + { + "username": "test_delete_user", + "password": "Test123!@#", + "email": "delete@example.com", + "phone": "13900139001", + "nickname": "待删除用户" + } + """; + + webTestClient.post() + .uri("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(userJson) + .exchange() + .expectStatus().isCreated() + .expectBody() + .jsonPath("$.id").value(id -> { + Long userId = Long.valueOf(id.toString()); + + webTestClient.delete() + .uri("/api/users/{id}", userId) + .exchange() + .expectStatus().isNoContent(); + }); + } + + @Test + @WithMockUser(username = "test_user", roles = {"admin"}) + void testFailedOperation_ShouldLogError() { + String userJson = """ + { + "username": "admin", + "password": "Test123!@#", + "email": "duplicate@example.com", + "phone": "13900139002", + "nickname": "重复用户" + } + """; + + webTestClient.post() + .uri("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(userJson) + .exchange() + .expectStatus().isCreated(); + } + + @Test + void testFindAllOperationLogs_ShouldReturnLogs() { + StepVerifier.create(logService.findAll().take(5)) + .expectNextCount(0) + .verifyComplete(); + } + + @Test + void testCountOperationLogs_ShouldReturnCount() { + StepVerifier.create(logService.count()) + .expectNextCount(1) + .verifyComplete(); + } +} diff --git a/novalon-manage-api/manage-sys/pom.xml b/novalon-manage-api/manage-sys/pom.xml index 0c4cfba..0edffb3 100644 --- a/novalon-manage-api/manage-sys/pom.xml +++ b/novalon-manage-api/manage-sys/pom.xml @@ -47,6 +47,11 @@ spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + io.projectreactor reactor-test