173 lines
6.7 KiB
Java
173 lines
6.7 KiB
Java
package com.yunhai.cms.support;
|
|
|
|
import com.yunhai.cms.entity.CmsArticle;
|
|
import com.yunhai.cms.entity.CmsBanner;
|
|
import com.yunhai.cms.entity.CmsCategory;
|
|
import com.yunhai.cms.entity.CmsLink;
|
|
import com.yunhai.cms.entity.CmsSite;
|
|
import com.yunhai.cms.enums.ArticleStatusEnum;
|
|
import com.yunhai.cms.enums.CategoryTypeEnum;
|
|
import com.yunhai.cms.repository.CmsArticleRepository;
|
|
import com.yunhai.cms.repository.CmsAttachmentRepository;
|
|
import com.yunhai.cms.repository.CmsBannerRepository;
|
|
import com.yunhai.cms.repository.CmsCategoryRepository;
|
|
import com.yunhai.cms.repository.CmsLinkRepository;
|
|
import com.yunhai.cms.repository.CmsSiteRepository;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
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.cache.CacheManager;
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
/**
|
|
* 集成测试基类:真实 Spring 上下文 + 本地 MySQL(bsch_cms_test) + Caffeine 缓存。
|
|
*
|
|
* <p>所有子类共享同一上下文配置(本类注解即完整配置),Spring TestContext 只启动一次,
|
|
* schema-cms-test.sql 的 DROP/CREATE 也只执行一次;跨测试的库与缓存清洁由
|
|
* {@link #clearCaches()} / {@link #purgeTables()} 负责:
|
|
* <ul>
|
|
* <li>@Transactional 用例:回滚即隔离,仅需清缓存(缓存是进程级全局的,不随事务回滚);</li>
|
|
* <li>非事务用例(事件 AFTER_COMMIT / MockMvc / 定时任务):@BeforeEach purge + @AfterEach purge。</li>
|
|
* </ul>
|
|
*/
|
|
@SpringBootTest(properties = "cms.schedule.auto-enabled=false")
|
|
@AutoConfigureMockMvc
|
|
public abstract class CmsIntegrationTestBase {
|
|
|
|
@Autowired
|
|
protected CacheManager cacheManager;
|
|
@Autowired
|
|
protected CmsSiteRepository siteRepository;
|
|
@Autowired
|
|
protected CmsCategoryRepository categoryRepository;
|
|
@Autowired
|
|
protected CmsArticleRepository articleRepository;
|
|
@Autowired
|
|
protected CmsBannerRepository bannerRepository;
|
|
@Autowired
|
|
protected CmsLinkRepository linkRepository;
|
|
@Autowired
|
|
protected CmsAttachmentRepository attachmentRepository;
|
|
|
|
@BeforeEach
|
|
void clearCachesBeforeEachTest() {
|
|
clearCaches();
|
|
}
|
|
|
|
/** 清空全部 CMS 缓存(cms:site / cms:article / cms:list),防止用例间缓存串扰 */
|
|
protected void clearCaches() {
|
|
for (String name : cacheManager.getCacheNames()) {
|
|
cacheManager.getCache(name).clear();
|
|
}
|
|
}
|
|
|
|
/** 清空 6 张业务表(无外键约束,顺序无碍),非事务用例的隔离手段 */
|
|
protected void purgeTables() {
|
|
attachmentRepository.deleteAllInBatch();
|
|
articleRepository.deleteAllInBatch();
|
|
categoryRepository.deleteAllInBatch();
|
|
bannerRepository.deleteAllInBatch();
|
|
linkRepository.deleteAllInBatch();
|
|
siteRepository.deleteAllInBatch();
|
|
}
|
|
|
|
// ===== 落库种子(返回带自增 id 的实体)=====
|
|
|
|
protected CmsSite persistSite(String code, Integer schId, String name) {
|
|
CmsSite site = new CmsSite();
|
|
site.setCode(code);
|
|
site.setPath(code); // W4:顶层 path=code(与 SiteService.save 口径一致)
|
|
site.setSchId(schId);
|
|
site.setSchName("学校-" + schId);
|
|
site.setName(name);
|
|
site.setTheme("default");
|
|
site.setStatus(1);
|
|
return siteRepository.saveAndFlush(site);
|
|
}
|
|
|
|
/** 带上级站点的落库(院系子站,《院系子站方案》):parentSiteId 传 null 视为顶层 0 */
|
|
protected CmsSite persistSite(String code, Integer schId, String name, Integer parentSiteId) {
|
|
CmsSite site = persistSite(code, schId, name);
|
|
if (parentSiteId == null || parentSiteId == 0) {
|
|
site.setParentSiteId(0);
|
|
} else {
|
|
CmsSite parent = siteRepository.findById(parentSiteId)
|
|
.orElseThrow(IllegalStateException::new);
|
|
site.setParentSiteId(parentSiteId);
|
|
site.setPath(parent.getPath() + "/" + code); // W4:子站 path=父path/code
|
|
}
|
|
return siteRepository.saveAndFlush(site);
|
|
}
|
|
|
|
protected CmsCategory persistCategory(Integer siteId, Integer parentId, String name,
|
|
CategoryTypeEnum type) {
|
|
CmsCategory c = new CmsCategory();
|
|
c.setSiteId(siteId);
|
|
c.setParentId(parentId == null ? 0 : parentId);
|
|
c.setName(name);
|
|
c.setType(type.getCode());
|
|
c.setStatus(1);
|
|
return categoryRepository.saveAndFlush(c);
|
|
}
|
|
|
|
protected CmsArticle persistArticle(Integer siteId, Integer categoryId, String title,
|
|
ArticleStatusEnum status, LocalDateTime publishTime) {
|
|
CmsArticle a = new CmsArticle();
|
|
a.setSiteId(siteId);
|
|
a.setCategoryId(categoryId);
|
|
a.setTitle(title);
|
|
a.setContent("<p>" + title + " 正文</p>");
|
|
a.setSummary(title + " 摘要");
|
|
a.setStatus(status.getCode());
|
|
a.setPublishTime(publishTime);
|
|
return articleRepository.saveAndFlush(a);
|
|
}
|
|
|
|
protected CmsBanner persistBanner(Integer siteId, String position, String title,
|
|
LocalDateTime start, LocalDateTime end) {
|
|
CmsBanner b = new CmsBanner();
|
|
b.setSiteId(siteId);
|
|
b.setPosition(position);
|
|
b.setTitle(title);
|
|
b.setImageUrl("/upload/cms/banner.png");
|
|
b.setLinkType(3);
|
|
b.setLinkValue("https://www.example.com");
|
|
b.setStatus(1);
|
|
b.setStartTime(start);
|
|
b.setEndTime(end);
|
|
return bannerRepository.saveAndFlush(b);
|
|
}
|
|
|
|
protected CmsLink persistLink(Integer siteId, String groupName, String name) {
|
|
CmsLink l = new CmsLink();
|
|
l.setSiteId(siteId);
|
|
l.setGroupName(groupName);
|
|
l.setName(name);
|
|
l.setLinkUrl("https://www.example.com");
|
|
l.setStatus(1);
|
|
return linkRepository.saveAndFlush(l);
|
|
}
|
|
|
|
/** 简易轮询等待(无 awaitility 依赖):最长 waitMillis 内每 50ms 检查一次期望 */
|
|
protected static void awaitTrue(long waitMillis, java.util.function.BooleanSupplier condition)
|
|
throws InterruptedException {
|
|
long deadline = System.currentTimeMillis() + waitMillis;
|
|
while (System.currentTimeMillis() < deadline) {
|
|
if (condition.getAsBoolean()) {
|
|
return;
|
|
}
|
|
Thread.sleep(50);
|
|
}
|
|
}
|
|
|
|
protected static LocalDateTime nowPlusSeconds(long seconds) {
|
|
return LocalDateTime.now().plusSeconds(seconds);
|
|
}
|
|
|
|
protected static LocalDateTime nowMinusSeconds(long seconds) {
|
|
return LocalDateTime.now().minusSeconds(seconds);
|
|
}
|
|
}
|