/* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.suren.autotest.web.framework.code; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.VisitorSupport; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.dom4j.xpath.DefaultXPath; import org.jaxen.SimpleNamespaceContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.stereotype.Component; import org.suren.autotest.web.framework.core.Callback; import org.suren.autotest.web.framework.util.StringUtils; import org.xml.sax.SAXException; /** * 根据元素定位的xml描述信息生成xml格式的运行套件(RunnerSuite)文件 * @author suren * @date 2016年12月14日 上午8:24:36 */ @Component("xml_to_suite_runner") public class DefaultXmlSuiteRunnerGenerator implements Generator { private static final Logger logger = LoggerFactory.getLogger(DefaultXmlDataSourceGenerator.class); private String outputDir; private String srcCoding; private Map<String, String> suiteActionMap = new HashMap<String, String>(); private Document suiteRunnerDoc = null; public DefaultXmlSuiteRunnerGenerator() { //key是元素定位中的类型,value是默认的操作名称 suiteActionMap.put("button", "click"); suiteActionMap.put("input", "fillValue"); suiteActionMap.put("select", "randomSelect"); suiteActionMap.put("file_upload", "upload"); } @Override public void generate(String srcCoding, String outputDir) { this.srcCoding = srcCoding; ClassLoader classLoader = this.getClass().getClassLoader(); //读取主配置文件 try(InputStream confInput = classLoader.getResourceAsStream(srcCoding)) { generate(confInput, outputDir, null); } catch (IOException e) { logger.error(String.format("Main config [%s] parse process error.", srcCoding), e); } } @SuppressWarnings("unchecked") @Override public void generate(InputStream input, String outputDir, Callback callback) { this.outputDir = outputDir; // String srcPath = srcCoding; // srcPath = srcPath.replace(".xml", ""); // srcPath = srcPath + "_runner.xml"; // ClassLoader clsLoader = this.getClass().getClassLoader(); // URL url = clsLoader.getResource(srcPath); // InputStream dsInput = null; // try // { // if(url != null) // { // dsInput = url.openStream(); // } // } // catch (IOException e1) // { // e1.printStackTrace(); // } // if(dsInput != null) // { // try // { // suiteRunnerDoc = new SAXReader().read(dsInput); // } // catch (DocumentException e) // { // e.printStackTrace(); // } // } // else // { suiteRunnerDoc = DocumentHelper.createDocument(); // } //读取主配置文件 try { read(input); } catch (DocumentException | IOException e) { logger.error(String.format("Main config [%s] parse process error.", srcCoding), e); } catch (SAXException e) { e.printStackTrace(); } XMLWriter xmlWriter = null; // if(dsInput != null) // { // try // { // dsInput.close(); // } // catch (IOException e) // { // e.printStackTrace(); // } // } // String outputFileName = null; // if(url != null) // { // outputFileName = new File(url.getFile()).getName(); // } // else // { // outputFileName = new File(srcPath).getName(); // } File outputDirFile = new File(outputDir); if(!outputDirFile.isDirectory()) { outputDirFile.mkdirs(); } File outputFile = new File(outputDir, System.currentTimeMillis() + ".xml"); try(OutputStream dsOutput = new FileOutputStream(outputFile)) { OutputFormat outputFormat = OutputFormat.createPrettyPrint(); outputFormat.setIndentSize(4); xmlWriter = new XMLWriter(dsOutput, outputFormat); xmlWriter.write(suiteRunnerDoc); if(callback != null) { callback.callback(outputFile); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 从流中读取配置文件 * * @param inputStream * @throws DocumentException * @throws IOException * @throws SAXException */ public void read(InputStream inputStream) throws DocumentException, IOException, SAXException { Document document = new SAXReader().read(inputStream); parse(document); } /** * @param document */ private void parse(Document doc) { SimpleNamespaceContext simpleNamespaceContext = new SimpleNamespaceContext(); simpleNamespaceContext.addNamespace("ns", "http://surenpi.com"); XPath xpath = new DefaultXPath("/ns:autotest/ns:includePage"); xpath.setNamespaceContext(simpleNamespaceContext); @SuppressWarnings("unchecked") List<Element> includePageList = xpath.selectNodes(doc); if(includePageList != null && includePageList.size() > 0) { for(Element includePage : includePageList) { String pageConfig = includePage.attributeValue("pageConfig"); generate(pageConfig, outputDir); } } xpath = new DefaultXPath("/ns:autotest/ns:pages"); xpath.setNamespaceContext(simpleNamespaceContext); Element pagesEle = (Element) xpath.selectSingleNode(doc); String pagePackage = pagesEle.attributeValue("pagePackage", ""); if(StringUtils.isNotBlank(pagePackage)) { pagePackage = pagePackage.trim(); } // pages parse progress xpath = new DefaultXPath("/ns:autotest/ns:pages/ns:page"); xpath.setNamespaceContext(simpleNamespaceContext); @SuppressWarnings("unchecked") List<Element> pageNodes = xpath.selectNodes(doc); if (pageNodes != null) { for (Element ele : pageNodes) { String pageClsStr = ele.attributeValue("class"); if (pageClsStr == null) { logger.warn("can not found class attribute."); continue; } try { parse(doc, pagePackage, pageClsStr, ele); } catch (NoSuchBeanDefinitionException e) { logger.error("Page element [{}] parse error, in document [{}].", "pageClsStr", doc); throw e; } catch (Exception e) { logger.error("Page element parse error.", e); } } } } /** * 解析页面Page对象 * * @param pageClsStr * @param dataSrc * @param ele */ private void parse(Document doc, final String pagePackage, final String pageClsStr, Element ele) throws Exception { updateXmlDataSourceByEle(ele, pagePackage, pageClsStr); } /** * @param ele */ private void updateXmlDataSourceByEle(Element ele, String pagePackage, String pageClsStr) { SimpleDateFormat dateFormat = new SimpleDateFormat(); suiteRunnerDoc.addComment("Auto created by AutoTest, " + dateFormat.format(new Date())); SimpleNamespaceContext simpleNamespaceContext = new SimpleNamespaceContext(); simpleNamespaceContext.addNamespace("ns", "http://suite.surenpi.com"); XPath xpath = new DefaultXPath("/ns:suite"); xpath.setNamespaceContext(simpleNamespaceContext); //先查找是否有该标签 Element dataSourcesEle = suiteRunnerDoc.getRootElement();//(Element) xpath.selectSingleNode(suiteRunnerDoc); if(dataSourcesEle == null) { String prefix = "suren"; dataSourcesEle = suiteRunnerDoc.addElement(prefix + ":suite"); dataSourcesEle.addNamespace(prefix, "http://suite.surenpi.com"); dataSourcesEle.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); dataSourcesEle.addAttribute("xsi:schemaLocation", "http://suite.surenpi.com " + "http://surenpi.com/schema/suite/autotest.web.framework.suite.xsd "); dataSourcesEle.addAttribute("pageConfig", this.srcCoding); dataSourcesEle.addAttribute("pagePackage", pagePackage); } xpath = new DefaultXPath("/ns:suite/ns:page[@class='" + pageClsStr + "']"); xpath.setNamespaceContext(simpleNamespaceContext); Element dataSourceEle = (Element) xpath.selectSingleNode(suiteRunnerDoc); if(dataSourceEle == null) { String prefix = dataSourcesEle.getNamespacePrefix(); if(StringUtils.isBlank("")) { String parentName = dataSourcesEle.getName(); if(parentName.contains(":")) { prefix = parentName.split(":")[0]; } } if(StringUtils.isNotBlank(prefix)) { prefix = prefix + ":"; } dataSourceEle = dataSourcesEle.addElement(prefix + "page"); dataSourceEle.addAttribute("class", pageClsStr); } //只更新第一个子标签 xpath = new DefaultXPath("/ns:suite/ns:page[@class='" + pageClsStr + "']/ns:actions[1]"); xpath.setNamespaceContext(simpleNamespaceContext); Element pageEle = (Element) xpath.selectSingleNode(dataSourceEle); if(pageEle == null) { String prefix = dataSourceEle.getNamespacePrefix(); if(StringUtils.isNotBlank(prefix)) { prefix = prefix + ":"; } pageEle = dataSourceEle.addElement(prefix + "actions"); } ele.accept(new PageFieldVisitor(pageEle)); } class PageFieldVisitor extends VisitorSupport { private SimpleNamespaceContext simpleNamespaceContext = new SimpleNamespaceContext(); private Element actionsEle; public PageFieldVisitor(Element pageEle) { this.actionsEle = pageEle; simpleNamespaceContext.addNamespace("ns", "http://suite.surenpi.com"); } @Override public void visit(Element node) { if (!"field".equals(node.getName())) { return; } String fieldName = node.attributeValue("name"); String type = node.attributeValue("type"); String action = suiteActionMap.get(type); if (StringUtils.isBlank(fieldName) || StringUtils.isBlank(action)) { return; } XPath xpath = new DefaultXPath("//ns:action[@field='" + fieldName + "']"); xpath.setNamespaceContext(simpleNamespaceContext); Element fieldEle = (Element) xpath.selectSingleNode(actionsEle); if(fieldEle == null) { String prefix = actionsEle.getNamespacePrefix(); if(StringUtils.isNotBlank(prefix)) { prefix = prefix + ":"; } fieldEle = actionsEle.addElement(prefix + "action"); fieldEle.addAttribute("field", fieldName); } fieldEle.addAttribute("name", action); } } }