luojunhui 1 неделя назад
Родитель
Сommit
e09f2250b3

+ 0 - 113
server/src/test/java/ArticleVectorJobIntegrationTest.java

@@ -1,113 +0,0 @@
-import com.tzld.videoVector.dao.mapper.pgVector.ext.ArticleDeconstructResultMapperExt;
-import com.tzld.videoVector.dao.mapper.pgVector.ext.ArticleVectorMapperExt;
-import com.tzld.videoVector.job.ArticleVectorJob;
-import com.tzld.videoVector.service.ArticleVectorStoreService;
-import com.xxl.job.core.biz.model.ReturnT;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Assumptions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.util.ReflectionTestUtils;
-import org.springframework.util.CollectionUtils;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-/**
- * ArticleVectorJob 集成测试:sync + vectorize(articleJob)。
- * <p>
- * 运行前改下面两个常量即可,无需配 VM Options。
- * <p>
- * 前置条件:
- * <ul>
- *   <li>PG article_deconstruct_result / article_vectors 表已创建(DDL 见 sql/article_vector_ddl.sql)</li>
- *   <li>AIGC taskId=66 有文章数据</li>
- * </ul>
- */
-@SpringBootTest(
-        classes = ArticleVectorJobIntegrationTestApp.class,
-        webEnvironment = SpringBootTest.WebEnvironment.NONE,
-        properties = {
-                "spring.main.web-application-type=none",
-                "spring.config.location=classpath:/application-test-local.yml"
-        }
-)
-@ActiveProfiles("test-local")
-@Slf4j
-public class ArticleVectorJobIntegrationTest {
-
-    /** 改为 true 后才会连 RDS / AIGC / DashScope 执行 */
-    private static final boolean RUN_LIVE_TEST = true;
-
-    /** 本次最多向量化文章数;sync 阶段仍全量,仅 vectorize 阶段限量 */
-    private static final int MAX_ARTICLE_COUNT = 5;
-
-    private static final String SOURCE_AIGC = "aigc_deconstruct";
-    private static final String CONFIG_VIDEO_TOPIC = "VIDEO_TOPIC";
-    private static final int TASK_ID = 66;
-
-    @Autowired
-    private ArticleVectorJob articleVectorJob;
-
-    @Autowired
-    private ArticleDeconstructResultMapperExt articleDeconstructResultMapperExt;
-
-    @Autowired
-    private ArticleVectorMapperExt articleVectorMapperExt;
-
-    @Autowired
-    private ArticleVectorStoreService articleVectorStoreService;
-
-    @BeforeEach
-    void injectTaskId() {
-        ReflectionTestUtils.setField(articleVectorJob, "articleTaskId", TASK_ID);
-    }
-
-    /**
-     * 完整链路:syncArticleDeconstructJob → vectorArticleJob
-     */
-    @Test
-    void articleJob_writesDeconstructResultAndVectors() {
-        Assumptions.assumeTrue(RUN_LIVE_TEST, "将 RUN_LIVE_TEST 改为 true 后运行");
-
-        log.info(">>> 文章集成测试开始, maxArticleCount={}", MAX_ARTICLE_COUNT);
-
-        Set<String> vectorIdsBefore = new HashSet<>(articleVectorMapperExt.selectAllArticleIds(CONFIG_VIDEO_TOPIC));
-        log.info("执行前 VIDEO_TOPIC 向量 articleId 数: {}", vectorIdsBefore.size());
-
-        ReturnT<String> result = articleVectorJob.articleJob(String.valueOf(MAX_ARTICLE_COUNT));
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode(),
-                "articleJob 应成功, msg=" + (result == null ? null : result.getMsg()));
-
-        List<String> deconstructArticleIds = articleDeconstructResultMapperExt
-                .selectArticleIdsBySourcePaged(SOURCE_AIGC, 0, MAX_ARTICLE_COUNT);
-        assertFalse(CollectionUtils.isEmpty(deconstructArticleIds),
-                "article_deconstruct_result 应有同步记录,请确认 AIGC taskId=66 有数据且 PG 表已建");
-
-        log.info("article_deconstruct_result 样本 articleIds: {}", deconstructArticleIds);
-
-        boolean hasNewOrExistingVector = false;
-        for (String articleId : deconstructArticleIds) {
-            if (articleVectorStoreService.exists(CONFIG_VIDEO_TOPIC, articleId)) {
-                hasNewOrExistingVector = true;
-                log.info("articleId={} 已有 VIDEO_TOPIC 向量", articleId);
-            }
-        }
-
-        Set<String> vectorIdsAfter = new HashSet<>(articleVectorMapperExt.selectAllArticleIds(CONFIG_VIDEO_TOPIC));
-        log.info("执行后 VIDEO_TOPIC 向量 articleId 数: {} (before={})",
-                vectorIdsAfter.size(), vectorIdsBefore.size());
-
-        assertTrue(hasNewOrExistingVector || vectorIdsAfter.size() > vectorIdsBefore.size(),
-                "article_vectors 应有 VIDEO_TOPIC 向量写入;若全部文章已向量化,可增大 MAX_ARTICLE_COUNT 后重试");
-    }
-}

+ 0 - 65
server/src/test/java/ArticleVectorJobIntegrationTestApp.java

@@ -1,65 +0,0 @@
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.FilterType;
-
-/**
- * ArticleVectorJob 集成测试专用 Spring Boot 入口。
- * <p>
- * 与 {@link MaterialVectorJobIntegrationTestApp} 使用相同的精简 ComponentScan。
- */
-@SpringBootApplication(excludeName = {
-        "com.tzld.commons.aliyun.log.AliyunLogAutoConfiguration"
-})
-@ComponentScan(
-        basePackages = "com.tzld.videoVector",
-        excludeFilters = {
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.Application"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.MaterialEmbeddingTestRunner"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.MaterialEmbeddingTestRunner\\$TestKickoffRunner"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.MaterialVectorEmbedOnlyRunner"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.MaterialVectorEmbedOnlyRunner\\$EmbedKickoffRunner"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.config\\.XxlJobConfig"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.config\\.AliOssConfig"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.util\\.AliOssFileTool"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.config\\.SwaggerConfig"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.config\\.WebMvcConfig"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.config\\.SchedulingConfig"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.filter\\..*"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.aop\\..*"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.controller\\..*"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.VideoTitleVectorJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.AiUnderstandingSyncJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.ChannelDemandMatchJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.VideoDetailSyncJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.VideoVectorJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.job\\.MaterialVectorJob"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.service\\.impl\\.MaterialSearchServiceImpl"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.service\\.impl\\.VideoSearchServiceImpl"),
-                @ComponentScan.Filter(type = FilterType.REGEX,
-                        pattern = "com\\.tzld\\.videoVector\\.service\\.recall\\..*")
-        }
-)
-public class ArticleVectorJobIntegrationTestApp {
-}

+ 0 - 217
server/src/test/java/ArticleVectorJobTest.java

@@ -1,217 +0,0 @@
-import com.alibaba.fastjson.JSONObject;
-import com.tzld.videoVector.api.AigcApiService;
-import com.tzld.videoVector.dao.mapper.pgVector.DeconstructVectorConfigMapper;
-import com.tzld.videoVector.dao.mapper.pgVector.ext.ArticleDeconstructResultMapperExt;
-import com.tzld.videoVector.job.ArticleVectorJob;
-import com.tzld.videoVector.model.po.pgVector.ArticleDeconstructResult;
-import com.tzld.videoVector.model.po.pgVector.DeconstructVectorConfig;
-import com.tzld.videoVector.service.ArticleVectorStoreService;
-import com.tzld.videoVector.service.EmbeddingService;
-import com.xxl.job.core.biz.model.ReturnT;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.test.util.ReflectionTestUtils;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyCollection;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * ArticleVectorJob 单元测试(对称 MaterialVectorJobTest)
- * Mock 外部依赖,不连 DB / AIGC / DashScope
- */
-@ExtendWith(MockitoExtension.class)
-@Slf4j
-public class ArticleVectorJobTest {
-
-    private static final String ARTICLE_ID = "10086";
-    private static final long TASK_INSTANCE_ID = 9002L;
-    private static final int TASK_ID = 66;
-
-    @Mock
-    private DeconstructVectorConfigMapper vectorConfigMapper;
-
-    @Mock
-    private ArticleDeconstructResultMapperExt articleDeconstructResultMapperExt;
-
-    @Mock
-    private ArticleVectorStoreService articleVectorStoreService;
-
-    @Mock
-    private EmbeddingService embeddingService;
-
-    @Mock
-    private AigcApiService aigcApiService;
-
-    @InjectMocks
-    private ArticleVectorJob articleVectorJob;
-
-    @BeforeEach
-    void setUp() {
-        ReflectionTestUtils.setField(articleVectorJob, "articleTaskId", TASK_ID);
-    }
-
-    // ==============================
-    // syncArticleDeconstructJob
-    // ==============================
-
-    @Test
-    void syncArticleDeconstructJob_skipsWhenNoData() {
-        when(aigcApiService.getTaskInputList(TASK_ID)).thenReturn(Collections.emptyList());
-
-        ReturnT<String> result = articleVectorJob.syncArticleDeconstructJob(null);
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(articleDeconstructResultMapperExt, never()).batchInsertIgnore(any());
-    }
-
-    @Test
-    void syncArticleDeconstructJob_insertsArticle() {
-        AigcApiService.AigcTaskInput input = new AigcApiService.AigcTaskInput();
-        input.setBizUniqueId(ARTICLE_ID);
-        input.setTaskInstanceId(TASK_INSTANCE_ID);
-        when(aigcApiService.getTaskInputList(TASK_ID)).thenReturn(Collections.singletonList(input));
-        when(articleDeconstructResultMapperExt.selectExistingArticleIds(eq("aigc_deconstruct"), any()))
-                .thenReturn(Collections.emptyList());
-        JSONObject dataContent = new JSONObject();
-        dataContent.put("title", "测试文章标题");
-        dataContent.put("content", "测试文章正文内容");
-        when(aigcApiService.getTaskCallbackDetail(TASK_INSTANCE_ID)).thenReturn(dataContent);
-        when(articleDeconstructResultMapperExt.batchInsertIgnore(any())).thenReturn(1);
-
-        ReturnT<String> result = articleVectorJob.syncArticleDeconstructJob(null);
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-
-        @SuppressWarnings("unchecked")
-        ArgumentCaptor<List<ArticleDeconstructResult>> captor = ArgumentCaptor.forClass(List.class);
-        verify(articleDeconstructResultMapperExt).batchInsertIgnore(captor.capture());
-        ArticleDeconstructResult saved = captor.getValue().get(0);
-        assertEquals(ARTICLE_ID, saved.getArticleId());
-        assertEquals("aigc_deconstruct", saved.getSource());
-        assertTrue(saved.getResult().contains("测试文章标题"));
-        assertTrue(saved.getResult().contains("测试文章正文内容"));
-    }
-
-    @Test
-    void syncArticleDeconstructJob_skipsExistingArticle() {
-        AigcApiService.AigcTaskInput input = new AigcApiService.AigcTaskInput();
-        input.setBizUniqueId(ARTICLE_ID);
-        input.setTaskInstanceId(TASK_INSTANCE_ID);
-        when(aigcApiService.getTaskInputList(TASK_ID)).thenReturn(Collections.singletonList(input));
-        when(articleDeconstructResultMapperExt.selectExistingArticleIds(eq("aigc_deconstruct"), any()))
-                .thenReturn(Collections.singletonList(ARTICLE_ID));
-
-        ReturnT<String> result = articleVectorJob.syncArticleDeconstructJob(null);
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(aigcApiService, never()).getTaskCallbackDetail(anyInt());
-        verify(articleDeconstructResultMapperExt, never()).batchInsertIgnore(any());
-    }
-
-    // ==============================
-    // vectorArticleJob
-    // ==============================
-
-    @Test
-    void vectorArticleJob_returnsSuccessWhenNoConfig() {
-        when(vectorConfigMapper.selectByExample(any())).thenReturn(Collections.emptyList());
-
-        ReturnT<String> result = articleVectorJob.vectorArticleJob("5");
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(articleDeconstructResultMapperExt, never()).selectArticleIdsBySourcePaged(anyString(), anyInt(), anyInt());
-    }
-
-    @Test
-    void vectorArticleJob_embedsAndStoresArticleVector() {
-        DeconstructVectorConfig config = buildTopicConfig();
-        when(vectorConfigMapper.selectByExample(any())).thenReturn(Collections.singletonList(config));
-        when(articleDeconstructResultMapperExt.selectArticleIdsBySourcePaged(eq("aigc_deconstruct"), eq(0), anyInt()))
-                .thenReturn(Collections.singletonList(ARTICLE_ID));
-        when(articleVectorStoreService.existsByIds(eq("VIDEO_TOPIC"), anyCollection()))
-                .thenReturn(Collections.emptySet());
-
-        ArticleDeconstructResult deconstructResult = new ArticleDeconstructResult();
-        deconstructResult.setArticleId(ARTICLE_ID);
-        JSONObject dataContent = new JSONObject();
-        dataContent.put("topic", "AI技术发展趋势");
-        dataContent.put("title", "AI技术发展趋势深度分析");
-        deconstructResult.setResult(dataContent.toJSONString());
-        when(articleDeconstructResultMapperExt.selectResultsByArticleIds(eq("aigc_deconstruct"), any()))
-                .thenReturn(Collections.singletonList(deconstructResult));
-
-        List<Float> vector = Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f);
-        when(articleVectorStoreService.getVectorByTextHash(anyString(), eq("VIDEO_TOPIC"))).thenReturn(null);
-        when(embeddingService.embed(anyString(), eq(config))).thenReturn(vector);
-
-        ReturnT<String> result = articleVectorJob.vectorArticleJob("1");
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(articleVectorStoreService).save(
-                eq("VIDEO_TOPIC"),
-                eq(ARTICLE_ID),
-                eq(vector),
-                eq("AI技术发展趋势")
-        );
-    }
-
-    @Test
-    void vectorArticleJob_skipsWhenArticleAlreadyVectorized() {
-        DeconstructVectorConfig config = buildTopicConfig();
-        when(vectorConfigMapper.selectByExample(any())).thenReturn(Collections.singletonList(config));
-        when(articleDeconstructResultMapperExt.selectArticleIdsBySourcePaged(eq("aigc_deconstruct"), eq(0), anyInt()))
-                .thenReturn(Collections.singletonList(ARTICLE_ID));
-        when(articleVectorStoreService.existsByIds(eq("VIDEO_TOPIC"), anyCollection()))
-                .thenReturn(Collections.singleton(ARTICLE_ID));
-
-        ReturnT<String> result = articleVectorJob.vectorArticleJob("1");
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(articleDeconstructResultMapperExt, never()).selectResultsByArticleIds(anyString(), any());
-        verify(embeddingService, never()).embed(anyString(), any());
-    }
-
-    // ==============================
-    // articleJob 编排
-    // ==============================
-
-    @Test
-    void articleJob_runsSyncThenVectorize() {
-        when(aigcApiService.getTaskInputList(TASK_ID)).thenReturn(Collections.emptyList());
-        when(vectorConfigMapper.selectByExample(any())).thenReturn(Collections.emptyList());
-
-        ReturnT<String> result = articleVectorJob.articleJob("3");
-
-        assertEquals(ReturnT.SUCCESS_CODE, result.getCode());
-        verify(vectorConfigMapper, times(1)).selectByExample(any());
-    }
-
-    private DeconstructVectorConfig buildTopicConfig() {
-        DeconstructVectorConfig config = new DeconstructVectorConfig();
-        config.setConfigCode("VIDEO_TOPIC");
-        config.setSourceField("aigc_deconstruct");
-        config.setSourcePath("$.topic");
-        config.setEnabled((short) 1);
-        config.setPriority(1);
-        return config;
-    }
-}