/* +----------------------------------------------------------------------+ | Class: CLauncherImpl | | | | Developper: Eric Gavaldo (eric.gavaldo@xqual.com) | | Version: 1.0 | +----------------------------------------------------------------------+ */ package com.xqual.xlauncher.sql_compare; import java.io.File; import java.io.FileWriter; import java.net.URL; import java.net.URLClassLoader; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.Calendar; import java.util.Vector; import com.xqual.xagent.launcher.CExecutionStep; import com.xqual.xagent.launcher.CLauncher; import com.xqual.xagent.launcher.CParamParsingException; import com.xqual.xagent.launcher.CReturnStatus; import com.xqual.xagent.launcher.runner.CRunner; import com.xqual.xagent.launcher.runner.IRunner; import com.xqual.xcommon.CAttribute; import com.xqual.xcommon.CDriverWrapper; import com.xqual.xcommon.IConstantsResults; import com.xqual.xcommon.utils.CCalendarUtils; import com.xqual.xcommon.utils.CFileUtils; /** * The CLauncherImpl implementation of ILauncher for SQL Compare. * @author egavaldo */ public class CLauncherImpl extends CLauncher implements IConstantsResults { // +==============================================================+ // | Attributes | // +==============================================================+ static final String TRACE_HEADER = "{sql_compare } "; // parameters impacting executing at run time set by the test operator private String sqlScriptRootPath; private String connectionUrl1; private String username1; private String password1; private String driverJar1; private String driverClassPath1; private boolean writeAllValues1; private String connectionUrl2; private String username2; private String password2; private String driverJar2; private String driverClassPath2; private boolean writeAllValues2; private boolean runCommandRemotelyBeforeRunningTest; private String plinkExe; private String plinkRemoteHost; private String plinkUsername; private String plinkPassword; private String command; private Connection connection1 = null; private Connection connection2 = null; File resultLogFile1 = null; File resultLogFile2 = null; // +==============================================================+ // | Constructors | // +==============================================================+ public CLauncherImpl() { super(TRACE_HEADER); } // +==============================================================+ // | Methods | // +==============================================================+ @Override public CReturnStatus initialize(int sutId, String sutName, String sutVersion) { setSutDetails(sutId, sutName, sutVersion); setDefaultTestcaseMustBeCreated(true); // if there is not testcase, let the systems create a default one // check the configuration sent by the manager printConfiguration(); Vector executionSteps = new Vector(); try { // retrieve the parameters we need sqlScriptRootPath = getStringParamValue("SQL", "sql script root path"); // i.e. Y:/XStudio/src connectionUrl1 = getStringParamValue("Connection1", "connection url"); // i.e. jdbc:mysql://localhost/xstudio_db username1 = getStringParamValue("Connection1", "username"); // i.e. xstudio password1 = getStringParamValue("Connection1", "password"); // i.e. xstudiopwd driverJar1 = getStringParamValue("Connection1", "driver jar"); // i.e. Y:/mysql-connector-java-3.1.12/mysql-connector-java-3.1.12-bin.jar driverClassPath1 = getStringParamValue("Connection1", "driver classpath"); // i.e. com.mysql.jdbc.Driver writeAllValues1 = getBooleanParamValue("Connection1", "write all values"); connectionUrl2 = getStringParamValue("Connection2", "connection url"); // i.e. jdbc:mysql://localhost/xstudio_db username2 = getStringParamValue("Connection2", "username"); // i.e. xstudio password2 = getStringParamValue("Connection2", "password"); // i.e. xstudiopwd driverJar2 = getStringParamValue("Connection2", "driver jar"); // i.e. Y:/mysql-connector-java-3.1.12/mysql-connector-java-3.1.12-bin.jar driverClassPath2 = getStringParamValue("Connection2", "driver classpath"); // i.e. com.mysql.jdbc.Driver writeAllValues2 = getBooleanParamValue("Connection2", "write all values"); runCommandRemotelyBeforeRunningTest = getBooleanParamValue("Scripts", "run command remotely before running test"); plinkExe = getStringParamValue("Scripts", "plink executable"); // i.e. C:/progra~1/Putty/plink.exe -batch plinkRemoteHost = getStringParamValue("Scripts", "remote host"); plinkUsername = getStringParamValue("Scripts", "username"); plinkPassword = getStringParamValue("Scripts", "password"); command = getStringParamValue("Scripts", "command"); // i.e. grep /~eric/ /var/log/httpd/access.log > fredlog } catch (CParamParsingException e) { traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization"); executionSteps.add(new CExecutionStep(RESULT_FAILURE, e.getMessage())); return new CReturnStatus(RESULT_FAILURE, executionSteps); } try { File driverFile1 = new File(driverJar1); URL driverUrl1 = driverFile1.toURI().toURL(); URLClassLoader jarLoader1 = URLClassLoader.newInstance(new URL[] { driverUrl1 }, CLauncherImpl.class.getClassLoader()); Class driverClass1 = Class.forName(driverClassPath1, true, jarLoader1); DriverManager.registerDriver(new CDriverWrapper((Driver) driverClass1.newInstance())); traceln(LOG_PRIORITY_INFO, "connecting to " + connectionUrl1 + " with " + username1 + ":" + password1 + "..."); connection1 = DriverManager.getConnection(connectionUrl1, username1, password1); } catch (Exception e) { traceln(LOG_PRIORITY_SEVERE, e.getStackTrace().toString()); traceln(LOG_PRIORITY_SEVERE, "connection to sql database 1 failed: " + e.getMessage()); executionSteps.add(new CExecutionStep(RESULT_FAILURE, "couldn't connect to sql database 1")); return new CReturnStatus(RESULT_FAILURE, executionSteps); } try { File driverFile2 = new File(driverJar2); URL driverUrl2 = driverFile2.toURI().toURL(); URLClassLoader jarLoader2 = URLClassLoader.newInstance(new URL[] { driverUrl2 }, CLauncherImpl.class.getClassLoader()); Class driverClass2 = Class.forName(driverClassPath2, true, jarLoader2); DriverManager.registerDriver(new CDriverWrapper((Driver) driverClass2.newInstance())); traceln(LOG_PRIORITY_INFO, "connecting to " + connectionUrl2 + " with " + username2 + ":" + password2 + "..."); connection2 = DriverManager.getConnection(connectionUrl2, username2, password2); } catch (Exception e) { traceln(LOG_PRIORITY_SEVERE, "connection to sql database 2 failed: " + e.getMessage()); traceln(LOG_PRIORITY_SEVERE, e.getStackTrace().toString()); executionSteps.add(new CExecutionStep(RESULT_FAILURE, "couldn't connect to sql database 2")); return new CReturnStatus(RESULT_FAILURE, executionSteps); } executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "successfully connected to both sql databases")); return new CReturnStatus(RESULT_SUCCESS, executionSteps); } @Override public CReturnStatus preRun(int testId, String testPath, String testName, Vector attributes, String additionalInfo) { traceln(LOG_PRIORITY_INFO, "preRun testId=" + testId + " testPath=" + testPath + " [" + testName + "]..."); Vector executionSteps = new Vector(); if (runCommandRemotelyBeforeRunningTest) { traceln(LOG_PRIORITY_INFO, "running the command remotely..."); CRunner pLinkRunner = new CRunner("[" + testId + "] " + testPath + ":" + testName, plinkExe + " " + plinkRemoteHost + " -l " + plinkUsername + " -pw " + plinkPassword + " " + "\"" + command + "\""); Calendar startTime = Calendar.getInstance(); short resultCommand = pLinkRunner.requestAction(IRunner.START_PROCESS, IRunner.WAIT_END_OF_EXECUTION); Calendar stopTime = Calendar.getInstance(); long duration = stopTime.getTimeInMillis() - startTime.getTimeInMillis(); if (resultCommand == RESULT_FAILURE) { executionSteps.add(new CExecutionStep(resultCommand, "plink failed in " + CCalendarUtils.millisTimeToDurationString(duration))); return new CReturnStatus(RESULT_FAILURE, executionSteps); } else { executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "plink completed in " + CCalendarUtils.millisTimeToDurationString(duration))); } } return new CReturnStatus(RESULT_SUCCESS, executionSteps); } @Override public CReturnStatus run(int testId, String testPath, String testName, int testcaseIndex, String testcaseName, String additionalInfo) { File logFile = new File("sqlCompare_log" + testcaseIndex + ".txt"); if (writeAllValues1) resultLogFile1 = new File("Results1_log" + testcaseIndex + ".txt"); if (writeAllValues2) resultLogFile2 = new File("Results2_log" + testcaseIndex + ".txt"); traceln(LOG_PRIORITY_INFO, "run testId=" + testId + " testPath=" + testPath + ":" + testName + " testcaseIndex=" + testcaseIndex + "..."); writeLog("\n\n\n" + "Executing test: " + testName + " testcaseIndex=" + testcaseIndex, logFile); Vector executionSteps = new Vector(); // +-----------------+ // | script 1 | // +-----------------+ String scriptPath1 = sqlScriptRootPath + "/" + testPath + "/" + testName + "_" + testcaseIndex + "_a.sql"; File script1 = new File(scriptPath1); if (!script1.exists()) { executionSteps.add(new CExecutionStep(RESULT_FAILURE, scriptPath1 + " script 1 not found")); return new CReturnStatus(RESULT_FAILURE, executionSteps); } String scriptContent1 = CFileUtils.FileToString(script1).trim(); writeLog("Query 1:" + scriptContent1, logFile); if (writeAllValues1) writeLog("Query 1:" + scriptContent1, resultLogFile1); // +-----------------+ // | script 1 | // +-----------------+ String scriptPath2 = sqlScriptRootPath + "/" + testPath + "/" + testName + "_" + testcaseIndex + "_b.sql"; File script2 = new File(scriptPath2); if (!script2.exists()) { executionSteps.add(new CExecutionStep(RESULT_FAILURE, scriptPath2 + " script 2 not found")); return new CReturnStatus(RESULT_FAILURE, executionSteps); } String scriptContent2 = CFileUtils.FileToString(script2).trim(); writeLog("Query: 2" + scriptContent2, logFile); if (writeAllValues2) writeLog("Query 2:" + scriptContent2, resultLogFile2); Vector itemVector = new Vector(); int count = 1; boolean error = false; try { Statement statement1 = connection1.createStatement(); Statement statement2 = connection2.createStatement(); ResultSet resultSet1 = statement1.executeQuery(scriptContent1); ResultSet resultSet2 = statement2.executeQuery(scriptContent2); ResultSetMetaData rsmd1 = resultSet1.getMetaData(); int numberOfColumns1 = rsmd1.getColumnCount(); ResultSetMetaData rsmd2 = resultSet2.getMetaData(); int numberOfColumns2 = rsmd2.getColumnCount(); boolean sameNumberOfColumn = numberOfColumns1 == numberOfColumns2; if (!sameNumberOfColumn) { executionSteps.add(new CExecutionStep(RESULT_FAILURE, "1st query Results have " + numberOfColumns1 + " column(s) and " + "2nd query Results have " + numberOfColumns2 + " column(s) => cannot compare")); } while (resultSet1.next()) { resultSet2.next(); traceln(LOG_PRIORITY_INFO, "[Record at line: " + count + "]"); writeLog("\nRecord at line: " + count + "", logFile); writeResults("\nRecord at line: " + count + ""); for (int i = 1; i <= numberOfColumns1; i++) { String columnsNameMysql = rsmd1.getColumnName(i); String columnsNameOracle = rsmd2.getColumnName(i); String field1 = resultSet1.getString(i); String field2 = resultSet2.getString(i); if (field1 == null) field1 = "null"; if (field2 == null) field2 = "null"; traceln(LOG_PRIORITY_INFO, "> " + columnsNameMysql + " (query 1)=" + field1); writeLog(columnsNameMysql + " (query 1)=" + field1, logFile); if (writeAllValues1) writeLog(columnsNameMysql + "(query 1)=" + field1, resultLogFile1); traceln(LOG_PRIORITY_INFO, "> " + columnsNameOracle + " (query 2)=" + field2); writeLog(columnsNameOracle + " (query 2)=" + field2, logFile); if (writeAllValues2) writeLog(columnsNameOracle + " (query 2)=" + field2, resultLogFile2); traceln(LOG_PRIORITY_INFO, "\n"); writeLog("", logFile); writeResults(""); if (field1.equals(field2)) { itemVector.add(field1); } else { executionSteps.add(new CExecutionStep(RESULT_FAILURE, "results differ at line #" + count + "and column #" + i + " where " + field1 + " != " + field2)); writeLog("ERROR: results differ at line #" + count + "and column #" + i + " where " + field1 + " != " + field2, logFile); executionSteps.add(new CExecutionStep(RESULT_FAILURE, "first correct results: " + itemVector)); writeLog("first correct results: " + itemVector, logFile); error = true; if (!writeAllValues1 && !writeAllValues2) { addAttachment(logFile); return new CReturnStatus(RESULT_FAILURE, executionSteps); } } } count++; } } catch (SQLException e) { traceln(LOG_PRIORITY_SEVERE, e.getMessage() + " / parsing error during comparison at entry " + count); executionSteps.add(new CExecutionStep(RESULT_FAILURE, e.getMessage() + " / parsing error during comparison at entry " + count)); addAttachment(logFile); if (writeAllValues1) addAttachment(resultLogFile1); if (writeAllValues2) addAttachment(resultLogFile2); return new CReturnStatus(RESULT_FAILURE, executionSteps); } addAttachment(logFile); if (writeAllValues1) addAttachment(resultLogFile1); if (writeAllValues2) addAttachment(resultLogFile2); if (!error) { executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "results are equals\n Test sucess")); writeLog("results are equals\n Test sucess", logFile); return new CReturnStatus(RESULT_SUCCESS, executionSteps); } else { return new CReturnStatus(RESULT_FAILURE, executionSteps); } } public CReturnStatus postRun(int testId, String testPath, String testName) { traceln(LOG_PRIORITY_INFO, "postRun testId=" + testId + " testPath=" + testPath + ":" + testName + "..."); Vector executionSteps = new Vector(); executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "post-run successful")); return new CReturnStatus(RESULT_SUCCESS, executionSteps); } public CReturnStatus terminate() { return new CReturnStatus(RESULT_SUCCESS); } private void writeResults(String string) { if (writeAllValues1) writeLog(string, resultLogFile1); if (writeAllValues2) writeLog(string, resultLogFile2); } private void writeLog(String s, File f) { try { FileWriter aWriter = new FileWriter(f, true); aWriter.write(s + System.getProperty("line.separator")); aWriter.flush(); aWriter.close(); } catch (java.io.IOException ex) { traceln(LOG_PRIORITY_INFO, "Problem with log file..."); } } }