86 lines
3.4 KiB
Java
86 lines
3.4 KiB
Java
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.springframework.boot.ApplicationRunner;
|
|
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;
|
|
import tech.easyflow.manuagent.mapper.AgentRunMapper;
|
|
|
|
/**
|
|
* 验证模型管理接口使用最小字段投影,不把加密 API Key 读入普通请求内存。
|
|
*/
|
|
class ModelServiceQueryTest {
|
|
|
|
/**
|
|
* 模型必须完全由管理接口和数据库维护,服务启动不得再通过 Key 文件自动灌入默认模型。
|
|
*/
|
|
@Test
|
|
void shouldNotInitializeModelConfigurationFromApplicationFiles() {
|
|
assertThat(ApplicationRunner.class.isAssignableFrom(ModelService.class)).isFalse();
|
|
}
|
|
|
|
/**
|
|
* 模型列表只需要页面展示字段,查询 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(AgentRunMapper.class),
|
|
mock(UserService.class),
|
|
mock(KeyCipher.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;
|
|
}
|
|
}
|