feat: 完善智能体图片聊天与会话恢复
- 增加私有图片上传、绑定、历史回显与生命周期清理 - 支持输入草稿恢复、图片交互和模型图片能力约束 - 修复旧脏会话幂等删除与前端会话恢复
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package tech.easyflow.admin.service.agent;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import tech.easyflow.agent.runtime.AgentRuntimeStateCleanupService;
|
||||
import tech.easyflow.agent.runtime.composer.AgentComposerDraftService;
|
||||
import tech.easyflow.agent.runtime.media.AgentMediaService;
|
||||
import tech.easyflow.agent.service.AgentService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
|
||||
import tech.easyflow.chatlog.service.ChatSessionCommandService;
|
||||
import tech.easyflow.chatlog.service.ChatSessionQueryService;
|
||||
import tech.easyflow.chatlog.support.ChatJsonSupport;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link AgentSessionService} 会话删除测试。
|
||||
*/
|
||||
public class AgentSessionServiceTest {
|
||||
|
||||
private static final BigInteger ACCOUNT_ID = BigInteger.valueOf(7);
|
||||
private static final BigInteger SESSION_ID = BigInteger.valueOf(101);
|
||||
|
||||
private ChatSessionQueryService chatSessionQueryService;
|
||||
private ChatSessionCommandService chatSessionCommandService;
|
||||
private AgentRuntimeStateCleanupService agentRuntimeStateCleanupService;
|
||||
private AgentMediaService agentMediaService;
|
||||
private AgentComposerDraftService agentComposerDraftService;
|
||||
private AgentSessionService service;
|
||||
private LoginAccount account;
|
||||
|
||||
/**
|
||||
* 初始化测试依赖。
|
||||
*/
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
chatSessionQueryService = mock(ChatSessionQueryService.class);
|
||||
chatSessionCommandService = mock(ChatSessionCommandService.class);
|
||||
agentRuntimeStateCleanupService = mock(AgentRuntimeStateCleanupService.class);
|
||||
agentMediaService = mock(AgentMediaService.class);
|
||||
agentComposerDraftService = mock(AgentComposerDraftService.class);
|
||||
service = new AgentSessionService(
|
||||
chatSessionQueryService,
|
||||
chatSessionCommandService,
|
||||
mock(AgentService.class),
|
||||
mock(DocumentCollectionService.class),
|
||||
mock(ResourceAccessService.class),
|
||||
agentRuntimeStateCleanupService,
|
||||
agentMediaService,
|
||||
agentComposerDraftService,
|
||||
mock(ChatJsonSupport.class)
|
||||
);
|
||||
account = new LoginAccount();
|
||||
account.setId(ACCOUNT_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证正常删除会清理运行态、写入删除命令并删除媒体目录。
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeleteActiveOwnedAgentSession() {
|
||||
when(chatSessionQueryService.getSessionSummary(SESSION_ID))
|
||||
.thenReturn(buildSession(ACCOUNT_ID, 0, "AGENT"));
|
||||
|
||||
service.deleteCurrentUserSession(account, SESSION_ID);
|
||||
|
||||
verify(agentRuntimeStateCleanupService).clearChatSession(SESSION_ID, ACCOUNT_ID);
|
||||
verify(chatSessionCommandService).deleteSession(SESSION_ID, ACCOUNT_ID, ACCOUNT_ID);
|
||||
verify(agentComposerDraftService).delete(AgentMediaService.MODE_FORMAL, "9", "101", account);
|
||||
verify(agentMediaService).deleteFormalSession(SESSION_ID.toString(), account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证会话已删除时重复请求仍会重试媒体目录清理并成功返回。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRetryMediaCleanupForDeletedSession() {
|
||||
when(chatSessionQueryService.getSessionSummary(SESSION_ID))
|
||||
.thenReturn(buildSession(ACCOUNT_ID, 1, "AGENT"));
|
||||
|
||||
service.deleteCurrentUserSession(account, SESSION_ID);
|
||||
|
||||
verify(agentRuntimeStateCleanupService, never()).clearChatSession(Mockito.any(), Mockito.any());
|
||||
verify(chatSessionCommandService, never()).deleteSession(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
verify(agentComposerDraftService).delete(AgentMediaService.MODE_FORMAL, "9", "101", account);
|
||||
verify(agentMediaService).deleteFormalSession(SESSION_ID.toString(), account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证查询不到会话时删除保持幂等,并按当前用户目录重试媒体清理。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRetryMediaCleanupWhenSessionIsMissing() {
|
||||
when(chatSessionQueryService.getSessionSummary(SESSION_ID)).thenReturn(null);
|
||||
|
||||
service.deleteCurrentUserSession(account, SESSION_ID);
|
||||
|
||||
verify(agentRuntimeStateCleanupService, never()).clearChatSession(Mockito.any(), Mockito.any());
|
||||
verify(chatSessionCommandService, never()).deleteSession(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
verify(agentComposerDraftService, never()).delete(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||
verify(agentMediaService).deleteFormalSession(SESSION_ID.toString(), account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证活动会话属于其他用户时仍拒绝删除,且不执行任何清理。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectActiveSessionOwnedByAnotherUser() {
|
||||
when(chatSessionQueryService.getSessionSummary(SESSION_ID))
|
||||
.thenReturn(buildSession(BigInteger.valueOf(8), 0, "AGENT"));
|
||||
|
||||
BusinessException exception = Assert.expectThrows(
|
||||
BusinessException.class,
|
||||
() -> service.deleteCurrentUserSession(account, SESSION_ID)
|
||||
);
|
||||
|
||||
Assert.assertEquals(exception.getMessage(), "无权访问该 Agent 会话");
|
||||
verify(agentRuntimeStateCleanupService, never()).clearChatSession(Mockito.any(), Mockito.any());
|
||||
verify(chatSessionCommandService, never()).deleteSession(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
verify(agentComposerDraftService, never()).delete(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||
verify(agentMediaService, never()).deleteFormalSession(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造会话摘要。
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param isDeleted 删除标记
|
||||
* @param assistantCode 助手类型
|
||||
* @return 会话摘要
|
||||
*/
|
||||
private ChatSessionSummary buildSession(BigInteger userId, Integer isDeleted, String assistantCode) {
|
||||
ChatSessionSummary summary = new ChatSessionSummary();
|
||||
summary.setId(SESSION_ID);
|
||||
summary.setUserId(userId);
|
||||
summary.setIsDeleted(isDeleted);
|
||||
summary.setAssistantCode(assistantCode);
|
||||
summary.setAssistantId(BigInteger.valueOf(9));
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user