feat(education): complete Flyway migration and atomic submit

This commit is contained in:
2026-07-30 12:06:55 +08:00
parent ce02f8acb4
commit 79a5799502
228 changed files with 32551 additions and 1376 deletions

View File

@@ -31,7 +31,7 @@ public interface DictTypeMapper extends BaseMapperX<DictTypeDO> {
return selectOne(DictTypeDO::getName, name);
}
@Update("UPDATE system_dict_type SET deleted = 1, deleted_time = #{deletedTime} WHERE id = #{id}")
@Update("UPDATE system_dict_type SET deleted = TRUE, deleted_time = #{deletedTime} WHERE id = #{id}")
void updateToDelete(@Param("id") Long id, @Param("deletedTime") LocalDateTime deletedTime);
}

View File

@@ -46,7 +46,8 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO
* @param limit 删除条数,防止一次删除太多
* @return 删除条数
*/
@Delete("DELETE FROM system_oauth2_access_token WHERE expires_time < #{expiresTime} LIMIT #{limit}")
@Delete("DELETE FROM system_oauth2_access_token WHERE id IN (" +
"SELECT id FROM system_oauth2_access_token WHERE expires_time < #{expiresTime} ORDER BY id LIMIT #{limit})")
Integer deleteByExpiresTimeLt(@Param("expiresTime") LocalDateTime expiresTime, @Param("limit") Integer limit);
}

View File

@@ -30,6 +30,7 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshToken
* @param limit 删除条数,防止一次删除太多
* @return 删除条数
*/
@Delete("DELETE FROM system_oauth2_refresh_token WHERE expires_time < #{expiresTime} LIMIT #{limit}")
@Delete("DELETE FROM system_oauth2_refresh_token WHERE id IN (" +
"SELECT id FROM system_oauth2_refresh_token WHERE expires_time < #{expiresTime} ORDER BY id LIMIT #{limit})")
Integer deleteByExpiresTimeLt(@Param("expiresTime") LocalDateTime expiresTime, @Param("limit") Integer limit);
}

View File

@@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.system.api.tenant;
import cn.iocoder.yudao.framework.common.biz.system.tenant.TenantCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.tenant.dto.TenantRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.lang.reflect.Modifier;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class TenantApiImplTest {
private TenantApiImpl tenantApi;
private TenantService tenantService;
@BeforeEach
void setUp() {
tenantService = mock(TenantService.class);
tenantApi = new TenantApiImpl();
ReflectionTestUtils.setField(tenantApi, "tenantService", tenantService);
}
@Test
void tenantLookupMethodsAreRequired() throws Exception {
assertRequired("getTenant", Long.class);
assertRequired("getTenantByName", String.class);
assertRequired("getTenantByWebsite", String.class);
}
@Test
void getTenantByNameDelegatesExactValueAndMapsDto() {
TenantDO tenant = tenant(1L, "School_01", List.of("school.example.com"));
when(tenantService.getTenantByName("School_01")).thenReturn(tenant);
TenantRespDTO result = tenantApi.getTenantByName("School_01");
verify(tenantService).getTenantByName("School_01");
assertMapped(result, tenant);
}
@Test
void getTenantByWebsiteDelegatesCanonicalExactValueAndMapsDto() {
TenantDO tenant = tenant(2L, "School_02", List.of("school.example.com"));
when(tenantService.getTenantByWebsite("school.example.com")).thenReturn(tenant);
TenantRespDTO result = tenantApi.getTenantByWebsite("school.example.com");
verify(tenantService).getTenantByWebsite("school.example.com");
assertMapped(result, tenant);
}
@Test
void getTenantByWebsiteDoesNotNormalizeNonCanonicalCandidate() {
tenantApi.getTenantByWebsite("https://school.example.com:8443/path");
verify(tenantService).getTenantByWebsite("https://school.example.com:8443/path");
}
private static void assertRequired(String methodName, Class<?> parameterType) throws Exception {
var method = TenantCommonApi.class.getMethod(methodName, parameterType);
assertFalse(method.isDefault());
assertEquals(Modifier.PUBLIC | Modifier.ABSTRACT, method.getModifiers());
}
private static TenantDO tenant(Long id, String name, List<String> websites) {
return new TenantDO().setId(id).setName(name).setStatus(0).setWebsites(websites)
.setExpireTime(LocalDateTime.now().plusDays(1));
}
private static void assertMapped(TenantRespDTO result, TenantDO tenant) {
assertEquals(tenant.getId(), result.getId());
assertEquals(tenant.getName(), result.getName());
assertEquals(tenant.getStatus(), result.getStatus());
assertEquals(tenant.getWebsites(), result.getWebsites());
assertEquals(tenant.getExpireTime(), result.getExpireTime());
}
}

View File

@@ -82,7 +82,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
dictDataMapper.insert(cloneIgnoreId(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
DictDataPageReqVO reqVO = new DictDataPageReqVO();
reqVO.setLabel("");
reqVO.setLabel("");
reqVO.setDictType("yunai");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());

View File

@@ -60,7 +60,7 @@ public class DictTypeServiceImplTest extends BaseDbUnitTest {
// 准备参数
DictTypePageReqVO reqVO = new DictTypePageReqVO();
reqVO.setName("nai");
reqVO.setType("");
reqVO.setType("");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2021, 1, 10, 2021, 1, 20));

View File

@@ -124,7 +124,7 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5))));
// 准备参数
NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO();
reqVO.setName("");
reqVO.setName("");
reqVO.setCode("est_01");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5));

View File

@@ -223,7 +223,8 @@ public class OAuth2ApproveServiceImplTest extends BaseDbUnitTest {
String clientId = randomString();
String scope = randomString();
Boolean approved = randomBoolean();
LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault());
LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault())
.truncatedTo(ChronoUnit.SECONDS);
// mock 方法
// 调用
@@ -237,7 +238,7 @@ public class OAuth2ApproveServiceImplTest extends BaseDbUnitTest {
assertEquals(clientId, result.get(0).getClientId());
assertEquals(scope, result.get(0).getScope());
assertEquals(approved, result.get(0).getApproved());
assertEquals(expireTime, result.get(0).getExpiresTime());
assertEquals(expireTime.truncatedTo(ChronoUnit.SECONDS), result.get(0).getExpiresTime());
}
@Test
@@ -251,7 +252,8 @@ public class OAuth2ApproveServiceImplTest extends BaseDbUnitTest {
String clientId = approve.getClientId();
String scope = approve.getScope();
Boolean approved = randomBoolean();
LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault());
LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault())
.truncatedTo(ChronoUnit.SECONDS);
// mock 方法
// 调用
@@ -266,7 +268,7 @@ public class OAuth2ApproveServiceImplTest extends BaseDbUnitTest {
assertEquals(clientId, result.get(0).getClientId());
assertEquals(scope, result.get(0).getScope());
assertEquals(approved, result.get(0).getApproved());
assertEquals(expireTime, result.get(0).getExpiresTime());
assertEquals(expireTime.truncatedTo(ChronoUnit.SECONDS), result.get(0).getExpiresTime());
}
}

View File

@@ -311,7 +311,8 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
// 测试 userType 不匹配
oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setClientId("it_client")));
// 测试 expireTime 不匹配
oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setExpiresTime(LocalDateTimeUtil.now())));
oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken,
o -> o.setExpiresTime(LocalDateTime.now().minusDays(1))));
// 准备参数
OAuth2AccessTokenPageReqVO reqVO = new OAuth2AccessTokenPageReqVO();
reqVO.setUserId(10L);

View File

@@ -153,7 +153,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
// 测试 name 不匹配
menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setName("")));
// 准备参数
MenuListReqVO reqVO = new MenuListReqVO().setName("").setStatus(CommonStatusEnum.ENABLE.getStatus());
MenuListReqVO reqVO = new MenuListReqVO().setName("").setStatus(CommonStatusEnum.ENABLE.getStatus());
// 调用
List<MenuDO> result = menuService.getMenuList(reqVO);

View File

@@ -460,7 +460,7 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
reqVO.setName("");
reqVO.setName("");
reqVO.setSocialType(SocialTypeEnum.GITEE.getType());
reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
reqVO.setClientId("yu");

View File

@@ -273,7 +273,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
// 准备参数
SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
reqVO.setType(SocialTypeEnum.GITEE.getType());
reqVO.setNickname("");
reqVO.setNickname("");
reqVO.setOpenid("yudao");
reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));

View File

@@ -307,7 +307,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
// 准备参数
TenantPageReqVO reqVO = new TenantPageReqVO();
reqVO.setName("恭学");
reqVO.setContactName("");
reqVO.setContactName("");
reqVO.setContactMobile("1560");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));

View File

@@ -695,7 +695,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
// 测试 nickname 不匹配
userMapper.insert(randomAdminUserDO(o -> o.setNickname("源码")));
// 准备参数
String nickname = "";
String nickname = "";
// 调用
List<AdminUserDO> result = userService.getUserListByNickname(nickname);