org.apache.falcon.regression.ui.pages.ProcessPage.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.falcon.regression.ui.pages.ProcessPage.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.falcon.regression.ui.pages;

import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.entity.v0.process.Process;
import org.apache.falcon.regression.core.helpers.ColoHelper;
import org.apache.falcon.regression.core.util.TimeUtil;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.Point;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Page of a process entity.
 */
public class ProcessPage extends EntityPage<Process> {

    private static final Logger LOGGER = Logger.getLogger(ProcessPage.class);
    private boolean isLineageOpened = false;

    private static final String INSTANCES_PANEL = "//div[@id='panel-instance']//span";
    private static final String INSTANCE_STATUS_TEMPLATE = INSTANCES_PANEL + "[contains(..,'%s')]";
    private static final String LINEAGE_LINK_TEMPLATE = "//a[@class='lineage-href' and @data-instance-name='%s']";

    //Lineage information xpaths
    private static final String CLOSE_LINEAGE_LINK_TEMPLATE = "//body[@class='modal-open']//button[contains(., 'Close')]";
    private static final String LINEAGE_MODAL = "//div[@id='lineage-modal']";
    private static final String SVG_ELEMENT = "//*[name() = 'svg']/*[name()='g']/*[name()='g']";
    private static final String VERTICES_BLOCKS = SVG_ELEMENT + "[not(@class='lineage-link')]";
    private static final String VERTICES_TEXT = VERTICES_BLOCKS + "//div[@class='lineage-node-text']";
    private static final String EDGE = SVG_ELEMENT + "[@class='lineage-link']//*[name()='path']";
    private static final String CIRCLE = "//*[name() = 'circle']";
    private static final String VERTICES = VERTICES_BLOCKS + CIRCLE;
    private static final String VERTEX_BLOCK_TEMPLATE = VERTICES_BLOCKS + "[contains(., '%s')]";
    private static final String VERTEX_TEMPLATE = VERTEX_BLOCK_TEMPLATE + CIRCLE;

    private static final String LINEAGE_INFO_PANEL_LIST = "//div[@id='lineage-info-panel']"
            + "//div[@class='col-md-3']";

    private static final String LINEAGE_TITLE = LINEAGE_MODAL + "//div[@class='modal-header']/h4";

    private static final String LINEAGE_LEGENDS_BLOCK = LINEAGE_MODAL
            + "//div[@class='modal-body']/div[ul[@class='lineage-legend']]";
    private static final String LINEAGE_LEGENDS_TITLE = LINEAGE_LEGENDS_BLOCK + "/h4";
    private static final String LINEAGE_LEGENDS_ELEMENTS = LINEAGE_LEGENDS_BLOCK + "/ul/li";

    public ProcessPage(WebDriver driver, ColoHelper helper, String entityName) {
        super(driver, helper, EntityType.PROCESS, Process.class, entityName);
    }

    /**
     * @param nominalTime particular instance of process, defined by it's start time
     */
    public void openLineage(String nominalTime) {
        waitForElement(String.format(LINEAGE_LINK_TEMPLATE, nominalTime), DEFAULT_TIMEOUT,
                "Lineage button didn't appear");
        LOGGER.info("Working with instance: " + nominalTime);
        WebElement lineage = driver.findElement(By.xpath(String.format(LINEAGE_LINK_TEMPLATE, nominalTime)));
        LOGGER.info("Opening lineage...");
        lineage.click();
        waitForElement(VERTICES, DEFAULT_TIMEOUT, "Circles not found");
        waitForDisplayed(LINEAGE_TITLE, DEFAULT_TIMEOUT, "Lineage title not found");
        isLineageOpened = true;
    }

    public void closeLineage() {
        LOGGER.info("Closing lineage...");
        if (isLineageOpened) {
            WebElement close = driver.findElement(By.xpath(CLOSE_LINEAGE_LINK_TEMPLATE));
            close.click();
            isLineageOpened = false;
            waitForDisappear(CLOSE_LINEAGE_LINK_TEMPLATE, DEFAULT_TIMEOUT, "Lineage didn't disappear");
        }
    }

    @Override
    public void refresh() {
        super.refresh();
        isLineageOpened = false;
    }

    /**
     * @return map with instances names and their nominal start time
     */
    public HashMap<String, List<String>> getAllVertices() {
        LOGGER.info("Getting all vertices from lineage graph...");
        HashMap<String, List<String>> map = null;
        if (isLineageOpened) {
            waitForElement(VERTICES_TEXT, DEFAULT_TIMEOUT, "Vertices blocks with names not found");
            List<WebElement> blocks = driver.findElements(By.xpath(VERTICES_TEXT));
            LOGGER.info(blocks.size() + " elements found");
            map = new HashMap<>();
            for (WebElement block : blocks) {
                waitForElement(block, ".[contains(.,'/')]", DEFAULT_TIMEOUT,
                        "Expecting text to contain '/' :" + block.getText());
                String text = block.getText();
                LOGGER.info("Vertex: " + text);
                String[] separate = text.split("/");
                String name = separate[0];
                String nominalTime = separate[1];
                if (map.containsKey(name)) {
                    map.get(name).add(nominalTime);
                } else {
                    List<String> instances = new ArrayList<>();
                    instances.add(nominalTime);
                    map.put(name, instances);
                }
            }
        }
        return map;
    }

    /**
     * @return list of all vertices names
     */
    public List<String> getAllVerticesNames() {
        LOGGER.info("Getting all vertices names from lineage graph...");
        List<String> list = new ArrayList<>();
        if (isLineageOpened) {
            waitForElement(CLOSE_LINEAGE_LINK_TEMPLATE, DEFAULT_TIMEOUT, "Close Lineage button not found");
            waitForElement(VERTICES_BLOCKS, DEFAULT_TIMEOUT, "Vertices not found");
            List<WebElement> blocks = driver.findElements(By.xpath(VERTICES_BLOCKS));
            LOGGER.info(blocks.size() + " elements found");
            for (WebElement block : blocks) {
                list.add(block.getText());
            }
        }
        LOGGER.info("Vertices: " + list);
        return list;
    }

    /**
     * Vertex is defined by it's entity name and particular time of it's creation.
     */
    public void clickOnVertex(String entityName, String nominalTime) {
        LOGGER.info("Clicking on vertex " + entityName + '/' + nominalTime);
        if (isLineageOpened) {
            WebElement circle = driver
                    .findElement(By.xpath(String.format(VERTEX_TEMPLATE, entityName + '/' + nominalTime)));
            Actions builder = new Actions(driver);
            builder.click(circle).build().perform();
            TimeUtil.sleepSeconds(0.5);
        }
    }

    /**
     * @return map of parameters from info panel and their values
     */
    public HashMap<String, String> getPanelInfo() {
        LOGGER.info("Getting info panel values...");
        HashMap<String, String> map = null;
        if (isLineageOpened) {
            //check if vertex was clicked
            waitForElement(LINEAGE_INFO_PANEL_LIST, DEFAULT_TIMEOUT, "Info panel not found");
            List<WebElement> infoBlocks = driver.findElements(By.xpath(LINEAGE_INFO_PANEL_LIST));
            LOGGER.info(infoBlocks.size() + " values found");
            map = new HashMap<>();
            for (WebElement infoBlock : infoBlocks) {
                String text = infoBlock.getText();
                String[] values = text.split("\n");
                map.put(values[0], values[1]);
            }
        }
        LOGGER.info("Values: " + map);
        return map;
    }

    /**
     * @return map of legends as key and their names on UI as values
     */
    public HashMap<String, String> getLegends() {
        HashMap<String, String> map = null;
        if (isLineageOpened) {
            map = new HashMap<>();
            List<WebElement> legends = driver.findElements(By.xpath(LINEAGE_LEGENDS_ELEMENTS));
            for (WebElement legend : legends) {
                String value = legend.getText();
                String elementClass = legend.getAttribute("class");
                map.put(elementClass, value);
            }
        }
        return map;
    }

    /**
     * @return the main title of Lineage UI
     */
    public String getLineageTitle() {
        LOGGER.info("Getting Lineage title...");
        if (isLineageOpened) {
            return driver.findElement(By.xpath(LINEAGE_TITLE)).getText();
        } else {
            return null;
        }
    }

    /**
     * @return the name of legends block
     */
    public String getLegendsTitle() {
        LOGGER.info("Getting Legends title...");
        if (isLineageOpened) {
            return driver.findElement(By.xpath(LINEAGE_LEGENDS_TITLE)).getText();
        } else {
            return null;
        }
    }

/**
 * @return list of edges present on UI. Each edge presented as two 2d points - beginning and
 * the end of the edge.
 */
public List<Point[]> getEdgesFromGraph() {
    List<Point[]> pathsEndpoints = null;
    LOGGER.info("Getting edges from lineage graph...");
    if (isLineageOpened) {
        pathsEndpoints = new ArrayList<>();
        List<WebElement> paths = driver.findElements(By.xpath(EDGE));
        LOGGER.info(paths.size() + " edges found");
        for (WebElement path : paths) {
            String[] coordinates = path.getAttribute("d").split("[MLC,]");
            int x = 0, y, i = 0;
            while (i < coordinates.length) {
                if (!coordinates[i].isEmpty()) {
                    x = (int) Double.parseDouble(coordinates[i]);
                    break;
                } else {
                    i++;
                }
            }
            y = (int) Double.parseDouble(coordinates[i + 1]);
            Point startPoint = new Point(x, y);
            x = (int) Math.round(Double.parseDouble(coordinates[coordinates.length - 2]));
            y = (int) Math.round(Double.parseDouble(coordinates[coordinates.length - 1]));
            Point endPoint = new Point(x, y);
            LOGGER.info("Edge " + startPoint + '' + endPoint);
            pathsEndpoints.add(new Point[]{startPoint, endPoint});
        }
    }
    return pathsEndpoints;
}

    /**
     * @return common value for radius of every vertex (circle) on the graph
     */
    public int getCircleRadius() {
        LOGGER.info("Getting value of vertex radius...");
        WebElement circle = driver.findElements(By.xpath(VERTICES)).get(0);
        return Integer.parseInt(circle.getAttribute("r"));
    }

    /**
     * Finds vertex on the graph by its name and evaluates its coordinates as 2d point.
     * @param vertex the name of vertex which point is needed
     * @return Point(x,y) object
     */
    public Point getVertexEndpoint(String vertex) {
        /** get circle of start vertex */
        LOGGER.info("Getting vertex coordinates...");
        WebElement block = driver.findElement(By.xpath(String.format(VERTEX_BLOCK_TEMPLATE, vertex)));
        String attribute = block.getAttribute("transform");
        attribute = attribute.replaceAll("[a-zA-Z]", "");
        String[] numbers = attribute.replaceAll("[()]", "").split(",");
        return new Point(Integer.parseInt(numbers[0]), Integer.parseInt(numbers[1]));
    }

    /**
     * Returns status of instance from instances panel.
     * @param instanceDate date stamp of instance
     * @return status of instance from instances panel
     */
    public String getInstanceStatus(String instanceDate) {
        waitForInstancesPanel();
        LOGGER.info("Getting status of " + instanceDate + " instance");
        List<WebElement> status = driver
                .findElements(By.xpath(String.format(INSTANCE_STATUS_TEMPLATE, instanceDate)));
        if (status.isEmpty()) {
            return null;
        } else {
            return status.get(0).getAttribute("class").replace("instance-icons instance-link-", "");
        }
    }

    /**
     * Checks if 'Lineage' link is present on instances panel.
     * @param instanceDate date stamp of instance
     * @return true if link is present
     */
    public boolean isLineageLinkPresent(String instanceDate) {
        waitForInstancesPanel();
        LOGGER.info("Checking if 'Lineage' link is present for " + instanceDate);
        List<WebElement> lineage = driver
                .findElements(By.xpath(String.format(LINEAGE_LINK_TEMPLATE, instanceDate)));
        return !lineage.isEmpty();
    }

    private void waitForInstancesPanel() {
        waitForElement(INSTANCES_PANEL, DEFAULT_TIMEOUT, "Instances panel didn't appear");
    }

    /**
     * Checks whether vertex is terminal or not.
     * @param vertexName name of vertex
     * @return whether it is terminal or not
     */
    public boolean isTerminal(String vertexName) {
        LOGGER.info("Checking if " + vertexName + " is 'terminal' instance");
        waitForElement(String.format(VERTEX_TEMPLATE, vertexName), DEFAULT_TIMEOUT, "Vertex not found");
        WebElement vertex = driver.findElement(By.xpath(String.format(VERTEX_TEMPLATE, vertexName)));
        String vertexClass = vertex.getAttribute("class");
        return vertexClass.contains("lineage-node-terminal");
    }
}