重构:使用 MyBatis-Flex 迁移应用 ORM
将应用自管表的 JdbcClient 数据访问迁移为实体、Mapper、构造器查询和必要的显式 SQL。 保留 AgentScope 自管表及原有业务语义,并补充事务、查询与数据库集成测试。
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package tech.easyflow.manuagent.model;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import tech.easyflow.manuagent.auth.UserService;
|
||||
import tech.easyflow.manuagent.config.AppProperties;
|
||||
import tech.easyflow.manuagent.entity.ModelConfigEntity;
|
||||
import tech.easyflow.manuagent.mapper.AppUserMapper;
|
||||
import tech.easyflow.manuagent.mapper.ModelAssignmentMapper;
|
||||
import tech.easyflow.manuagent.mapper.ModelConfigMapper;
|
||||
|
||||
/**
|
||||
* 验证模型管理接口使用最小字段投影,不把加密 API Key 读入普通请求内存。
|
||||
*/
|
||||
class ModelServiceQueryTest {
|
||||
|
||||
/**
|
||||
* 模型列表只需要页面展示字段,查询 SQL 不得包含密文和密钥版本列。
|
||||
*/
|
||||
@Test
|
||||
void shouldExcludeEncryptedKeyFromModelListQuery() {
|
||||
ModelConfigMapper modelMapper = mock(ModelConfigMapper.class);
|
||||
when(modelMapper.selectListByQuery(any(QueryWrapper.class)))
|
||||
.thenReturn(List.of(modelViewEntity()));
|
||||
ModelService service = new ModelService(
|
||||
modelMapper,
|
||||
mock(ModelAssignmentMapper.class),
|
||||
mock(AppUserMapper.class),
|
||||
mock(UserService.class),
|
||||
mock(KeyCipher.class),
|
||||
mock(AppProperties.class),
|
||||
new ObjectMapper());
|
||||
|
||||
List<ModelService.ModelView> models = service.list();
|
||||
|
||||
ArgumentCaptor<QueryWrapper> queryCaptor = ArgumentCaptor.forClass(QueryWrapper.class);
|
||||
verify(modelMapper).selectListByQuery(queryCaptor.capture());
|
||||
String sql = queryCaptor.getValue().toSQL().toLowerCase(java.util.Locale.ROOT);
|
||||
assertThat(models).hasSize(1);
|
||||
assertThat(sql)
|
||||
.contains("api_key_hint", "capabilities_json", "is_default")
|
||||
.doesNotContain("api_key_ciphertext", "key_version");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造包含全部展示字段的实体,避免测试依赖数据库或模型密钥解密逻辑。
|
||||
*
|
||||
* @return 模拟数据库返回的安全投影实体
|
||||
*/
|
||||
private ModelConfigEntity modelViewEntity() {
|
||||
ModelConfigEntity entity = new ModelConfigEntity();
|
||||
entity.setId(UUID.randomUUID());
|
||||
entity.setName("测试模型");
|
||||
entity.setProvider("OPENAI_COMPATIBLE");
|
||||
entity.setBaseUrl("https://example.test");
|
||||
entity.setModelId("model");
|
||||
entity.setApiKeyHint("••••1234");
|
||||
entity.setConfigJson("{}");
|
||||
entity.setCapabilitiesJson("{\"contextWindow\":8192}");
|
||||
entity.setEnabled(true);
|
||||
entity.setDefaultModel(true);
|
||||
entity.setUpdatedAt(OffsetDateTime.now());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user