view src/org/thermostat/qa/framework/ThermostatGuiTest.java @ 150:3d06e2d323cb

refactoring of the framework+testsuites for gui tests so Xvfb+fluxbox may be used
author Jana Fabrikova <jfabriko@redhat.com>
date Tue, 01 Apr 2014 15:09:08 +0200
parents 793668818e6c
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.AWTException;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.lang.reflect.Method;



import java.util.LinkedList;
import java.util.List;



import org.thermostat.qa.framework.ThermostatUtilities.AgentThread;

public abstract class ThermostatGuiTest extends ThermostatTest
{
    private static final String PATTERNS_DIRECTORY = "patterns";
    private static final String AA_SUBDIR = "AA";
    private static final String NOAA_SUBDIR = "noAA";

    private boolean useAntialiasedText = isTextAntialiasingOn();

    /**
     * Test if text antialiasing is used for rendering graphical user interface elements.
     *
     * @return true if system is sure that text antialiasing is used, false otherwise
     */
    protected static boolean isTextAntialiasingOn()
    {
        try
        {
            // Class sun.awt.SunToolkit is not part of Java standard API, so to compile
            // this tool it's needed to use reflections or to disable ct.sym file during
            // compilation.
            Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit");
            Method getDesktopFontHintsMethod = sunToolkitClass.getDeclaredMethod("getDesktopFontHints", (Class<?>[]) null);
            RenderingHints renderingHints = ((RenderingHints) getDesktopFontHintsMethod.invoke(null));
            if (renderingHints == null)
            {
                return false;
            }
            Object textAntialiasing = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
            return textAntialiasing != RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
        }
        catch (Exception e)
        {
            return false;
        }
    }

    /**
     * Test if system font antialiasing setting is used for rendering graphical user interface elements.
     *
     * @return true if system font antialiasing setting is used, false otherwise
     */
    protected static boolean useSystemFontAASettings()
    {
        try
        {
            // Class sun.awt.SunToolkit is not part of Java standard API, so to compile
            // this tool it's needed to use reflections or to disable ct.sym file during
            // compilation.
            Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit");
            Method useSystemAAFontSettingsMethod = sunToolkitClass.getDeclaredMethod("useSystemAAFontSettings", (Class<?>[]) null);
            // make this private method callable
            useSystemAAFontSettingsMethod.setAccessible(true);
            return ((Boolean) useSystemAAFontSettingsMethod.invoke(null)).booleanValue();
        }
        catch (Exception e)
        {
            return false;
        }
    }
    
    public void setupForGuiTests()
    {
        switch(this.configuration.getScreenshotsSource()){
            case DUMMY:
                //do nothing
                break;
                
            case NORMAL:
                //do nothing
                break;
                
            case XVFB:
                //TODO - run script that starts Xvfb and fluxbox
                //export DISPLAY=:1
                //Xvfb :1 -screen 0 1024x768x24 &
                //fluxbox &
                List<String> content = new LinkedList<String>();
                content.add("export DISPLAY=:1");
                content.add("Xvfb :1 -screen 0 1024x768x24 &");
                content.add("fluxbox 2>err &");
                try
                {
                    ThermostatUtilities.runBashScriptWithContent("xvfbStart.sh", content);
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                break;
        }; 
    }
    
    public void tearDownGuiTests()
    {
        switch(this.configuration.getScreenshotsSource()){
            case DUMMY:
                //do nothing
                break;
                
            case NORMAL:
                //do nothing
                break;
                
            case XVFB:
                //TODO - run script that stops Xvfb and fluxbox
                //killall Xvfb
                //killall fluxbox
                List<String> content = new LinkedList<String>();
                content.add("killall fluxbox");
                content.add("killall Xvfb");
                try
                {
                    ThermostatUtilities.runBashScriptWithContent("xvfbStop.sh", content);
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                break;
        };         
    }

    /**
     * Start Thermostat GUI client in a new thread.
     */
    protected void runThermostatGuiInANewThread()
    {
        if(this.configuration.useRealScreenshots())
        {
            new GuiThread().start();
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI started");
        }else{
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI not started, because using dummy screenshots");
        }
    }

    /**
     * Start Thermostat storage.
     */
    protected GuiRobot startStorageOnly() throws AWTException
    {
        GuiRobot robot = new GuiRobot(this.configuration);
        startStorage();
        return robot;
    }

    /**
     * Start Thermostat storage and also Thermostat GUI client in a new thread.
     */
    protected GuiRobot startThermostatAndStorage() throws AWTException, IOException
    {
        GuiRobot robot = new GuiRobot(this.configuration);

        if (this.configuration.useRealScreenshots())
        {
            startStorage();
            runThermostatGuiInANewThread();
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI+storage started");
            sleep(FIVE_SEC);
        }else{
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI+storage not started, because using dummy screenshots");
        }
        return robot;
    }

    /**
     * Start Thermostat web storage and also Thermostat GUI client in a new
     * thread.
     */
    protected GuiRobot startThermostatAndWebStorage() throws AWTException, IOException
    {
        GuiRobot robot = new GuiRobot(this.configuration);

        if (this.configuration.useRealScreenshots())
        {
            startWebStorage();
            runThermostatGuiInANewThread();
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI+web storage started");
            sleep(FIVE_SEC);
        }else{
            logInfo("runThermostatGuiInANewThread", "Thermostat GUI+web storage not started, because using dummy screenshots");
        }
        return robot;
    }
    
    /**
     * Try to find some pattern on the screenshot.
     *
     * @return rectangle with pattern coordinates if pattern is found, null otherwise.
     */
    protected Rectangle findPattern(GuiRobot robot, String patternFileName, String patternName) throws IOException
    {
        logInfo("checkForPattern", "looking for pattern " + patternName);

        // patterns should be divided into two categories: one for desktop with text AA enabled
        // and one for desktop with AA disabled
        String subdir = this.configuration.getThermostatVersion()+"/"+
                        (this.useAntialiasedText ? AA_SUBDIR : NOAA_SUBDIR);
        String fullPatternName = PATTERNS_DIRECTORY + "/" + subdir + "/" + patternFileName + ".png";

        return robot.findPattern(fullPatternName);
    }

    /**
     * Try to find some pattern on the screenshot.
     *
     * @return rectangle with pattern coordinates if pattern is found, null otherwise.
     */
    protected Rectangle findPattern(GuiRobot robot, String[] patternFileNames, String patternName) throws IOException
    {
        Rectangle result = null;
        int version = 1;
        for (String pattern : patternFileNames)
        {
            result = findPattern(robot, pattern, patternName + " version " + version);
            version++;
            if (result != null)
                break;
        }
        return result;
    }

    /**
     * Check if some pattern can really be located on a screenshot.
     *
     * @return rectangle with pattern coordinates if pattern is found, null otherwise.
     */
    protected Rectangle checkForPattern(GuiRobot robot, String patternFileName, String patternName) throws IOException
    {
        Rectangle rectangle = findPattern(robot, patternFileName, patternName);

        if (rectangle == null)
        {
            stopThermostatAndStorage(robot);
        }
        else
        {
            logInfo("checkForPattern", "pattern found at " + rectangle.toString());
        }
        Assert.assertNotNull(rectangle, "Error: " + patternName + " pattern can't be found!");
        robot.highlightRectangle(rectangle);
        return rectangle;
    }

    /**
     * Check if one of the patterns can really be located on a screenshot.
     *
     * @return rectangle with pattern coordinates if pattern is found, null otherwise.
     */
    protected Rectangle checkForPattern(GuiRobot robot, String[] patternFileNames, String patternName) throws IOException
    {
        Rectangle rectangle = findPattern(robot, patternFileNames, patternName);

        if (rectangle == null)
        {
            stopThermostatAndStorage(robot);
        }
        else
        {
            logInfo("checkForPattern", "pattern found at " + rectangle.toString());
        }
        Assert.assertNotNull(rectangle, "Error: " + patternName + " pattern can't be found!");
        robot.highlightRectangle(rectangle);
        return rectangle;
    }

    /**
     * Stop Thermostat storage and also Thermostat GUI client.
     */
    protected void stopThermostatAndStorage(GuiRobot robot) throws IOException
    {
        if (this.configuration.useRealScreenshots())
        {
            stopStorage();
            stopGUI(robot);
        }
    }

    /**
     * Stop Thermostat web storage and also Thermostat GUI client.
     */
    protected void stopThermostatAndWebStorage(GuiRobot robot) throws IOException
    {
        if (this.configuration.useRealScreenshots())
        {
            stopWebStorage();
            stopGUI(robot);
        }
    }
    
    /**
     * Method createScreenshot distinguishes 3 cases from the configuration
     *  <ul>
     *  <li> loading a gtx screenshot,
     *  <li> creating a new screenshot in a classical way from the visible
     *  display, 
     *  <li> creating a new screenshot using Xvbf
     *  </ul>
     * 
     * @param robot
     * @param screenshotName
     * @throws IOException
     */
    protected void prepareScreenshot(GuiRobot robot, String screenshotName) throws IOException
    {
        sleep(ONE_SEC);
        robot.prepareScreenshot(screenshotName);
    }

    public void sleepIfRealScreen(int ms)
    {
        if(this.configuration.useRealScreenshots())
        {
            sleep(ms);
        }
    }
    
    /**
     * Move focus to the Thermostat GUI client main menu by simulating F10 key press action.
     */
    protected void enterMainMenu(GuiRobot robot)
    {
        robot.pressFNKey(10);
    }
    
    /**
     * Method clickOnVMView starts the gui and activates the VM view. 
     * This method distinguishes between the case when we need real
     * screenshots and dummy screenshots. The if statements are not that
     * necessary, they only cut the delays created by (sleep) when dummy
     * screenshots are being used.
     * 
     * @return
     * @throws IOException
     * @throws AWTException
     */
    protected GuiRobot clickOnVMView() throws IOException, AWTException{
        //start storage
        GuiRobot robot = startStorageOnly();
        //start agent
        new AgentThread().start();
        logInfo("runAgentThread", "Thermostat Agent started");
               
        //start gui
        runThermostatGuiInANewThread();
        sleepIfRealScreen(15000);
        
        robot.prepareScreenshot("GuiStarted1");

        //if only host icon is visible, click the '>' icon to see all its vms
        Rectangle r = findPattern(robot, Patterns.MainWindow.HOST_ICON_WITH_ARROW, "host view icon with arrow");
        if(r != null)
        {
            r.width = 6;
            robot.clickToRectangle(r);
            sleepIfRealScreen(ONE_SEC);
        }
        robot.prepareScreenshot("GuiStarted2");
        
        r = checkForPattern(robot, Patterns.MainWindow.VM_VIEW_ICON, "vm view icon");
        
        if(r != null)
        {
            robot.clickToRectangle(r);
            sleepIfRealScreen(2000);
        }
        robot.prepareScreenshot("VMViewActive1");
        
        checkForPattern(robot, Patterns.MainWindow.VM_VIEW_ICON_ACTIVE, "vm view active icon");
        robot.saveScreenshot("VMViewActive2");
        
        return robot;
    }

}