content: package com.alibaba.markovdemo.engine.AI.GACaseGenerator;
  
  import com.alibaba.fastjson.JSONArray;
  import com.alibaba.fastjson.JSONObject;
  import com.alibaba.markovdemo.BO.MultiAIInfo;
  import com.alibaba.markovdemo.BO.TestCaseInput;
  import com.alibaba.markovdemo.engine.MultiAIPlusController;
  import com.alibaba.markovdemo.engine.SingleController;
  import com.alibaba.markovdemo.engine.stages.ResultStatus;
  import com.alibaba.markovdemo.entity.GotCaseAccuracy;
  import com.alibaba.markovdemo.entity.GotCaseGenerateTask;
  import com.alibaba.markovdemo.entity.GotReports;
  import com.alibaba.markovdemo.entity.GotTestCase;
  import com.alibaba.markovdemo.service.CaseAccuracyService;
  import com.alibaba.markovdemo.service.CaseGenerateTaskService;
  import com.alibaba.markovdemo.service.GotReportsService;
  import com.alibaba.markovdemo.service.TestcaseService;
  import org.apache.commons.lang.SerializationUtils;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Component;
  
  import java.util.*;
  
  @Component
  public class GenerateProcessor {
      @Autowired
      TestcaseService testcaseService;
      @Autowired
      GAOperator operator;
      @Autowired
      CaseAccuracyService caseAccuracyService;
      @Autowired
      MultiAIPlusController multiAIController;
      @Autowired
      GotReportsService gotReportsService;
      @Autowired
      CaseGenerateTaskService caseGenerateTaskService;
      private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SingleController.class);
  
  
      public Long startTask(TestCaseInput seedCase, Long scenarioId, HashMap envInfo, String featureConf){
          try{
              //创建生成任务
              GotCaseGenerateTask aiTask = new GotCaseGenerateTask();
  
              JSONObject conf = JSONObject.parseObject(featureConf);
              JSONObject fields = conf.getJSONObject("field_setting");
              JSONArray ignore = conf.getJSONArray("neg_tesla_key");
              //构建基因库
              Map<String, List<Object>> geneBankMap = buildGeneBank(scenarioId, featureConf, fields, ignore);
  
              aiTask.setTaskStatus("created");
              aiTask.setSeedCaseList(seedCase.getId().toString());
              aiTask.setFeatureConf(featureConf);
              aiTask.setEnvInfo(envInfo.toString());
              aiTask.setGeneBankSnap(geneBankMap.toString());
              aiTask.setScenarioId(scenarioId);
              caseGenerateTaskService.save(aiTask);
  
  
              //启动新线程，开始执行任务
              GenetateTaskThread thread = new GenetateTaskThread(aiTask, geneBankMap, seedCase, ignore, (String)envInfo.get("name") );
              thread.start();
  
              //返回任务添加状态
              return aiTask.getId();
          }catch(Exception e){
              //
              e.printStackTrace();
              return -1L;
          }
      }
  
      public Map<String, Object> extractFeatures(TestCaseInput testcase, JSONArray ignoreConf){
          //从用例数据中抽取特征，需由业务定义 by 用户
          Map<String,Object> featureMap = new HashMap<>();
          JSONObject query = getCaseQuery(testcase);
  
          try{
              for(Object key : query.keySet()){
                  if( !isIgnore(key, ignoreConf) ){
                      featureMap.put(key.toString(), query.get(key));
                  }
              }
          }catch(Exception e){
              //
          }
          return featureMap;
      }
  
      public ArrayList<String> buildChromo(Map<String,Object> featureMap){
          ArrayList<String> res = new ArrayList<>();
          for(String key: featureMap.keySet()){
              res.add(key);
          }
          return res;
      }
  
  
      public void handleFeatureConf(){
      }
  
      public boolean isIgnore(Object key, JSONArray ignoreFields){
          //是否配置为需要忽略的特征
          //需要从task的配置字段中判断
          //todo
          if(ignoreFields.contains(key)){
              return true;
          }
          return false;
      }
  
  
  
      public boolean needTerminate(){
          return false;
      }
  
  
      public JSONObject getCaseQuery(TestCaseInput testcase){
          String query = testcase.getCaseRunStage().get(0).getData().get(0).input;
          JSONObject queryObject = JSONObject.parseObject(query);
          return queryObject;
  
      }
  
      /**
       * 构建基因库，demo中基于同场景的已有用例进行构建
       * @param scenarioId
       * @return
       */
      public Map<String, List<Object>> buildGeneBank(Long scenarioId, String featureConf ,JSONObject fields, JSONArray ignore){
  
          List<TestCaseInput> casesList = testcaseService.getAllCaseByScenarioId(scenarioId);
          Map<String, List<Object>> geneBankMap = new HashMap<>();
  
  
          for(TestCaseInput singleCase : casesList){
              Map<String, Object> featureMap = extractFeatures(singleCase,ignore);
              for(String featureKey : featureMap.keySet()){
                  if(geneBankMap.keySet().contains(featureKey)){
                      List<Object> valueList = geneBankMap.get(featureKey);
                      Object value = featureMap.get(featureKey);
                      if(!valueList.contains(value)) {
                          geneBankMap.get(featureKey).add(featureMap.get(featureKey));
                      }
                  }else{
                      List<Object> valueList = new ArrayList<>();
                      valueList.add(featureMap.get(featureKey));
  
                      geneBankMap.put(featureKey, valueList);
                  }
              }
          }
  
          try {
              for (String key : fields.keySet()){
                  if(geneBankMap.keySet().contains(key)){
                      List<Object> valueList = geneBankMap.get(key);
                      for(Object value : fields.getJSONArray(key)){
                          if(!valueList.contains(value)){
                              valueList.add(value);
                          }
                      }
  
                  }else{
                      List<Object> valueList = new ArrayList<>();
                      for(Object value : fields.getJSONArray(key)){
                          if(!valueList.contains(value)){
                              valueList.add(value);
                          }
                      }
                      geneBankMap.put(key, valueList);
                  }
              }
          }catch(Exception e){
  
          }
  
          return geneBankMap;
  
      }
  
  
  
  
      public class GenetateTaskThread extends Thread{
          GotCaseGenerateTask aiTask;
          Map<String, List<Object>> geneBankMap;
          Map<String, List<Object>> extralGeneMap = new HashMap<>();
          TestCaseInput seedCase;
          List<String> chromoSeq;
          List<Long> newCaseIdList = new ArrayList<>();
          List<Long> allCaseList = new ArrayList<>();
          Map<String, Integer> historyCov = new HashMap<>();
          List<String> diffLineList = new ArrayList<>();
          JSONArray ignoreConf;
          List<GotTestCase> relatedSeedCase = new ArrayList<>();
          String env;
  
  
  
          public GenetateTaskThread(GotCaseGenerateTask task, Map<String, List<Object>> geneMap, TestCaseInput seed, JSONArray ignore, String env){
              aiTask = task;
              geneBankMap = geneMap;
              seedCase = seed;
              ignoreConf = ignore;
              env = env;
          }
  
          @Override
          public void run(){
              String covReport = "";
              int covRate = 0;
              try {
                  aiTask.setTaskStatus("executing");
                  caseGenerateTaskService.update(aiTask);
  
  
                  Map<String, Object> featureMap = extractFeatures(seedCase, ignoreConf);
                  this.chromoSeq = buildChromo(featureMap);
  
                  List<Long> originCases = searchRelateCase(seedCase);
                  for(Long caseId : originCases){
                      relatedSeedCase.add(testcaseService.findById(caseId));
                  }
  
                  //运行种子及相关用例, todo
                  diffLineList = CovMock.getDiffLines();
                  runCasePopulation(relatedSeedCase, env);
                  for (GotTestCase newCase : relatedSeedCase) {
                      Long caseId = newCase.getId();
  
                      GotCaseAccuracy accuracyObj = caseAccuracyService.getLastedByCaseId(caseId);
                      String[] caseCov = accuracyObj.getCovLine().split("\n");
  
                      for (String covLine : caseCov) {
                          if (historyCov.keySet().contains(covLine.trim())) {
                              historyCov.put(covLine, historyCov.get(covLine) + 1);
                          } else {
                              historyCov.put(covLine, 1);
                          }
                      }
                  }
  
                  covRate = calCovRate();
                  covReport += ("种子及相关用例代码覆盖率:" +covRate +"%\n");
                  covReport += ("当前共生成用例"+allCaseList.size()+"个\n");
                  covReport += ("有效用例"+newCaseIdList.size()+"个\n");
  
  
                  //step1：构建初始化种群
                  List<Object[]> initPopulationChromo = buildInitPopulation(seedCase.getId());
  
                  //step2：转化为初始种群测试用例，运行获取覆盖
                  List<GotTestCase> initPopulationCase = new ArrayList<>();
                  for (Object[] chromo : initPopulationChromo) {
                      initPopulationCase.add(decodeCase(chromo));
                  }
  
  
                  int lastPopulationValidNum = 1;
                  List<GotTestCase> nextPopulationCase = initPopulationCase;
                  List<Object[]> nextPopulation = initPopulationChromo;
  
                  int invalidLoopCount = 0;
                  int loopCount = 1;
  
  
  
  
                  while (true) {
  
                      int validCaseNum = 0;
  
                      //todo 运行nextPopulationCase
                      runCasePopulation(nextPopulationCase, env);
  
                      //step3：计算初始种群用例适应度
  
                      List<Double> fitnessList = new ArrayList<>();
                      for (GotTestCase newCase : nextPopulationCase) {
                          allCaseList.add(newCase.getId());
                          Long caseId = newCase.getId();
  
                          GotCaseAccuracy accuracyObj = caseAccuracyService.getLastedByCaseId(caseId);
                          String[] caseCov = accuracyObj.getCovLine().split("\n");
  
                          for (String covLine : caseCov) {
                              if (historyCov.keySet().contains(covLine.trim())) {
                                  historyCov.put(covLine, historyCov.get(covLine) + 1);
                              } else {
                                  historyCov.put(covLine, 1);
                                  if (!newCaseIdList.contains(caseId)) {
                                      newCaseIdList.add(caseId);
                                      validCaseNum += 1;
                                  }
                              }
                          }
                      }
  
                      for(GotTestCase newCase : nextPopulationCase){
                          Long caseId = newCase.getId();
                          GotCaseAccuracy accuracyObj = caseAccuracyService.getLastedByCaseId(caseId);
                          String[] caseCov = accuracyObj.getCovLine().split("\n");
  
                          Double fitness = operator.fiteness(caseCov, historyCov);
                          fitnessList.add(fitness);
                      }
  
                      //step4：计算代码覆盖率
                      covReport += ("当前循环第"+loopCount+"次" + "\n");
                      loopCount++;
                      covRate = calCovRate();
                      covReport += ("代码覆盖率:" + covRate +"%\n");
                      covReport += ("当前共生成用例"+allCaseList.size()+"个\n");
                      covReport += ("有效用例"+newCaseIdList.size()+"个\n");
  
                      if (validCaseNum == 0) {
                          //break loop
                          if(invalidLoopCount >= 5) {
                              break;
                          }else{
                              invalidLoopCount++;
                          }
                      }else {
                          invalidLoopCount = 0;
                      }
  
                      lastPopulationValidNum = validCaseNum;
  
                      //step5：选择
                      nextPopulation = operator.selection(nextPopulation, fitnessList);
  
                      //step6：杂交
                      nextPopulation = operator.crossover(nextPopulation);
                      nextPopulation = operator.mutation(nextPopulation, geneBankMap, chromoSeq);
  
                      //step7：生成新一代种群用例
                      nextPopulationCase = new ArrayList<>();
                      for (Object[] chromo : nextPopulation) {
                          nextPopulationCase.add(decodeCase(chromo));
                      }
  
                  }
                  logger.info(covReport);
              }catch(Exception e){
                  logger.info(e.getMessage());
              }
  
              JSONArray validCaseIds = new JSONArray();
              for(Long caseId : allCaseList){
                  if(newCaseIdList.contains(caseId)){
                      validCaseIds.add(caseId);
                      continue;
                  }else{
                      testcaseService.deleteTestCase(caseId);
  
                  }
              }
  
              int count = 0;
              try {
                  for (Long caseId : newCaseIdList) {
                      GotTestCase testCase = testcaseService.findById(caseId);
                      String desp = testCase.getDescription();
                      testCase.setDescription(desp + "--后代用例" + (count++));
                      testcaseService.update(testCase);
                  }
              }catch(Exception e){
                  System.out.print(e.getMessage());
              }
  
              JSONObject res = new JSONObject();
              res.put("all_num", allCaseList.size());
              res.put("valid_ids", validCaseIds);
              res.put("detail", covReport);
              res.put("cov_rate", covRate);
  
  
              try {
                  aiTask.setTaskStatus("success");
                  aiTask.setTaskResult(res.toJSONString());
                  caseGenerateTaskService.update(aiTask);
              }catch(Exception e){
                  System.out.print(e.getMessage());
              }
  
  
          }
  
  
          public List<Long> searchRelateCase(TestCaseInput seedCase){
              List<Long> caseRes = new ArrayList<>();
              List<TestCaseInput> allList = testcaseService.getAllCaseByScenarioId(seedCase.getScenarioId());
  
              for(TestCaseInput singleCase : allList){
                  Map<String, Object> features = extractFeatures(singleCase, ignoreConf);
  
                  int commonFeatureNum = 0;
                  for(String key : features.keySet()){
                      if(chromoSeq.contains(key)){
                          commonFeatureNum++;
                      }
                  }
  
                  if((commonFeatureNum*1.0/ chromoSeq.size()) > 0.5){ // 如果有一半以上的相同特征，则属于相似关联用例
                      caseRes.add(singleCase.getId());
                  }
              }
              return caseRes;
          }
  
  
          /**
           * 构建初始种群，根据库中已有的用例返回染色体列表
           * @param seedCaseId
           * @return
           */
          public List<Object[]> buildInitPopulation( Long seedCaseId){
              List<Object[]> population = new ArrayList<>();
              Object[] seedChromo = new Object[chromoSeq.size()];;
  
              //用例库中已有用例作为初始用例
              for(GotTestCase singleCase : relatedSeedCase){
  
                  Map<String, Object> featureMap = extractFeatures(testcaseService.getTestCaseById(singleCase.getId()) , ignoreConf);
                  Object[] chromo = new Object[chromoSeq.size()];
                  for(int i = 0 ; i < chromoSeq.size(); i++){
                      Object value = "";
                      if(featureMap.get(chromoSeq.get(i)) != null){
                          value = featureMap.get(chromoSeq.get(i));
                      }
                      chromo[i] = value;
                  }
                  Long id = singleCase.getId();
                  if(singleCase.getId().equals(seedCaseId)){
                      seedChromo = chromo.clone();
                  }
  
                  population.add(chromo);
              }
  
              //在种子用例基础上，修改字段为用户配置的参数值，构建初始用例
              //for(String geneKey : extralGeneMap.keySet()){
              for(String geneKey : chromoSeq){
                  int keyIndex = chromoSeq.indexOf(geneKey);
                  for(Object geneValue : geneBankMap.get(geneKey)){
                      Object[] chromo = seedChromo.clone();
  
                      chromo[keyIndex] = geneValue;
  
                      population.add(chromo);
                  }
              }
  
              return population;
          }
  
          /**
           * 从基因型解码为新用例
           * @param chromo
           * @return
           */
          public GotTestCase decodeCase(Object[] chromo){
              //解码基因型形成新case
              try{
                  JSONObject seedQuery = getCaseQuery(seedCase);
                  for(int i = 0; i < chromoSeq.size(); i++){
                      String key = chromoSeq.get(i);
                      Object value = chromo[i];
  
                      seedQuery.put(key, value);
                  }
  
                  TestCaseInput newCase = (TestCaseInput) SerializationUtils.clone(seedCase);
  
                  newCase.getCaseRunStage().get(0).getData().get(0).input = seedQuery.toJSONString();
  
                  newCase.setIsVisible(1);
  
                  return testcaseService.addNewTestCase(newCase);
              }catch(Exception e){
                  return null;
              }
          }
  
          /**
           * 构建用例运行任务，获取每个case覆盖的被测代码
           * @param casePopulation
           * @return
           */
          public void runCasePopulation(List<GotTestCase> casePopulation, String env){
              MultiAIInfo multiAIInfo = new MultiAIInfo();
              String caseIds = "";
              for(GotTestCase testCase : casePopulation){
                  caseIds += (testCase.getId()+",");
              }
              if(caseIds.endsWith(",")){
                  caseIds = caseIds.substring(0, caseIds.length()-1);
              }
              multiAIInfo.setCaseIds(caseIds);
              multiAIInfo.setTaskName("用例生成-运行任务");
              multiAIInfo.setTaskType(0);
              multiAIInfo.setCaseType("0");
              multiAIInfo.setExecId(""+(new Date()).getTime());
              multiAIInfo.setScenarioId(seedCase.getScenarioId());
              multiAIInfo.setRegAccuracy(true);
              multiAIInfo.setCreator("markov AI");
              multiAIInfo.setRunType("AI");
              multiAIInfo.setAppId(1L);
              multiAIInfo.setCaseTemplate("C++");
              multiAIInfo.setBranchName("master");
              multiAIInfo.setRegAccuracy(true);
  
              //mock
  
              Map<String, List<String>> envInfo = new HashMap<>();
              List<String> dockers = new ArrayList<>();
              dockers.add("mock docker");
              envInfo.put(env,dockers);
              multiAIInfo.setEnvInfo(envInfo);
  
  
              Long reportId = multiAIController.runIntelligent(multiAIInfo);
              while(true){
                  GotReports report = gotReportsService.findById(reportId);
                  if(report.getStatus().equals(ResultStatus.SUCCESS.name()) || report.getStatus().equals(ResultStatus.ERROR.name()) || report.getStatus().equals(ResultStatus.FAILURE.name())){
                      break;
                  }else{
                      try {
                          Thread.sleep(1000);
                      }catch(Exception e){
                          continue;
                      }
                  }
              }
          }
  
  
          public int calCovRate(){
              int covRate = 0; //百分比整数值
              try{
                  int allLineNum = diffLineList.size();
                  int covedNum = historyCov.keySet().size();
  
                  covRate = (int)((covedNum*1.0)/allLineNum * 100);
  
              }catch(Exception e){
                  //
              }
              return covRate;
          }
  
      }
  
  }
  