001package com.thed.zblast.launcher;
002
003import com.google.gson.Gson;
004import com.thed.launcher.InputStreamHandler;
005import com.thed.model.AutomationJobDetail;
006import com.thed.model.ExecutionRequest;
007import com.thed.model.ZblastScriptExecutionResult;
008import com.thed.parser.ParserUtil;
009import com.thed.util.Utils;
010import com.thed.util.ZeeConstants;
011import com.thed.util.gson.GsonUtil;
012import com.thed.zblast.parser.EggplantParser;
013import com.thed.zblast.parser.JUnitResultParser;
014import com.thed.zblast.parser.TestNGXMLResultParserImpl;
015import com.thed.zblast.parser.jaxb.junit.Failure;
016import com.thed.zblast.parser.jaxb.junit.Testcase;
017import com.thed.zblast.parser.jaxb.junit.Testsuite;
018import com.thed.zblast.parser.model.EggPlantResult;
019import com.thed.zblast.parser.model.TestCase;
020import com.thed.zblast.parser.model.TestngResults;
021import com.thed.zblast.parser.model.TestngResults.Testsuite.Test.Class;
022import com.thed.zblast.parser.model.TestngResults.Testsuite.Test.Class.TestMethod;
023import org.apache.commons.configuration.PropertiesConfiguration;
024import org.apache.commons.io.FilenameUtils;
025import org.apache.commons.lang.StringUtils;
026import org.apache.commons.lang.SystemUtils;
027import org.xml.sax.SAXException;
028
029import javax.xml.parsers.ParserConfigurationException;
030import java.io.*;
031import java.math.BigDecimal;
032import java.util.*;
033import java.util.concurrent.TimeUnit;
034import java.util.logging.Level;
035import java.util.logging.Logger;
036import java.util.stream.Collectors;
037
038public class ZblastLauncher {
039  
040    private final Logger logger = Logger.getLogger(ZblastLauncher.class.getName());
041    String logstatus;
042
043    public void invoke(AutomationJobDetail automationJobDetail, ZblastScriptExecutionResult executionResult) {
044        String frameworkSelected = automationJobDetail.getAutomationFramework().toLowerCase();
045
046        PropertiesConfiguration props = Utils.getZbotProperties();
047        String useGenericParser=props.getString("use_generic_parser");
048        Boolean isGenericParserUsed = Boolean.valueOf((useGenericParser==null)?"false":useGenericParser);
049
050        if (automationJobDetail.isInvokeScript())
051            testcaseExecutionRun(automationJobDetail, executionResult);
052
053        if (automationJobDetail.isInvokeScript() && !executionResult.isScriptExecutionSatus())
054            return;
055        if (frameworkSelected.equalsIgnoreCase(ZeeConstants.SELENIUM) || frameworkSelected.equalsIgnoreCase(ZeeConstants.UFT) || frameworkSelected.contains(ZeeConstants.TOSCA)
056                        || frameworkSelected.equalsIgnoreCase(ZeeConstants.JUNIT)|| frameworkSelected.equalsIgnoreCase(ZeeConstants.CUCUMBER)
057        || frameworkSelected.equalsIgnoreCase(ZeeConstants.SOAP_UI_PRO) ||frameworkSelected.equalsIgnoreCase(ZeeConstants.SOAPUI_PRO) || frameworkSelected.equalsIgnoreCase(ZeeConstants.TESTCOMPLETE)) {
058                List<Testsuite> testsuites=null;
059                if(isGenericParserUsed){
060                        testsuites=getTestSuitesFromGenericParser(automationJobDetail.getResultPath(),automationJobDetail.getParserTemplate());
061                }else{
062                        testsuites = JUnitResultParser.parseResults(automationJobDetail.getResultPath());
063                }
064            executionResult.setTestSuite(testsuites);
065    } else if (frameworkSelected.equalsIgnoreCase(ZeeConstants.EGG_PLANT)) {
066                                try {
067                                        // TODO : sut and image url support implementation if required by customers
068                                        EggplantParser eggplantParser = new EggplantParser("unknownSUT", "url");
069                                        // result path must point to RunHistory.csv (Ex. D:\\eggPlant\\Untitled\\RunHistory.csv)
070                                        ArrayList<EggPlantResult> eggPlantResults = eggplantParser.invoke(new File(FilenameUtils.separatorsToSystem(automationJobDetail.getResultPath())));
071                                                List<Testsuite> testSuite=getTestsSuitsForEggplant(eggPlantResults,automationJobDetail,isGenericParserUsed);
072                                                executionResult.setTestSuite(testSuite);
073                                        } catch (Exception e) {
074                                        logger.info("exception parsing eggPlant results: " + e.getMessage());
075                                }
076                        }
077    else if( frameworkSelected.equalsIgnoreCase(ZeeConstants.TEST_NG) ) {
078        List<Testsuite> testSuite=getSuiteForTestNg(automationJobDetail,isGenericParserUsed);
079        executionResult.setTestSuite(testSuite);
080    } else if(isGenericParserUsed) {
081        List<Testsuite> testsuites=getTestSuitesFromGenericParser(automationJobDetail.getResultPath(),automationJobDetail.getParserTemplate());
082        executionResult.setTestSuite(testsuites);
083    }
084    }
085
086        private List<Testsuite> getSuiteForTestNg(AutomationJobDetail automationJobDetail, Boolean isGenericParserUsed) {
087                List<Testsuite> testsuites=new ArrayList<>();
088        if(isGenericParserUsed){
089                        testsuites=getTestSuitesFromGenericParser(automationJobDetail.getResultPath(),automationJobDetail.getParserTemplate());
090                }else{
091                        testsuites=getResultForTestNg(automationJobDetail);
092                }
093        return testsuites;
094        }
095
096        private List<Testsuite> getResultForTestNg(AutomationJobDetail automationJobDetail) {
097                List<Testsuite> testSuite=new ArrayList<>();
098                List<com.thed.zblast.parser.model.TestngResults.Testsuite> testNgResults=TestNGXMLResultParserImpl.parseResults(automationJobDetail.getResultPath());
099                for(com.thed.zblast.parser.model.TestngResults.Testsuite suite: testNgResults) {
100                        Testsuite tests=new Testsuite();
101                        List<TestngResults.Testsuite.Test> test1 = suite.getTest();
102                        List<Class> testClass = new ArrayList<>();
103                        test1.stream().forEach(t->testClass.addAll(t.getClazz()));
104                        List<TestMethod> testMethods=new ArrayList<>();
105                        List<List<TestMethod>> testMethodsList = testClass.stream().map(s -> s.getTestMethod()).collect(Collectors.toList());
106                        testMethodsList.forEach(su-> {testMethods.addAll(su);});
107                        List<Testcase> testcases=new ArrayList<>();
108                        for (TestMethod testcase : testMethods) {
109                                String name = testcase.getName();
110                                Testcase test=new Testcase();
111
112                                if (name.equals(ZeeConstants.BEFORE_CLASS) || name.equals(ZeeConstants.AFTER_CLASS) || name.equals(ZeeConstants.BEFORE_SUITE)
113                                                || name.equals(ZeeConstants.AFTER_SUITE) || name.equals(ZeeConstants.BEFORE_METHOD) || name.equals(ZeeConstants.AFTER_METHOD)) {
114                                        continue;
115                                }
116                                String status = testcase.getStatus();
117                                test.setName(name);
118                                test.setStatus(status);
119                                Failure failure=new Failure();
120                                if(testcase.getException()!=null) {
121                                        failure.setContent(testcase.getException().getMessage()+SystemUtils.LINE_SEPARATOR+testcase.getException().getFullStacktrace());
122                                        test.getFailure().add(failure);
123                                }
124                                testcases.add(test);
125                        }
126                        tests.getTestcase().addAll(testcases);
127                        testSuite.add(tests);
128                }
129                return testSuite;
130        }
131
132        private List<Testsuite> getTestSuitesFromGenericParser(String resultPath,String parserTemplate) {
133        File result = new File(resultPath);
134        List<Testsuite> testsuites=new ArrayList<>();
135        List<String> xmlResultFile = new ArrayList<>();
136        if(result.exists()){
137                if(result.isDirectory()){
138                        //get all .xml files
139                                File[] resultFiles = result.listFiles((file, name) -> name.endsWith(".xml"));
140                                List<String> files=Arrays.asList(resultFiles).stream().map(file -> file.getAbsolutePath()).collect(Collectors.toList());
141                                xmlResultFile.addAll(files);
142                        }else{
143                        // add the file to the list of files
144                                xmlResultFile.add(resultPath);
145                        }
146                }
147
148        xmlResultFile.forEach((resultFile)->{
149                        try {
150                                List<Map> dataMap = new ParserUtil().parseXmlLang(resultFile, parserTemplate);
151                                Testsuite testsuite=getTestSuiteFromDataMap(dataMap);
152                                //required for Eggplant, ignoring for other frameworks
153                                testsuite.setAttachmentFile(resultFile);
154                                testsuites.add(testsuite);
155                        } catch (IOException e) {
156                                e.printStackTrace();
157                        } catch (SAXException e) {
158                                e.printStackTrace();
159                        } catch (ParserConfigurationException e) {
160                                e.printStackTrace();
161                        }
162                });
163        return testsuites;
164        }
165
166        private Testsuite getTestSuiteFromDataMap(List<Map> dataMapList) {
167                Testsuite testsuite=new Testsuite();
168                List<Testcase> testcaseList=getTestcaseFromDataMap(dataMapList);
169                Map map = dataMapList.get(0);
170                if(map.containsKey("timestamp")){
171                        String timestamp = (String) map.get("timestamp");
172                        testsuite.setTimestamp(timestamp);
173                }
174                testsuite.setTestcase(testcaseList);
175                return testsuite;
176        }
177
178        private List<Testcase> getTestcaseFromDataMap(List<Map> dataMapList) {
179        List<Testcase> testcaseList=new ArrayList<>();
180                for (Map map : dataMapList) {
181                        Testcase tc=extractTestcase(map);
182                        if(tc!=null){
183                                testcaseList.add(tc);
184                        }
185                }
186                return testcaseList;
187        }
188
189        private Testcase extractTestcase(Map dataMap) {
190        //implement here
191                Testcase tc=new Testcase();
192                Set<String> requirementIds = new HashSet<>();
193                Set<String> packageNames = new HashSet<>();
194                List<String> attachments = new ArrayList<>();
195                packageNames.add(dataMap.get("packageName").toString());
196                Map testcaseMap = (Map) dataMap.get("testcase");
197
198                String testcaseJson = new Gson().toJson(testcaseMap);
199                TestCase testcase = new Gson().fromJson(testcaseJson, TestCase.class);
200
201                if(testcase.getName().isEmpty()) {
202                        return null;
203                }
204
205                if(dataMap.containsKey("skipTestcaseNames")) {
206                        boolean isSkipTestcase=false;
207                        String[] skipTestcaseNames = dataMap.get("skipTestcaseNames").toString().split(",");
208                        for (String testcaseName : skipTestcaseNames) {
209                                if(testcase.getName().equals(testcaseName)) {
210                                        //name matches, skip this testcase
211                                        isSkipTestcase=true;
212                                        continue;
213                                }
214                        }
215                        if(isSkipTestcase){
216                                return null;
217                        }
218                }
219
220                String packageName = dataMap.get("packageName").toString();
221
222                Map<String, String> statusCondition = new HashMap<>();
223                if(dataMap.containsKey("statuses") && dataMap.get("statuses") != null) {
224                        List<Map> statuses = (List) dataMap.get("statuses");
225                        boolean matched = false;
226                        for(Map sc : statuses) {
227                                if((sc.get("statusString") == null && sc.get("status") != null && StringUtils.isNotEmpty(sc.get("status").toString())) //status is not empty
228                                                || (sc.get("statusString") != null && sc.get("statusString").equals(sc.get("status")))) { //status matches statusString
229                                        statusCondition = sc;
230                                        matched = true;
231                                        break;
232                                }
233                        }
234                        if(!matched) {
235                                //none of the status condition satisfied, search for default
236                                for(Map sc : statuses) {
237                                        if(sc.get("default") != null && Boolean.valueOf(sc.get("default").toString())) { //default status
238                                                Object val = dataMap.get("stepText");
239                                                if (val != null && !val.toString().isEmpty() && val.toString().contains("skipped")) {
240                                                        sc.put("statusId", "10");
241                                                        statusCondition = sc;
242                                                } else {
243                                                        statusCondition = sc;
244                                                        break;
245                                                }
246                                        }
247                                }
248                        }
249                }
250
251                //get requirement from datamap
252                if(dataMap.containsKey("requirements")) {
253                        List<Map> requirements = (List) dataMap.get("requirements");
254                        for (Map requirement : requirements) {
255                                String id = requirement.get("id").toString();
256                                String[] splitRequirementId = id.split("_");
257                                if(id.startsWith("ID_") || id.startsWith("AltID_")) {
258                                        requirementIds.add(id);
259                                }
260                        }
261                }
262                //fetch attachment tags
263
264                if(dataMap.containsKey("attachments")) {
265                        List<Map> attachmentFilePaths = (List) dataMap.get("attachments");
266                        for(Map attachment : attachmentFilePaths) {
267                                String filePath = attachment.get("filePath").toString();
268                                attachments.add(filePath);
269                        }
270                }
271
272                if(statusCondition.containsKey("attachmentText")) {
273                        String attachmentText = statusCondition.get("attachmentText");
274                        tc.setStatusAttachment(attachmentText);
275                }
276
277                if(dataMap.containsKey("stepText")) {
278                        String stepStr = dataMap.get("stepText").toString();
279                        tc.setSystemOut(Arrays.asList(stepStr));
280                        System.out.println("system-out: "+stepStr);
281                }
282
283                if(dataMap.containsKey("execution")) {
284                        Map<String, Object> executionDataMap = (Map<String, Object>) dataMap.get("execution");
285                        Object actualTimeObj = executionDataMap.get("actualTime");
286                        Object actualTimeUnitObj = executionDataMap.get("actualTimeUnit");
287                        executionDataMap.remove("actualTime");
288                        ExecutionRequest executionRequest = GsonUtil.CUSTOM_GSON.fromJson(GsonUtil.CUSTOM_GSON.toJson(executionDataMap), ExecutionRequest.class);
289                        if(executionRequest == null) {
290                                executionRequest = new ExecutionRequest();
291                        }
292                        if(actualTimeObj != null && StringUtils.isNotBlank(actualTimeObj.toString())) {
293                                BigDecimal actualTimeSrc = new BigDecimal(actualTimeObj.toString());
294                                TimeUnit actualTimeUnit = null;
295                                try {
296                                        actualTimeUnit = actualTimeUnitObj != null
297                                                        ? TimeUnit.valueOf(actualTimeUnitObj.toString())
298                                                        : TimeUnit.SECONDS;
299                                } catch (Exception e) {
300                                        logger.warning(ZeeConstants.ERROR_MESSAGE_ACTUAL_TIME_UNIT.formatted(actualTimeUnitObj.toString()));
301                                        actualTimeUnit = TimeUnit.SECONDS;
302                                }
303                                switch (actualTimeUnit) {
304                                        case MILLISECONDS: executionRequest.setActualTime(actualTimeSrc.longValue());
305                                                break;
306
307                                        case SECONDS:
308                                        default:
309                                                actualTimeSrc = actualTimeSrc.multiply(new BigDecimal("1000"));
310                                                executionRequest.setActualTime(actualTimeSrc.longValue());
311                                                break;
312
313                                }
314                        }
315                        if(statusCondition.containsKey("statusId")) {
316                                executionRequest.setStatus(statusCondition.get("statusId"));
317                        }
318                        tc.setExecutionRequest(executionRequest);
319                } else {
320                        ExecutionRequest executionRequest = new ExecutionRequest();
321                        if(statusCondition.containsKey("statusId")) {
322                                executionRequest.setStatus(statusCondition.get("statusId"));
323                                tc.setExecutionRequest(executionRequest);
324                        }
325                }
326
327                tc.setName(testcase.getName());
328                tc.setTag(testcase.getTag());
329                tc.setClassname(packageName);
330                tc.setRequirementIds(requirementIds);
331                tc.setAttachmentList(attachments);
332                return tc;
333        }
334
335
336        private List<Testsuite> getTestsSuitsForEggplant(ArrayList<EggPlantResult> invoke, AutomationJobDetail automationJobDetail, Boolean isGenericParserUsed) {
337        List<Testsuite> testSuits=new ArrayList<>();
338        Map<String,Testsuite> eggPlantSuite=new HashMap<>();
339                for(EggPlantResult eggPlant:invoke){
340                        List<Testsuite> suiteList=null;
341                        if(isGenericParserUsed){
342                                suiteList=getTestSuitesFromGenericParser(eggPlant.getXmlResultFile(),automationJobDetail.getParserTemplate());
343                        }else{
344                                suiteList=JUnitResultParser.parseResults(eggPlant.getXmlResultFile());
345                        }
346                        if(!suiteList.isEmpty()){
347                                Testsuite suite=null;
348                                String testCaseName=null;
349                                if(isGenericParserUsed){
350                                        testCaseName=suiteList.get(0).getTestcase().get(0).getName();
351                                }else{
352                                        testCaseName=suiteList.get(0).getName();
353                                }
354                                suite=eggPlantSuite.get(testCaseName);
355
356                                if(suite==null){
357                                        eggPlantSuite.put(testCaseName,suiteList.get(0));
358                                }else{
359                                        if(suite.getTimeInDate().before(suiteList.get(0).getTimeInDate())){
360                                                eggPlantSuite.put(testCaseName,suiteList.get(0));
361                                        }
362                                }
363                        }
364                }
365                eggPlantSuite.forEach((key,value)->{
366                        testSuits.add(value);
367                });
368        return testSuits;
369        }
370
371        public void testcaseExecutionRun(AutomationJobDetail automationJobDetail, ZblastScriptExecutionResult executionResult) {
372
373        int status = 0;
374        try {
375            logger.info("about to run script with path: " + automationJobDetail.getScriptPath());
376            StringBuilder command = new StringBuilder(automationJobDetail.getScriptPath());
377        final Process process = Runtime.getRuntime().exec(command.toString());
378            logger.info("Waiting for execution completion...");
379                StringBuffer inBuffer = new StringBuffer();
380                InputStream inStream = process.getInputStream();
381                new InputStreamHandler( inBuffer, inStream );
382
383                StringBuffer errBuffer = new StringBuffer();
384                InputStream errStream = process.getErrorStream();
385                new InputStreamHandler( errBuffer , errStream );
386                status = process.waitFor();
387
388                if(status!=0){
389                        logger.log(Level.SEVERE,"Script execution failed. Error : "+errBuffer.toString());
390                }else{
391                        logger.info("Script successfully executed ");
392                }
393
394            executionResult.setExitCode(status);
395            executionResult.setScriptExecutionSatus(true);
396            executionResult.setScriptExecutionSatusMsg("Script Executed Successfully");
397
398        } catch (Exception e) {
399                logger.info("""
400                                Automation Job Id : %s: STATUS: Execution Error %s""".formatted(automationJobDetail.getId(), e.getMessage()));
401            logger.info("Script run exit code: " + status);
402            executionResult.setExitCode(status);
403            executionResult.setScriptExecutionSatus(false);
404            executionResult.setScriptExecutionSatusMsg(e.getMessage());
405            e.printStackTrace();
406        }
407
408    }
409
410    static class ProcessStreamReader extends Thread {
411        BufferedReader br;
412        private final Logger logger = Logger.getLogger(this.getClass().getName());
413
414        public ProcessStreamReader(InputStream in) {
415            super();
416            br = new BufferedReader(new InputStreamReader(in));
417        }
418
419        @Override
420        public void run() {
421            String line;
422            try {
423                while ((line = br.readLine()) != null) {
424                    logger.info(Thread.currentThread().getName() + " | Read output..." + line);
425                }
426            } catch (IOException e) {
427                logger.log(Level.SEVERE, "Error in reading process steams \n", e);
428            } finally {
429                if (br != null) {
430                    try {
431                        br.close();
432                    } catch (IOException e) {
433                    }
434                }
435            }
436            logger.info(Thread.currentThread().getName() + " | Done reading process log input stream");
437        }
438    }
439
440}