view src/org/thermostat/qa/framework/ThermostatUtilities.java @ 167:7baba5d67a16

Fixes of gui tests and web storage tests, making tests more independent * Makefile: added possibility to change backend for making screenshots * Makefile: fixed problem with web storage (content of thermostat webapp direcory is copied in /webaps/thermostat instead of *.war) * Makefile: add coping configuration files to thermostat user directory, which fixed problem of some tests relying on leftower configuration and make it possible run them independently * README.md: new informations about screenshot backends included * src/org/thermostat/qa/framework/Patterns.java: new possible patterns for some tabs added (versions of tabs highlighted under cursor) * src/org/thermostat/qa/framework/ThermostatUtilities.java: thermostats jaas configruation file is now passed to tomcat * src/org/thermostat/qa/testsuites/GuiClientSmokeTest.java: adding 1 second delay fixed problem, when test sometimes failed * src/org/thermostat/qa/testsuites/GuiHostViewSmokeTest.java: window is now not resized more than necessary (caused problem where part of the window did not fit in lower resolution (1024x768) displays/vncs and test failed) * patterns/1.1.0/noAA/ClientPreferencesDialog/connection_info_label.png: added/updated pattern * patterns/1.1.0/noAA/HostView/memory_tab_chsen.png: same as previous * patterns/1.1.0/noAA/HostView/notes_tab.png: same as previous * patterns/1.1.0/noAA/HostView/notes_tab_chosen.png: same as previous * patterns/1.1.0/noAA/HostView/memory_tab_chosen2.png: same as previous * patterns/1.1.0/noAA/HostView/numa_tab_chosen2.png: same as previous * patterns/1.1.0/noAA/HostView/processor_tab_chosen2.png: same as previous
author Zdenek Zambersky <zzambers@redhat.com>
date Fri, 21 Nov 2014 10:50:09 +0100
parents e8ad3e5e4893
children
line wrap: on
line source

/*

    ThermostatQA - test framework for Thermostat Monitoring Tool

    Copyright 2013 Red Hat, Inc.

This file is part of ThermostatQA

ThermostatQA is distributed under the GNU General Public License,
version 2 or any later version (with a special exception described
below, commonly known as the "Classpath Exception").

A copy of GNU General Public License (GPL) is included in this
distribution, in the file COPYING.

Linking ThermostatQA code with other modules is making a combined work
based on ThermostatQA.  Thus, the terms and conditions of the GPL
cover the whole combination.

As a special exception, the copyright holders of ThermostatQA give you
permission to link this code with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on ThermostatQA code.  If you modify ThermostatQA, you may
extend this exception to your version of the software, but you are
not obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.
*/



package org.thermostat.qa.framework;

import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;



import org.thermostat.qa.common.Configuration;
import org.thermostat.qa.reporter.FileUtils;



/**
 * Class ThermostatUtilities
 * contains the helper methods for running thermostat commands in processes,
 * running auxiliary scripts, and getting output from the processes.
 *
 */

public abstract class ThermostatUtilities
{

    private static final String tomcatHome = System.getProperty("tomcat.home");

    /**
     * Expected exit value of all thermostat processes.
     */
    protected static final int EXPECTED_EXIT_VALUE = 0;

    protected static final int ONE_SEC = 1000;
    protected static final int FIVE_SEC = 5 * ONE_SEC;
    
    protected String mongoPortString = null;

    /**
     * Current configuration of thermostat tests.
     */
    protected Configuration configuration = null;
    
    public void setConfigurationFromProperties(String[] args)
    {
        this.configuration = new Configuration(args);
    }

    public class ServiceStarter implements Runnable
    {
        @Override
        public void run()
        {
            Process process;
            try
            {
                process = runThermostatInNewProcess("service", "");
                List<String> processOutput = readProcessOutput(process);
                for (String s : processOutput)
                {
                    logInfo("run", "Service starter: " +  s);
                }
                Assert.assertNotNull(processOutput, "error getting standard output");
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    public class StorageStarter implements Runnable
    {
        @Override
        public void run()
        {
            Process process;
            try
            {
                process = runThermostatInNewProcess("storage", "--start");
                List<String> processOutput = readProcessOutput(process);
                for (String s : processOutput)
                {
                    logInfo("run", "Storage starter: " +  s);
                }
                Assert.assertNotNull(processOutput, "error getting standard output");
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    public class GuiThread extends Thread
    {
        @Override
        public void run()
        {
            Process process;
            try
            {
                process = runThermostatInNewProcess("gui");
                List<String> processOutput = readProcessOutput(process);
                sleep(ONE_SEC);
                Assert.assertNotNull(processOutput, "no output from process");
                int exitValue = process.exitValue();
                Assert.assertEquals(exitValue, EXPECTED_EXIT_VALUE, "Bad thermostat exit value " + exitValue);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    public class AgentThread extends Thread
    {
        @Override
        public void run()
        {
         Process process;
         try
         {
             process = runThermostatInNewProcess("agent");
             List<String> processOutput = readProcessOutput(process);
             sleep(ONE_SEC);
             Assert.assertNotNull(processOutput, "no output from process");
//             int exitValue = process.exitValue();
//             Assert.assertEquals(exitValue, EXPECTED_EXIT_VALUE, "Bad thermostat exit value " + exitValue);
         }
         catch (IOException e)
         {
             e.printStackTrace();
         }
         catch (InterruptedException e)
         {
             e.printStackTrace();
         }
        }        
    }

    /**
     * Log into a standard output.
     * 
     * @param prefix
     *            string printed before class name.
     * @param delimiter
     *            delimiter between prefix and the class name.
     * @param methodName
     *            name of method implementing the test.
     */
    protected void log(String prefix, char delimiter, String methodName) {
        System.out.println(prefix + ": " + this.getClass().getName() + delimiter + methodName);
    }

    protected void logInfo(String methodName, String message)
    {
        log("INFO", '.', methodName + ": " + message);
    }

    /**
     * Log into a standard output.
     * 
     * @param prefix
     *            string printed before class name.
     * @param delimiter
     *            delimiter between prefix and the class name.
     * @param methodName
     *            name of method implementing the test.
     * @param exception
     *            message generated from exception
     */
    protected void log(String prefix, char delimiter, String methodName, String exception) {
        System.out.println(prefix + ": " + this.getClass().getName() + delimiter + methodName + " " + exception);
    }

    /**
     * Returns version of Java. The input could have the following form: "1.7.0_06"
     * and we are interested only in "7" in this case.
     * 
     * @return Java version
     */
    protected int getJavaVersion() {
        String javaVersionStr = System.getProperty("java.version");
        String[] parts = javaVersionStr.split("\\.");
        return Integer.parseInt(parts[1]);
    }

    /**
     * 
     * @param process
     * @throws IOException
     */
    protected void waitForExternalProcess(Process process) throws IOException
    {
        InputStreamReader processStdOut = new InputStreamReader(process.getInputStream());
        while (processStdOut.read() != -1)
        {
            // should be empty ;-)
        }
        processStdOut.close();
    }

    /**
     * 
     * @param process
     * @return
     * @throws IOException
     */
    public static List<String> readProcessOutput(Process process) throws IOException
    {
        List<String> out = new ArrayList<String>();
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = bufferedReader.readLine()) != null)
        {
            out.add(line);
        }
        bufferedReader.close();
        return out;
    }
  
    /**
     * 
     * @param cmd
     * @return
     * @throws IOException
     */
    protected static Process runProcess(String... cmd) throws IOException
    {
        return Runtime.getRuntime().exec(cmd);
    }

    /**
     * 
     * @return
     * @throws IOException
     */
    protected Process runThermostatInNewProcess() throws IOException
    {
        return Runtime.getRuntime().exec(this.configuration.getThermostatExecutable());
    }

    /**
     * 
     * @param flags
     * @return
     * @throws IOException
     */
    public Process runThermostatInNewProcess(String... flags) throws IOException
    {
        if (!useFlags(flags))
        {
            return runThermostatInNewProcess();
        }
        String[] cmdArray = new String[flags.length + 1];
        cmdArray[0] = this.configuration.getThermostatExecutable();
        System.arraycopy(flags, 0, cmdArray, 1, flags.length);
        return Runtime.getRuntime().exec(cmdArray);
    }

    /**
     * 
     * @param flags
     * @return
     */
    private static boolean useFlags(String... flags)
    {
        return !(flags == null || flags.length == 0 || flags[0] == null);
    }

    /**
     * 
     * @param scriptName
     * @return
     * @throws IOException
     */
    public static List<String> runHelperBashScript(String scriptName, String... params) throws IOException
    {
        String readScriptName = "./scripts/" + scriptName;

        if (!useFlags(params))
        {
            Process process = runProcess("bash", readScriptName);
            return readProcessOutput(process);
        }
        String[] cmdArray = new String[params.length + 2];
        cmdArray[0] = "bash";
        cmdArray[1] = readScriptName;
        System.arraycopy(params, 0, cmdArray, 2, params.length);
        Process process = runProcess(cmdArray);
        return readProcessOutput(process);
    }
    
    /**
     * Method makeScriptExecutable 
     * takes a name of a file in ./scripts and performs chmod +x
     * 
     * @param scriptName
     * @throws IOException
     */
    protected static void makeScriptExecutable(String scriptName) throws IOException
    {
        String[] cmdArray = new String[]{"chmod","+x","./scripts/"+scriptName};
        Runtime.getRuntime().exec(cmdArray);
    }
    
    /**
     * Method runBashScriptWithContent
     * gets list of strings which it writes as a content of a script with
     * given name, makes this script executable and runs it.
     * 
     * @param scriptName
     * 
     * @param content
     * @param params
     * @return
     * @throws IOException
     */
    public static List<String> runBashScriptWithContent(String scriptName, List<String> content, String... params) throws IOException
    {
        //write content into a file in ./scripts
        FileUtils.writeTextFile("./scripts/"+scriptName, content);
        makeScriptExecutable(scriptName);        
        return runHelperBashScript(scriptName, params);
    }
    
    /**
     * Method thermostatPingHost
     * calls thermostat ping hostId, usable when the db does not require
     * login and password.
     * 
     * @param hostId
     * @return
     * @throws IOException 
     */
    protected List<String> thermostatPingHost(String hostId) throws IOException{
        String scriptname="thermostatPingHost.sh";
        
        List<String> content = new LinkedList<String>();
        content.add(this.configuration.getThermostatExecutable() + " ping "+hostId);
                
        return runBashScriptWithContent(scriptname, content);
    }
    
    /**
     * Method thermostatPingHost
     * calls thermostat ping hostId, usable when the db requires
     * login and password (possibly empty).
     *  
     * @param hostId
     * @param login
     * @param passwd
     * @return
     * @throws IOException
     */
    protected List<String> thermostatPingHost(String hostId, String login, String passwd) throws IOException{
        String scriptname="thermostatPingHost.sh";
        
        List<String> dblogin = new LinkedList<String>();
        dblogin.add(login);
        dblogin.add(passwd);
        FileUtils.writeTextFile("./scripts/dblogin.txt", dblogin);
        
        List<String> content = new LinkedList<String>();
        content.add(this.configuration.getThermostatExecutable() + " ping "+hostId+" < ./scripts/dblogin.txt");
                
        return runBashScriptWithContent(scriptname, content);
    }
    
    protected List<String> thermostatListVms(String login, String passwd) throws IOException{
        String scriptname="thermostatListVms.sh";
        
        createDBLoginTextFile(login, passwd);
        
        List<String> content = new LinkedList<String>();
        content.add(this.configuration.getThermostatExecutable() + " list-vms < ./scripts/dblogin.txt");
                
        return runBashScriptWithContent(scriptname, content);
    }

    protected List<String> thermostatDumpHeap(String hostId, String vmId, String login, String passwd) throws IOException{
        String scriptname="thermostatDumpHeap.sh";
        
        createDBLoginTextFile(login, passwd);
        
        List<String> content = new LinkedList<String>();
        content.add(this.configuration.getThermostatExecutable() + " dump-heap -a " + hostId + " -v " + vmId + " < ./scripts/dblogin.txt" );
                
        return runBashScriptWithContent(scriptname, content);
    }
    
    protected void createDBLoginTextFile(String login, String passwd){
        List<String> dblogin = new LinkedList<String>();
        dblogin.add(login);
        dblogin.add(passwd);
        FileUtils.writeTextFile("./scripts/dblogin.txt", dblogin);
        
    }
    
    protected void sleep(int ms)
    {
        try
        {
            Thread.sleep(ms);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    protected void printOutput(List<String> out)
    {
        for (String s : out)
        {
            System.out.println(s);
        }
    }

    protected void startStorage()
    {
        new Thread(new StorageStarter()).start();
        // let the storage to setup and warm-up
        sleep(2 * ONE_SEC);
    }

    protected void stopStorage() throws IOException
    {
        Process process = runThermostatInNewProcess("storage", "--stop");
        List<String> processOutput = readProcessOutput(process);
        for (String s : processOutput)
        {
            logInfo("run", "Storage stopper: " +  s);
        }
        Assert.assertNotNull(processOutput, "error getting standard output");
    }
    
    public List<String> runCommandsInThermostatShell(String commandsFileName) throws IOException
    {
        String scriptFileName = "run_thermostat_shell_with_commands.sh";
        //write the script specific to our test.properties
        //thermostat bin shell + commands for thermostat shell
        List<String> lines = new LinkedList<String>();
        lines.add(this.configuration.getThermostatExecutable() + " shell < ./scripts/" + commandsFileName);
        FileUtils.writeTextFile("./scripts/"+scriptFileName, lines);
        
        //chmod - make the script executable
        makeScriptExecutable(scriptFileName);
                
        //run the new script
        return runHelperBashScript(scriptFileName);
    }
    
    public List<String> runCommandsInMongoShell(String commandsFileName) throws IOException
    {
        String scriptFileName = "run_mongo_shell_with_commands.sh";
        //write the script specific to our test.properties
        //thermostat bin shell + commands for thermostat shell
        List<String> lines = new LinkedList<String>();
        lines.add("mongo 127.0.01:27518 " + commandsFileName);
        FileUtils.writeTextFile("./scripts/"+scriptFileName, lines);
        
        //chmod - make the script executable
        makeScriptExecutable(scriptFileName);
                
        //run the new script
        return runHelperBashScript(scriptFileName);        
    }
    
    protected void stopGUI(GuiRobot robot)
    {
        robot.pressCtrlPlusSmallLetter('q');
    }

    protected void startWebStorage() throws IOException
    {
        // whereas the storage would be started/stopped many times
        startStorage();
        startTomcat();
    }

    protected void stopWebStorage() throws IOException
    {
        stopTomcat();
        stopStorage();
    }

    /**
     * Method prepareWebStorageConfigFiles
     * copies thermostat configuration files for agent and client logins
     * and thermostat-roles, thermostat-users from 
     * /storageconfig/web-tomcat.
     * The method does it by creating a script 
     * webStorage_prepareWebConfig.sh
     * and running this script.
     * 
     * @throws IOException
     */
    protected void prepareWebStorageConfigFiles() throws IOException
    {
        List<String> lines = new LinkedList<String>();
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/agent.auth "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/agent.properties "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/client.properties "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/thermostat-roles.properties "+this.configuration.getThermostatHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/thermostat-users.properties "+this.configuration.getThermostatHome() + "etc/");

        runBashScriptWithContent("webStorage_prepareWebConfig.sh", lines);        
    }

    /**
     * Method prepareWebStorageBadClientLoginFile
     * copies a thermostat configuration file for client logins that would not
     * work, because the login and password will be different from the ones
     * given in the thermostat configuration. 
     * 
     * The method does it by creating a script 
     * webStorage_prepareBadClientAuth.sh
     * and running this script.
     * 
     * @throws IOException
     */
    protected void prepareWebStorageBadClientLoginFile() throws IOException
    {
        List<String> lines = new LinkedList<String>();
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/client.badauth "+this.configuration.getThermostatUserHome() + "etc/client.properties");
        
        runBashScriptWithContent("webStorage_prepareBadClientAuth.sh", lines);        
    }
    
    /**
     * Method prepareWebStorageBadAgentLoginFile
     * copies a thermostat configuration file for agent logins that would not
     * work, because the login and password will be different from the ones
     * given in the thermostat configuration. 
     * 
     * The method does it by creating a script 
     * webStorage_prepareBadAgentAuth.sh
     * and running this script.
     * 
     * @throws IOException
     */
    protected void prepareWebStorageBadAgentLoginFile() throws IOException
    {
        List<String> lines = new LinkedList<String>();
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/web-tomcat/agent.badauth "+this.configuration.getThermostatUserHome() + "etc/agent.auth");
        
        runBashScriptWithContent("webStorage_prepareBadAgentAuth.sh", lines);        
    }

    /**
     * Method restoreNormalStorageConfigFiles
     * copies the configuration files for agent and client logins
     * and thermostat-roles, thermostat-users from 
     * /storageconfig/db-mongodb. 
     * The method does it by creating a script 
     * webStorage_restoreNormalConfig.sh
     * and running this script.
     * 
     * @throws IOException
     */
    protected void restoreNormalStorageConfigFiles() throws IOException
    {
        //move back the original versions of the configuration files
        //web storage -> mongodb
        List<String> lines = new LinkedList<String>();
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/db-mongodb/agent.auth "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/db-mongodb/agent.properties "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/db-mongodb/client.properties "+this.configuration.getThermostatUserHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/db-mongodb/thermostat-roles.properties "+this.configuration.getThermostatHome() + "etc/");
        lines.add("cp ./storageconfig/"+this.configuration.getThermostatVersion()+"/db-mongodb/thermostat-users.properties "+this.configuration.getThermostatHome() + "etc/");

        runBashScriptWithContent("webStorage_restoreNormalConfig.sh", lines);     
    }

    protected void startTomcat() throws IOException
    {
        //startup.sh from the apache-tomcat dir
        List<String> lines = new LinkedList<String>();
        lines.add("JAVA_OPTS=\"-Djava.security.auth.login.config=" + configuration.getThermostatHome() + "etc/thermostat_jaas.conf\" " + tomcatHome + File.separator + "bin/startup.sh");

        runBashScriptWithContent("webStorage_startTomcat.sh", lines);     
    }

    protected void stopTomcat() throws IOException
    {
        //shutdown.sh from the apache-tomcat dir
        List<String> lines = new LinkedList<String>();
        lines.add(tomcatHome + File.separator + "bin/shutdown.sh");

        runBashScriptWithContent("webStorage_stopTomcat.sh", lines);  
    }

    protected List<String> getTomcatOutputs(String filename) 
    {
        List<String> result = new LinkedList<String>();
        
        //for now only the catalina.out file
        String catalinaOutFile = tomcatHome + File.separator + "logs/" + filename;
        result = FileUtils.readTextFile(catalinaOutFile);
        
        return result;
    }
    
    protected void createTomcatThermostatOutputFiles() throws IOException
    {
        //cat all files of thermostat-web-storage-* into one text file
        //called thermostat-web-storage-logs.txt
        //similarly for catalina* files
        //and localhost_access_log_* files
        
        List<String> lines = new LinkedList<String>();
        lines.add("cat " + tomcatHome + File.separator + "logs/thermostat-web-storage.* > " +
                        tomcatHome + File.separator + "logs/thermostat-web-storage-logs.txt");

        lines.add("cat " + tomcatHome + File.separator + "logs/localhost_access_log_* > " +
                        tomcatHome + File.separator + "logs/localhost_access_logs.txt");

        lines.add("cat " + tomcatHome + File.separator + "logs/catalina* > " +
                        tomcatHome + File.separator + "logs/catalina-logs.txt");
        
        runBashScriptWithContent("webStorage_allThermostatLogsInOne.sh", lines);  
    }

    protected void eraseTomcatOutputFiles() throws IOException
    {
        //rm all log files
        List<String> lines = new LinkedList<String>();
                
        lines.add("rm "+ tomcatHome + File.separator + "logs/catalina*");
        lines.add("rm "+ tomcatHome + File.separator + "logs/thermostat-web-storage*");
        lines.add("rm "+ tomcatHome + File.separator + "logs/localhost_access_log*");
        
        runBashScriptWithContent("webStorage_removeAllThermostatLogsFromTomcat.sh", lines);
    }
    
    protected String getMongoPortString() throws IOException
    {
        if(this.mongoPortString == null)
        {
            startStorage();
            runHelperBashScript("find_mongo_port.sh");
            List<String> lines = FileUtils.readTextFile("./scripts/mongoPortNumber.txt");
            this.mongoPortString = lines.get(0);
            stopStorage();
        }
        return this.mongoPortString;
    }
}