/**
* 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.search;
import org.apache.commons.lang.StringUtils;
import org.apache.falcon.entity.v0.cluster.ACL;
import org.apache.falcon.entity.v0.cluster.ClusterLocationType;
import org.apache.falcon.entity.v0.cluster.Interface;
import org.apache.falcon.entity.v0.cluster.Interfacetype;
import org.apache.falcon.entity.v0.cluster.Location;
import org.apache.falcon.entity.v0.cluster.Property;
import org.apache.falcon.regression.Entities.ClusterMerlin;
import org.apache.falcon.regression.core.util.UIAssert;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.FindBys;
import org.testng.Assert;
import java.util.List;
/** Page object of the Cluster creation page. */
public class ClusterWizardPage extends EntityWizardPage {
private static final Logger LOGGER = Logger.getLogger(ClusterWizardPage.class);
@FindBys({
@FindBy(className = "mainUIView"),
@FindBy(className = "clusterForm")
})
private WebElement clusterBox;
@FindBy(id = "cluster.step1")
private WebElement next;
@FindBy(id = "cluster.step2")
private WebElement save;
@FindBy(id = "cluster.backToStep1")
private WebElement previous;
@FindBy(xpath = "//a[contains(text(), 'Cancel')]")
private WebElement cancel;
@FindBy(xpath = "//div[contains(@class, 'clusterSummaryRow')][h4]")
private WebElement summaryBox;
public ClusterWizardPage(WebDriver driver) {
super(driver);
}
@Override
public void checkPage() {
UIAssert.assertDisplayed(clusterBox, "Cluster box");
}
/**
* Fills cluster setup forms with values retrieved from Filling object.
*/
public void fillForm(ClusterMerlin cluster) {
setName(cluster.getName());
setColo(cluster.getColo());
setDescription(cluster.getDescription());
setTags(cluster.getTags());
ACL acl = cluster.getACL();
setOwner(acl.getOwner());
setGroup(acl.getGroup());
setPermissions(acl.getPermission());
for(Interface iface : cluster.getInterfaces().getInterfaces()) {
setInterface(iface);
}
for (Property property : cluster.getProperties().getProperties()) {
addProperty(property.getName(), property.getValue());
}
setLocations(cluster.getLocations().getLocations());
waitForAngularToFinish();
}
/**
* Methods to fill specific wizard fields.
*/
public void setName(String name) {
WebElement nameInput = getNameInput();
nameInput.clear();
sendKeysSlowly(nameInput, name);
}
public String getName() {
return getNameInput().getAttribute("value");
}
private WebElement getNameInput() {
return driver.findElement(By.xpath("//div[label[text()='Name']]/input"));
}
public void setColo(String colo) {
WebElement coloInput = clusterBox.findElement(By.xpath("//div[label[text()='Colo']]/input"));
coloInput.clear();
sendKeysSlowly(coloInput, colo);
}
public void setDescription(String description) {
WebElement descriptionInput = clusterBox.findElement(By.xpath("//div[label[text()='Description']]/input"));
descriptionInput.clear();
sendKeysSlowly(descriptionInput, description);
}
public void setOwner(String owner) {
WebElement ownerInput = clusterBox.findElement(By.xpath("//div[label[text()='Owner']]/input"));
ownerInput.clear();
sendKeysSlowly(ownerInput, owner);
}
public void setGroup(String group) {
WebElement groupInput = clusterBox.findElement(By.xpath("//div[label[text()='Group']]/input"));
groupInput.clear();
sendKeysSlowly(groupInput, group);
}
public void setPermissions(String permissions) {
WebElement permissionsInput = clusterBox.findElement(By.xpath("//div[label[text()='Permissions']]/input"));
permissionsInput.clear();
sendKeysSlowly(permissionsInput, permissions);
}
/**
* Common method to fill interfaces.
*/
public void setInterface(Interface iface) {
String xpath = "//input[contains(@ng-model,"
+ " 'clusterEntity.clusterModel.cluster.interfaces.interface[%sPos]._endpoint')]";
WebElement ifaceEndpoint = clusterBox.findElement(By.xpath(String.format(xpath, iface.getType().value())));
ifaceEndpoint.clear();
sendKeysSlowly(ifaceEndpoint, iface.getEndpoint());
setInterfaceVersion(iface);
}
/**
* Set interface version by interface type.
*/
public void setInterfaceVersion(Interface iface) {
WebElement ifaceVersion = getInterfaceVersionInput(iface.getType());
if (iface.getVersion() != null) {
ifaceVersion.clear();
sendKeysSlowly(ifaceVersion, iface.getVersion());
}
}
/**
* Get input for interface version by interface type.
*/
private WebElement getInterfaceVersionInput(Interfacetype interfacetype) {
return clusterBox.findElement(By.xpath(String.format(
"//input[@ng-model='clusterEntity.clusterModel.cluster.interfaces.interface[%sPos]._version']",
interfacetype.value())));
}
/**
* Populates form with tags.
*/
public void setTags(String tagsStr){
if (!StringUtils.isEmpty(tagsStr)) {
String [] tags = tagsStr.split(",");
for (int i = 0; i < tags.length; i++) {
if (i > 0){
clickAddTag();
}
String key = tags[i].trim().split("=")[0];
String value = tags[i].trim().split("=")[1];
addTag(key, value);
}
}
}
/**
* Populates last (empty) tag and value fields and creates new fields.
* @param key tag key
* @param value tag value
*/
public void addTag(String key, String value) {
List<WebElement> tagInputs = clusterBox.findElements(By.xpath("//input[@ng-model='tag.key']"));
List<WebElement> valueInputs = clusterBox.findElements(By.xpath("//input[@ng-model='tag.value']"));
WebElement tagInput = tagInputs.get(tagInputs.size() - 1);
sendKeysSlowly(tagInput, key);
WebElement valueInput = valueInputs.get(valueInputs.size() - 1);
sendKeysSlowly(valueInput, value);
}
public void clickAddTag() {
clusterBox.findElement(By.xpath("//button[contains(., 'add tag')]")).click();
}
public void clickDeleteTag() {
List<WebElement> buttons = clusterBox
.findElements(By.xpath("//div[@class='row dynamic-table-spacer ng-scope']//button[contains(.,'delete')]"));
buttons.get(buttons.size() - 1).click();
}
/**
* Fills property fields and creates new empty property fields.
*/
public void addProperty(String name, String value) {
List<WebElement> propInputs = clusterBox.findElements(By.xpath("//input[@ng-model='property._name']"));
List<WebElement> valueInputs = clusterBox.findElements(By.xpath("//input[@ng-model='property._value']"));
WebElement propInput = propInputs.get(propInputs.size()-1);
sendKeysSlowly(propInput, name);
WebElement valueInput = valueInputs.get(valueInputs.size() - 1);
sendKeysSlowly(valueInput, value);
clickAddProperty();
}
public void clickAddProperty() {
clusterBox.findElement(By.xpath("//button[contains(., 'add property')]")).click();
}
/**
* Method to set locations. Location can be only one of ClusterLocationType. So adding new location only after
* respective compulsory location was filled.
* @param locations locations
*/
public void setLocations(List<Location> locations) {
boolean staging = false, temp = false, working = false;
for(Location location : locations) {
WebElement pathInput = null;
if (location.getName() == ClusterLocationType.STAGING && !staging) {
pathInput = clusterBox.findElement(By.id("location.staging"));
staging = true;
} else if (location.getName() == ClusterLocationType.TEMP && !temp) {
pathInput = clusterBox.findElement(By.id("location.temp"));
temp = true;
} else if (location.getName() == ClusterLocationType.WORKING && !working) {
pathInput = clusterBox.findElement(By.id("location.working"));
working = true;
} else {
fillAdditionalLocation(location);
}
if (pathInput != null) {
pathInput.clear();
sendKeysSlowly(pathInput, location.getPath());
}
}
}
/**
* Method populates last location fields with values and creates new fields.
*/
public void fillAdditionalLocation(Location location) {
List<WebElement> allNameInputs = clusterBox
.findElements(By.xpath("//input[contains(@ng-model, 'location._name')]"));
sendKeysSlowly(allNameInputs.get(allNameInputs.size() - 1), location.getName().value());
List<WebElement> allPathInputs = clusterBox
.findElements(By.xpath("//input[contains(@ng-model, 'location._path')]"));
sendKeysSlowly(allPathInputs.get(allPathInputs.size() - 1), location.getPath());
}
public void clickAddLocation() {
clusterBox.findElement(By.xpath("//button[contains(., 'add location')]")).click();
}
public void clickDeleteLocation() {
List<WebElement> buttons = clusterBox
.findElements(By.xpath("//div[@class='row ng-scope']//button[contains(.,'delete')]"));
Assert.assertFalse(buttons.isEmpty(), "Delete button should be present.");
buttons.get(buttons.size() - 1).click();
}
public boolean checkElementByContent(String elementTag, String content) {
List<WebElement> elements = clusterBox.findElements(By.xpath("//" + elementTag));
for(WebElement element : elements) {
if (element.getAttribute("value").equals(content)) {
return true;
}
}
return false;
}
/**
* Method to assert the staging and Working location are same.
*/
public void assertLocationsEqualError(){
// Assertion for Staging Location.
LOGGER.info(" Assertion for Staging Directory ");
Assert.assertTrue(checkErrorMessageByElement("input[contains(@id,'location.staging')]//following-sibling::"
+ "span[contains(@ng-show, 'locationsEqualError')]",
"Staging and Working location should be different"));
// Assertion for Working Location.
LOGGER.info("Assertion for Working Directory");
Assert.assertTrue(checkErrorMessageByElement("input[contains(@id,'location.working')]//following-sibling::"
+ "span[contains(@ng-show, 'locationsEqualError')]",
"Staging and Working location should be different"));
}
/**
* Method to get the Error text message displayed based on Xpath and compares.
* with the input string paramater : errMessage
* @param elementTag elementTag
* @param errMessage errMessage
*/
public boolean checkErrorMessageByElement(String elementTag, String errMessage) {
List<WebElement> elements = clusterBox.findElements(By.xpath("//" + elementTag));
if (!elements.isEmpty()){
for (WebElement element : elements) {
Assert.assertEquals(element.getText(), errMessage);
LOGGER.info("Error Message Displayed : " + element.getText());
}
return true;
}else{
LOGGER.info(" No Elements found with the xpath " + elementTag);
return false;
}
}
/**
* Retrieves the value of the summary box and parses it to cluster properties.
* @param draft empty cluster to contain all properties.
* @return cluster filled with properties from the summary.
*/
public ClusterMerlin getSummary(ClusterMerlin draft) {
ClusterMerlin cluster = new ClusterMerlin(draft.toString());
String summaryBoxText = summaryBox.getText();
LOGGER.info("Summary block text : " + summaryBoxText);
String[] slices;
String value;
String path;
String label;
//retrieve basic properties
String basicProps = summaryBoxText.split("ACL")[0];
for (String line : basicProps.split("\\n")) {
slices = line.split(" ");
label = slices[0].replace(":", "").trim();
value = getValueFromSlices(slices, line);
switch (label) {
case "Name":
cluster.setName(value);
break;
case "Colo":
cluster.setColo(value);
break;
case "Description":
cluster.setDescription(value);
break;
case "Tags":
cluster.setTags(value);
break;
default:
break;
}
}
//retrieve ALC
String propsLeft = summaryBoxText.split("ACL")[1];
String[] acl = propsLeft.split("Interfaces")[0].split(" ");
cluster.getACL().setOwner(acl[1]);
cluster.getACL().setGroup(acl[3]);
cluster.getACL().setPermission(acl[5].trim());
//retrieve interfaces
propsLeft = propsLeft.split("Interfaces")[1];
boolean propertiesPresent = propsLeft.contains("Properties");
String nextLabel = propertiesPresent ? "Properties" : "Locations";
String interfaces = propsLeft.split(nextLabel)[0].trim();
for (String line : interfaces.split("\\n")) {
slices = line.split(" ");
label = slices[0].replace(":", "").trim();
String endpoint = slices[1].trim();
String version = slices[3].trim();
switch (label) {
case "readonly":
cluster.addInterface(Interfacetype.READONLY, endpoint, version);
break;
case "write":
cluster.addInterface(Interfacetype.WRITE, endpoint, version);
break;
case "execute":
cluster.addInterface(Interfacetype.EXECUTE, endpoint, version);
break;
case "workflow":
cluster.addInterface(Interfacetype.WORKFLOW, endpoint, version);
break;
case "messaging":
cluster.addInterface(Interfacetype.MESSAGING, endpoint, version);
break;
case "registry":
cluster.addInterface(Interfacetype.REGISTRY, endpoint, version);
break;
default:
break;
}
}
//retrieve properties
if (propertiesPresent) {
propsLeft = propsLeft.split("Properties")[1];
String properties = propsLeft.split("Locations")[0].trim();
for (String line : properties.split("\\n")) {
int indx = line.indexOf(":");
String name = line.substring(0, indx).trim();
value = line.substring(indx + 1, line.length()).trim();
cluster.withProperty(name, value);
}
}
//retrieve locations
propsLeft = propsLeft.split("Locations")[1].trim();
for (String line : propsLeft.split("\\n")) {
slices = line.split(" ");
label = slices[0].replace(":", "").trim();
path = getValueFromSlices(slices, line);
switch (label) {
case "staging":
cluster.addLocation(ClusterLocationType.STAGING, path);
break;
case "temp":
cluster.addLocation(ClusterLocationType.TEMP, path);
break;
default:
cluster.addLocation(ClusterLocationType.WORKING, path);
break;
}
}
return cluster;
}
/**
* Clicks on cancel button.
*/
public void cancel() {
cancel.click();
}
/**
* Click on next button which is the same as finish step 1.
*/
public void clickNext() {
next.click();
waitForAngularToFinish();
Assert.assertTrue(summaryBox.isDisplayed(), "Summary box should be displayed.");
}
/**
* Click on next button in the cluster creation page.
*/
public void clickJustNext() {
next.click();
waitForAngularToFinish();
}
/**
* Click on save button.
*/
public void clickSave() {
save.click();
waitForAlert();
}
/**
* Clicks on previous button.
*/
public void clickPrevious() {
previous.click();
waitForAngularToFinish();
UIAssert.assertDisplayed(clusterBox, "Cluster box");
}
/**
* Method imitates click on check box.
* @param expectedState whether check box is expected to be enabled or not after click.
*/
public void checkRegistry(boolean expectedState) {
WebElement checkbox = clusterBox.findElement(By.xpath("//input[@type='checkbox']"));
clickCheckBoxSecurely(checkbox, expectedState);
waitForAngularToFinish();
}
public WebElement getInterfaceEndpoint(Interfacetype interfacetype) {
String xpath = String.format("//input[@ng-model='clusterEntity.clusterModel.cluster.interfaces"
+ ".interface[%sPos]._endpoint']", interfacetype.value());
return clusterBox.findElement(By.xpath(xpath));
}
public String getInterfaceEndpointValue(Interfacetype interfacetype) {
return getInterfaceEndpoint(interfacetype).getAttribute("value");
}
public WebElement getInterfaceVersion(Interfacetype interfacetype) {
String xpath = String.format("//input[@ng-model='clusterEntity.clusterModel.cluster.interfaces"
+ ".interface[%sPos]._version']", interfacetype.value());
return clusterBox.findElement(By.xpath(xpath));
}
public String getInterfaceVersionValue(Interfacetype interfacetype) {
return getInterfaceVersion(interfacetype).getAttribute("value");
}
/**
* Method preventing the NullPointerException.
*/
public String getValueFromSlices(String[] slices, String line) {
String trimValue;
if (slices[0].length()==(line.length())) {
trimValue = "";
}else {
trimValue = slices[1].trim();
}
return trimValue;
}
/**
* Checks whether registry interface is enabled for input or not.
*/
public boolean isRegistryEnabled() {
return getInterfaceEndpoint(Interfacetype.REGISTRY).isEnabled()
&& getInterfaceVersion(Interfacetype.REGISTRY).isEnabled();
}
private WebElement getNameUnavailable(){
return clusterBox.findElement(By.xpath(
"//div[contains(@class, 'nameInputDisplay') and contains(@class, 'custom-danger')]"));
}
public void checkNameUnavailableDisplayed(boolean isDisplayed) {
if (isDisplayed){
UIAssert.assertDisplayed(getNameUnavailable(), "Name Unavailable not displayed");
}else {
try{
getNameUnavailable();
Assert.fail("Name Unavailable found");
} catch (Exception ex){
LOGGER.info("Name Unavailable not found");
}
}
}
@Override
public WebElement getEditXMLButton() {
return driver.findElement(By.id("cluster.editXML"));
}
@Override
public ClusterMerlin getEntityFromXMLPreview() {
return new ClusterMerlin(getXMLPreview());
}
}