mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-28 11:25:00 +00:00
feat: complete Chunk 1 - backend skeleton and infrastructure
- Migrate all Maven groupId and Java packages to com.iflytek.skillhub - Add Docker Compose with PostgreSQL 16, Redis 7, MinIO - Add Flyway V1 migration with Phase 1 core schema (user, auth, RBAC, namespace, audit) - Add RequestIdFilter with MDC tracing and X-Request-Id header - Add GlobalExceptionHandler and ErrorResponse DTO - Add HealthController (/api/v1/health) and OpenAPI config - Add basic SecurityConfig permitting public endpoints - Add H2 test profile for CI-friendly testing without external services - Add top-level Makefile for dev workflow orchestration - All 3 tests passing
This commit is contained in:
parent
6e66425f4e
commit
ca0a3c738f
21 changed files with 488 additions and 20 deletions
29
Makefile
Normal file
29
Makefile
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
.PHONY: dev dev-down build test clean
|
||||
|
||||
# 启动本地开发环境(仅依赖服务)
|
||||
dev:
|
||||
docker compose up -d
|
||||
@echo "Waiting for services to be healthy..."
|
||||
@sleep 5
|
||||
@echo "Services ready. Start backend with: cd server && ./mvnw spring-boot:run -Dspring-boot.run.profiles=local"
|
||||
|
||||
# 停止本地开发环境
|
||||
dev-down:
|
||||
docker compose down
|
||||
|
||||
# 构建后端
|
||||
build:
|
||||
cd server && ./mvnw clean package -DskipTests
|
||||
|
||||
# 运行测试
|
||||
test:
|
||||
cd server && ./mvnw test
|
||||
|
||||
# 清理构建产物
|
||||
clean:
|
||||
cd server && ./mvnw clean
|
||||
docker compose down -v
|
||||
|
||||
# 生成 OpenAPI 类型(前端用,Phase 1 暂不实现)
|
||||
generate-api:
|
||||
@echo "Frontend not yet implemented"
|
||||
47
docker-compose.yml
Normal file
47
docker-compose.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_DB: skillhub
|
||||
POSTGRES_USER: skillhub
|
||||
POSTGRES_PASSWORD: skillhub_dev
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U skillhub"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
command: server /data --console-address ":9001"
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
minio_data:
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
|
@ -36,27 +36,27 @@
|
|||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-domain</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-auth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-search</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-storage</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-infra</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
@ -28,15 +28,15 @@
|
|||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-infra</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
@ -70,6 +70,11 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.skillhub;
|
||||
package com.iflytek.skillhub;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.iflytek.skillhub.config;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.servers.Server;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class OpenApiConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI skillhubOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("SkillHub API")
|
||||
.description("Skills Registry Platform")
|
||||
.version("0.1.0"))
|
||||
.servers(List.of(
|
||||
new Server().url("http://localhost:8080").description("Local development")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.iflytek.skillhub.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/api/v1/health", "/actuator/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.iflytek.skillhub.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1")
|
||||
public class HealthController {
|
||||
|
||||
@GetMapping("/health")
|
||||
public Map<String, String> health() {
|
||||
return Map.of("status", "UP");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.iflytek.skillhub.dto;
|
||||
|
||||
public record ErrorResponse(
|
||||
int status,
|
||||
String error,
|
||||
String message
|
||||
) {}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.iflytek.skillhub.exception;
|
||||
|
||||
import com.iflytek.skillhub.dto.ErrorResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {
|
||||
logger.error("Unhandled exception", ex);
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||
"Internal server error",
|
||||
ex.getMessage()
|
||||
);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.iflytek.skillhub.filter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class RequestIdFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final String REQUEST_ID_HEADER = "X-Request-Id";
|
||||
private static final String REQUEST_ID_MDC_KEY = "requestId";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String requestId = request.getHeader(REQUEST_ID_HEADER);
|
||||
if (requestId == null || requestId.isBlank()) {
|
||||
requestId = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
MDC.put(REQUEST_ID_MDC_KEY, requestId);
|
||||
response.setHeader(REQUEST_ID_HEADER, requestId);
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} finally {
|
||||
MDC.remove(REQUEST_ID_MDC_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,5 +16,5 @@ spring:
|
|||
|
||||
logging:
|
||||
level:
|
||||
com.skillhub: DEBUG
|
||||
com.iflytek.skillhub: DEBUG
|
||||
org.springframework.security: DEBUG
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
-- Phase 1 核心表:认证与授权
|
||||
|
||||
-- 用户账号表
|
||||
CREATE TABLE user_account (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
display_name VARCHAR(128) NOT NULL,
|
||||
email VARCHAR(256),
|
||||
avatar_url VARCHAR(512),
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
merged_to_user_id BIGINT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_account_email ON user_account(email);
|
||||
CREATE INDEX idx_user_account_status ON user_account(status);
|
||||
|
||||
-- OAuth 身份绑定表
|
||||
CREATE TABLE identity_binding (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES user_account(id),
|
||||
provider_code VARCHAR(64) NOT NULL,
|
||||
subject VARCHAR(256) NOT NULL,
|
||||
login_name VARCHAR(128),
|
||||
extra_json JSONB,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(provider_code, subject)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_identity_binding_user_id ON identity_binding(user_id);
|
||||
|
||||
-- API Token 表
|
||||
CREATE TABLE api_token (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
subject_type VARCHAR(32) NOT NULL DEFAULT 'USER',
|
||||
subject_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL REFERENCES user_account(id),
|
||||
name VARCHAR(128) NOT NULL,
|
||||
token_prefix VARCHAR(16) NOT NULL,
|
||||
token_hash VARCHAR(64) NOT NULL UNIQUE,
|
||||
scope_json JSONB NOT NULL,
|
||||
expires_at TIMESTAMP,
|
||||
last_used_at TIMESTAMP,
|
||||
revoked_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_api_token_user_id ON api_token(user_id);
|
||||
CREATE INDEX idx_api_token_hash ON api_token(token_hash);
|
||||
|
||||
-- 角色表
|
||||
CREATE TABLE role (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(64) NOT NULL UNIQUE,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
description VARCHAR(512),
|
||||
is_system BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 权限表
|
||||
CREATE TABLE permission (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code VARCHAR(128) NOT NULL UNIQUE,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
group_code VARCHAR(64)
|
||||
);
|
||||
|
||||
-- 角色权限关联表
|
||||
CREATE TABLE role_permission (
|
||||
role_id BIGINT NOT NULL REFERENCES role(id),
|
||||
permission_id BIGINT NOT NULL REFERENCES permission(id),
|
||||
PRIMARY KEY (role_id, permission_id)
|
||||
);
|
||||
|
||||
-- 用户角色绑定表
|
||||
CREATE TABLE user_role_binding (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES user_account(id),
|
||||
role_id BIGINT NOT NULL REFERENCES role(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, role_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_role_binding_user_id ON user_role_binding(user_id);
|
||||
|
||||
-- 命名空间表
|
||||
CREATE TABLE namespace (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
slug VARCHAR(64) NOT NULL UNIQUE,
|
||||
display_name VARCHAR(128) NOT NULL,
|
||||
type VARCHAR(32) NOT NULL,
|
||||
description TEXT,
|
||||
avatar_url VARCHAR(512),
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_by BIGINT REFERENCES user_account(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 命名空间成员表
|
||||
CREATE TABLE namespace_member (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
namespace_id BIGINT NOT NULL REFERENCES namespace(id),
|
||||
user_id BIGINT NOT NULL REFERENCES user_account(id),
|
||||
role VARCHAR(32) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(namespace_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_namespace_member_user_id ON namespace_member(user_id);
|
||||
CREATE INDEX idx_namespace_member_namespace_id ON namespace_member(namespace_id);
|
||||
|
||||
-- 审计日志表
|
||||
CREATE TABLE audit_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
actor_user_id BIGINT REFERENCES user_account(id),
|
||||
action VARCHAR(64) NOT NULL,
|
||||
target_type VARCHAR(64),
|
||||
target_id BIGINT,
|
||||
request_id VARCHAR(64),
|
||||
client_ip VARCHAR(64),
|
||||
user_agent VARCHAR(512),
|
||||
detail_json JSONB,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_audit_log_actor ON audit_log(actor_user_id);
|
||||
CREATE INDEX idx_audit_log_created_at ON audit_log(created_at);
|
||||
CREATE INDEX idx_audit_log_request_id ON audit_log(request_id);
|
||||
|
||||
-- 插入系统内置角色
|
||||
INSERT INTO role (code, name, description, is_system) VALUES
|
||||
('SUPER_ADMIN', '超级管理员', '拥有所有权限', TRUE),
|
||||
('SKILL_ADMIN', '技能管理员', '全局空间审核、提升审核、隐藏/撤回', TRUE),
|
||||
('USER_ADMIN', '用户管理员', '准入审批、封禁/解封、角色分配', TRUE),
|
||||
('AUDITOR', '审计员', '查看审计日志', TRUE);
|
||||
|
||||
-- 插入系统权限
|
||||
INSERT INTO permission (code, name, group_code) VALUES
|
||||
('skill:publish', '发布技能', 'skill'),
|
||||
('skill:manage', '管理技能', 'skill'),
|
||||
('skill:promote', '提升到全局', 'skill'),
|
||||
('review:approve', '审核技能', 'review'),
|
||||
('promotion:approve', '审核提升申请', 'promotion'),
|
||||
('user:manage', '管理用户', 'user'),
|
||||
('user:approve', '审批用户准入', 'user'),
|
||||
('audit:read', '查看审计日志', 'audit');
|
||||
|
||||
-- 绑定角色权限
|
||||
INSERT INTO role_permission (role_id, permission_id)
|
||||
SELECT r.id, p.id FROM role r, permission p WHERE r.code = 'SKILL_ADMIN' AND p.code IN ('review:approve', 'skill:manage', 'promotion:approve');
|
||||
|
||||
INSERT INTO role_permission (role_id, permission_id)
|
||||
SELECT r.id, p.id FROM role r, permission p WHERE r.code = 'USER_ADMIN' AND p.code IN ('user:manage', 'user:approve');
|
||||
|
||||
INSERT INTO role_permission (role_id, permission_id)
|
||||
SELECT r.id, p.id FROM role r, permission p WHERE r.code = 'AUDITOR' AND p.code = 'audit:read';
|
||||
|
||||
-- 插入系统内置 @global 命名空间
|
||||
INSERT INTO namespace (slug, display_name, type, description, status)
|
||||
VALUES ('global', 'Global', 'GLOBAL', 'Platform-level public namespace', 'ACTIVE');
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.iflytek.skillhub.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
class HealthControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void shouldReturnHealthStatus() throws Exception {
|
||||
mockMvc.perform(get("/api/v1/health"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value("UP"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.iflytek.skillhub.filter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
class RequestIdFilterTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void shouldGenerateRequestIdWhenNotProvided() throws Exception {
|
||||
mockMvc.perform(get("/actuator/health"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().exists("X-Request-Id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreserveProvidedRequestId() throws Exception {
|
||||
String requestId = "test-request-123";
|
||||
mockMvc.perform(get("/actuator/health")
|
||||
.header("X-Request-Id", requestId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("X-Request-Id", requestId));
|
||||
}
|
||||
}
|
||||
20
server/skillhub-app/src/test/resources/application-test.yml
Normal file
20
server/skillhub-app/src/test/resources/application-test.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
flyway:
|
||||
enabled: false
|
||||
data:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
autoconfigure:
|
||||
exclude:
|
||||
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
|
||||
- org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
|
|
@ -5,14 +5,14 @@
|
|||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skillhub-auth</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skillhub-infra</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-domain</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>skillhub-search</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-domain</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.skillhub</groupId>
|
||||
<groupId>com.iflytek.skillhub</groupId>
|
||||
<artifactId>skillhub-parent</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue