diff --git a/orion-ops-dependencies/pom.xml b/orion-ops-dependencies/pom.xml index a0357a51..84c77fc9 100644 --- a/orion-ops-dependencies/pom.xml +++ b/orion-ops-dependencies/pom.xml @@ -29,6 +29,9 @@ 3.18.0 2.7.10 2.14.2 + 4.11.0 + 1.0.7 + 7.2.11.RELEASE @@ -125,6 +128,11 @@ orion-ops-spring-boot-starter-monitor ${revision} + + com.orion.ops + orion-ops-spring-boot-starter-test + ${revision} + @@ -241,6 +249,47 @@ ${transmittable-thread-local.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring.boot.version} + + + asm + org.ow2.asm + + + org.mockito + mockito-core + + + com.vaadin.external.google + android-json + + + + + + + org.mockito + mockito-inline + ${mockito-inline.version} + + + + + com.github.fppt + jedis-mock + ${jedis-mock.version} + + + + + uk.co.jemos.podam + podam + ${podam.version} + diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDatasourceAutoConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDataSourceAutoConfiguration.java similarity index 97% rename from orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDatasourceAutoConfiguration.java rename to orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDataSourceAutoConfiguration.java index a96a3b6f..d0468a72 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDatasourceAutoConfiguration.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/java/com/orion/ops/framework/datasource/config/OrionDataSourceAutoConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_DATASOURCE) @EnableTransactionManagement(proxyTargetClass = true) @EnableConfigurationProperties(DruidStatProperties.class) -public class OrionDatasourceAutoConfiguration { +public class OrionDataSourceAutoConfiguration { /** * @param properties 配置 diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 7611e1ca..85d18ef4 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/orion-ops-framework/orion-ops-spring-boot-starter-datasource/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1 @@ -com.orion.ops.framework.datasource.config.OrionDatasourceAutoConfiguration \ No newline at end of file +com.orion.ops.framework.datasource.config.OrionDataSourceAutoConfiguration \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/config/OrionMybatisAutoConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/config/OrionMybatisAutoConfiguration.java index 5a939b32..b18b44ea 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/config/OrionMybatisAutoConfiguration.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/config/OrionMybatisAutoConfiguration.java @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -31,6 +32,7 @@ public class OrionMybatisAutoConfiguration { * @return 字段填充元数据处理器 */ @Bean + @ConditionalOnBean(SecurityHolder.class) public MetaObjectHandler defaultMetaObjectHandler(SecurityHolder securityHolder) { // 设置填充工具参数 DomainFillUtils.setSecurityHolder(securityHolder); diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-test/pom.xml b/orion-ops-framework/orion-ops-spring-boot-starter-test/pom.xml new file mode 100644 index 00000000..4a1d1179 --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-test/pom.xml @@ -0,0 +1,66 @@ + + + + com.orion.ops + orion-ops-framework + ${revision} + + + 4.0.0 + orion-ops-spring-boot-starter-test + ${project.artifactId} + jar + + 项目单元测试包 + https://github.com/lijiahangmax/orion-ops-pro + + + + com.orion.ops + orion-ops-common + + + + com.orion.ops + orion-ops-spring-boot-starter-mybatis + + + + com.orion.ops + orion-ops-spring-boot-starter-datasource + + + + + org.springframework.boot + spring-boot-starter-test + + + + + org.mockito + mockito-inline + + + + + com.h2database + h2 + + + + + com.github.fppt + jedis-mock + + + + + uk.co.jemos.podam + podam + + + + \ No newline at end of file diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionH2SqlInitializationTestConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionH2SqlInitializationTestConfiguration.java new file mode 100644 index 00000000..1757b0cf --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionH2SqlInitializationTestConfiguration.java @@ -0,0 +1,53 @@ +package com.orion.ops.framework.test.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Profile; + +import javax.sql.DataSource; + +/** + * 单元测试 H2 数据库 DML 初始化脚本 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/8/23 17:17 + */ +@Profile("unit-test") +@Lazy(value = false) +@Configuration(proxyBeanMethods = false) +@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) +@ConditionalOnSingleCandidate(DataSource.class) +@ConditionalOnClass(name = "org.springframework.jdbc.datasource.init.DatabasePopulator") +@EnableConfigurationProperties(SqlInitializationProperties.class) +public class OrionH2SqlInitializationTestConfiguration { + + /** + * 数据源脚本初始化 Bean + */ + @Bean + public DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, + SqlInitializationProperties initializationProperties) { + // TODO 看看正常情况下会不会有 + // 初始化配置 + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations(initializationProperties.getSchemaLocations()); + settings.setDataLocations(initializationProperties.getDataLocations()); + settings.setContinueOnError(initializationProperties.isContinueOnError()); + settings.setSeparator(initializationProperties.getSeparator()); + settings.setEncoding(initializationProperties.getEncoding()); + settings.setMode(initializationProperties.getMode()); + // 初始化 + return new DataSourceScriptDatabaseInitializer(dataSource, settings); + } + +} diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionMockRedisTestConfiguration.java b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionMockRedisTestConfiguration.java new file mode 100644 index 00000000..ed4d60f7 --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/config/OrionMockRedisTestConfiguration.java @@ -0,0 +1,38 @@ +package com.orion.ops.framework.test.config; + +import com.github.fppt.jedismock.RedisServer; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Profile; + +/** + * 单元测试 redis 初始化 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/8/23 17:19 + */ +@Lazy(false) +@Profile("unit-test") +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(RedisProperties.class) +public class OrionMockRedisTestConfiguration { + + /** + * mockRedisServer + */ + @Bean + public RedisServer redisServer(RedisProperties properties) { + // TODO 看看正常情况下会不会有 + RedisServer redisServer = new RedisServer(properties.getPort()); + try { + redisServer.start(); + } catch (Exception ignore) { + } + return redisServer; + } + +} diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/base/BaseUnitTest.java b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/base/BaseUnitTest.java new file mode 100644 index 00000000..fc69c90f --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/base/BaseUnitTest.java @@ -0,0 +1,46 @@ +package com.orion.ops.framework.test.core.base; + +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.orion.ops.framework.datasource.config.OrionDataSourceAutoConfiguration; +import com.orion.ops.framework.mybatis.config.OrionMybatisAutoConfiguration; +import com.orion.ops.framework.test.config.OrionH2SqlInitializationTestConfiguration; +import com.orion.ops.framework.test.config.OrionMockRedisTestConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * 单元测试父类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/8/23 15:12 + */ +@Rollback +@ActiveProfiles("unit-test") +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseUnitTest.Application.class) +public class BaseUnitTest { + + @Import({ + // datasource + OrionDataSourceAutoConfiguration.class, + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + OrionH2SqlInitializationTestConfiguration.class, + DruidDataSourceAutoConfigure.class, + // mybatis + OrionMybatisAutoConfiguration.class, + MybatisPlusAutoConfiguration.class, + // redis + OrionMockRedisTestConfiguration.class, + }) + public static class Application { + } + +} diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/utils/EntityRandoms.java b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/utils/EntityRandoms.java new file mode 100644 index 00000000..4e03d870 --- /dev/null +++ b/orion-ops-framework/orion-ops-spring-boot-starter-test/src/main/java/com/orion/ops/framework/test/core/utils/EntityRandoms.java @@ -0,0 +1,86 @@ +package com.orion.ops.framework.test.core.utils; + +import com.orion.lang.utils.Arrays1; +import com.orion.lang.utils.random.Randoms; +import uk.co.jemos.podam.api.PodamFactory; +import uk.co.jemos.podam.api.PodamFactoryImpl; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 对象生成器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/8/23 14:13 + */ +public class EntityRandoms { + + private EntityRandoms() { + } + + private static final int RANDOM_STRING_LENGTH = 5; + + private static final int RANDOM_INT_MAX = 10; + + private static final int RANDOM_COLLECTION_LENGTH = 5; + + private static final String DELETED = "deleted"; + + private static final PodamFactory FACTORY = new PodamFactoryImpl(); + + static { + // 字符串 + FACTORY.getStrategy().addOrReplaceTypeManufacturer(String.class, (dataProviderStrategy, attributeMetadata, map) -> Randoms.randomLetter(RANDOM_STRING_LENGTH)); + // Integer + FACTORY.getStrategy().addOrReplaceTypeManufacturer(Integer.class, (dataProviderStrategy, attributeMetadata, map) -> Randoms.randomInt(0, RANDOM_INT_MAX)); + // Boolean + FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { + if (DELETED.equals(attributeMetadata.getAttributeName())) { + return false; + } + return Randoms.randomBoolean(); + }); + } + + @SafeVarargs + public static T random(Class clazz, Consumer... consumers) { + T e = FACTORY.manufacturePojo(clazz); + if (Arrays1.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(e)); + } + return e; + } + + @SafeVarargs + public static T random(Class clazz, Type type, Consumer... consumers) { + T e = FACTORY.manufacturePojo(clazz, type); + if (Arrays1.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(e)); + } + return e; + } + + @SafeVarargs + public static Set randomSet(Class clazz, Consumer... consumers) { + return Stream.iterate(0, i -> i) + .limit(Randoms.randomInt(1, RANDOM_COLLECTION_LENGTH)) + .map(o -> random(clazz, consumers)) + .collect(Collectors.toSet()); + } + + @SafeVarargs + public static List randomList(Class clazz, Consumer... consumers) { + return Stream.iterate(0, i -> i) + .limit(Randoms.randomInt(1, RANDOM_COLLECTION_LENGTH)) + .map(o -> random(clazz, consumers)) + .collect(Collectors.toList()); + } + +} diff --git a/orion-ops-framework/pom.xml b/orion-ops-framework/pom.xml index 25fd3ca0..ca365b7f 100644 --- a/orion-ops-framework/pom.xml +++ b/orion-ops-framework/pom.xml @@ -30,6 +30,7 @@ orion-ops-spring-boot-starter-storage orion-ops-spring-boot-starter-security orion-ops-spring-boot-starter-monitor + orion-ops-spring-boot-starter-test \ No newline at end of file