public class AcceptanceTestContext {

	private Logger logger = Logger.getLogger(AcceptanceTestContext.class.getSimpleName());
	
	public final static String
	    PROP_SOAP_ACTION_11 = "SOAPAction",
	    PROP_SOAP_ACTION_12 = "action=",
	    PROP_CONTENT_TYPE = "Content-Type",
	    PROP_CONTENT_LENGTH = "Content-Length",
	    PROP_AUTH = "Authorization",
	    PROP_PROXY_AUTH = "Proxy-Authorization",
	    PROP_PROXY_CONN = "Proxy-Connection",
	    PROP_KEEP_ALIVE = "Keep-Alive",
	    PROP_BASIC_AUTH = "Basic",
	    PROP_DELIMITER = "; ";
	
	public final static String
	    SOAP_1_1_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/",
	    SOAP_1_2_NAMESPACE = "http://www.w3.org/2003/05/soap-envelope";
	
	public final static String
	    MIMETYPE_TEXT_HTML = "text/html",
	    MIMETYPE_TEXT_PLAIN = "text/plain",
	    MIMETYPE_TEXT_XML = "text/xml",
	    MIMETYPE_APPLICATION_XML = "application/soap+xml";
	
	public static final String GATF_SERVER_LOGS_API_FILE_NM = "gatf-logging-api-int.xml";
	
	private final Map<String, List<TestCase>> relatedTestCases = new HashMap<String, List<TestCase>>();
	
	private final Map<String, String> httpHeaders = new HashMap<String, String>();

	private ConcurrentHashMap<Integer, String> sessionIdentifiers = new ConcurrentHashMap<Integer, String>();
	
	private final Map<String, String> soapEndpoints = new HashMap<String, String>();
	
	private final Map<String, Document> soapMessages = new HashMap<String, Document>();
	
	private final Map<String, String> soapStrMessages = new HashMap<String, String>();
	
	private final Map<String, String> soapActions = new HashMap<String, String>();
	
	private final WorkflowContextHandler workflowContextHandler = new WorkflowContextHandler();
	
	private List<TestCase> serverLogsApiLst = new ArrayList<TestCase>();
	
	private GatfExecutorConfig gatfExecutorConfig;
	
	private ClassLoader projectClassLoader;
	
	private Map<String, Method> prePostTestCaseExecHooks = new HashMap<String, Method>();
	
	public static final UrlValidator URL_VALIDATOR = new UrlValidator(new String[]{"http","https"}, UrlValidator.ALLOW_LOCAL_URLS);
	
	public static boolean isValidUrl(String url) {
		if(!URL_VALIDATOR.isValid(url)) {
			if(url.startsWith("host.docker.internal")) {
				url = url.replace("host.docker.internal", "");
				if(url.length()>0 && url.charAt(0)==':') {
					url = url.substring(1);
				}
				if(url.indexOf("/")!=-1) {
					url = url.substring(0, url.indexOf("/"));
				}
				try {
					Integer.parseInt(url);
				} catch (Exception e) {
					return false;
				}
			}
		}
		return true;
	}
	
	public static void setCorsHeaders(Response response) {
		if(Boolean.FALSE.toString().equalsIgnoreCase(System.getenv("cors.enabled")) || Boolean.FALSE.toString().equalsIgnoreCase(System.getProperty("cors.enabled"))) {
		} else {
			response.setHeader("Access-Control-Allow-Origin", "*");
			response.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
			response.setHeader("Access-Control-Allow-Headers", "*");
		}
	}
	
	public ClassLoader getProjectClassLoader() {
		return projectClassLoader;
	}

	private final Map<String, List<Map<String, String>>> providerTestDataMap = new HashMap<String, List<Map<String,String>>>();
	private final Map<String, String> fileProviderStateMap = new HashMap<String, String>();
	
	public List<Map<String, String>> getProviderTestDataMap(String providerName) {
	    if(liveProviders.containsKey(providerName))
        {
            GatfTestDataProvider provider = liveProviders.get(providerName);
            return getProviderData(provider, null);
        }
	    else 
	    {
	        return providerTestDataMap.get(providerName);
	    }
	}
	
	public String getFileProviderHash(String name) {
	    if(!fileProviderStateMap.containsKey(name)) {
	        return fileProviderStateMap.get(name);
	    }
	    return null;
	}
	
	public void newProvider(String name) {
	    if(!providerTestDataMap.containsKey(name)) {
	        providerTestDataMap.put(name, new ArrayList<Map<String,String>>());
	    }
	}
	
	private final Map<String, TestDataSource> dataSourceMap = new HashMap<String, TestDataSource>();
	
	private final Map<String, TestDataSource> dataSourceMapForProfiling = new HashMap<String, TestDataSource>();
	
	private final Map<String, GatfTestDataSourceHook> dataSourceHooksMap = new HashMap<String, GatfTestDataSourceHook>();

	private final SingleTestCaseExecutor singleTestCaseExecutor = new SingleTestCaseExecutor();
	
	private final ScenarioTestCaseExecutor scenarioTestCaseExecutor = new ScenarioTestCaseExecutor();
	
	private final PerformanceTestCaseExecutor performanceTestCaseExecutor = new PerformanceTestCaseExecutor();
	
	private final Map<String, GatfTestDataProvider> liveProviders = new HashMap<String, GatfTestDataProvider>();

	public SingleTestCaseExecutor getSingleTestCaseExecutor() {
		return singleTestCaseExecutor;
	}

	public ScenarioTestCaseExecutor getScenarioTestCaseExecutor() {
		return scenarioTestCaseExecutor;
	}

	public PerformanceTestCaseExecutor getPerformanceTestCaseExecutor() {
		return performanceTestCaseExecutor;
	}

	public AcceptanceTestContext(){}
	
	public AcceptanceTestContext(GatfExecutorConfig gatfExecutorConfig, ClassLoader projectClassLoader)
	{
		this.gatfExecutorConfig = gatfExecutorConfig;
		this.projectClassLoader = projectClassLoader;
		getWorkflowContextHandler().init();
	}
	
	public AcceptanceTestContext(DistributedAcceptanceContext dContext, ClassLoader projectClassLoader)
	{
        this.projectClassLoader = projectClassLoader;
		this.gatfExecutorConfig = dContext.getConfig();
		this.httpHeaders.putAll(dContext.getHttpHeaders());
		this.soapEndpoints.putAll(dContext.getSoapEndpoints());
		this.soapActions.putAll(dContext.getSoapActions());
		try {
			if(dContext.getSoapMessages()!=null) {
				DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
				DocumentBuilder db = dbf.newDocumentBuilder();
				for (Map.Entry<String, String> soapMsg : dContext.getSoapMessages().entrySet()) {
					Document soapMessage = db.parse(new ByteArrayInputStream(soapMsg.getValue().getBytes()));
					this.soapMessages.put(soapMsg.getKey(), soapMessage);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			// TODO: handle exception
		}
		getWorkflowContextHandler().init();
	}
	
	public GatfExecutorConfig getGatfExecutorConfig() {
		return gatfExecutorConfig;
	}

	public void setGatfExecutorConfig(GatfExecutorConfig gatfExecutorConfig) {
		this.gatfExecutorConfig = gatfExecutorConfig;
	}

	public ConcurrentHashMap<Integer, String> getSessionIdentifiers() {
		return sessionIdentifiers;
	}

	public void setSessionIdentifiers(
			ConcurrentHashMap<Integer, String> sessionIdentifiers) {
		this.sessionIdentifiers = sessionIdentifiers;
	}

	public void setSessionIdentifier(String identifier, TestCase testCase) {
		Integer simulationNumber = testCase.getSimulationNumber();
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			simulationNumber = -1;
		} else if(testCase.isExternalApi()) {
			simulationNumber = -2;
		} else if(simulationNumber==null) {
			simulationNumber = 0;
		}
		sessionIdentifiers.put(simulationNumber, identifier);
	}
	
	public String getSessionIdentifier(TestCase testCase) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return sessionIdentifiers.get(-1);
		}
		if(testCase.isExternalApi()) {
			return sessionIdentifiers.get(-2);
		}
		if(testCase.getSimulationNumber()!=null)
			return sessionIdentifiers.get(testCase.getSimulationNumber());
		
		return sessionIdentifiers.get(0);
	}
	
	public Map<String, String> getHttpHeaders() {
		return httpHeaders;
	}

	public Map<String, String> getSoapEndpoints() {
		return soapEndpoints;
	}

	public Map<String, Document> getSoapMessages() {
		return soapMessages;
	}

	public Map<String, String> getSoapActions() {
		return soapActions;
	}

	public WorkflowContextHandler getWorkflowContextHandler() {
		return workflowContextHandler;
	}
	
	@SuppressWarnings("rawtypes")
	public Class addTestCaseHooks(Method method) {
		Class claz = null;
		if(method!=null && Modifier.isStatic(method.getModifiers())) {
			
			Annotation preHook = method.getAnnotation(PreTestCaseExecutionHook.class);
            Annotation postHook = method.getAnnotation(PostTestCaseExecutionHook.class);
			
			if(preHook!=null)
			{
				PreTestCaseExecutionHook hook = (PreTestCaseExecutionHook)preHook;
				
				if(method.getParameterTypes().length!=1 || !method.getParameterTypes()[0].equals(TestCase.class))
				{
					logger.severe("PreTestCaseExecutionHook annotated methods should " +
							"confirm to the method signature - `public static void {methodName} (" +
							"TestCase testCase)`");
					return claz;
				}
				
				if(hook.value()!=null && hook.value().length>0)
				{
					for (String testCaseName : hook.value()) {
						if(testCaseName!=null && !testCaseName.trim().isEmpty())  {
							prePostTestCaseExecHooks.put("pre"+testCaseName, method);
						}
					}
				}
				else
				{
					prePostTestCaseExecHooks.put("preAll", method);
				}
				claz = method.getDeclaringClass();
			}
			if(postHook!=null)
			{
				PostTestCaseExecutionHook hook = (PostTestCaseExecutionHook)postHook;
				
				if(method.getParameterTypes().length!=1 || !method.getParameterTypes()[0].equals(TestCaseReport.class))
				{
					logger.severe("PostTestCaseExecutionHook annotated methods should " +
							"confirm to the method signature - `public static void {methodName} (" +
							"TestCaseReport testCaseReport)`");
					return claz;
				}
				
				if(hook.value()!=null && hook.value().length>0)
				{
					for (String testCaseName : hook.value()) {
						if(testCaseName!=null && !testCaseName.trim().isEmpty())  {
							prePostTestCaseExecHooks.put("post"+testCaseName, method);
						}
					}
				}
				else
				{
					prePostTestCaseExecHooks.put("postAll", method);
				}
				claz = method.getDeclaringClass();
			}
		}
		return claz;
	}
	
	public List<Method> getPrePostHook(TestCase testCase, boolean isPreHook) {
		List<Method> methods = new ArrayList<Method>();
		String hookKey = (isPreHook?"pre":"post") + testCase.getName();
		Method meth = prePostTestCaseExecHooks.get(hookKey);
		if(meth!=null)
			methods.add(meth);
		meth = prePostTestCaseExecHooks.get((isPreHook?"preAll":"postAll"));
		if(meth!=null)
			methods.add(meth);
		return methods;
	}
	
	public File getResourceFile(String filename) {
		File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
	    File testPath = new File(basePath, gatfExecutorConfig.getTestCaseDir());
	    File resource = new File(testPath, filename);
        if(!resource.exists()) {
            resource = new File(basePath, filename);
        }
		return resource;
	}
	
	public File getNewOutResourceFile(String filename) {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		File file = new File(resource, filename);
		if(!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
			}
		}
		return file;
	}
	
	public File getOutDir() {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		return resource;
	}
	
	public String getOutDirPath() {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		return resource.getAbsolutePath();
	}
	
	public Map<String, List<TestCase>> getRelatedTestCases() {
		return relatedTestCases;
	}

	public static void removeFolder(File folder)
	{
		if(folder==null || !folder.exists())return;
		try {
			FileUtils.deleteDirectory(folder);
		} catch (IOException e) {
		}
	}
	
	public void validateAndInit(boolean flag) throws Exception
	{
		gatfExecutorConfig.validate();
		
		if(gatfExecutorConfig.getOutFilesBasePath()!=null)
		{
			File basePath = new File(gatfExecutorConfig.getOutFilesBasePath().trim());
			Assert.assertTrue("Invalid out files base path..", basePath.exists());
			gatfExecutorConfig.setOutFilesBasePath(basePath.getAbsolutePath());
		}
		else
		{
			File basePath = new File(System.getProperty("user.dir"));
			gatfExecutorConfig.setOutFilesBasePath(basePath.getAbsolutePath());
		}
		
		if(gatfExecutorConfig.getTestCasesBasePath()!=null)
		{
			File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
			Assert.assertTrue("Invalid test cases base path..", basePath.exists());
			gatfExecutorConfig.setTestCasesBasePath(basePath.getAbsolutePath());
		}
		else
		{
			File basePath = new File(System.getProperty("user.dir"));
			gatfExecutorConfig.setTestCasesBasePath(basePath.getAbsolutePath());
		}
		
		Assert.assertEquals("Testcase directory not found...", getResourceFile(gatfExecutorConfig.getTestCaseDir()).exists(), true);
		
		if(StringUtils.isNotBlank(gatfExecutorConfig.getBaseUrl()))
		{
			Assert.assertTrue("Base URL is not valid", AcceptanceTestContext.isValidUrl(gatfExecutorConfig.getBaseUrl()));
		}
		
		if(gatfExecutorConfig.getOutFilesDir()!=null && !gatfExecutorConfig.getOutFilesDir().trim().isEmpty())
		{
			try
			{
				if(gatfExecutorConfig.getOutFilesBasePath()!=null)
				{
					File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
					File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
					if(flag)
					{
						removeFolder(resource);
						File nresource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
						nresource.mkdirs();
						Assert.assertTrue("Out files directory could not be created...", nresource.exists());
					}
				}
				else
				{
					File resource = new File(System.getProperty("user.dir"));
					File file = new File(resource, gatfExecutorConfig.getOutFilesDir());
					if(flag)
					{
						removeFolder(file);
						File nresource = new File(resource, gatfExecutorConfig.getOutFilesDir());
						nresource.mkdir();
						Assert.assertTrue("Out files directory could not be created...", nresource.exists());
					}
				}
			} catch (Exception e) {
				gatfExecutorConfig.setOutFilesDir(null);
			}
			Assert.assertNotNull("Testcase out file directory not found...", gatfExecutorConfig.getOutFilesDir());
		}
		else
		{
			File resource = new File(System.getProperty("user.dir"));
			if(flag)
			{
				removeFolder(resource);
				File nresource = new File(System.getProperty("user.dir"), "out");
				nresource.mkdir();
			}
			gatfExecutorConfig.setOutFilesDir("out");
			gatfExecutorConfig.setOutFilesBasePath(System.getProperty("user.dir"));
		}
		
		if(flag)
		{
			initSoapContextAndHttpHeaders();
			
			initTestDataProviderAndGlobalVariables();
		}
		
		initServerLogsApis();
	}
	
	public void initServerLogsApis() throws Exception {
		File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
		File resource = new File(basePath, GATF_SERVER_LOGS_API_FILE_NM);
		if(resource.exists() && gatfExecutorConfig.isFetchFailureLogs()) {
			TestCaseFinder finder = new XMLTestCaseFinder();
			serverLogsApiLst.clear();
			serverLogsApiLst.addAll(finder.resolveTestCases(resource));
			for (TestCase testCase : serverLogsApiLst) {
				testCase.setSourcefileName(GATF_SERVER_LOGS_API_FILE_NM);
				if(testCase.getSimulationNumber()==null)
				{
					testCase.setSimulationNumber(0);
				}
				testCase.setExternalApi(true);
				testCase.validate(getHttpHeaders(), null);
			}
		}
	}

	private void initTestDataProviderAndGlobalVariables() throws Exception {
		GatfTestDataConfig gatfTestDataConfig = null;
		if(gatfExecutorConfig.getTestDataConfigFile()!=null) {
			File file = getResourceFile(gatfExecutorConfig.getTestDataConfigFile());
			Assert.assertNotNull("Testdata configuration file not found...", file);
			Assert.assertEquals("Testdata configuration file not found...", file.exists(), true);
			
			if(gatfExecutorConfig.getTestDataConfigFile().trim().endsWith(".xml")) {
				XStream xstream = new XStream(new DomDriver("UTF-8"));
		       
		        xstream.allowTypes(new Class[]{GatfTestDataConfig.class, GatfTestDataProvider.class});
				xstream.processAnnotations(new Class[]{GatfTestDataConfig.class, GatfTestDataProvider.class});
				xstream.alias("gatf-testdata-provider", GatfTestDataProvider.class);
				xstream.alias("args", String[].class);
				xstream.alias("arg", String.class);
				gatfTestDataConfig = (GatfTestDataConfig)xstream.fromXML(file);
			} else  {
				gatfTestDataConfig = WorkflowContextHandler.OM.readValue(file, GatfTestDataConfig.class);
			}
			gatfExecutorConfig.setGatfTestDataConfig(gatfTestDataConfig);
		} else {
			gatfTestDataConfig = gatfExecutorConfig.getGatfTestDataConfig();
		}
		
		handleTestDataSourcesAndHooks(gatfTestDataConfig);
	}

	public void handleTestDataSourcesAndHooks(GatfTestDataConfig gatfTestDataConfig) {
		if(gatfTestDataConfig!=null) {
			getWorkflowContextHandler().addGlobalVariables(gatfTestDataConfig.getGlobalVariables());
			
			if(gatfTestDataConfig.getDataSourceList()!=null)
			{
				handleDataSources(gatfTestDataConfig.getDataSourceList(), false);
			}
			
			if(gatfTestDataConfig.getDataSourceListForProfiling()!=null)
			{
				handleDataSources(gatfTestDataConfig.getDataSourceListForProfiling(), true);
			}
			
			if(gatfTestDataConfig.getDataSourceHooks()!=null)
			{
				handleHooks(gatfTestDataConfig.getDataSourceHooks());
			}
				
			if(gatfTestDataConfig.getProviderTestDataList()!=null)
			{
				handleProviders(gatfTestDataConfig.getProviderTestDataList());
			}
		}
	}

	public static Map<String, String> getHttpHeadersMap() throws Exception
	{
		Map<String, String> headers = new HashMap<String, String>();
		Field[] declaredFields = HttpHeaders.class.getDeclaredFields();
		for (Field field : declaredFields) {
			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())
					&& field.getType().equals(String.class)) {
				headers.put(field.get(null).toString().toLowerCase(), field.get(null).toString());
			}
		}
		return headers;
	}
	
	private void initSoapContextAndHttpHeaders() throws Exception
	{
		Field[] declaredFields = HttpHeaders.class.getDeclaredFields();
		for (Field field : declaredFields) {
			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())
					&& field.getType().equals(String.class)) {
				httpHeaders.put(field.get(null).toString().toLowerCase(), field.get(null).toString());
			}
		}
		
		File file = null;
		if(gatfExecutorConfig.getWsdlLocFile()!=null && !gatfExecutorConfig.getWsdlLocFile().trim().isEmpty())
			file = getResourceFile(gatfExecutorConfig.getWsdlLocFile());
		
		if(file!=null)
		{
			Scanner s = new Scanner(file);
			s.useDelimiter("\n");
			List<String> list = new ArrayList<String>();
			while (s.hasNext()) {
				list.add(s.next().replace("\r", ""));
			}
			s.close();
	
			for (String wsdlLoc : list) {
				if(!wsdlLoc.trim().isEmpty())
				{
					String[] wsdlLocParts = wsdlLoc.split(",");
					logger.info("Started Parsing WSDL location - " + wsdlLocParts[1]);
					Wsdl wsdl = Wsdl.parse(wsdlLocParts[1]);
					for (QName bindingName : wsdl.getBindings()) {
						SoapBuilder builder = wsdl.getBuilder(bindingName);
						for (SoapOperation operation : builder.getOperations()) {
							String request = builder.buildInputMessage(operation);
							DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
							DocumentBuilder db = dbf.newDocumentBuilder();
							Document soapMessage = db.parse(new ByteArrayInputStream(request.getBytes()));
							
							if(gatfExecutorConfig.isDistributedLoadTests()) {
								soapStrMessages.put(wsdlLocParts[0]+operation.getOperationName(), request);
							}
							
							soapMessages.put(wsdlLocParts[0]+operation.getOperationName(), soapMessage);
							if(operation.getSoapAction()!=null) {
								soapActions.put(wsdlLocParts[0]+operation.getOperationName(), operation.getSoapAction());
							}
							logger.info("Adding message for SOAP operation - " + operation.getOperationName());
						}
						soapEndpoints.put(wsdlLocParts[0], builder.getServiceUrls().get(0));
						logger.info("Adding SOAP Service endpoint - " + builder.getServiceUrls().get(0));
					}
					logger.info("Done Parsing WSDL location - " + wsdlLocParts[1]);
				}
			}
		}
	}

	public void shutdown() {
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooksMap.values()) {
			TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
			
			Assert.assertNotNull("No DataSource found", dataSource);
			
			if(dataSourceHook.isExecuteOnShutdown() && dataSourceHook.getQueryStrs()!=null) {
				for (String query : dataSourceHook.getQueryStrs()) {
					boolean flag = false;
					try {
						flag = dataSource.execute(query);
					} catch (Throwable e) {
					}
					if(!flag) {
						logger.severe("Shutdown DataSourceHook execution for " + dataSourceHook.getHookName()
								+ " failed, queryString = " + query);
					}
				}
			}
		}
		
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooksMap.values()) {
			TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
			
			Assert.assertNotNull("No DataSource found", dataSource);
			
			dataSource.destroy();
		}
	}
	
	public void executeDataSourceHook(String hookName) {
		GatfTestDataSourceHook dataSourceHook = dataSourceHooksMap.get(hookName);
		Assert.assertNotNull("No DataSourceHook found", dataSourceHook);
		
		TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
		Assert.assertNotNull("No DataSource found", dataSource);
		
		for (String query : dataSourceHook.getQueryStrs()) {
			boolean flag = dataSource.execute(query);
			if(!flag) {
				Assert.assertNotNull("DataSourceHook execution for " + dataSourceHook.getHookName()
						+ " failed...", null);
			}
		}
	}
	
	@SuppressWarnings("rawtypes")
	private void handleDataSources(List<GatfTestDataSource> dataSourceList, boolean forProfiling)
	{
		for (GatfTestDataSource dataSource : dataSourceList) {
			Assert.assertNotNull("DataSource name is not defined", dataSource.getDataSourceName());
			Assert.assertNotNull("DataSource class is not defined", dataSource.getDataSourceClass());
			Assert.assertNotNull("DataSource args not defined", dataSource.getArgs());
			Assert.assertTrue("DataSource args empty", dataSource.getArgs().length>0);
			Assert.assertNull("Duplicate DataSource name found", dataSourceMap.get(dataSource.getDataSourceName()));
			
			TestDataSource testDataSource = null;
			if(SQLDatabaseTestDataSource.class.getCanonicalName().equals(dataSource.getDataSourceClass())) {
				testDataSource = new SQLDatabaseTestDataSource();
			} else if(MongoDBTestDataSource.class.getCanonicalName().equals(dataSource.getDataSourceClass())) {
				testDataSource = new MongoDBTestDataSource();
			} else {
				try {
					Class claz = loadCustomClass(dataSource.getDataSourceClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataSource.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("DataSource class should extend the TestDataSource class", validProvider);
					@SuppressWarnings("unchecked")
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataSource = (TestDataSource)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			}
			
			testDataSource.setClassName(dataSource.getDataSourceClass());
			testDataSource.setArgs(dataSource.getArgs());
			testDataSource.setContext(this);
			testDataSource.setDataSourceName(dataSource.getDataSourceName());
			if(dataSource.getPoolSize()>1)
			{
				testDataSource.setPoolSize(dataSource.getPoolSize());
			}
			
			if(forProfiling)
			{
				testDataSource.setPoolSize(1);
				testDataSource.init();
				dataSourceMapForProfiling.put(dataSource.getDataSourceName(), testDataSource);
			}
			else
			{
				testDataSource.init();
				dataSourceMap.put(dataSource.getDataSourceName(), testDataSource);
			}
		}
	}
	
	public Map<String, TestDataSource> getDataSourceMapForProfiling()
	{
		return dataSourceMapForProfiling;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void handleHooks(List<GatfTestDataSourceHook> dataSourceHooks)
	{
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooks) {
			Assert.assertNotNull("DataSourceHook name is not defined", dataSourceHook.getHookName());
			Assert.assertNotNull("DataSourceHook query string is not defined", dataSourceHook.getQueryStrs());
			Assert.assertNull("Duplicate DataSourceHook name found", dataSourceHooksMap.get(dataSourceHook.getHookName()));
			
			TestDataSource dataSource = null;
			if(dataSourceHook.getDataSourceName()!=null && dataSourceHook.getHookClass()==null)
			{
				dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
				Assert.assertNotNull("No DataSource found", dataSource);
			}
			else if(dataSourceHook.getDataSourceName()!=null && dataSourceHook.getHookClass()!=null)
			{
				Assert.assertNotNull("Specify either hookClass or dataSourceName", null);
			}
			else if(dataSourceHook.getDataSourceName()==null && dataSourceHook.getHookClass()==null)
			{
				Assert.assertNotNull("Specify any one of hookClass or dataSourceName", null);
			}
			
			dataSourceHooksMap.put(dataSourceHook.getHookName(), dataSourceHook);
			
			TestDataHook testDataHook = null;
			if(dataSourceHook.getHookClass()!=null) {
				try {
					Class claz = loadCustomClass(dataSourceHook.getHookClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataProvider.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("Hook class should implement the TestDataHook class", validProvider);
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataHook = (TestDataHook)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			} else {
				testDataHook = dataSource;
			}
			
			if(dataSourceHook.isExecuteOnStart()) {
				for (String query : dataSourceHook.getQueryStrs()) {
					boolean flag = false;
					try {
						flag = testDataHook.execute(query);
					} catch (Throwable e) {
					}
					if(!flag) {
						logger.severe("Startup DataSourceHook execution for " + dataSourceHook.getHookName()
								+ " failed, queryString = " + query);
					}
				}
			}
		}
	}
	
	private void handleProviders(List<GatfTestDataProvider> providerTestDataList)
	{
		for (GatfTestDataProvider provider : providerTestDataList) {
			Assert.assertNotNull("Provider name is not defined", provider.getProviderName());
			
			Assert.assertNotNull("Provider properties is not defined", provider.getProviderProperties());
			
			Assert.assertNull("Duplicate Provider name found", providerTestDataMap.get(provider.getProviderName()));
			
			TestDataSource dataSource = null;
			if(provider.getDataSourceName()!=null && provider.getProviderClass()==null)
			{	
				Assert.assertNotNull("Provider DataSource name is not defined", provider.getDataSourceName());
				dataSource = dataSourceMap.get(provider.getDataSourceName());
				
				Assert.assertNotNull("No DataSource found", dataSource);
				
				if(dataSource instanceof MongoDBTestDataSource)
				{
					Assert.assertNotNull("Provider query string is not defined", provider.getQueryStr());
					Assert.assertNotNull("Provider source properties not defined", provider.getSourceProperties());
				}
				
				if(dataSource instanceof SQLDatabaseTestDataSource)
				{
					Assert.assertNotNull("Provider query string is not defined", provider.getQueryStr());
				}
			}
			else if(provider.getDataSourceName()!=null && provider.getProviderClass()!=null)
			{
				Assert.assertNotNull("Specify either providerClass or dataSourceName", null);
			}
			else if(provider.getDataSourceName()==null && provider.getProviderClass()==null)
			{
				Assert.assertNotNull("Specify any one of providerClass or dataSourceName", null);
			}
			
			
			if(provider.isEnabled()==null) {
				provider.setEnabled(true);
			}
			
			if(!provider.isEnabled()) {
				logger.info("Provider " + provider.getProviderName() + " is Disabled...");
				continue;
			}
			
			if(provider.isLive()) {
				liveProviders.put(provider.getProviderName(), provider);
				logger.info("Provider " + provider.getProviderName() + " is a Live one...");
				continue;
			}
			
			List<Map<String, String>> testData = getProviderData(provider, null);
			if(gatfExecutorConfig.isSeleniumExecutor() && gatfExecutorConfig.getConcurrentUserSimulationNum()>1) {
			    for (int i = 0; i < gatfExecutorConfig.getConcurrentUserSimulationNum(); i++)
                {
			        if(FileTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
			            if(i==0) {
			                providerTestDataMap.put(provider.getProviderName()+(i+1), testData);
			                continue;
			            }
			            GatfTestDataProvider tp = new GatfTestDataProvider(provider);
	                    tp.setProviderName(provider.getProviderName()+(i+1));
	                    tp.getArgs()[0] = tp.getArgs()[0] + i;
	                    try {
	                        logger.info("Concurrent simulation scenario #"+(i+1)+" fetching provider with filePath "+tp.getArgs()[0]);
	                        List<Map<String, String>> testDataT = getProviderData(tp, null);
	                        if(testDataT==null) {
	                            testDataT = testData;
	                        }
	                        providerTestDataMap.put(tp.getProviderName(), testDataT);
	                    } catch (Throwable e) {
	                        logger.severe("Cannot find data provider for the concurrent simulation scenario #"+(i+1)+" with name " + tp.getProviderName());
	                        providerTestDataMap.put(tp.getProviderName(), testData);
	                    }
			        } else {
			            logger.severe("Concurrent simulation scenarios need file data providers");
			        }
                }
			} else {
			    providerTestDataMap.put(provider.getProviderName(), testData);
			}
		}
	}
	
	public List<Map<String, String>> getLiveProviderData(String provName, TestCase testCase)
	{
		GatfTestDataProvider provider = liveProviders.get(provName);
		return getProviderData(provider, testCase);
	}
	
	public List<Map<String, String>> getAnyProviderData(String provName, TestCase testCase)
	{
		if(liveProviders.containsKey(provName))
		{
			GatfTestDataProvider provider = liveProviders.get(provName);
			return getProviderData(provider, testCase);
		}
		else
		{
			return providerTestDataMap.get(provName);
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List<Map<String, String>> getProviderData(GatfTestDataProvider provider, TestCase testCase) {
		
		TestDataSource dataSource = dataSourceMap.get(provider.getDataSourceName());
		
		TestDataProvider testDataProvider = null;
		List<Map<String, String>> testData = null;
		if(provider.getProviderClass()!=null) {
			if(FileTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new FileTestDataProvider();
			} else if(InlineValueTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new InlineValueTestDataProvider();
			} else if(RandomValueTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new RandomValueTestDataProvider();
			} else {
				try {
					Class claz = loadCustomClass(provider.getProviderClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataProvider.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("Provider class should implement the TestDataProvider class", validProvider);
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataProvider = (TestDataProvider)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			}
		} else {
			testDataProvider = dataSource;
		}
		
		//Live provider queries can have templatized parameter names
		if(provider.isLive() && provider.getQueryStr()!=null)
		{
			String oQs = provider.getQueryStr();
			provider = new GatfTestDataProvider(provider);
			if(testCase!=null)
			{
				provider.setQueryStr(getWorkflowContextHandler().evaluateTemplate(testCase, provider.getQueryStr(), this));
				if(provider.getQueryStr()==null || provider.getQueryStr().isEmpty()) {
					provider.setQueryStr(oQs);
				}
			}
		}
		
		testData = testDataProvider.provide(provider, this);
		if(testDataProvider instanceof FileTestDataProvider) {
			fileProviderStateMap.put(provider.getProviderName(), ((FileTestDataProvider)testDataProvider).getHash());
		}
		return testData;
	}

	public DistributedAcceptanceContext getDistributedContext(String node, List<Object[]> selTestdata)
	{
		DistributedAcceptanceContext distributedTestContext = new DistributedAcceptanceContext();
		distributedTestContext.setConfig(gatfExecutorConfig);
		distributedTestContext.setHttpHeaders(httpHeaders);
		distributedTestContext.setSoapActions(soapActions);
		distributedTestContext.setSoapEndpoints(soapEndpoints);
		distributedTestContext.setSoapMessages(soapStrMessages);
		distributedTestContext.setNode(node);
		distributedTestContext.setSelTestdata(selTestdata);
		
		return distributedTestContext;
	}
	
	@SuppressWarnings("rawtypes")
	private Class loadCustomClass(String className) throws ClassNotFoundException
	{
		return getProjectClassLoader().loadClass(className);
	}
	
	public List<TestCase> getServerLogsApiLst() {
		return serverLogsApiLst;
	}
	
	public TestCase getServerLogApi(boolean isAuth)
	{
		if(serverLogsApiLst.size()>0)
		{
			for (TestCase tc : serverLogsApiLst) {
				if(isAuth && gatfExecutorConfig.isServerLogsApiAuthEnabled() && "authapi".equals(tc.getName()))
				{
					tc.setServerApiAuth(true);
					tc.setExternalApi(true);
					return tc;
				}
				else if(!isAuth && "targetapi".equals(tc.getName()))
				{
					tc.setServerApiTarget(true);
					tc.setSecure(gatfExecutorConfig.isServerLogsApiAuthEnabled());
					tc.setExternalApi(true);
					return tc;
				}
			}
		}
		return null;
	}
}
 @XStreamAlias("TestCase")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class TestCase implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private static final Logger logger = Logger.getLogger(TestCase.class);
	
	private static final String PRE = UUID.randomUUID().toString() + "__";
	
	private static final Pattern quotedString = Pattern.compile("((?<![\\\\])['\"])((?:.(?!(?<![\\\\])\\1))*.?)\\1");
	
	public static final String[] CDATA_NODES = new String[]{"content","expectedResContent"};
	
	private String baseUrl;
	
	private String url;
	
	private String name;
	
	@XStreamAsAttribute
	private String method;
	
	private String description;
	
	private String content;
	
	private String contentFile;
	
	private Map<String, String> headers = new HashMap<String, String>();
	
	@XStreamAsAttribute
	private String exQueryPart;
	
	@XStreamAsAttribute
	private int expectedResCode;
	
	@XStreamAsAttribute
	private String expectedResContentType;
	
	private String expectedResContent;
	
	@XStreamAsAttribute
	private boolean skipTest;
	
	@XStreamAsAttribute
	private boolean detailedLog;
	
	@XStreamAsAttribute
	private boolean secure;
	
	private List<String> expectedNodes = new ArrayList<String>();
	
	@XStreamAsAttribute
	private boolean soapBase;
	
	private String wsdlKey;
	
	private String operationName;
	
	private Map<String, String> soapParameterValues = new HashMap<String, String>();
	
	private Map<String, String> workflowContextParameterMap = new HashMap<String, String>();
	
	@XStreamAsAttribute
	private int sequence = 0;
	
	private List<String> multipartContent = new ArrayList<String>();
	
	private String outFileName;
	
	private List<Map<String, String>> repeatScenarios = new ArrayList<Map<String,String>>();
	
	@XStreamOmitField
	@JsonIgnore
	private List<Map<String, String>> repeatScenariosOrig = new ArrayList<Map<String,String>>();
	
	private String repeatScenarioProviderName;
	
	@XStreamOmitField
	@JsonIgnore
	private String sourcefileName;
	
	@XStreamOmitField
	@JsonIgnore
	private String aurl;
	
	@XStreamOmitField
	@JsonIgnore
	private String aexQueryPart;
	
	@XStreamOmitField
	@JsonIgnore
	private String acontent;
	
	@XStreamOmitField
	@JsonIgnore
	private List<String> aexpectedNodes = new ArrayList<String>();
	
	@XStreamAsAttribute
	private Integer numberOfExecutions = 1;
	
	@XStreamAsAttribute
	private boolean repeatScenariosConcurrentExecution;
	
	@XStreamAsAttribute	
	private boolean stopOnFirstFailureForPerfTest;

	@XStreamOmitField
	@JsonIgnore
	private volatile boolean failed;
	
	@XStreamOmitField
	private Integer simulationNumber;
	
	@XStreamAsAttribute
	private Long preWaitMs;
	
	@XStreamAsAttribute
	private Long postWaitMs;
	
	@XStreamAsAttribute
	private Boolean reportResponseContent = true;
	
	private String preExecutionDataSourceHookName;
	
	private String postExecutionDataSourceHookName;
	
	@XStreamAsAttribute
	private boolean abortOnInvalidStatusCode;
	
	@XStreamAsAttribute
	private boolean abortOnInvalidContentType;
	
	private String relatedTestName;
	
	@XStreamOmitField
	@JsonIgnore
	//Parameters carried over from related testcases
	private Map<String, String> carriedOverVariables;
	
	@XStreamOmitField
	@JsonIgnore
	private String identifierPrefix =  "Run";
	
	private String executeOnCondition;
	
	private List<String> logicalValidations;
	
	@XStreamAsAttribute
	private boolean disablePreHooks = false;
	
	@XStreamAsAttribute
	private boolean disablePostHooks = false;
	
	@XStreamOmitField
	@JsonIgnore
	private Map<String, String> currentScenarioVariables;
	
	@XStreamOmitField
	@JsonIgnore
	private boolean isServerApiAuth = false;
	
	@XStreamOmitField
	@JsonIgnore
	private boolean isServerApiTarget = false;
	
	@XStreamOmitField
	@JsonIgnore
	private boolean isExternalApi = false;
	
	private PerformanceConfig perfConfig;
	
	public String getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getContentFile() {
		return contentFile;
	}

	public void setContentFile(String contentFile) {
		this.contentFile = contentFile;
	}

	public Map<String, String> getHeaders() {
		return headers;
	}

	public void setHeaders(Map<String, String> headers) {
		this.headers = headers;
	}

	public int getExpectedResCode() {
		return expectedResCode;
	}

	public void setExpectedResCode(int expectedResCode) {
		this.expectedResCode = expectedResCode;
	}

	public String getExpectedResContent() {
		return expectedResContent;
	}

	public void setExpectedResContent(String expectedResContent) {
		this.expectedResContent = expectedResContent;
	}

	public boolean isSkipTest() {
		return skipTest;
	}

	public void setSkipTest(boolean skipTest) {
		this.skipTest = skipTest;
	}

	public List<String> getExpectedNodes() {
		return expectedNodes;
	}

	public void setExpectedNodes(List<String> expectedNodes) {
		this.expectedNodes = expectedNodes;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getExpectedResContentType() {
		return expectedResContentType;
	}

	public void setExpectedResContentType(String expectedResContentType) {
		this.expectedResContentType = expectedResContentType;
	}

	public String getExQueryPart() {
		return exQueryPart;
	}

	public void setExQueryPart(String exQueryPart) {
		this.exQueryPart = exQueryPart;
	}

	public boolean isDetailedLog() {
		return detailedLog;
	}

	public void setDetailedLog(boolean detailedLog) {
		this.detailedLog = detailedLog;
	}

	public boolean isSecure() {
		return secure;
	}

	public void setSecure(boolean secure) {
		this.secure = secure;
	}

	public Map<String, String> getSoapParameterValues() {
		return soapParameterValues;
	}

	public void setSoapParameterValues(Map<String, String> soapParameterValues) {
		this.soapParameterValues = soapParameterValues;
	}
	
	public boolean isSoapBase() {
		return soapBase;
	}

	public void setSoapBase(boolean soapBase) {
		this.soapBase = soapBase;
	}
	
	public String getWsdlKey() {
		return wsdlKey;
	}

	public void setWsdlKey(String wsdlKey) {
		this.wsdlKey = wsdlKey;
	}

	public String getOperationName() {
		return operationName;
	}

	public void setOperationName(String operationName) {
		this.operationName = operationName;
	}

	public List<String> getMultipartContent() {
		return multipartContent;
	}

	public void setMultipartContent(List<String> multipartContent) {
		this.multipartContent = multipartContent;
	}
	
	public Map<String, String> getWorkflowContextParameterMap() {
		return workflowContextParameterMap;
	}

	public void setWorkflowContextParameterMap(
			Map<String, String> workflowContextParameterMap) {
		this.workflowContextParameterMap = workflowContextParameterMap;
	}

	public int getSequence() {
		return sequence;
	}

	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	public String getOutFileName() {
		return outFileName;
	}

	public void setOutFileName(String outFileName) {
		this.outFileName = outFileName;
	}

	public List<Map<String, String>> getRepeatScenarios() {
		return repeatScenarios;
	}

	public void setRepeatScenarios(List<Map<String, String>> repeatScenarios) {
		this.repeatScenarios = repeatScenarios;
	}

	public List<Map<String, String>> getRepeatScenariosOrig() {
		return repeatScenariosOrig;
	}

	public void setRepeatScenariosOrig(List<Map<String, String>> repeatScenariosOrig) {
		this.repeatScenariosOrig = repeatScenariosOrig;
	}

	public void setSourcefileName(String sourcefileName) {
		this.sourcefileName = sourcefileName;
	}

	public String getAurl() {
		return aurl;
	}

	public void setAurl(String aurl) {
		this.aurl = aurl;
	}

	public String getAexQueryPart() {
		return aexQueryPart;
	}

	public void setAexQueryPart(String aexQueryPart) {
		this.aexQueryPart = aexQueryPart;
	}

	public String getAcontent() {
		return acontent;
	}

	public void setAcontent(String acontent) {
		this.acontent = acontent;
	}

	public List<String> getAexpectedNodes() {
		return aexpectedNodes;
	}

	public void setAexpectedNodes(List<String> aexpectedNodes) {
		this.aexpectedNodes = aexpectedNodes;
	}

	public Integer getNumberOfExecutions() {
		return numberOfExecutions;
	}

	public void setNumberOfExecutions(Integer numberOfExecutions) {
		this.numberOfExecutions = numberOfExecutions;
	}
	
	public boolean isRepeatScenariosConcurrentExecution() {
		return repeatScenariosConcurrentExecution;
	}

	public void setRepeatScenariosConcurrentExecution(
			boolean repeatScenariosConcurrentExecution) {
		this.repeatScenariosConcurrentExecution = repeatScenariosConcurrentExecution;
	}

	public String getRepeatScenarioProviderName() {
		return repeatScenarioProviderName;
	}

	public void setRepeatScenarioProviderName(String repeatScenarioProviderName) {
		this.repeatScenarioProviderName = repeatScenarioProviderName;
	}

	public boolean isStopOnFirstFailureForPerfTest() {
		return stopOnFirstFailureForPerfTest;
	}

	public void setStopOnFirstFailureForPerfTest(
			boolean stopOnFirstFailureForPerfTest) {
		this.stopOnFirstFailureForPerfTest = stopOnFirstFailureForPerfTest;
	}

	public Integer getSimulationNumber() {
		return simulationNumber;
	}

	public void setSimulationNumber(Integer simulationNumber) {
		this.simulationNumber = simulationNumber;
	}

	public Long getPreWaitMs() {
		return preWaitMs;
	}

	public void setPreWaitMs(Long preWaitMs) {
		this.preWaitMs = preWaitMs;
	}

	public Long getPostWaitMs() {
		return postWaitMs;
	}

	public void setPostWaitMs(Long postWaitMs) {
		this.postWaitMs = postWaitMs;
	}

	public Boolean getReportResponseContent() {
		return reportResponseContent;
	}

	public void setReportResponseContent(Boolean reportResponseContent) {
		this.reportResponseContent = reportResponseContent;
	}

	public String getPreExecutionDataSourceHookName() {
		return preExecutionDataSourceHookName;
	}

	public void setPreExecutionDataSourceHookName(
			String preExecutionDataSourceHookName) {
		this.preExecutionDataSourceHookName = preExecutionDataSourceHookName;
	}

	public String getPostExecutionDataSourceHookName() {
		return postExecutionDataSourceHookName;
	}

	public void setPostExecutionDataSourceHookName(
			String postExecutionDataSourceHookName) {
		this.postExecutionDataSourceHookName = postExecutionDataSourceHookName;
	}

	public boolean isAbortOnInvalidStatusCode() {
		return abortOnInvalidStatusCode;
	}

	public void setAbortOnInvalidStatusCode(boolean abortOnInvalidStatusCode) {
		this.abortOnInvalidStatusCode = abortOnInvalidStatusCode;
	}

	public boolean isAbortOnInvalidContentType() {
		return abortOnInvalidContentType;
	}

	public void setAbortOnInvalidContentType(boolean abortOnInvalidContentType) {
		this.abortOnInvalidContentType = abortOnInvalidContentType;
	}

	public String getIdentifierPrefix() {
		if(identifierPrefix==null) {
			identifierPrefix = "Run";
		}
		return identifierPrefix;
	}

	public void setIdentifierPrefix(String identifierPrefix) {
		this.identifierPrefix = identifierPrefix;
	}

	public boolean isFailed() {
		return failed;
	}

	public void setFailed(boolean failed) {
		this.failed = failed;
	}

	public String getIdentifier() {
		if(getSimulationNumber()==null || getSimulationNumber()==0) {
			return sourcefileName;
		} else {
			return getIdentifierPrefix() + "-" + getSimulationNumber();
		}
	}
	
	public String getSourcefileName() {
		return sourcefileName;
	}
	
	public String getRelatedTestName() {
		return relatedTestName;
	}

	public void setRelatedTestName(String relatedTestName) {
		this.relatedTestName = relatedTestName;
	}

	public Map<String, String> getCarriedOverVariables() {
		return carriedOverVariables;
	}

	public void setCarriedOverVariables(Map<String, String> carriedOverVariables) {
		this.carriedOverVariables = carriedOverVariables;
	}

	public String getExecuteOnCondition() {
		return executeOnCondition;
	}

	public void setExecuteOnCondition(String executeOnCondition) {
		this.executeOnCondition = executeOnCondition;
	}

	public List<String> getLogicalValidations() {
		return logicalValidations;
	}

	public void setLogicalValidations(List<String> logicalValidations) {
		this.logicalValidations = logicalValidations;
	}

	public Map<String, String> getCurrentScenarioVariables() {
		return currentScenarioVariables;
	}

	public void setCurrentScenarioVariables(
			Map<String, String> currentScenarioVariables) {
		this.currentScenarioVariables = currentScenarioVariables;
	}

	public boolean isServerApiAuth() {
		return isServerApiAuth;
	}

	public void setServerApiAuth(boolean isServerApiAuth) {
		this.isServerApiAuth = isServerApiAuth;
	}

	public boolean isServerApiTarget() {
		return isServerApiTarget;
	}

	public void setServerApiTarget(boolean isServerApiTarget) {
		this.isServerApiTarget = isServerApiTarget;
	}

	public boolean isDisablePreHooks() {
		return disablePreHooks;
	}

	public void setDisablePreHooks(boolean disablePreHooks) {
		this.disablePreHooks = disablePreHooks;
	}

	public boolean isDisablePostHooks() {
		return disablePostHooks;
	}

	public void setDisablePostHooks(boolean disablePostHooks) {
		this.disablePostHooks = disablePostHooks;
	}

	public boolean isExternalApi() {
		return isExternalApi;
	}

	public void setExternalApi(boolean isExternalApi) {
		this.isExternalApi = isExternalApi;
	}

	public PerformanceConfig getPerfConfig() {
		return perfConfig;
	}

	public void setPerfConfig(PerformanceConfig perfConfig) {
		this.perfConfig = perfConfig;
	}

	@Override
	public String toString() {
		final int maxLen = 10;
		StringBuilder builder = new StringBuilder();
		builder.append("TestCase = [\n");
		builder.append("baseUrl=");
		builder.append(baseUrl);
		builder.append("\nurl=");
		builder.append(url);
		builder.append("\nname=");
		builder.append(name);
		builder.append("\nmethod=");
		builder.append(method);
		builder.append("\ndescription=");
		builder.append(description);
		builder.append("\ncontent=");
		builder.append(content);
		builder.append("\nheaders=");
		builder.append(headers != null ? toString(headers.entrySet(), maxLen)
				: null);
		builder.append("\nexQueryPart=");
		builder.append(exQueryPart);
		builder.append("\nexpectedResCode=");
		builder.append(expectedResCode);
		builder.append("\nexpectedResContentType=");
		builder.append(expectedResContentType);
		builder.append("\nexpectedResContent=");
		builder.append(expectedResContent);
		builder.append("\nskipTest=");
		builder.append(skipTest);
		builder.append("\ndetailedLog=");
		builder.append(detailedLog);
		builder.append("\nsecure=");
		builder.append(secure);
		builder.append("\nexpectedNodes=");
		builder.append(expectedNodes != null ? toString(expectedNodes, maxLen)
				: null);
		builder.append("\nsoapBase=");
		builder.append(soapBase);
		builder.append("\nwsdlKey=");
		builder.append(wsdlKey);
		builder.append("\noperationName=");
		builder.append(operationName);
		builder.append("\nsoapParameterValues=");
		builder.append(soapParameterValues != null ? toString(
				soapParameterValues.entrySet(), maxLen) : null);
		builder.append("\nworkflowContextParameterMap=");
		builder.append(workflowContextParameterMap != null ? toString(
				workflowContextParameterMap.entrySet(), maxLen) : null);
		builder.append("\nsequence=");
		builder.append(sequence);
		builder.append("\nfilesToUpload=");
		builder.append(multipartContent != null ? toString(multipartContent, maxLen)
				: null);
		builder.append("\noutFileName=");
		builder.append(outFileName);
		builder.append("\nrepeatScenarios=");
		builder.append(repeatScenarios != null ? toString(repeatScenarios,
				maxLen) : null);
		builder.append("\nrepeatScenarioProviderName=");
		builder.append(repeatScenarioProviderName);
		builder.append("\nsourcefileName=");
		builder.append(sourcefileName);
		builder.append("\naurl=");
		builder.append(aurl);
		builder.append("\naexQueryPart=");
		builder.append(aexQueryPart);
		builder.append("\nacontent=");
		builder.append(acontent);
		builder.append("\naexpectedNodes=");
		builder.append(aexpectedNodes != null ? toString(aexpectedNodes, maxLen)
				: null);
		builder.append("\nnumberOfExecutions=");
		builder.append(numberOfExecutions);
		builder.append("\nrepeatScenariosConcurrentExecution=");
		builder.append(repeatScenariosConcurrentExecution);
		builder.append("\nstopOnFirstFailureForPerfTest=");
		builder.append(stopOnFirstFailureForPerfTest);
		builder.append("\nfailed=");
		builder.append(failed);
		builder.append("\nsimulationNumber=");
		builder.append(simulationNumber);
		builder.append("\npreWaitMs=");
		builder.append(preWaitMs);
		builder.append("\npostWaitMs=");
		builder.append(postWaitMs);
		builder.append("\nreportResponseContent=");
		builder.append(reportResponseContent);
		builder.append("\npreExecutionDataSourceHookName=");
		builder.append(preExecutionDataSourceHookName);
		builder.append("\npostExecutionDataSourceHookName=");
		builder.append(postExecutionDataSourceHookName);
		builder.append("\nabortOnInvalidContentType=");
		builder.append(abortOnInvalidContentType);
		builder.append("\nabortOnInvalidStatusCode=");
		builder.append(abortOnInvalidStatusCode);
		builder.append("\nrelatedTestName=");
		builder.append(relatedTestName);
		builder.append("\nexecuteOnCondition=");
		builder.append(executeOnCondition);
		builder.append("\nlogicalValidations=");
		builder.append(logicalValidations != null ? toString(logicalValidations, maxLen)
				: null);
		builder.append("]\n");
		return builder.toString();
	}

	private String toString(Collection<?> collection, int maxLen) {
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		int i = 0;
		for (Iterator<?> iterator = collection.iterator(); iterator.hasNext()
				&& i < maxLen; i++) {
			if (i > 0)
				builder.append(", ");
			builder.append(iterator.next());
		}
		builder.append("]");
		return builder.toString();
	}

	public TestCase() {
	}
	
	public TestCase(String[] csvP) {
		boolean valid = false;
		if(csvP!=null) {
			List<String> csvParts = Arrays.asList(csvP);
			for (int i = 0; i < csvParts.size(); i++) {
				setProperties(csvParts, i);
			}
			valid = csvParts.size()>4;
		} else {
			valid = false;
		}
		if(!valid)
		{
			throw new RuntimeException("Invalid CSV data provided for creating TestCase");
		}
	}
	
	public TestCase(String[] csvP, Map<Integer, Integer> mappings) {
		boolean valid = false;
		if(csvP!=null) {
			List<String> csvParts = Arrays.asList(csvP);
			List<String> csvPartsN = new ArrayList<String>(40);
			for (int i = 0; i < 40; i++) {
				csvPartsN.add(null);
			}
			for (int i = 0; i < csvParts.size(); i++) {
				if(mappings.get(i)!=null)
				{
					csvPartsN.set(mappings.get(i), csvParts.get(i));
				}
			}
			for (int i = 0; i < csvPartsN.size(); i++) {
				setProperties(csvPartsN, i);
			}
			valid = csvPartsN.size()>4;
		} else {
			valid = false;
		}
		if(!valid)
		{
			throw new RuntimeException("Invalid CSV data provided for creating TestCase");
		}
	}
	
	public String toCSV() {
		StringBuilder build = new StringBuilder();
		build.append(getCsvValue(getUrl()));
		build.append(",");
		build.append(getCsvValue(getName()));
		build.append(",");
		build.append(getCsvValue(getMethod()));
		build.append(",");
		build.append(getCsvValue(getDescription()));
		build.append(",");
		build.append(getCsvValue(getContent()));
		build.append(",");
		if(getHeaders()!=null)
		{
			for (Map.Entry<String, String> entry : getHeaders().entrySet()) {
				build.append(getInternalCsvValue(entry.getKey()));
				build.append(":");
				build.append(getInternalCsvValue(entry.getValue()));
				build.append("|");
			}
		}
		build.append(",");
		build.append(getCsvValue(getExQueryPart()));
		build.append(",");
		build.append(getExpectedResCode());
		build.append(",");
		build.append(getCsvValue(getExpectedResContentType()));
		build.append(",");
		build.append(getCsvValue(getExpectedResContent()));
		build.append(",");
		if(getExpectedNodes()!=null)
		{
			for (String node : getExpectedNodes()) {
				build.append(getInternalCsvValue(node));
				build.append("|");
			}
		}
		build.append(",");
		build.append(isSkipTest());
		build.append(",");
		build.append(isDetailedLog());
		build.append(",");
		build.append(isSecure());
		build.append(",");
		if(getMultipartContent()!=null)
		{
			for (String node : getMultipartContent()) {
				build.append(getInternalCsvValue(node));
				build.append("|");
			}
		}
		build.append(",");
		build.append(isSoapBase());
		build.append(",");
		if(getSoapParameterValues()!=null)
		{
			for (Map.Entry<String, String> entry : getSoapParameterValues().entrySet()) {
				build.append(getInternalCsvValue(entry.getKey()));
				build.append(":");
				build.append(getInternalCsvValue(entry.getValue()));
				build.append("|");
			}
		}
		build.append(",");
		build.append(getCsvValue(getWsdlKey()));
		build.append(",");
		build.append(getCsvValue(getOperationName()));
		build.append(",");
		build.append(getSequence());
		build.append(",");
		if(getWorkflowContextParameterMap()!=null)
		{
			for (Map.Entry<String, String> entry : getWorkflowContextParameterMap().entrySet()) {
				build.append(getInternalCsvValue(entry.getKey()));
				build.append(":");
				build.append(getInternalCsvValue(entry.getValue()));
				build.append("|");
			}
		}
		build.append(",");
		build.append(getCsvValue(getOutFileName()));
		build.append(",");
		build.append(getCsvValue(getRepeatScenarioProviderName()));
		build.append(",");
		build.append(getNumberOfExecutions());
		build.append(",");
		build.append(isRepeatScenariosConcurrentExecution());
		build.append(",");
		build.append(isStopOnFirstFailureForPerfTest());
		build.append(",");
		build.append(getPreWaitMs());
		build.append(",");
		build.append(getPostWaitMs());
		build.append(",");
		build.append(getReportResponseContent());
		build.append(",");
		build.append(getPreExecutionDataSourceHookName());
		build.append(",");
		build.append(getPostExecutionDataSourceHookName());
		build.append(",");
		build.append(isAbortOnInvalidContentType());
		build.append(",");
		build.append(isAbortOnInvalidStatusCode());
		build.append(",");
		build.append(getRelatedTestName());
		build.append(",");
		build.append(getExecuteOnCondition());
		build.append(",");
		if(getLogicalValidations()!=null)
		{
			for (String node : getLogicalValidations()) {
				build.append(getInternalCsvValue(node));
				build.append(":");
			}
		}
		return build.toString();
	}
	
	private String getCsvValue(String value)
	{
		if(value==null) {
			return "";
		} else {
			return "\"" + value + "\"";
		}
	}
	
	private String getInternalCsvValue(String value)
	{
		if(value==null) {
			return "";
		} else {
			return value.replaceAll(",", "").replaceAll("\\|", "").replaceAll("\n", "");
		}
	}
	
	public void validate(Map<String, String> httpHeaders, String baseUrl) {
		
		if(StringUtils.isBlank(getName()))
			throw new RuntimeException("Blank Name specified for testcase");
		
		if(!isSoapBase())
		{
			if(StringUtils.isBlank(baseUrl) && StringUtils.isBlank(getBaseUrl()))
				throw new RuntimeException("No Base URL specified");
				
			if(StringUtils.isNotBlank(getBaseUrl()))
				Assert.assertTrue("Base URL is not valid", AcceptanceTestContext.isValidUrl(getBaseUrl()));
			
			String fullUrl = StringUtils.isBlank(getBaseUrl())?baseUrl:getBaseUrl();
			fullUrl = fullUrl.trim() + "/" + getUrl().trim();
			String parturl = fullUrl.substring(fullUrl.indexOf("://")+3);
			fullUrl = fullUrl.substring(0, fullUrl.indexOf("://")+3) + parturl.replace("//", "/");
			
			if(StringUtils.isBlank(getUrl()))
				throw new RuntimeException("Blank URL sepcified for testcase");
			
			if(StringUtils.isBlank(getMethod()))
				throw new RuntimeException("Blank HTTP Method specified for testcase");
			
			if(!getMethod().toUpperCase().equals(HttpMethod.GET) && !getMethod().toUpperCase().equals(HttpMethod.PUT)
					&& !getMethod().toUpperCase().equals(HttpMethod.POST) && !getMethod().toUpperCase().equals(HttpMethod.DELETE))
				throw new RuntimeException("Invalid HTTP Method specified for testcase");
			
			//if(("POST".equalsIgnoreCase(getMethod()) || "PUT".equalsIgnoreCase(getMethod())) && getHeaders().isEmpty())
			//	throw new RuntimeException("No Content-Type Header provided");
		}
		
		Map<String, String> nHeaders = new HashMap<String, String>();
		if(getHeaders()!=null)
		{
			for (Map.Entry<String, String> entry : getHeaders().entrySet()) {
				if(httpHeaders.containsKey(entry.getKey().toLowerCase())) {
					nHeaders.put(httpHeaders.get(entry.getKey().toLowerCase()), entry.getValue());
				} else {
					logger.info("Custom HTTP Header " + entry.getKey() + " specified for testcase");
					nHeaders.put(entry.getKey(), entry.getValue());
				}
			}
			setHeaders(nHeaders);
		}
		
		if(!isSoapBase() && (StringUtils.isNotBlank(getContent()) || StringUtils.isNotBlank(getContentFile())) && 
				(getHeaders()==null || !getHeaders().containsKey(HttpHeaders.CONTENT_TYPE)))
			throw new RuntimeException("No Content-Type Header provided");
		
		/*try {
			MediaType.valueOf(getHeaders().get(HttpHeaders.CONTENT_TYPE));
		} catch (Exception e) {
			throw new RuntimeException("Invalid Content-Type Header specified for testcase");
		}*/
		
		try {
			Status.fromStatusCode(getExpectedResCode());
		} catch (Exception e) {
			throw new RuntimeException("Invalid expected Status code specified for testcase");
		}
		
		if(StringUtils.isNotBlank(getExpectedResContentType()))
		{
			try {
				MediaType.valueOf(getExpectedResContentType());
				getHeaders().put(HttpHeaders.ACCEPT, getExpectedResContentType());
			} catch (Exception e) {
				//throw new RuntimeException("Invalid expected response content type specified for testcase");
			}
		}
		
		setExQueryPart(getExQueryPart()==null?"":getExQueryPart());
		
		if(!isSoapBase())
		{
			if(getUrl().indexOf("?")==-1 && !getExQueryPart().trim().isEmpty()) {
				setUrl(getUrl() + "?" + getExQueryPart());
			} else if(getUrl().indexOf("?")!=-1 && !getExQueryPart().trim().isEmpty()) {
				setUrl(getUrl() + "&" + getExQueryPart());
			}
		}
		
		setDescription(getDescription()==null?"":getDescription());
		
		if(isSoapBase()) {
			if(getWsdlKey()==null || getOperationName()==null) {
				throw new RuntimeException("Invalid wsdlkey/operationName specified for testcase");
			}
		}
		
		if(getWorkflowContextParameterMap()!=null)
		{
			for (Map.Entry<String, String> entry : getWorkflowContextParameterMap().entrySet()) {
				if(!entry.getKey().trim().matches("(^[a-zA-Z][a-zA-Z0-9_]*)|(^[_][a-zA-Z0-9_]+)")) {
					throw new RuntimeException("Invalid workflow variable name " + entry.getKey() + " specified for testcase...skipping...");
				}
			}
		}
		
		if(getRepeatScenarios()!=null && !getRepeatScenarios().isEmpty()) {
			Assert.assertNull("Only one of repeatScenarios or repeatScenarioProviderName allowed", getRepeatScenarioProviderName());
		}
	}

	public TestCase(TestCase other) {
		super();
		this.url = other.url;
		this.name = other.name;
		this.method = other.method;
		this.description = other.description;
		this.content = other.content;
		if(other.headers!=null)
		{
			this.headers = new HashMap<String, String>(other.headers);
		}
		this.exQueryPart = other.exQueryPart;
		this.expectedResCode = other.expectedResCode;
		this.expectedResContentType = other.expectedResContentType;
		this.expectedResContent = other.expectedResContent;
		this.skipTest = other.skipTest;
		this.detailedLog = other.detailedLog;
		this.secure = other.secure;
		if(other.expectedNodes!=null)
		{
			this.expectedNodes = new ArrayList<String>(other.expectedNodes);
		}
		this.soapBase = other.soapBase;
		this.wsdlKey = other.wsdlKey;
		this.operationName = other.operationName;
		if(other.soapParameterValues!=null)
		{
			this.soapParameterValues = new HashMap<String, String>(other.soapParameterValues);
		}
		if(other.workflowContextParameterMap!=null)
		{
			this.workflowContextParameterMap = new HashMap<String, String>(other.workflowContextParameterMap);
		}
		this.sequence = other.sequence;
		this.multipartContent = other.multipartContent;
		this.outFileName = other.outFileName;
		if(other.repeatScenarios!=null)
		{
			this.repeatScenarios = new ArrayList<Map<String,String>>(other.repeatScenarios);
		}
		if(other.repeatScenariosOrig!=null)
		{
			this.repeatScenariosOrig = new ArrayList<Map<String,String>>(other.repeatScenariosOrig);
		}
		this.sourcefileName = other.sourcefileName;
		this.aurl = other.aurl;
		this.aexQueryPart = other.aexQueryPart;
		this.acontent = other.acontent;
		this.aexpectedNodes = new ArrayList<String>();
		this.numberOfExecutions = other.numberOfExecutions;
		this.repeatScenariosConcurrentExecution = other.repeatScenariosConcurrentExecution;
		this.stopOnFirstFailureForPerfTest = other.stopOnFirstFailureForPerfTest;
		this.failed = other.failed;
		this.simulationNumber = other.simulationNumber;
		this.baseUrl = other.baseUrl;
		this.preWaitMs = other.preWaitMs;
		this.postWaitMs = other.postWaitMs;
		this.reportResponseContent = other.reportResponseContent;
		this.repeatScenarioProviderName = other.repeatScenarioProviderName;
		this.preExecutionDataSourceHookName = other.preExecutionDataSourceHookName;
		this.postExecutionDataSourceHookName = other.postExecutionDataSourceHookName;
		this.abortOnInvalidContentType = other.abortOnInvalidContentType;
		this.abortOnInvalidStatusCode = other.abortOnInvalidStatusCode;
		this.identifierPrefix = other.identifierPrefix;
		this.relatedTestName = other.relatedTestName;
		this.carriedOverVariables = other.carriedOverVariables;
		this.executeOnCondition = other.executeOnCondition;
		this.logicalValidations = other.logicalValidations;
		this.currentScenarioVariables = other.currentScenarioVariables;
		this.isServerApiAuth = other.isServerApiAuth;
		this.isServerApiTarget = other.isServerApiTarget;
		this.isExternalApi = other.isExternalApi;
		this.perfConfig = other.perfConfig;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (abortOnInvalidContentType ? 1231 : 1237);
		result = prime * result + (abortOnInvalidStatusCode ? 1231 : 1237);
		result = prime * result
				+ ((acontent == null) ? 0 : acontent.hashCode());
		result = prime * result
				+ ((aexQueryPart == null) ? 0 : aexQueryPart.hashCode());
		result = prime * result
				+ ((aexpectedNodes == null) ? 0 : aexpectedNodes.hashCode());
		result = prime * result + ((aurl == null) ? 0 : aurl.hashCode());
		result = prime * result + ((baseUrl == null) ? 0 : baseUrl.hashCode());
		result = prime
				* result
				+ ((carriedOverVariables == null) ? 0 : carriedOverVariables
						.hashCode());
		result = prime * result + ((content == null) ? 0 : content.hashCode());
		result = prime * result
				+ ((description == null) ? 0 : description.hashCode());
		result = prime * result + (detailedLog ? 1231 : 1237);
		result = prime * result
				+ ((exQueryPart == null) ? 0 : exQueryPart.hashCode());
		result = prime
				* result
				+ ((executeOnCondition == null) ? 0 : executeOnCondition
						.hashCode());
		result = prime * result
				+ ((expectedNodes == null) ? 0 : expectedNodes.hashCode());
		result = prime * result + expectedResCode;
		result = prime
				* result
				+ ((expectedResContent == null) ? 0 : expectedResContent
						.hashCode());
		result = prime
				* result
				+ ((expectedResContentType == null) ? 0
						: expectedResContentType.hashCode());
		result = prime * result
				+ ((multipartContent == null) ? 0 : multipartContent.hashCode());
		result = prime * result + ((headers == null) ? 0 : headers.hashCode());
		result = prime
				* result
				+ ((identifierPrefix == null) ? 0 : identifierPrefix.hashCode());
		result = prime
				* result
				+ ((logicalValidations == null) ? 0 : logicalValidations
						.hashCode());
		result = prime * result + ((method == null) ? 0 : method.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime
				* result
				+ ((numberOfExecutions == null) ? 0 : numberOfExecutions
						.hashCode());
		result = prime * result
				+ ((operationName == null) ? 0 : operationName.hashCode());
		result = prime * result
				+ ((outFileName == null) ? 0 : outFileName.hashCode());
		result = prime
				* result
				+ ((postExecutionDataSourceHookName == null) ? 0
						: postExecutionDataSourceHookName.hashCode());
		result = prime * result
				+ ((postWaitMs == null) ? 0 : postWaitMs.hashCode());
		result = prime
				* result
				+ ((preExecutionDataSourceHookName == null) ? 0
						: preExecutionDataSourceHookName.hashCode());
		result = prime * result
				+ ((preWaitMs == null) ? 0 : preWaitMs.hashCode());
		result = prime * result
				+ ((relatedTestName == null) ? 0 : relatedTestName.hashCode());
		result = prime
				* result
				+ ((repeatScenarioProviderName == null) ? 0
						: repeatScenarioProviderName.hashCode());
		result = prime * result
				+ ((repeatScenarios == null) ? 0 : repeatScenarios.hashCode());
		result = prime * result
				+ (repeatScenariosConcurrentExecution ? 1231 : 1237);
		result = prime
				* result
				+ ((repeatScenariosOrig == null) ? 0 : repeatScenariosOrig
						.hashCode());
		result = prime
				* result
				+ ((reportResponseContent == null) ? 0 : reportResponseContent
						.hashCode());
		result = prime * result + (secure ? 1231 : 1237);
		result = prime * result + sequence;
		result = prime
				* result
				+ ((simulationNumber == null) ? 0 : simulationNumber.hashCode());
		result = prime * result + (skipTest ? 1231 : 1237);
		result = prime * result + (soapBase ? 1231 : 1237);
		result = prime
				* result
				+ ((soapParameterValues == null) ? 0 : soapParameterValues
						.hashCode());
		result = prime * result
				+ ((sourcefileName == null) ? 0 : sourcefileName.hashCode());
		result = prime * result + (stopOnFirstFailureForPerfTest ? 1231 : 1237);
		result = prime * result + ((url == null) ? 0 : url.hashCode());
		result = prime
				* result
				+ ((workflowContextParameterMap == null) ? 0
						: workflowContextParameterMap.hashCode());
		result = prime * result + ((wsdlKey == null) ? 0 : wsdlKey.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		TestCase other = (TestCase) obj;
		if (abortOnInvalidContentType != other.abortOnInvalidContentType)
			return false;
		if (abortOnInvalidStatusCode != other.abortOnInvalidStatusCode)
			return false;
		if (acontent == null) {
			if (other.acontent != null)
				return false;
		} else if (!acontent.equals(other.acontent))
			return false;
		if (aexQueryPart == null) {
			if (other.aexQueryPart != null)
				return false;
		} else if (!aexQueryPart.equals(other.aexQueryPart))
			return false;
		if (aexpectedNodes == null) {
			if (other.aexpectedNodes != null)
				return false;
		} else if (!aexpectedNodes.equals(other.aexpectedNodes))
			return false;
		if (aurl == null) {
			if (other.aurl != null)
				return false;
		} else if (!aurl.equals(other.aurl))
			return false;
		if (baseUrl == null) {
			if (other.baseUrl != null)
				return false;
		} else if (!baseUrl.equals(other.baseUrl))
			return false;
		if (carriedOverVariables == null) {
			if (other.carriedOverVariables != null)
				return false;
		} else if (!carriedOverVariables.equals(other.carriedOverVariables))
			return false;
		if (content == null) {
			if (other.content != null)
				return false;
		} else if (!content.equals(other.content))
			return false;
		if (description == null) {
			if (other.description != null)
				return false;
		} else if (!description.equals(other.description))
			return false;
		if (detailedLog != other.detailedLog)
			return false;
		if (exQueryPart == null) {
			if (other.exQueryPart != null)
				return false;
		} else if (!exQueryPart.equals(other.exQueryPart))
			return false;
		if (executeOnCondition == null) {
			if (other.executeOnCondition != null)
				return false;
		} else if (!executeOnCondition.equals(other.executeOnCondition))
			return false;
		if (expectedNodes == null) {
			if (other.expectedNodes != null)
				return false;
		} else if (!expectedNodes.equals(other.expectedNodes))
			return false;
		if (expectedResCode != other.expectedResCode)
			return false;
		if (expectedResContent == null) {
			if (other.expectedResContent != null)
				return false;
		} else if (!expectedResContent.equals(other.expectedResContent))
			return false;
		if (expectedResContentType == null) {
			if (other.expectedResContentType != null)
				return false;
		} else if (!expectedResContentType.equals(other.expectedResContentType))
			return false;
		if (multipartContent == null) {
			if (other.multipartContent != null)
				return false;
		} else if (!multipartContent.equals(other.multipartContent))
			return false;
		if (headers == null) {
			if (other.headers != null)
				return false;
		} else if (!headers.equals(other.headers))
			return false;
		if (identifierPrefix == null) {
			if (other.identifierPrefix != null)
				return false;
		} else if (!identifierPrefix.equals(other.identifierPrefix))
			return false;
		if (logicalValidations == null) {
			if (other.logicalValidations != null)
				return false;
		} else if (!logicalValidations.equals(other.logicalValidations))
			return false;
		if (method == null) {
			if (other.method != null)
				return false;
		} else if (!method.equals(other.method))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (numberOfExecutions == null) {
			if (other.numberOfExecutions != null)
				return false;
		} else if (!numberOfExecutions.equals(other.numberOfExecutions))
			return false;
		if (operationName == null) {
			if (other.operationName != null)
				return false;
		} else if (!operationName.equals(other.operationName))
			return false;
		if (outFileName == null) {
			if (other.outFileName != null)
				return false;
		} else if (!outFileName.equals(other.outFileName))
			return false;
		if (postExecutionDataSourceHookName == null) {
			if (other.postExecutionDataSourceHookName != null)
				return false;
		} else if (!postExecutionDataSourceHookName
				.equals(other.postExecutionDataSourceHookName))
			return false;
		if (postWaitMs == null) {
			if (other.postWaitMs != null)
				return false;
		} else if (!postWaitMs.equals(other.postWaitMs))
			return false;
		if (preExecutionDataSourceHookName == null) {
			if (other.preExecutionDataSourceHookName != null)
				return false;
		} else if (!preExecutionDataSourceHookName
				.equals(other.preExecutionDataSourceHookName))
			return false;
		if (preWaitMs == null) {
			if (other.preWaitMs != null)
				return false;
		} else if (!preWaitMs.equals(other.preWaitMs))
			return false;
		if (relatedTestName == null) {
			if (other.relatedTestName != null)
				return false;
		} else if (!relatedTestName.equals(other.relatedTestName))
			return false;
		if (repeatScenarioProviderName == null) {
			if (other.repeatScenarioProviderName != null)
				return false;
		} else if (!repeatScenarioProviderName
				.equals(other.repeatScenarioProviderName))
			return false;
		if (repeatScenarios == null) {
			if (other.repeatScenarios != null)
				return false;
		} else if (!repeatScenarios.equals(other.repeatScenarios))
			return false;
		if (repeatScenariosConcurrentExecution != other.repeatScenariosConcurrentExecution)
			return false;
		if (repeatScenariosOrig == null) {
			if (other.repeatScenariosOrig != null)
				return false;
		} else if (!repeatScenariosOrig.equals(other.repeatScenariosOrig))
			return false;
		if (reportResponseContent == null) {
			if (other.reportResponseContent != null)
				return false;
		} else if (!reportResponseContent.equals(other.reportResponseContent))
			return false;
		if (secure != other.secure)
			return false;
		if (sequence != other.sequence)
			return false;
		if (simulationNumber == null) {
			if (other.simulationNumber != null)
				return false;
		} else if (!simulationNumber.equals(other.simulationNumber))
			return false;
		if (skipTest != other.skipTest)
			return false;
		if (soapBase != other.soapBase)
			return false;
		if (soapParameterValues == null) {
			if (other.soapParameterValues != null)
				return false;
		} else if (!soapParameterValues.equals(other.soapParameterValues))
			return false;
		if (sourcefileName == null) {
			if (other.sourcefileName != null)
				return false;
		} else if (!sourcefileName.equals(other.sourcefileName))
			return false;
		if (stopOnFirstFailureForPerfTest != other.stopOnFirstFailureForPerfTest)
			return false;
		if (url == null) {
			if (other.url != null)
				return false;
		} else if (!url.equals(other.url))
			return false;
		if (workflowContextParameterMap == null) {
			if (other.workflowContextParameterMap != null)
				return false;
		} else if (!workflowContextParameterMap
				.equals(other.workflowContextParameterMap))
			return false;
		if (wsdlKey == null) {
			if (other.wsdlKey != null)
				return false;
		} else if (!wsdlKey.equals(other.wsdlKey))
			return false;
		return true;
	}
	
	protected static List<String> getAndSanitizeParts(String csvLine) {
		
		Matcher match = quotedString.matcher(csvLine);
		int i = 0;
		List<String> csvParts = new ArrayList<String>();
		Map<String, String> params = new HashMap<String, String>();
		while(match.find())
		{
			csvLine = csvLine.replace(match.group(0), PRE+i);
			params.put(PRE+i, match.group(2));
			i++;
		}
		String[] parts = csvLine.split(",");
		for (i=0;i<parts.length;i++) {
			String part = parts[i];
			if(params.containsKey(part)) {
				part = params.get(part);
			}
			csvParts.add(part);
		}
		return csvParts;
	}
	
	private void setProperties(List<String> csvParts, int index)
	{
		if(index==0 && csvParts.size()>0 && csvParts.get(0)!=null)
			setUrl(csvParts.get(0));
		if(index==1 && csvParts.size()>1 && csvParts.get(1)!=null)
			setName(csvParts.get(1));
		if(index==2 && csvParts.size()>2 && csvParts.get(2)!=null)
			setMethod(csvParts.get(2));
		if(index==3 && csvParts.size()>3 && csvParts.get(3)!=null)
			setDescription(csvParts.get(3));
		if(index==4 && csvParts.size()>4 && StringUtils.isNotBlank(csvParts.get(4)))
			setContent(StringEscapeUtils.unescapeJava(csvParts.get(4)));
		else if(index==4 && csvParts.size()>4)
			setContent(null);
		if(index==5 && csvParts.size()>5 && csvParts.get(5)!=null)
		{	
			setHeaders(new HashMap<String, String>());
			String[] headers = csvParts.get(5).split("\\|");
			for (String header : headers) {
				String[] kv = header.split(":");
				if(kv.length!=2) {
					logger.error("Invalid Header specified for testcase - " + header);
				}
				if(!kv[0].isEmpty() && !kv[1].isEmpty())
				{
					getHeaders().put(kv[0], kv[1]);
				}
			}
		}
		if(index==6 && csvParts.size()>6 && csvParts.get(6)!=null)
			setExQueryPart(csvParts.get(6));
		if(index==7 && csvParts.size()>7 && csvParts.get(7)!=null)
			setExpectedResCode(Integer.parseInt(csvParts.get(7)));
		if(index==8 && csvParts.size()>8 && csvParts.get(8)!=null)
			setExpectedResContentType(csvParts.get(8));
		if(index==9 && csvParts.size()>9 && StringUtils.isNotBlank(csvParts.get(9)))
			setExpectedResContent(StringEscapeUtils.unescapeJava(csvParts.get(9)));
		else if(index==9 && csvParts.size()>9)
			setExpectedResContent(null);
		if(index==10 && csvParts.size()>10 && csvParts.get(10)!=null)
		{
			setExpectedNodes(new ArrayList<String>());
			String[] nodes = csvParts.get(10).split("\\|");
			for (String node : nodes) {
				if(!node.isEmpty())
				{
					getExpectedNodes().add(node);
				}
			}
		}
		if(index==11 && csvParts.size()>11 && csvParts.get(11)!=null)
			setSkipTest(getBooleanValue(csvParts.get(11)));
		if(index==12 && csvParts.size()>12 && csvParts.get(12)!=null)
			setDetailedLog(getBooleanValue(csvParts.get(12)));
		if(index==13 && csvParts.size()>13 && csvParts.get(13)!=null)
			setSecure(getBooleanValue(csvParts.get(13)));
		if(index==14 && csvParts.size()>14 && csvParts.get(14)!=null)
		{
			setMultipartContent(new ArrayList<String>());
			String[] files = csvParts.get(14).split("\\|");
			for (String multfile : files) {
				if(!multfile.isEmpty())
				{
					String[] mulff = multfile.split(":");
					//controlname:type:filenameOrText:contentType
					if(mulff.length==4 || mulff.length==3) {
						getMultipartContent().add(multfile);
					}
				}
			}
		}
		if(index==15 && csvParts.size()>15 && csvParts.get(15)!=null)
			setSoapBase(getBooleanValue(csvParts.get(15)));
		if(index==16 && csvParts.size()>16 && csvParts.get(16)!=null)
		{
			setSoapParameterValues(new HashMap<String, String>());
			String[] soapVals = csvParts.get(16).split("\\|");
			for (String soapVal : soapVals) {
				String[] kv = soapVal.split(":");
				if(kv.length!=2) {
					logger.error("Invalid Soap Parameter key/value specified for testcase - " + soapVal);
				}
				if(!kv[0].isEmpty() && !kv[1].isEmpty())
				{
					getSoapParameterValues().put(kv[0], kv[1]);
				}
			}
		}
		if(index==17 && csvParts.size()>17 && csvParts.get(17)!=null)
			setWsdlKey(csvParts.get(17));
		if(index==18 && csvParts.size()>18 && csvParts.get(18)!=null)
			setOperationName(csvParts.get(18));
		if(index==19 && csvParts.size()>19 && csvParts.get(19)!=null)
			setSequence(Integer.parseInt(csvParts.get(19)));
		if(index==20 && csvParts.size()>20 && csvParts.get(20)!=null)
		{	
			setWorkflowContextParameterMap(new HashMap<String, String>());
			String[] workflowParams = csvParts.get(20).split("\\|");
			for (String workflowParam : workflowParams) {
				String[] kv = workflowParam.split(":");
				if(kv.length!=2) {
					logger.error("Invalid Workflow Parameter key/value specified for testcase - " + workflowParam);
				}
				if(!kv[0].isEmpty() && !kv[1].isEmpty())
				{
					getWorkflowContextParameterMap().put(kv[0], kv[1]);
				}
			}
		}
		if(index==21 && csvParts.size()>21 && csvParts.get(21)!=null)
			setOutFileName(csvParts.get(21));
		if(index==22 && csvParts.size()>22 && csvParts.get(22)!=null)
			setRepeatScenarioProviderName(csvParts.get(22));
		if(index==23 && csvParts.size()>23 && csvParts.get(23)!=null)
			setNumberOfExecutions(Integer.parseInt(csvParts.get(23)));
		if(index==24 && csvParts.size()>24 && csvParts.get(24)!=null)
			setRepeatScenariosConcurrentExecution(getBooleanValue(csvParts.get(24)));
		if(index==25 && csvParts.size()>25 && csvParts.get(25)!=null)
			setStopOnFirstFailureForPerfTest(getBooleanValue(csvParts.get(25)));
		if(index==26 && csvParts.size()>26 && csvParts.get(26)!=null)
			setPreWaitMs(Long.parseLong(csvParts.get(26)));
		if(index==27 && csvParts.size()>27 && csvParts.get(27)!=null)
			setPostWaitMs(Long.parseLong(csvParts.get(27)));
		if(index==28 && csvParts.size()>28 && csvParts.get(28)!=null)
			setReportResponseContent(getBooleanValue(csvParts.get(28)));
		if(index==29 && csvParts.size()>29 && csvParts.get(29)!=null)
			setPreExecutionDataSourceHookName(csvParts.get(29));
		if(index==30 && csvParts.size()>30 && csvParts.get(30)!=null)
			setPostExecutionDataSourceHookName(csvParts.get(30));
		if(index==31 && csvParts.size()>31 && csvParts.get(31)!=null)
			setAbortOnInvalidContentType(getBooleanValue(csvParts.get(31)));
		if(index==32 && csvParts.size()>32 && csvParts.get(32)!=null)
			setAbortOnInvalidStatusCode(getBooleanValue(csvParts.get(32)));
		if(index==33 && csvParts.size()>33 && csvParts.get(33)!=null)
			setRelatedTestName(csvParts.get(33));
		if(index==34 && csvParts.size()>34 && csvParts.get(34)!=null)
			setExecuteOnCondition(csvParts.get(34));
		if(index==35 && csvParts.size()>35 && csvParts.get(35)!=null)
		{
			setLogicalValidations(new ArrayList<String>());
			String[] nodes = csvParts.get(35).split(":");
			for (String node : nodes) {
				if(!node.isEmpty())
				{
					getLogicalValidations().add(node);
				}
			}
		}
		if(index==35)
		{	
			if(getNumberOfExecutions()==null)
				setNumberOfExecutions(1);
			if(getHeaders().size()==0)
				setHeaders(null);
			if(getExpectedNodes().size()==0)
				setExpectedNodes(null);
			if(getWorkflowContextParameterMap().size()==0)
				setWorkflowContextParameterMap(null);
			if(getSoapParameterValues().size()==0)
				setSoapParameterValues(null);
			if(getRepeatScenarios().size()==0)
				setRepeatScenarios(null);
			if(getMultipartContent().size()==0)
				setMultipartContent(null);
		}
	}
	
	private boolean getBooleanValue(String value)
	{
		if(value.trim().equalsIgnoreCase("y") || value.trim().equalsIgnoreCase("yes")
				|| value.trim().equalsIgnoreCase("1"))
			return true;
		else if(value.trim().equalsIgnoreCase("n") || value.trim().equalsIgnoreCase("no")
				|| value.trim().equalsIgnoreCase("0"))
			return false;
		return Boolean.valueOf(value);
	}
}
 public class AutocannonTestCaseExecutor {

	public static void execute(AcceptanceTestContext context, TestCase tc, TestCaseReport tcr, boolean isSingleExecutionContext) throws Exception {
		GatfExecutorConfig config = context.getGatfExecutorConfig();

		if(tc.getPerfConfig()!=null && tc.getPerfConfig().getType()!=null && tc.getPerfConfig().getType().startsWith("autocannon")) {
			List<String> builderList = new ArrayList<>();
			builderList.add(config.getAutocannonPath());
			
			Integer c = tc.getPerfConfig().getConnections();
			if(c>=0) {
				builderList.add("-c");
				builderList.add(c.toString());
			}
			
			Integer t = tc.getPerfConfig().getThreads();
			if(t>=0) {
				builderList.add("-w");
				builderList.add(t.toString());
			}
			
			Integer r = tc.getPerfConfig().getRate();
			if(r>0) {
				builderList.add("-R");
				builderList.add(c.toString());
			}
			
			builderList.add("--no-progress");
			
			Integer d = tc.getPerfConfig().getDurationSeconds();
			if(d<=0) {
				d = 10;
			}
			builderList.add("-d");
			builderList.add(d.toString());
			
			Integer to = tc.getPerfConfig().getTimeout();
			if(to>0) {
				builderList.add("-t");
				builderList.add(to.toString());
			}
			
			if(tc.getPerfConfig().isLatency()) {
				builderList.add("--latency");
			}
			
			File script = null;
			
			if(StringUtils.isNotBlank(tc.getPerfConfig().getFilePath()) && context.getResourceFile(tc.getPerfConfig().getFilePath().trim()).exists()) {
				script = context.getResourceFile(tc.getPerfConfig().getFilePath().trim());
			}
			
			if(script==null && StringUtils.isNotBlank(tc.getContentFile())) {
				if(context.getResourceFile(tc.getContentFile().trim()).exists()) {
					script = context.getResourceFile(tc.getContentFile().trim());
				}
			}
			
			if(script==null && StringUtils.isNotBlank(tc.getContent())) {
				script = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
				FileUtils.write(script, tc.getContent(), "UTF-8");
			}
			
			if(!tc.getMethod().equalsIgnoreCase("GET")) {
				if(script!=null) {
					builderList.add("-b");
					builderList.add(script.getAbsolutePath());
				}
			}
			
			for (String hdr : tc.getHeaders().keySet()) {
				builderList.add("-H");
				builderList.add(hdr+"="+tc.getHeaders().get(hdr));
			}
			
			builderList.add(tc.getAurl());
			
			StringBuilder out = new StringBuilder();
			StringBuilder err = new StringBuilder();
			
			long start = System.currentTimeMillis();
 			
 			if(tcr.getTestCase()==null) {
 				tcr.setTestCase(tc);
 			}
			executeInt(builderList, out, err, tcr, tc.getBaseUrl());
			
			if(isSingleExecutionContext) {
				if(config.getGatfTestDataConfig()!=null && config.isCompareEnabled() && config.getGatfTestDataConfig().getCompareEnvBaseUrls()!=null) {
					for (String burl : config.getGatfTestDataConfig().getCompareEnvBaseUrls()) {
						String aurl = tc.getAurl().replaceFirst(config.getBaseUrl(), burl);
						builderList.set(builderList.size()-1, aurl);
						executeInt(builderList, out, err, tcr, burl);
					}
				}
			}
			
			if(script!=null) {
				script.delete();
			}

			if(out.length()>0) {
				tcr.setResponseContent(out.toString());
				tcr.setResponseContentType(MediaType.TEXT_PLAIN);
				tcr.setStatus(TestStatus.Success.status);
			}
 			if(err.length()>0) {
 				tcr.setErrorText(err.toString());
				tcr.setStatus(TestStatus.Failed.status);
			}
 			
 			tcr.setExecutionTime(System.currentTimeMillis() - start);
		}
	}
	
	public static void executeInt(List<String> builderList, StringBuilder out, StringBuilder err, TestCaseReport tcr, String baseUrl) {
		StringBuilder out1 = new StringBuilder();
		StringBuilder err1 = new StringBuilder();
		GatfFunctionHandler.executeCmd(builderList, out1, err1, true);
		if(err1.length()>0) {
			//Map<String, Object> retval = parse_autocannon_output(out1);
			//tcr.getPerfResult().add(retval);
			out.append(String.join(" ", builderList)+"\n\n");
			out.append("Result for ");
			out.append(baseUrl);
			out.append("\n");
			String errd = err1.toString();
			errd = errd.replace('?', '*');
			out.append(errd);
			out.append("\n\n");
		}
		/*if(err1.length()>0) {
			err.append(String.join(" ", builderList)+"\n\n");
			err.append("Error for ");
			err.append(baseUrl);
			err.append("\n");
			err.append(err1.toString());
			err.append("\n\n");
		}*/
	}
} public class VegetaTestCaseExecutor {

	public static void execute(AcceptanceTestContext context, TestCase tc, TestCaseReport tcr, boolean isSingleExecutionContext) throws Exception {
		GatfExecutorConfig config = context.getGatfExecutorConfig();

		if(tc.getPerfConfig()!=null && tc.getPerfConfig().getType()!=null && tc.getPerfConfig().getType().startsWith("vegeta")) {
			List<String> builderList = new ArrayList<>();
			builderList.add(config.getVegetaPath());
			builderList.add("attack");
			
			Integer c = tc.getPerfConfig().getConnections();
			if(c>=0) {
				builderList.add("-connections");
				builderList.add(c.toString());
			}
			
			Integer t = tc.getPerfConfig().getThreads();
			if(t>=0) {
				builderList.add("-workers");
				builderList.add(t.toString());
			}
			
			Integer r = tc.getPerfConfig().getRate();
			if(r>0) {
				builderList.add("-rate");
				builderList.add(c.toString());
			}
			
			Integer d = tc.getPerfConfig().getDurationSeconds();
			if(d<=0) {
				d = 10;
			}
			builderList.add("-duration");
			builderList.add(d+"s");
			
			Integer to = tc.getPerfConfig().getTimeout();
			if(to>0) {
				builderList.add("-timeout");
				builderList.add(to+"s");
			}
			
			boolean isPlot = StringUtils.isNotBlank(tc.getPerfConfig().getExtras()) && tc.getPerfConfig().getExtras().indexOf("plot=1")!=-1;
			
			File script = null;
			
			if(StringUtils.isNotBlank(tc.getPerfConfig().getFilePath()) && context.getResourceFile(tc.getPerfConfig().getFilePath().trim()).exists()) {
				script = context.getResourceFile(tc.getPerfConfig().getFilePath().trim());
			}
			
			if(script==null && StringUtils.isNotBlank(tc.getContentFile())) {
				if(context.getResourceFile(tc.getContentFile().trim()).exists()) {
					script = context.getResourceFile(tc.getContentFile().trim());
				}
			}
			
			if(script==null && StringUtils.isNotBlank(tc.getContent())) {
				script = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
				FileUtils.write(script, tc.getContent(), "UTF-8");
			}
			
			StringBuilder out = new StringBuilder();
			StringBuilder err = new StringBuilder();
			
			long start = System.currentTimeMillis();
 			
 			if(tcr.getTestCase()==null) {
 				tcr.setTestCase(tc);
 			}
 			
			execCmd(config.getVegetaPath(), out, err, tcr, tc, script, builderList, tc.getAurl(), tc.getBaseUrl(), isPlot);
			
			if(isSingleExecutionContext) {
				if(config.getGatfTestDataConfig()!=null && config.isCompareEnabled() && config.getGatfTestDataConfig().getCompareEnvBaseUrls()!=null) {
					for (String burl : config.getGatfTestDataConfig().getCompareEnvBaseUrls()) {
						String aurl = tc.getAurl().replaceFirst(config.getBaseUrl(), burl);
						execCmd(config.getVegetaPath(), out, err, tcr, tc, script, builderList, aurl, burl, isPlot);
					}
				}
			}
			
			if(script!=null) {
				script.delete();
			}

			if(out.length()>0) {
				tcr.setResponseContent(out.toString());
				tcr.setResponseContentType(MediaType.TEXT_PLAIN);
				tcr.setStatus(TestStatus.Success.status);
			}
 			if(err.length()>0) {
 				tcr.setErrorText(err.toString());
				tcr.setStatus(TestStatus.Failed.status);
			}
 			
 			tcr.setExecutionTime(System.currentTimeMillis() - start);
		}
	}
	
	@SuppressWarnings("unchecked")
	private static void execCmd(String vegetaPath, StringBuilder out, StringBuilder err, TestCaseReport tcr, TestCase tc, File script, List<String> bl, String url, String baseUrl, boolean isPlot) throws Exception {
		File results = File.createTempFile(UUID.randomUUID().toString(), ".bin");
		File target = null;
		List<String> builderList = new ArrayList<>();
		if(tc.getHeaders()!=null && tc.getHeaders().size()>0) {
			StringBuilder httpreq = new StringBuilder(tc.getMethod().toUpperCase() + " " + url);
			httpreq.append("\r\n");
			for (String hdr : tc.getHeaders().keySet()) {
				httpreq.append(hdr);
				httpreq.append(": ");
				httpreq.append(tc.getHeaders().get(hdr));
				httpreq.append("\r\n");
			}
			if(script!=null) {
				httpreq.append("@");
				httpreq.append(script.getAbsolutePath());
			}
			target = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
			FileUtils.write(target, httpreq.toString(), "UTF-8");
			
			bl.add("-format");
			bl.add("http");
			bl.add("-targets");
			bl.add(target.getAbsolutePath());
			builderList = bl;
		} else {
			builderList.add("echo");
			builderList.add("'GET");
			builderList.add(tc.getAurl());
			builderList.add("'|");
			builderList.addAll(bl);
		}
		
		builderList.add("|");
		builderList.add("tee");
		builderList.add(results.getAbsolutePath());
		builderList.add("|");
		builderList.add(vegetaPath);
		builderList.add("report");
		
		StringBuilder out1 = new StringBuilder();
		StringBuilder err1 = new StringBuilder();
		GatfFunctionHandler.executeCmd(builderList, out1, err1, true);
		if(out1.length()>0) {
			List<String> rbl = new ArrayList<>();
			rbl.add(vegetaPath);
			rbl.add("report");
			rbl.add("-type=json");
			rbl.add(results.getAbsolutePath());
			StringBuilder out2 = new StringBuilder();
			GatfFunctionHandler.executeCmd(rbl, out2, null, true);
			Map<String, Object> retval = WorkflowContextHandler.OM.readValue(out2.toString(), Map.class);
			tcr.getPerfResult().add(retval);
			
			if(isPlot) {
				File plothtml = File.createTempFile(UUID.randomUUID().toString(), ".html");
				rbl = new ArrayList<>();
				rbl.add("cat");
				rbl.add(results.getAbsolutePath());
				rbl.add("|");
				rbl.add(vegetaPath);
				rbl.add("plot");
				rbl.add(">");
				rbl.add(plothtml.getAbsolutePath());
				
				if(retval!=null) {
					GatfFunctionHandler.executeCmd(rbl, null, null, true);
					retval.put("_plot_html_", plothtml.getAbsolutePath());
				}
			}
			
			out.append(String.join(" ", builderList)+"\n\n");
			out.append("Result for ");
			out.append(baseUrl);
			out.append("\n");
			out.append(out1.toString());
			out.append("\n\n");
		}
		if(err1.length()>0) {
			err.append(String.join(" ", builderList)+"\n\n");
			err.append("Error for ");
			err.append(baseUrl);
			err.append("\n");
			err.append(err1.toString());
			err.append("\n\n");
		}
		
		if(target!=null) {
			target.delete();
		}
		
		results.delete();
	}
} public class WrkTestCaseExecutor {

	//Transfomed from https://github.com/MaartenSmeets/db_perftest/blob/master/test_scripts/wrk_parser.py
	
	static Pattern B1_PAT = Pattern.compile("^(\\d+\\.*\\d*)(\\w+)$");
	private static BigDecimal get_bytes(String size_str) {
		Matcher m = B1_PAT.matcher(size_str);
		if(m.matches()) {
			float size = Float.valueOf(m.group(1)).floatValue();
			String suffix = m.group(2).toLowerCase();
			if(suffix.equals("b"))
		        return new BigDecimal(size).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("kb") || suffix.equals("kib"))
		        return new BigDecimal(size * 1024).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("mb") || suffix.equals("mib"))
		        return new BigDecimal(size * 1024 * 1024).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("gb") || suffix.equals("gib"))
		        return new BigDecimal(size * 1024 * 1024 * 1024).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("tb") || suffix.equals("tib"))
		        return new BigDecimal(size * 1024 * 1024 * 1024 * 1024).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("pb") || suffix.equals("pib"))
		        return new BigDecimal(size * 1024 * 1024 * 1024 * 1024 * 1024).setScale(2, RoundingMode.HALF_DOWN);
		}
	    return BigDecimal.ZERO;
	}


	static Pattern B2_PAT = Pattern.compile("^(\\d+\\.*\\d*)(\\w*)$");
	private static BigDecimal get_number(String size_str) {
		Matcher m = B2_PAT.matcher(size_str);
		if(m.matches()) {
			float size = Float.valueOf(m.group(1)).floatValue();
			String suffix = m.group(2).toLowerCase();
			if(suffix.equals("k"))
		        return new BigDecimal(size * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("m"))
		        return new BigDecimal(size * 1000 * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("g"))
		        return new BigDecimal(size * 1000 * 1000 * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("t"))
		        return new BigDecimal(size * 1000 * 1000 * 1000 * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("p"))
		        return new BigDecimal(size * 1000 * 1000 * 1000 * 1000 * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else
		        return new BigDecimal(size).setScale(2, RoundingMode.HALF_DOWN);
		}
	    return BigDecimal.ZERO;
	}

	private static BigDecimal get_ms(String size_str) {
		Matcher m = B2_PAT.matcher(size_str);
		if(m.matches()) {
			float size = Float.valueOf(m.group(1)).floatValue();
			String suffix = m.group(2).toLowerCase();
			if(suffix.equals("us"))
		        return new BigDecimal(size / 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("ms"))
		        return new BigDecimal(size).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("s"))
		        return new BigDecimal(size * 1000).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("m"))
		        return new BigDecimal(size * 1000 * 60).setScale(2, RoundingMode.HALF_DOWN);
		    else if(suffix.equals("h"))
		        return new BigDecimal(size * 1000 * 60 * 60).setScale(2, RoundingMode.HALF_DOWN);
		    else
		        return new BigDecimal(size).setScale(2, RoundingMode.HALF_DOWN);
		}
	    return BigDecimal.ZERO;
	}
	
	static Pattern LAT_PAT = Pattern.compile("^\\s*Latency\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+%).*$");
	static Pattern RQS_PAT = Pattern.compile("^\\s*Req/Sec\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+\\w*)\\s+(\\d+\\.\\d+%).*$");
	static Pattern RQI_PAT = Pattern.compile("^\\s*(\\d+)\\ requests in (\\d+\\.\\d+\\w*)\\,\\ (\\d+\\.\\d+\\w*)\\ read.*$");
	static Pattern FRQS_PAT = Pattern.compile("^Requests\\/sec\\:\\s+(\\d+\\.*\\d*).*$");
	static Pattern TRFS_PAT = Pattern.compile("^Transfer\\/sec\\:\\s+(\\d+\\.*\\d*\\w+).*$");
	static Pattern SCE_PAT = Pattern.compile("^\\s+Socket errors:\\ connect (\\d+\\w*)\\,\\ read (\\d+\\w*)\\,\\ write\\ (\\d+\\w*)\\,\\ timeout\\ (\\d+\\w*).*$");
	static Pattern LPER_PAT = Pattern.compile("^(50|75|90|99)%\\s+(\\d+\\.\\d+\\w*)$");
	static Pattern LPER_PAT2 = Pattern.compile("^(\\d+\\.\\d+)%\\s+(\\d+\\.\\d+\\w*)$");
	static Pattern HDR_PAT2 = Pattern.compile("^(\\d+\\.\\d+)\\s+(\\d+\\.\\d+)\\s+(\\d+)\\s+(\\d+\\.\\d+|inf)$");
	@SuppressWarnings("unchecked")
	private static Map<String, Object> parse_wrk_output(StringBuilder out) {
		Map<String, Object> retval = new HashMap<String, Object>();
		String[] lines = out.toString().split("\\r?\\n");
		boolean latstarted = false;
		boolean onelatdone = false;
		boolean onehdrdone = false;
		int hdrstarted = 0;
		for (String line : lines) {
			line = line.trim();
			if(line.startsWith("Latency Distribution")) {
				latstarted = true;
				continue;
			} else if(line.startsWith("Non-2xx or 3xx responses: ")) {
				retval.put("non_2xx_resp", Long.valueOf(line.substring(line.lastIndexOf(" ")+1)));
				continue;
			} else if(line.startsWith("Detailed Percentile spectrum:")) {
				hdrstarted++;
				continue;
			} else if(hdrstarted>0) {
				if(hdrstarted==3) {
					boolean matched = false;
					Matcher m = HDR_PAT2.matcher(line);
					if(m.matches()) {
						matched = true;
						String key = onehdrdone?"dps_details_2":"dps_details";
						List<String[]> rows = (List<String[]>)retval.get(key);
						if(rows==null) {
							rows = new ArrayList<String[]>();
							retval.put(key, rows);
						}
						rows.add(new String[] {m.group(1), m.group(2), m.group(3), m.group(4)});
						
					}
					if(matched) {
						continue;
					} else {
						hdrstarted = 0;
						onehdrdone = true;
					}
				} else {
					hdrstarted++;
					continue;
				}
			} else if(latstarted) {
				boolean matched = false;
				Matcher m = LPER_PAT.matcher(line);
				if(m.matches()) {
					matched = true;
					retval.put("lat_dis_"+m.group(1)+(onelatdone?"_2":"")+"_s", m.group(2));
					retval.put("lat_dis_"+m.group(1)+(onelatdone?"_2":""), get_ms(m.group(2)));
				} else {
					m = LPER_PAT2.matcher(line);
					if(m.matches()) {
						String vals = "";
						BigDecimal val = new BigDecimal(m.group(1)).setScale(3, RoundingMode.UNNECESSARY);
						BigDecimal frc = val.remainder(BigDecimal.ONE);
						if(frc.floatValue()>0) {
							frc = frc.multiply(new BigDecimal(1000)).setScale(0, RoundingMode.UNNECESSARY);
							vals = val.intValue() + "_" +frc.toPlainString();
						} else {
							vals = val.intValue() + "";
						}
						retval.put("lat_dis_"+vals+(onelatdone?"_2":"")+"_s", m.group(2));
						retval.put("lat_dis_"+vals+(onelatdone?"_2":""), get_ms(m.group(2)));
						matched = true;
					}
				}
				if(matched) {
					continue;
				} else {
					latstarted = false;
					onelatdone = true;
				}
			}
			
			Matcher m = LAT_PAT.matcher(line);
			if(m.matches()) {
				retval.put("lat_avg_s", m.group(1));
	            retval.put("lat_stdev_s", m.group(2));
	            retval.put("lat_max_s", m.group(3));
				retval.put("lat_avg", get_ms(m.group(1)));
	            retval.put("lat_stdev", get_ms(m.group(2)));
	            retval.put("lat_max", get_ms(m.group(3)));
	            retval.put("lat_stdev_perc", m.group(4));
			} else {
				m = RQS_PAT.matcher(line);
				if(m.matches()) {
					retval.put("req_avg_s", m.group(1));
		            retval.put("req_stdev_s", m.group(2));
		            retval.put("req_max_s", m.group(3));
					retval.put("req_avg", get_number(m.group(1)));
		            retval.put("req_stdev", get_number(m.group(2)));
		            retval.put("req_max", get_number(m.group(3)));
		            retval.put("req_stdev_perc", m.group(4));
				} else {
					m = RQI_PAT.matcher(line);
					if(m.matches()) {
						retval.put("tot_requests_s", m.group(1));
			            retval.put("tot_duration_s", m.group(2));
			            retval.put("read_s", m.group(3));
						retval.put("tot_requests", get_number(m.group(1)));
			            retval.put("tot_duration", get_ms(m.group(2)));
			            retval.put("read", get_bytes(m.group(3)));
					} else {
						m = FRQS_PAT.matcher(line);
						if(m.matches()) {
							retval.put("req_sec_tot_s", m.group(1));
							retval.put("req_sec_tot", get_number(m.group(1)));
						} else {
							m = TRFS_PAT.matcher(line);
							if(m.matches()) {
								retval.put("read_tot_s", m.group(1));
								retval.put("read_tot", get_bytes(m.group(1)));
							} else {
								m = SCE_PAT.matcher(line);
								if(m.matches()) {
									retval.put("err_connect_s", m.group(1));
						            retval.put("err_read_s", m.group(2));
						            retval.put("err_write_s", m.group(3));
						            retval.put("err_timeout_s", m.group(4));
									retval.put("err_connect", get_number(m.group(1)));
						            retval.put("err_read", get_number(m.group(2)));
						            retval.put("err_write", get_number(m.group(3)));
						            retval.put("err_timeout", get_number(m.group(4)));
								}
							}
						}
					}
				}
			}
		}
	    if(!retval.containsKey("err_connect")) {
	        retval.put("err_connect_s", "0");
	        retval.put("err_connect", 0);
	    }
	    if(!retval.containsKey("err_read")) {
	        retval.put("err_read_s", "0");
	        retval.put("err_read", 0);
	    }
	    if(!retval.containsKey("err_write")) {
	        retval.put("err_write_s", "0");
	        retval.put("err_write", 0);
	    }
	    if(!retval.containsKey("err_timeout")) {
	        retval.put("err_timeout_s", "0");
	        retval.put("err_timeout", 0);
	    }
	    
	    return retval;
	}

	public static void execute(AcceptanceTestContext context, TestCase tc, TestCaseReport tcr, boolean isSingleExecutionContext) throws Exception {
		GatfExecutorConfig config = context.getGatfExecutorConfig();

		if(tc.getPerfConfig()!=null && tc.getPerfConfig().getType()!=null && tc.getPerfConfig().getType().startsWith("wrk")) {
			List<String> builderList = new ArrayList<>();
			builderList.add(tc.getPerfConfig().getType().equals("wrk")?config.getWrkPath():config.getWrk2Path());
			
			Integer c = tc.getPerfConfig().getConnections();
			if(c<=0) {
				c = 10; 
			}
			builderList.add("-c");
			builderList.add(c.toString());
			
			Integer r = tc.getPerfConfig().getRate();
			if(tc.getPerfConfig().getType().equals("wrk2")) {
				if(r<=0) {
					r = 1000;
				}
				builderList.add("-R");
				builderList.add(r.toString());
			}
			
			Integer d = tc.getPerfConfig().getDurationSeconds();
			if(d<=0) {
				d = 10;
			}
			builderList.add("-d");
			builderList.add(d+"s");
			
			Integer t = tc.getPerfConfig().getThreads();
			if(t<=0) {
				t = 10;
			}
			builderList.add("-t");
			builderList.add(t.toString());
			
			Integer to = tc.getPerfConfig().getTimeout();
			if(to>0) {
				builderList.add("--timeout");
				builderList.add(to+"s");
			}
			
			if(tc.getPerfConfig().isLatency()) {
				builderList.add("--latency");
			}
			
			if(tc.getPerfConfig().getType().equals("wrk2")) {
				builderList.add("--u_latency");
			}
			
			File script = null;
			
			if(StringUtils.isNotBlank(tc.getPerfConfig().getFilePath()) && context.getResourceFile(tc.getPerfConfig().getFilePath().trim()).exists()) {
				script = context.getResourceFile(tc.getPerfConfig().getFilePath().trim());
				builderList.add("-s ");
				builderList.add(context.getResourceFile(tc.getPerfConfig().getFilePath().trim()).getAbsolutePath());
			}
			
			if(script==null) {
				if(tc.getHeaders()!=null && tc.getHeaders().size()>0) {
					StringBuilder prog = new StringBuilder();
					prog.append("wrk.method = \"");
					prog.append(tc.getMethod().toUpperCase());
					prog.append("\"\n");
					for (String hdr : tc.getHeaders().keySet()) {
						prog.append("wrk.headers[\""+hdr+"] = \"");
						prog.append(tc.getHeaders().get(hdr));
						prog.append("\"\n");
					}
					prog.append("wrk.body = [====================[\n");
					String content = tc.getContent();
					if(StringUtils.isBlank(content) && tc.getContentFile()!=null) {
						if(context.getResourceFile(tc.getContentFile().trim()).exists()) {
							content = FileUtils.readFileToString(context.getResourceFile(tc.getContentFile().trim()), "UTF-8");
						}
					}
					if(content==null) {
						content = "";
					}
					prog.append(content);
					prog.append("\n]====================]\n");
					
					script = File.createTempFile(UUID.randomUUID().toString(), ".lua");
					FileUtils.write(script, prog.toString(), "UTF-8");
					
					builderList.add("-s");
					builderList.add(script.getAbsolutePath());
				}
			}
			
			builderList.add(tc.getAurl());
 			
 			if(tcr.getTestCase()==null) {
 				tcr.setTestCase(tc);
 			}
			
			StringBuilder out = new StringBuilder();
			StringBuilder err = new StringBuilder();
			
			long start = System.currentTimeMillis();
			executeInt(builderList, out, err, tcr, tc.getBaseUrl());
			
			if(isSingleExecutionContext) {
				if(config.getGatfTestDataConfig()!=null && config.isCompareEnabled() && config.getGatfTestDataConfig().getCompareEnvBaseUrls()!=null) {
					for (String burl : config.getGatfTestDataConfig().getCompareEnvBaseUrls()) {
						String aurl = tc.getAurl().replaceFirst(config.getBaseUrl(), burl);
						builderList.set(builderList.size()-1, aurl);
						executeInt(builderList, out, err, tcr, burl);
					}
				}
			}
			
			if(script!=null) {
				script.delete();
			}

			if(out.length()>0) {
				tcr.setResponseContent(out.toString());
				tcr.setResponseContentType(MediaType.TEXT_PLAIN);
				tcr.setStatus(TestStatus.Success.status);
			}
 			if(err.length()>0) {
 				tcr.setErrorText(err.toString());
				tcr.setStatus(TestStatus.Failed.status);
			}
 			
 			tcr.setExecutionTime(System.currentTimeMillis() - start);
		}
	}
	
	public static void executeInt(List<String> builderList, StringBuilder out, StringBuilder err, TestCaseReport tcr, String baseUrl) {
		StringBuilder out1 = new StringBuilder();
		StringBuilder err1 = new StringBuilder();
		GatfFunctionHandler.executeCmd(builderList, out1, err1, false);
		if(out1.length()>0) {
			Map<String, Object> retval = parse_wrk_output(out1);
			tcr.getPerfResult().add(retval);
			out.append(String.join(" ", builderList)+"\n\n");
			out.append("Result for ");
			out.append(baseUrl);
			out.append("\n");
			out.append(out1.toString());
			out.append("\n\n");
		}
		if(err1.length()>0) {
			err.append(String.join(" ", builderList)+"\n\n");
			err.append("Error for ");
			err.append(baseUrl);
			err.append("\n");
			err.append(err1.toString());
			err.append("\n\n");
		}
	}
} @JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class TestCaseReport implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private String actualUrl;
	
	private String url;
	
	private String method;
	
	private String workflowName;

	private TestCase testCase;
	
	private String status;
	
	private String failureReason;
	
	private Integer numberOfRuns;
	
	private Long executionTime = 0L;
	
	private List<Long> executionTimes = new ArrayList<Long>();
	
	private Long averageExecutionTime;
	
	private String requestContent;
	
	private String requestHeaders;
	
	private String responseHeaders;
	
	private String requestContentType;
	
	private String responseContentType;
	
	private String responseContent;
	
	private Integer responseStatusCode;
	
	private String error;
	
	private String errorText;
	
	private Map<String, String> errors = new HashMap<String, String>();
	
	private String testIdentifier;
	
	private List<String> aexpectedNodes = new ArrayList<String>();
	
	private String serverLogs;

	@XStreamOmitField
	@JsonIgnore
	private Map<String, List<String>> resHeaders;
	
	private List<Map<String, Object>> perfResult = new ArrayList<Map<String, Object>>();
	
	public String getWorkflowName() {
		return workflowName;
	}

	public void setWorkflowName(String workflowName) {
		this.workflowName = workflowName;
	}

	public TestCase getTestCase() {
		return testCase;
	}

	public void setTestCase(TestCase testCase) {
		this.testCase = testCase;
		if(testCase!=null) {
			if(testCase.getIdentifier().equals(testCase.getSourcefileName()))
				setTestIdentifier(testCase.getIdentifier()+"\n"+testCase.getName());
			else
				setTestIdentifier(testCase.getIdentifier()+"\n"+testCase.getSourcefileName()+"\n"+testCase.getName());
			if(testCase.getAurl()!=null)
			{
				setActualUrl(testCase.getAurl());
			}
			else
			{
				setActualUrl(testCase.getUrl());
			}
			setRequestContent(testCase.getAcontent());
			setUrl(testCase.getUrl());
			setMethod(testCase.getMethod());
			setAexpectedNodes(testCase.getAexpectedNodes());
		}
	}
	
	public void setTestCaseExternalApi(TestCase testCase) {
		this.testCase = testCase;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public Integer getNumberOfRuns() {
		return numberOfRuns;
	}

	public void setNumberOfRuns(Integer numberOfRuns) {
		this.numberOfRuns = numberOfRuns;
	}

	public Long getExecutionTime() {
		return executionTime;
	}

	public void setExecutionTime(Long executionTime) {
		this.executionTime = executionTime;
	}

	public List<Long> getExecutionTimes() {
		return executionTimes;
	}

	public void setExecutionTimes(List<Long> executionTimes) {
		this.executionTimes = executionTimes;
	}

	public String getRequestContent() {
		return requestContent;
	}

	public void setRequestContent(String requestContent) {
		this.requestContent = requestContent;
	}

	public String getResponseHeaders() {
		return responseHeaders;
	}

	public void setResponseHeaders(String responseHeaders) {
		this.responseHeaders = responseHeaders;
	}

	public String getResponseContent() {
		return responseContent;
	}

	public void setResponseContent(String responseContent) {
		this.responseContent = responseContent;
	}

	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public String getActualUrl() {
		return actualUrl;
	}

	public void setActualUrl(String actualUrl) {
		this.actualUrl = actualUrl;
	}

	public String getErrorText() {
		return errorText;
	}

	public void setErrorText(String errorText) {
		this.errorText = errorText;
	}

	public String getTestIdentifier() {
		return testIdentifier;
	}

	public void setTestIdentifier(String testIdentifier) {
		this.testIdentifier = testIdentifier;
	}

	public Long getAverageExecutionTime() {
		return averageExecutionTime;
	}

	public void setAverageExecutionTime(Long averageExecutionTime) {
		this.averageExecutionTime = averageExecutionTime;
	}

	public Map<String, String> getErrors() {
		return errors;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public void setErrors(Map<String, String> errors) {
		this.errors = errors;
	}

	public String getRequestHeaders() {
		return requestHeaders;
	}

	public void setRequestHeaders(String requestHeaders) {
		this.requestHeaders = requestHeaders;
	}

	public String getRequestContentType() {
		return requestContentType;
	}

	public void setRequestContentType(String requestContentType) {
		this.requestContentType = requestContentType;
	}

	public String getResponseContentType() {
		return responseContentType;
	}

	public void setResponseContentType(String responseContentType) {
		this.responseContentType = responseContentType;
	}

	public Integer getResponseStatusCode() {
		return responseStatusCode;
	}

	public void setResponseStatusCode(Integer responseStatusCode) {
		this.responseStatusCode = responseStatusCode;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getFailureReason() {
		return failureReason;
	}

	public void setFailureReason(String failureReason) {
		this.failureReason = failureReason;
	}

	public List<String> getAexpectedNodes() {
		return aexpectedNodes;
	}

	public void setAexpectedNodes(List<String> aexpectedNodes) {
		this.aexpectedNodes = aexpectedNodes;
	}

	public Map<String, List<String>> getResHeaders() {
		return resHeaders;
	}

	public void setResHeaders(Map<String, List<String>> resHeaders) {
		this.resHeaders = resHeaders;
	}

	public String getServerLogs() {
		return serverLogs;
	}

	public void setServerLogs(String serverLogs) {
		this.serverLogs = serverLogs;
	}

	public List<Map<String, Object>> getPerfResult() {
		return perfResult;
	}

	public void setPerfResult(List<Map<String, Object>> perfResult) {
		this.perfResult = perfResult;
	}

	public TestCaseReport(){}
	
	public TestCaseReport(TestCaseReport other) {
		super();
		this.actualUrl = other.actualUrl;
		this.workflowName = other.workflowName;
		this.testCase = other.testCase;
		this.status = other.status;
		this.numberOfRuns = other.numberOfRuns;
		this.executionTime = other.executionTime;
		if(other.executionTimes!=null)
		{
			this.executionTimes = new ArrayList<Long>(other.executionTimes);
		}
		this.requestContent = other.requestContent;
		this.responseHeaders = other.responseHeaders;
		this.responseContent = other.responseContent;
		this.error = other.error;
		this.errorText = other.errorText;
		this.testIdentifier = other.testIdentifier;
		if(other.errors!=null)
		{
			this.errors = other .errors;
		}
		this.responseStatusCode = other.responseStatusCode;
		this.method = other.method;
		this.failureReason = other.failureReason;
		this.perfResult = other.perfResult;
	}

	@Override
	public String toString() {
		final int maxLen = 10;
		StringBuilder builder = new StringBuilder();
		builder.append("TestCaseReport = [\n");
		builder.append("actualUrl=");
		builder.append(actualUrl);
		builder.append("\nurl=");
		builder.append(url);
		builder.append("\nmethod=");
		builder.append(method);
		builder.append("\nworkflowName=");
		builder.append(workflowName);
		builder.append("\nstatus=");
		builder.append(status);
		builder.append("\nfailureReason=");
		builder.append(failureReason);
		builder.append("\nnumberOfRuns=");
		builder.append(numberOfRuns);
		builder.append("\nexecutionTime=");
		builder.append(executionTime);
		builder.append("\nexecutionTimes=");
		builder.append(executionTimes != null ? toString(executionTimes, maxLen)
				: null);
		builder.append("\naverageExecutionTime=");
		builder.append(averageExecutionTime);
		builder.append("\nrequestContent=");
		builder.append(requestContent);
		builder.append("\nrequestHeaders=");
		builder.append(requestHeaders);
		builder.append("\nresponseHeaders=");
		builder.append(responseHeaders);
		builder.append("\nrequestContentType=");
		builder.append(requestContentType);
		builder.append("\nresponseContentType=");
		builder.append(responseContentType);
		builder.append("\nresponseContent=");
		builder.append(responseContent);
		builder.append("\nresponseStatusCode=");
		builder.append(responseStatusCode);
		builder.append("\nerror=");
		builder.append(error);
		builder.append("\nerrorText=");
		builder.append(errorText);
		builder.append("\nerrors=");
		builder.append(errors != null ? toString(errors.entrySet(), maxLen)
				: null);
		builder.append("\ntestIdentifier=");
		builder.append(testIdentifier);
		builder.append("]\n");
		return builder.toString();
	}

	private String toString(Collection<?> collection, int maxLen) {
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		int i = 0;
		for (Iterator<?> iterator = collection.iterator(); iterator.hasNext()
				&& i < maxLen; i++) {
			if (i > 0)
				builder.append("\n");
			builder.append(iterator.next());
		}
		builder.append("]");
		return builder.toString();
	}
	
	public static enum TestStatus {
		Success("Success"),
		Skipped("Skipped"),
		Failed("Failed");
		
		public String status;
		private TestStatus(String status) {
			this.status = status;
		}
	}
	
	public static enum TestFailureReason {
		InvalidStatusCode("InvalidStatusCode"),
		Exception("Exception"),
		NodeValidationFailed("NodeValidationFailed"),
		InvalidContentType("InvalidContentType"),
		ExecuteConditionFailed("ExecConditionFailed");
		
		public String status;
		private TestFailureReason(String status) {
			this.status = status;
		}
	}
	
	private String sanitizeString(String inp)
	{
		return inp.replace("\"", "\\\"").replace("\n", "\\\n");
	}
	
	public String toStatisticsCsv()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("\"");
		if(testCase.getSourcefileName().equals(testCase.getIdentifier()))
		{
			builder.append(sanitizeString(testCase.getSourcefileName()));
		}
		else
		{
			builder.append(sanitizeString(testCase.getSourcefileName()));
			builder.append("(");
			builder.append(testCase.getIdentifier());
			builder.append(")");
		}
		builder.append("\"");
		builder.append(",");
		builder.append("\"");
		builder.append(sanitizeString(testCase.getName()));
		builder.append("\"");
		builder.append(",");
		builder.append("\"");
		builder.append(method);
		builder.append("\"");
		builder.append(",");
		builder.append("\"");
		builder.append(actualUrl);
		builder.append("\"");
		builder.append(",");
		builder.append("\"");
		builder.append(sanitizeString(testCase.getDescription()));
		builder.append("\"");
		builder.append(",");
		builder.append(executionTime);
		builder.append(",");
		builder.append(responseStatusCode);
		builder.append(",");
		builder.append("\"");
		builder.append(status);
		builder.append("\"\n");
		return builder.toString();
	}
}
 public static enum TestFailureReason {
	InvalidStatusCode("InvalidStatusCode"),
	Exception("Exception"),
	NodeValidationFailed("NodeValidationFailed"),
	InvalidContentType("InvalidContentType"),
	ExecuteConditionFailed("ExecConditionFailed");
		
	public String status;
	private TestFailureReason(String status) {
		this.status = status;
	}
}
 public static enum TestStatus {
	Success("Success"),
	Skipped("Skipped"),
	Failed("Failed");
		
	public String status;
	private TestStatus(String status) {
		this.status = status;
	}
}
 public class JSONResponseValidator extends ResponseValidator {

	protected Object getInternalObject(TestCaseReport testCaseReport) throws Exception
	{
		return testCaseReport.getResponseContent();
	}

	protected String getNodeValue(Object intObj, String node) throws Exception {
		String nvalue = null;
		try {
			nvalue = JsonPath.read((String)intObj, node).toString();
		} catch (Exception e) {
			//throw new AssertionError("Expected Node " + node + " not found");
		}
		return nvalue;
	}

	protected ResponseType getType() {
		return ResponseType.JSON;
	}

	protected List<Map<String, String>> getResponseMappedValue(String expression, String propNames, Object nodeLst) throws Exception {
		if(expression.equals("")) {
			expression = "$";
		}
		
		List<Map<String, String>> jsonValues = JsonPath.read((String)nodeLst, expression);
		return jsonValues;
	}

	protected int getResponseMappedCount(String expression, Object nodeLst) throws Exception {
		String responseMappedCount = JsonPath.read((String)nodeLst, expression).toString();
		
		int responseCount = -1;
		try {
			responseCount = Integer.valueOf(responseMappedCount);
		} catch (Exception e) {
			throw new AssertionError("Invalid responseMappedCount variable defined, " +
					"derived value should be number - "+expression);
		}
		
		return responseCount;
	}
}
 public class NoContentResponseValidator extends ResponseValidator {

	protected Object getInternalObject(TestCaseReport testCaseReport) throws Exception {
		return null;
	}

	protected ResponseType getType() {
		return ResponseType.NONE;
	}

	protected String getNodeValue(Object intObj, String node) throws Exception {
		return null;
	}

	protected List<Map<String, String>> getResponseMappedValue(
			String expression, String propNames, Object nodeLst)
			throws Exception {
		return null;
	}

	protected int getResponseMappedCount(
			String expression, Object nodeLst) throws Exception {
		return -1;
	}
}
 public class SOAPResponseValidator extends ResponseValidator {

	public static String getLocalNodeName(String nodeName) {
		if(nodeName!=null && nodeName.indexOf(":")!=-1) {
			return nodeName.substring(nodeName.indexOf(":")+1);
		}
		return nodeName;
	}
	
	public static Node getNodeByNameCaseInsensitive(Node node, String nodeName) {
		if(node.getNodeName().equalsIgnoreCase(nodeName) ||
				getLocalNodeName(node.getNodeName()).equalsIgnoreCase(nodeName))
			return node;
		for (int i=0;i<node.getChildNodes().getLength();i++) {
			if(node.getChildNodes().item(i).getNodeType()==Node.ELEMENT_NODE) {
				if(node.getChildNodes().item(i).getNodeName().equalsIgnoreCase(nodeName) ||
						getLocalNodeName(node.getChildNodes().item(i).getNodeName()).equalsIgnoreCase(nodeName)) {
					return node.getChildNodes().item(i);
				}
			}
		}
		return null;
	}
	
	public static Node getNextElement(Node node) {
		for (int i=0;i<node.getChildNodes().getLength();i++) {
			if(node.getChildNodes().item(i).getNodeType()==Node.ELEMENT_NODE) {
				return node.getChildNodes().item(i);
			}
		}
		return null;
	}
	
	public static String createXPathExpression(String suffix, Node... nodes) {
		StringBuilder build = new StringBuilder();
		for (Node node : nodes) {
			build.append("/");
			build.append(getLocalNodeName(node.getNodeName()));
		}
		build.append("/");
		build.append(suffix.replaceAll("\\.", "\\/"));
		return build.toString();
	}
	
	public static void processSOAPRequest(Document soapMessage, TestCase testCase) throws Exception
	{
		if(testCase.getSoapParameterValues()==null)return;
		for (Map.Entry<String, String> entry : testCase.getSoapParameterValues().entrySet()) {
			Node envelope = getNodeByNameCaseInsensitive(soapMessage.getFirstChild(), "envelope");
			Node body = getNodeByNameCaseInsensitive(envelope, "body");
			Node requestBody = getNextElement(body);
			String expression = createXPathExpression(entry.getKey(), envelope, body, requestBody);
			XPath xPath = XPathFactory.newInstance().newXPath();
			NodeList nodelist = (NodeList) xPath.compile(expression).evaluate(soapMessage, XPathConstants.NODESET);
			Assert.assertNotNull("Cannot find soap parameter " + entry.getKey(), 
					nodelist!=null && nodelist.getLength()>0);
			nodelist.item(0).getFirstChild().setNodeValue(entry.getValue());
		}
	}
	
	protected Object getInternalObject(TestCaseReport testCaseReport) throws Exception
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document xmlDocument = db.parse(new ByteArrayInputStream(testCaseReport.getResponseContent().getBytes()));
		return xmlDocument;
	}

	protected String getNodeValue(Object intObj, String node) throws Exception {
	    NodeList xmlNodeList = null;
	    String xmlValue = null;
        try
        {
            Document xmlDocument = (Document)intObj;
            Node envelope = getNodeByNameCaseInsensitive(xmlDocument.getFirstChild(), "envelope");
            Node body = getNodeByNameCaseInsensitive(envelope, "body");
            Node requestBody = getNextElement(body);
            Node returnBody = getNextElement(requestBody);
            String expression = createXPathExpression(node, envelope, body, requestBody, returnBody);
            if(expression.indexOf("/[")!=-1)
                expression = expression.replaceAll("/[", "[");
            xmlNodeList = getNodeByXpath(node, (Document)intObj);
            //Assert.assertTrue("Expected Node " + node + " is null", xmlNodeList!=null && xmlNodeList.getLength()>0);
            xmlValue = getXMLNodeValue(xmlNodeList.item(0));
        }
        catch (Exception e)
        {
        }
		return xmlValue;
	}

	protected ResponseType getType() {
		return ResponseType.SOAP;
	}

	protected List<Map<String, String>> getResponseMappedValue(String expression, String propNames, Object nodeLst) throws Exception {
		expression = expression.replaceAll("\\.", "\\/");
		if(expression.length()>1 && expression.charAt(0)!='/')
			expression = "/" + expression;
		
		Node envelope = getNodeByNameCaseInsensitive(((Document)nodeLst).getFirstChild(), "envelope");
		Node body = getNodeByNameCaseInsensitive(envelope, "body");
		Node requestBody = getNextElement(body);
		Node returnBody = getNextElement(requestBody);
		if(expression.equals(""))
			expression = SOAPResponseValidator.createXPathExpression(expression, envelope, body, requestBody) + "*";
		else	
			expression = SOAPResponseValidator.createXPathExpression(expression, envelope, body, requestBody, returnBody);
		
		XPath xPath =  XPathFactory.newInstance().newXPath();
		NodeList xmlNodeList = (NodeList) xPath.compile(expression).evaluate((Document)nodeLst, XPathConstants.NODESET);
		Assert.assertTrue("Workflow soap variable " + expression +" is null",  
				xmlNodeList!=null && xmlNodeList.getLength()>0);
		
		List<Map<String, String>> soapValues = WorkflowContextHandler.getNodeValueMapList(propNames, xmlNodeList);
		return soapValues;
	}

	protected int getResponseMappedCount(String expression, Object nodeLst) throws Exception {
		expression = expression.replaceAll("\\.", "\\/");
		if(expression.length()>1 && expression.charAt(0)!='/')
			expression = "/" + expression;
		
		Node envelope = getNodeByNameCaseInsensitive(((Document)nodeLst).getFirstChild(), "envelope");
		Node body = getNodeByNameCaseInsensitive(envelope, "body");
		Node requestBody = getNextElement(body);
		Node returnBody = getNextElement(requestBody);
		if(expression.equals(""))
			expression = SOAPResponseValidator.createXPathExpression(expression, envelope, body, requestBody) + "*";
		else	
			expression = SOAPResponseValidator.createXPathExpression(expression, envelope, body, requestBody, returnBody);
		
		XPath xPath =  XPathFactory.newInstance().newXPath();
		NodeList xmlNodeList = (NodeList) xPath.compile(expression).evaluate((Document)nodeLst, XPathConstants.NODESET);
		Assert.assertTrue("Workflow soap variable " + expression +" is null",  
				xmlNodeList!=null && xmlNodeList.getLength()>0);

		String xmlValue = XMLResponseValidator.getXMLNodeValue(xmlNodeList.item(0));
		Assert.assertNotNull("Workflow soap variable " + expression +" is null", xmlValue);
		
		int responseCount = -1;
		try {
			responseCount = Integer.valueOf(xmlValue);
		} catch (Exception e) {
			throw new AssertionError("Invalid responseMappedCount variable defined, " +
					"derived value should be number - "+expression);
		}
		return responseCount;
	}
}
 public class TextResponseValidator extends ResponseValidator {

	protected Object getInternalObject(TestCaseReport testCaseReport) throws Exception {
		return testCaseReport.getResponseContent();
	}

	protected ResponseType getType() {
		return ResponseType.PLAIN;
	}

	protected String getNodeValue(Object intObj, String node) throws Exception {
		String nvalue = null;
		try {
			String cont = (String)intObj;
			if(cont!=null && cont.indexOf("&")!=-1) {
				String[] params = cont.split("&");
				for (String pdef : params) {
					String[] pv = pdef.split("=");
					if(pv.length>1 && pv[0].equals(node)) {
						nvalue = pv[1];
						break;
					}
				}
			}
		} catch (Exception e) {
			throw new AssertionError("Expected Node " + node + " not found");
		}
		return nvalue;
	}

	protected List<Map<String, String>> getResponseMappedValue(
			String expression, String propNames, Object nodeLst)
			throws Exception {
		return null;
	}

	protected int getResponseMappedCount(
			String expression, Object nodeLst) throws Exception {
		return -1;
	}
}
 public class XMLResponseValidator extends ResponseValidator {

	protected Object getInternalObject(TestCaseReport testCaseReport) throws Exception
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document xmlDocument = db.parse(new ByteArrayInputStream(testCaseReport.getResponseContent().getBytes()));
		return xmlDocument;
	}

	protected String getNodeValue(Object intObj, String node) throws Exception {
	    NodeList xmlNodeList = null;
	    String xmlValue = null;
	    try
        {
	        xmlNodeList = getNodeByXpath(node, (Document)intObj);
	        xmlValue = getXMLNodeValue(xmlNodeList.item(0));
        }
        catch (Exception e)
        {
        }
	    //Assert.assertTrue("Expected Node " + node + " is null", xmlNodeList!=null && xmlNodeList.getLength()>0);
	    return xmlValue;
	}

	protected ResponseType getType() {
		return ResponseType.XML;
	}

	protected List<Map<String, String>> getResponseMappedValue(String expression, String propNames, Object initObj) throws Exception {
		expression = expression.replaceAll("\\.", "\\/");
		if(expression.equals("")) {
			expression = "/*";
		}
		
		if(expression.charAt(0)!='/')
			expression = "/" + expression;
		
		XPath xPath =  XPathFactory.newInstance().newXPath();
		NodeList xmlNodeList = (NodeList) xPath.compile(expression).evaluate((Document)initObj, XPathConstants.NODESET);
		Assert.assertTrue("Workflow xml variable " + expression +" is null",  
				xmlNodeList!=null && xmlNodeList.getLength()>0);
		
		List<Map<String, String>> xmlValues = WorkflowContextHandler.getNodeValueMapList(propNames, xmlNodeList);
		return xmlValues;
	}

	protected int getResponseMappedCount(String expression, Object initObj) throws Exception {
		expression = expression.replaceAll("\\.", "\\/");
		if(expression.charAt(0)!='/')
			expression = "/" + expression;
		
		XPath xPath =  XPathFactory.newInstance().newXPath();
		NodeList xmlNodeList = (NodeList) xPath.compile(expression).evaluate((Document)initObj, XPathConstants.NODESET);
		Assert.assertTrue("Workflow xml variable " + expression +" is null", 
				xmlNodeList!=null && xmlNodeList.getLength()>0);

		String xmlValue = XMLResponseValidator.getXMLNodeValue(xmlNodeList.item(0));
		Assert.assertNotNull("Workflow xml variable " + expression +" is null", xmlValue);
		
		int responseCount = -1;
		try {
			responseCount = Integer.valueOf(xmlValue);
		} catch (Exception e) {
			throw new AssertionError("Invalid responseMappedCount variable defined, " +
					"derived value should be number - "+expression);
		}
		return responseCount;
	}
}

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Assert;
import org.w3c.dom.Document;
import com.gatf.executor.core.AcceptanceTestContext;
import com.gatf.executor.core.TestCase;
import com.gatf.executor.ext.AutocannonTestCaseExecutor;
import com.gatf.executor.ext.VegetaTestCaseExecutor;
import com.gatf.executor.ext.WrkTestCaseExecutor;
import com.gatf.executor.report.TestCaseReport;
import com.gatf.executor.report.TestCaseReport.TestFailureReason;
import com.gatf.executor.report.TestCaseReport.TestStatus;
import com.gatf.executor.validator.JSONResponseValidator;
import com.gatf.executor.validator.NoContentResponseValidator;
import com.gatf.executor.validator.SOAPResponseValidator;
import com.gatf.executor.validator.TextResponseValidator;
import com.gatf.executor.validator.XMLResponseValidator;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.MultipartBody;
import okhttp3.MultipartBody.Part;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

						if(turl.indexOf("?")!=-1) {
							String urlpart = turl.substring(0, turl.indexOf("?")+1);
							String paramstr = turl.substring(turl.indexOf("?")+1);
							String[] params = paramstr.split("&");
							boolean isAppendAuthToken = false;
							for (String param : params) {
								String[] pair = param.split("=");
								String key = pair[0];
								String value = pair.length>1?pair[1]:"";
								if(key.trim().equals(authExtractAuthParams[2])) {
									urlpart += (key + "=" + sessIdentifier);
									isAppendAuthToken = true;
								} else {
									urlpart += (key + "=" + value);
								}
								urlpart += "&";
							}
							if(!isAppendAuthToken) {
								urlpart += (authExtractAuthParams[2] + "=" + sessIdentifier);
							}
							turl = urlpart;
						} else {
							turl += "?" + authExtractAuthParams[2] + "=" + sessIdentifier;
						}
					}
				}
				else if(authExtractAuthParams[3].equalsIgnoreCase("header"))
				{
					testCase.getHeaders().put(authExtractAuthParams[2], sessIdentifier);
				}
				else if(authExtractAuthParams[3].equalsIgnoreCase("cookie"))
				{
					testCase.getHeaders().put("Cookie", authExtractAuthParams[2] + "=" + sessIdentifier);
				}
			}

			String completeUrl = getUrl(testCase.getBaseUrl(), turl);
			
			testCase.setAurl(completeUrl);
			try {
			    builder = builder.url(testCase.getAurl());
            } catch (IllegalArgumentException e) {
                Assert.assertTrue("Invalid URL, please check the url provided ("+ completeUrl + ")", false);
            }
			
		} else {
			
			Assert.assertNotNull("No wsdlKey specified for SOAP test", testCase.getWsdlKey());
			Assert.assertNotNull("No operation specified for SOAP test", testCase.getOperationName());
			
			String request = testCase.getAcontent();
			
			String soapAction = context.getSoapActions().get(testCase.getWsdlKey()+testCase.getOperationName());
			if (request.contains(AcceptanceTestContext.SOAP_1_1_NAMESPACE)) {
                soapAction = soapAction != null ? "\"" + soapAction + "\"" : "";
                builder.addHeader(AcceptanceTestContext.PROP_SOAP_ACTION_11, soapAction);
                builder.addHeader(AcceptanceTestContext.PROP_CONTENT_TYPE, AcceptanceTestContext.MIMETYPE_TEXT_XML);
                //TODO recheck this later builder.addParameter(AcceptanceTestContext.PROP_CONTENT_TYPE, AcceptanceTestContext.MIMETYPE_TEXT_XML);
                testCase.getHeaders().put(AcceptanceTestContext.PROP_CONTENT_TYPE, AcceptanceTestContext.MIMETYPE_TEXT_XML);
            } else if (request.contains(AcceptanceTestContext.SOAP_1_2_NAMESPACE)) {
                String contentType = AcceptanceTestContext.MIMETYPE_APPLICATION_XML;
                if (soapAction != null) {
                    contentType = contentType + AcceptanceTestContext.PROP_DELIMITER + AcceptanceTestContext.PROP_SOAP_ACTION_12 + "\"" + soapAction + "\"";
                }
                builder.addHeader(AcceptanceTestContext.PROP_CONTENT_TYPE, contentType);
                testCase.getHeaders().put(AcceptanceTestContext.PROP_CONTENT_TYPE, contentType);
            }
			
			String endpoint = context.getSoapEndpoints().get(testCase.getWsdlKey());
			Assert.assertNotNull("No endpoints found for " + testCase.getWsdlKey()
					 + ", please define the wsdlLocFile in your config", endpoint);
			if(testCase.isSecure() && context.getGatfExecutorConfig().isSoapAuthEnabled() 
					&& !context.getGatfExecutorConfig().isSoapAuthTestCase(testCase)) {
				String sessIdentifier = context.getSessionIdentifier(testCase);
				String tokenNm = context.getGatfExecutorConfig().getAuthExtractAuthParams()[2];
				if(context.getWorkflowContextHandler().getSuiteWorkflowContext(testCase)!=null &&
						context.getWorkflowContextHandler().getSuiteWorkflowContext(testCase).get(tokenNm)!=null)
				{
					sessIdentifier = context.getWorkflowContextHandler().getSuiteWorkflowContext(testCase).get(tokenNm);
				}
				
				Assert.assertNotNull("Authentication Token is null", sessIdentifier);
				if(endpoint.indexOf("?")!=-1) {
					endpoint += "&" + context.getGatfExecutorConfig().getSoapAuthExtractAuthParams()[1] + "=" + sessIdentifier;
				} else {
					endpoint += "?" + context.getGatfExecutorConfig().getSoapAuthExtractAuthParams()[1] + "=" + sessIdentifier;
				}
			}
			testCase.setAurl(endpoint);
			
			if(request==null || request.trim().isEmpty())
			{
				Document soapMessage = context.getSoapMessages().get(testCase.getWsdlKey()+testCase.getOperationName());
				SOAPResponseValidator.processSOAPRequest(soapMessage, testCase);
				
				Transformer transformer = TransformerFactory.newInstance().newTransformer();
				transformer.setOutputProperty(OutputKeys.INDENT, "yes");        
				StringWriter sw = new StringWriter();
				StreamResult result = new StreamResult(sw);
				DOMSource source = new DOMSource(soapMessage);
				transformer.transform(source, result);
				request = sw.toString();
				body = RequestBody.create(request, null);
			}
			
			try {
			    builder = builder.url(testCase.getAurl());
            } catch (IllegalArgumentException e) {
                Assert.assertTrue("Invalid URL, please check the url provided ("+ testCase.getAurl() + ")", false);
            }
		}
		
		if(testCase.getMethod().equalsIgnoreCase("post") || testCase.getMethod().equalsIgnoreCase("put")) {
			if(body==null) {
				body = RequestBody.create(StringUtils.EMPTY, null);
			}
		}
		builder.method(testCase.getMethod().toUpperCase(), body);
	}
	

	public CompletableFuture<TestCaseReport> executeTestCase(TestCase testCase, TestCaseReport testCaseReport)
