测试用例生成以及AFL逻辑修改

This commit is contained in:
even 2025-07-23 16:31:36 +08:00
parent 87b96c6ddd
commit 9c9ddfdfb0
5 changed files with 182 additions and 29 deletions

View File

@ -129,10 +129,10 @@ public class AFLSlotCompileWorker extends DockerWorker {
"cd "+prefix+"\n";
return cmd;
}
if ("gz".equals(suffix)) {
if (fileName.contains(".tar")||fileName.contains(".tar.gz")) {
String cmd ="tar -zxvf "+fileName+"\n" +
"chmod -R o+rwx "+prefix+"/\n"+
"cd "+prefix+"\n";
"cd "+fileName.replace(".tar.gz","").replace(".tar","")+"\n";
return cmd;
}
return "";

View File

@ -115,9 +115,12 @@ public class AFLWorker extends DockerWorker {
}
}
private String cdSourceName(String fileName){
int dotIndex = fileName.lastIndexOf(".");
if (dotIndex!=-1) {
return "cd "+fileName.substring(0, dotIndex)+"\n";
if (fileName.contains(".zip")||fileName.contains(".tar")||fileName.contains(".tar.gz")) {
String cdPath = fileName
.replace(".zip","")
.replace(".tar.gz","")
.replace(".tar","");
return "cd "+cdPath+"\n";
}
return "";
}

View File

@ -2,7 +2,7 @@ package cd.casic.ci.process.engine.worker.afl;
import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.resource.ResourceQueryReq;
import cd.casic.ci.process.dto.req.testCase.TestCaseAITaskCreateReq;
import cd.casic.ci.process.dto.resp.resource.ResourceDetailResp;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.DockerWorker;
@ -11,20 +11,24 @@ import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.dataObject.testCase.TestCaseInfo;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.ci.process.process.service.testCase.TestCaseAIGeneratorService;
import cd.casic.ci.process.process.service.testCase.TestCaseInfoService;
import cd.casic.ci.process.util.SftpUploadUtil;
import cd.casic.module.execute.docker.dataobject.dto.DockerEndpointDo;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.utils.CryptogramUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jcraft.jsch.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import static cd.casic.ci.process.engine.constant.PipelineVariableConstant.*;
import static cd.casic.ci.process.engine.constant.TestCaseGenerationConstant.*;
@ -36,6 +40,8 @@ public class TestCaseGenerationWorker extends DockerWorker {
private TestCaseInfoService testCaseInfoService;
@Resource
private TargetVersionService targetVersionService;
@Resource
private TestCaseAIGeneratorService aiGeneratorService;
@Override
public void execute(TaskRunContext context) {
int statusCode = -1;
@ -45,7 +51,6 @@ public class TestCaseGenerationWorker extends DockerWorker {
String seedPath= workDir+File.separator+ AFL_DOCKER_SEED;
Map<String, Object> taskProperties = taskDef.getTaskProperties();
Object caseType = taskProperties.get(CASE_TYPE_KEY);
String binaryName = taskProperties.get(BINARY_NAME) instanceof String ? ((String) taskProperties.get("binaryName")) : null;
String managerId = getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY)) : null;
Object itemListObject = taskProperties.get(ITEM_LIST);
List<String> itemList = JSON.parseArray(JSON.toJSONString(itemListObject),String.class);
@ -55,23 +60,21 @@ public class TestCaseGenerationWorker extends DockerWorker {
if (Objects.isNull(machineInfo)||Objects.isNull(dockerInfo)) {
append(context,"该资源不支持docker或者ssh");
}
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
String fileName = targetVersion.getFileName();
String imageName = getVariableNearby(context,IMAGE_NAME) instanceof String ? ((String) getVariableNearby(context,IMAGE_NAME)) : null;
//如果machineId为0则说明该节点没有配置机器则使用开始节点的机器
if (CASE_TYPE_AI.equals(caseType)) {
// 容器内部test 目录, 获取编译后的文件
String runScript = "docker run -v "+ AFL_VOLUME_WORK_DIR_PREFIX +":"+ AFL_DOCKER_BASE_DIR+" -it "+imageName+" bash\n" // 目前测试用例ai生成只有这个路径能跑
+ "cd "+ AFL_DOCKER_BASE_DIR+"\n" +
"mkdir -p "+seedPath +"\n"+
"cd "+seedPath +"\n"+
"PYTHONPATH="+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src python3 "+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src/CaseGenerator/main.py --work-dir "+workDir+" --binary "+workDir+File.separator+getSourceName(fileName)+File.separator+binaryName+" --output-dir "+seedPath+" --count 100";
//将节点的配置信息反编译成对象
log.info("测试用例生成-AI生成实际执行命令:{}" , runScript);
append(context,"测试用例生成-AI生成实际执行命令:"+runScript);
//获取机器
dockerRun(runScript,dockerInfo,context);
// // 容器内部test 目录, 获取编译后的文件
// String runScript = "docker run -v "+ AFL_VOLUME_WORK_DIR_PREFIX +":"+ AFL_DOCKER_BASE_DIR+" -it "+imageName+" bash\n" // 目前测试用例ai生成只有这个路径能跑
// + "cd "+ AFL_DOCKER_BASE_DIR+"\n" +
// "mkdir -p "+seedPath +"\n"+
// "cd "+seedPath +"\n"+
// "PYTHONPATH="+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src python3 "+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src/CaseGenerator/main.py --work-dir "+workDir+" --binary "+workDir+File.separator+getSourceName(fileName)+File.separator+binaryName+" --output-dir "+seedPath+" --count 100";
// //将节点的配置信息反编译成对象
// log.info("测试用例生成-AI生成实际执行命令:{}" , runScript);
// append(context,"测试用例生成-AI生成实际执行命令:"+runScript);
// //获取机器
// dockerRun(runScript,dockerInfo,context);
handleAIGenerator(context);
} else if (CASE_TYPE_FILE.equals(caseType)){
// 文件上传
Object filePathObj = taskProperties.get(SEED_SOURCE);
@ -121,10 +124,89 @@ public class TestCaseGenerationWorker extends DockerWorker {
globalVariables.put(AFL_DOCKER_SEED_PATH_KEY,seedPath);
}
}
public String getSourceName(String fileName){
int dotIndex = fileName.lastIndexOf(".");
if (dotIndex!=-1) {
return fileName.substring(0, dotIndex);
public void handleAIGenerator(TaskRunContext context){
PipTask taskDef = context.getContextDef() instanceof PipTask ? ((PipTask) context.getContextDef()) : null;
Map<String, Object> taskProperties = taskDef.getTaskProperties();
String binaryName = taskProperties.get(BINARY_NAME) instanceof String ? ((String) taskProperties.get("binaryName")) : null;
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
String managerId = getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY)) : null;
ResourceDetailResp resourceById = resourceManagerService.findResourceDetailById(managerId);
MachineInfoDO machineInfo = resourceById.getMachineInfo();
DockerEndpointDo dockerInfo = resourceById.getDockerInfo();
String fileName = targetVersion.getFileName();
if (Objects.isNull(machineInfo)||Objects.isNull(dockerInfo)) {
append(context,"该资源不支持docker或者ssh");
}
// TODO 需要新增的项
String prompt = "你是一个模糊测试专家,当前程序输入为文本例如 aa aaa 这种";
Integer count = 10;
// 获取编译后的文文件的inputStream
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession(machineInfo.getUsername(),machineInfo.getHostIp(), machineInfo.getSshPort());
session.setPassword( CryptogramUtil.doDecrypt(machineInfo.getPassword()));
// 跳过 host key 检查
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
sftp.connect();
String workDir = (String)getGlobalVariable(context,AFL_DOCKER_WORK_DIR_KEY);
String filePath = AFL_DOCKER_BASE_DIR + File.separator + workDir+File.separator+getSourceName(fileName)+File.separator+binaryName;
InputStream inputStream = sftp.get(filePath);
String targetUploadRes = aiGeneratorService.targetUpload("./" + binaryName, inputStream);
String binaryId = JSON.parseObject(targetUploadRes).getString("id");
// 创建task
TestCaseAITaskCreateReq req = new TestCaseAITaskCreateReq();
req.setBinaryId(binaryId);
req.setCustomPrompt(prompt);
req.setCount(count);
String taskCreateRes = aiGeneratorService.taskCreate(req);
String taskId = JSON.parseObject(taskCreateRes).getString("task_id");
while (true){
// 获取状态及日志
String taskStatusRes = aiGeneratorService.getTaskStatus(taskId);
String status = JSONObject.parseObject(taskStatusRes).getString("status");
if ("success".equals(status)) {
break;
} else if("failed".equals(status)){
toBadEnding();
} else {
String logRes = aiGeneratorService.getTaskLog(taskId);
String logStr = JSON.parseObject(logRes).getString("log");
append(context,logStr);
}
}
File tempFile = File.createTempFile("seed", ".zip");
tempFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempFile);
// 下载生成的种子
aiGeneratorService.downloadTestCase(taskId,fos);
fos.close();
FileInputStream fis = new FileInputStream(tempFile);
// 上传种子zip到目标服务器
sftp.put(fis,"");
sftp.disconnect();
String seedPath= workDir+File.separator+ AFL_DOCKER_SEED;
String seedTarget = AFL_VOLUME_WORK_DIR_PREFIX+File.separator+seedPath+File.separator+"seed.zip";
String seedDir = AFL_VOLUME_WORK_DIR_PREFIX+File.separator+seedPath;
// 解压种子zip
ChannelExec exec = (ChannelExec)session.openChannel("exec");
exec.setCommand("unzip -o "+seedTarget+" -d "+seedDir);
} catch (Exception e) {
append(context,"测试用例生成失败");
}
}
private String getSourceName(String fileName){
if (fileName.contains(".zip")||fileName.contains(".tar")||fileName.contains(".tar.gz")) {
return fileName
.replace(".zip","")
.replace(".tar.gz","")
.replace(".tar","");
}
return "";
}

View File

@ -43,6 +43,7 @@ public class TestCaseAIGeneratorServiceImpl implements TestCaseAIGeneratorServic
zos.putNextEntry(entry);
IOUtils.copy(inputStream,zos);
zos.closeEntry();
zos.close();
inputStream.close();
FileSystemResource fsr = new FileSystemResource(tempFile);
String url = properties.getBaseUrl()+ TestCaseAIGeneratorConstant.targetUpload;
@ -100,7 +101,8 @@ public class TestCaseAIGeneratorServiceImpl implements TestCaseAIGeneratorServic
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>("{}",headers);
String url = properties.getBaseUrl() + TestCaseAIGeneratorConstant.downloadTestCase+taskId;
ResponseEntity<InputStream> exchange = restTemplate.exchange(url, HttpMethod.GET, entity, InputStream.class, new HashMap<>());
IOUtils.copy(exchange.getBody(),outputStream);
ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.GET, entity, byte[].class, new HashMap<>());
outputStream.write(exchange.getBody());
}
}

View File

@ -0,0 +1,66 @@
package cd.casic.server;
import cd.casic.ci.process.constant.TestCaseAIGeneratorConstant;
import cd.casic.ci.process.dto.req.testCase.TestCaseAITaskCreateReq;
import cd.casic.ci.process.process.service.testCase.TestCaseAIGeneratorService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.web.WebAppConfiguration;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
@Slf4j
@WebAppConfiguration
public class TestCaseAIGeneratorTest {
@Resource
private TestCaseAIGeneratorService service;
@Test
public void targetUpload() throws IOException {
//{"success":true,"msg":"","id":"8711fd176b686eebcc4e3f49bdde1a18"}
ClassPathResource classPathResource = new ClassPathResource("static/pcre2test");
String s = service.targetUpload("./pcre2test", classPathResource.getInputStream());
System.out.println(s);
}
@Test
public void taskCreate(){
// {"success":true,"msg":"","task_id":"7c5d7df0-68d5-4935-aae7-00287976ae44"}
// {"success":true,"msg":"","task_id":"a70f92e9-9b8c-4be3-974f-8b0efa253237"}
TestCaseAITaskCreateReq req = new TestCaseAITaskCreateReq();
req.setBinaryId("8711fd176b686eebcc4e3f49bdde1a18");
req.setCustomPrompt("你是一个模糊测试专家,当前程序输入为文本例如 aa aaa 这种");
req.setCount(10);
String s = service.taskCreate(req);
System.out.println(s);
}
@Test
public void getTaskStatus(){
// {"success":true,"msg":"","task_id":"7c5d7df0-68d5-4935-aae7-00287976ae44","status":"success"}
String taskStatus = service.getTaskStatus("1e6e9694-5ae2-425e-ad80-9af266d33bea");
System.out.println(taskStatus);
}
@Test
public void getTaskLog(){
// {"success":true,"msg":"","log":"智能体初始化中...\n"}
String taskLog = service.getTaskLog("1e6e9694-5ae2-425e-ad80-9af266d33bea");
System.out.println(taskLog);
}
@Test
public void downloadSeed() throws IOException {
File tempFile = File.createTempFile("seed", ".zip");
FileOutputStream fos = new FileOutputStream(tempFile);
service.downloadTestCase("1e6e9694-5ae2-425e-ad80-9af266d33bea",fos);
tempFile.deleteOnExit();
fos.close();
System.out.println();
}
}