package com.tcm.training.admin.bootstrap;
|
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
|
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
|
import org.junit.jupiter.api.Test;
|
import org.springframework.boot.DefaultApplicationArguments;
|
import org.springframework.beans.factory.ObjectProvider;
|
|
import java.util.LinkedHashMap;
|
import java.util.Map;
|
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.when;
|
|
/**
|
* 海诊通动态数据源启动校验测试。
|
*/
|
class HaizhentongDataSourceStartupValidatorTest {
|
|
/**
|
* 缺少海诊通数据源配置时应在启动阶段直接失败。
|
*/
|
@Test
|
void runShouldFailWhenHaizhentongConfigMissing() {
|
DynamicDataSourceProperties properties = buildProperties(false);
|
HaizhentongDataSourceStartupValidator validator = new HaizhentongDataSourceStartupValidator(
|
properties,
|
emptyProvider()
|
);
|
|
IllegalStateException exception = assertThrows(IllegalStateException.class,
|
() -> validator.run(new DefaultApplicationArguments(new String[0])));
|
|
assertEquals("海诊通数据源 haizhentong 未配置,请检查当前激活环境的配置文件", exception.getMessage());
|
}
|
|
/**
|
* 配置存在但运行期未注册海诊通数据源时也应直接失败。
|
*/
|
@Test
|
void runShouldFailWhenHaizhentongDatasourceNotRegistered() {
|
DynamicDataSourceProperties properties = buildProperties(true);
|
DynamicRoutingDataSource routingDataSource = mock(DynamicRoutingDataSource.class);
|
when(routingDataSource.getDataSources()).thenReturn(new LinkedHashMap<String, javax.sql.DataSource>());
|
HaizhentongDataSourceStartupValidator validator = new HaizhentongDataSourceStartupValidator(
|
properties,
|
fixedProvider(routingDataSource)
|
);
|
|
IllegalStateException exception = assertThrows(IllegalStateException.class,
|
() -> validator.run(new DefaultApplicationArguments(new String[0])));
|
|
assertEquals("海诊通数据源 haizhentong 未注册成功,请检查多数据源配置", exception.getMessage());
|
}
|
|
/**
|
* 配置与运行期注册都完整时应通过启动校验。
|
*/
|
@Test
|
void runShouldPassWhenHaizhentongDatasourceConfiguredAndRegistered() {
|
DynamicDataSourceProperties properties = buildProperties(true);
|
DynamicRoutingDataSource routingDataSource = mock(DynamicRoutingDataSource.class);
|
Map<String, javax.sql.DataSource> dataSourceMap = new LinkedHashMap<String, javax.sql.DataSource>();
|
dataSourceMap.put("master", mock(javax.sql.DataSource.class));
|
dataSourceMap.put("haizhentong", mock(javax.sql.DataSource.class));
|
when(routingDataSource.getDataSources()).thenReturn(dataSourceMap);
|
HaizhentongDataSourceStartupValidator validator = new HaizhentongDataSourceStartupValidator(
|
properties,
|
fixedProvider(routingDataSource)
|
);
|
|
assertDoesNotThrow(() -> validator.run(new DefaultApplicationArguments(new String[0])));
|
}
|
|
/**
|
* 存在海诊通配置但当前上下文拿不到动态路由 Bean 时,应跳过运行期校验而不是阻断启动。
|
*/
|
@Test
|
void runShouldPassWhenRoutingDatasourceBeanUnavailable() {
|
DynamicDataSourceProperties properties = buildProperties(true);
|
HaizhentongDataSourceStartupValidator validator = new HaizhentongDataSourceStartupValidator(
|
properties,
|
emptyProvider()
|
);
|
|
assertDoesNotThrow(() -> validator.run(new DefaultApplicationArguments(new String[0])));
|
}
|
|
/**
|
* 构造动态数据源配置对象,模拟 application.yml 中的多数据源声明。
|
*/
|
private DynamicDataSourceProperties buildProperties(boolean includeHaizhentong) {
|
DynamicDataSourceProperties properties = new DynamicDataSourceProperties();
|
Map<String, DataSourceProperty> datasource = new LinkedHashMap<String, DataSourceProperty>();
|
datasource.put("master", new DataSourceProperty());
|
if (includeHaizhentong) {
|
datasource.put("haizhentong", new DataSourceProperty());
|
}
|
properties.setDatasource(datasource);
|
return properties;
|
}
|
|
/**
|
* 构造返回固定 Bean 的 ObjectProvider 测试桩。
|
*/
|
private ObjectProvider<DynamicRoutingDataSource> fixedProvider(DynamicRoutingDataSource routingDataSource) {
|
return new SimpleObjectProvider(routingDataSource);
|
}
|
|
/**
|
* 构造返回空值的 ObjectProvider 测试桩。
|
*/
|
private ObjectProvider<DynamicRoutingDataSource> emptyProvider() {
|
return new SimpleObjectProvider(null);
|
}
|
|
/**
|
* 以最小实现满足测试对 ObjectProvider 的使用。
|
*/
|
private static class SimpleObjectProvider implements ObjectProvider<DynamicRoutingDataSource> {
|
|
private final DynamicRoutingDataSource value;
|
|
/**
|
* 注入当前测试需要暴露的动态路由 Bean。
|
*/
|
private SimpleObjectProvider(DynamicRoutingDataSource value) {
|
this.value = value;
|
}
|
|
/**
|
* 按固定值返回 Bean,模拟 Spring 容器中的直接获取。
|
*/
|
@Override
|
public DynamicRoutingDataSource getObject() {
|
return value;
|
}
|
|
/**
|
* 按固定值返回 Bean,模拟 Spring 容器中的可选注入。
|
*/
|
@Override
|
public DynamicRoutingDataSource getObject(Object... args) {
|
return value;
|
}
|
|
/**
|
* 按固定值返回 Bean,模拟 Spring 容器中的可选注入。
|
*/
|
@Override
|
public DynamicRoutingDataSource getIfAvailable() {
|
return value;
|
}
|
|
/**
|
* 按固定值返回 Bean,模拟 Spring 容器中的唯一候选。
|
*/
|
@Override
|
public DynamicRoutingDataSource getIfUnique() {
|
return value;
|
}
|
|
/**
|
* 返回简单迭代结果,满足 ObjectProvider 的接口约束。
|
*/
|
@Override
|
public java.util.Iterator<DynamicRoutingDataSource> iterator() {
|
return value == null
|
? java.util.Collections.<DynamicRoutingDataSource>emptyList().iterator()
|
: java.util.Collections.singletonList(value).iterator();
|
}
|
}
|
}
|