FALCON-1249 Tests for process setup wizard conributed by Namit Maheshwari and Paul Isaychuk
Project: http://git-wip-us.apache.org/repos/asf/falcon/repo Commit: http://git-wip-us.apache.org/repos/asf/falcon/commit/ff9c78e3 Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/ff9c78e3 Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/ff9c78e3 Branch: refs/heads/master Commit: ff9c78e3c82e45a4e3543924fffe834773dc3880 Parents: 8ee6d45 Author: Raghav Kumar Gautam <[email protected]> Authored: Thu Jun 4 11:51:00 2015 -0700 Committer: Raghav Kumar Gautam <[email protected]> Committed: Thu Jun 4 11:52:46 2015 -0700 ---------------------------------------------------------------------- falcon-regression/CHANGES.txt | 2 + .../regression/Entities/ProcessMerlin.java | 178 +++- .../ui/search/AbstractSearchPage.java | 1 + .../regression/ui/search/ProcessWizardPage.java | 806 ++++++++++++++- .../regression/searchUI/ProcessSetupTest.java | 982 ++++++++++++++++++- 5 files changed, 1919 insertions(+), 50 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/falcon/blob/ff9c78e3/falcon-regression/CHANGES.txt ---------------------------------------------------------------------- diff --git a/falcon-regression/CHANGES.txt b/falcon-regression/CHANGES.txt index d9af012..46799e8 100644 --- a/falcon-regression/CHANGES.txt +++ b/falcon-regression/CHANGES.txt @@ -5,6 +5,8 @@ Trunk (Unreleased) INCOMPATIBLE CHANGES NEW FEATURES + FALCON-1249 Tests for process setup wizard (Namit Maheshwari and Paul Isaychuk) + FALCON-1242 Search UI test for entity upload button (Namit Maheshwari) FALCON-1222 Feed Wizard multiple tests (Namit Maheshwari) http://git-wip-us.apache.org/repos/asf/falcon/blob/ff9c78e3/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/Entities/ProcessMerlin.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/Entities/ProcessMerlin.java b/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/Entities/ProcessMerlin.java index 9e3d2d7..615587d 100644 --- a/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/Entities/ProcessMerlin.java +++ b/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/Entities/ProcessMerlin.java @@ -38,16 +38,22 @@ import org.apache.falcon.entity.v0.process.Property; import org.apache.falcon.entity.v0.process.Validity; import org.apache.falcon.entity.v0.process.Workflow; import org.apache.falcon.regression.core.util.TimeUtil; +import org.apache.falcon.regression.core.util.Util; +import org.apache.log4j.Logger; import org.testng.Assert; +import org.testng.asserts.SoftAssert; import javax.xml.bind.JAXBException; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** Class for representing a process xml. */ public class ProcessMerlin extends Process { + private static final Logger LOGGER = Logger.getLogger(ProcessMerlin.class); public ProcessMerlin(String processData) { this((Process) TestEntityUtil.fromString(EntityType.PROCESS, processData)); } @@ -87,6 +93,34 @@ public class ProcessMerlin extends Process { return null; } + /** + * Compares two process cluster lists, if they are equal or not. + */ + public static void assertClustersEqual(List<Cluster> clusters1, List<Cluster> clusters2) { + if (clusters1.size() != clusters2.size()) { + Assert.fail("Cluster sizes are different."); + } + Comparator<Cluster> clusterComparator = new Comparator<Cluster>() { + @Override + public int compare(Cluster cluster1, Cluster cluster2) { + return cluster1.getName().compareTo(cluster2.getName()); + } + }; + Collections.sort(clusters1, clusterComparator); + Collections.sort(clusters2, clusterComparator); + SoftAssert softAssert = new SoftAssert(); + for(int i = 0; i < clusters1.size(); i++) { + Cluster cluster1 = clusters1.get(i); + Cluster cluster2 = clusters2.get(i); + softAssert.assertEquals(cluster1.getName(), cluster2.getName(), "Cluster names are different."); + softAssert.assertEquals(cluster1.getValidity().getStart(), cluster2.getValidity().getStart(), + String.format("Validity start is not the same for cluster %s", cluster1.getName())); + softAssert.assertEquals(cluster1.getValidity().getEnd(), cluster2.getValidity().getEnd(), + String.format("Cluster validity end is not the same for cluster %s", cluster1.getName())); + } + softAssert.assertAll(); + } + public Input getInputByName(String name) { for (Input input : getInputs().getInputs()) { if (input.getName().equals(name)) { @@ -332,8 +366,6 @@ public class ProcessMerlin extends Process { getOutputs().getOutputs().add(out2); } - - /** * Adds one input into process. */ @@ -349,7 +381,6 @@ public class ProcessMerlin extends Process { getInputs().getInputs().add(in2); } - public void setInputFeedWithEl(String inputFeedName, String startEl, String endEl) { Inputs inputs = new Inputs(); Input input = new Input(); @@ -388,7 +419,6 @@ public class ProcessMerlin extends Process { this.setOutputs(outputs); } - /** * Sets partition for each input, according to number of supplied partitions. * @@ -432,8 +462,6 @@ public class ProcessMerlin extends Process { this.setTimeout(frq); } - - public void setWorkflow(String wfPath, String libPath, EngineType engineType) { Workflow w = this.getWorkflow(); if (engineType != null) { @@ -455,6 +483,144 @@ public class ProcessMerlin extends Process { return EntityType.PROCESS; } + public void assertGeneralProperties(ProcessMerlin newProcess){ + SoftAssert softAssert = new SoftAssert(); + // Assert all the the General Properties + softAssert.assertEquals(newProcess.getName(), getName(), + "Process Name is different"); + softAssert.assertEquals(newProcess.getTags(), getTags(), + "Process Tags Value is different"); + softAssert.assertEquals(newProcess.getWorkflow().getName(), getWorkflow().getName(), + "Process Workflow Name is different"); + if (getWorkflow().getEngine() == EngineType.OOZIE || getWorkflow().getEngine() == null) { + softAssert.assertTrue(newProcess.getWorkflow().getEngine() == EngineType.OOZIE + || newProcess.getWorkflow().getEngine() == null, "Process Workflow Engine is different"); + } else { + softAssert.assertEquals(newProcess.getWorkflow().getEngine().toString(), + getWorkflow().getEngine().toString(), + "Process Workflow Engine is different"); + } + softAssert.assertEquals(newProcess.getWorkflow().getPath(), getWorkflow().getPath(), + "Process Workflow Path is different"); + softAssert.assertEquals(newProcess.getACL().getOwner(), getACL().getOwner(), + "Process ACL Owner is different"); + softAssert.assertEquals(newProcess.getACL().getGroup(), getACL().getGroup(), + "Process ACL Group is different"); + softAssert.assertEquals(newProcess.getACL().getPermission(), getACL().getPermission(), + "Process ACL Permission is different"); + softAssert.assertAll(); + } + + public void assertPropertiesInfo(ProcessMerlin newProcess){ + SoftAssert softAssert = new SoftAssert(); + // Assert all the Properties Info + softAssert.assertEquals(newProcess.getTimezone().getID(), getTimezone().getID(), + "Process TimeZone is different"); + softAssert.assertEquals(newProcess.getFrequency().getFrequency(), getFrequency().getFrequency(), + "Process Frequency is different"); + softAssert.assertEquals(newProcess.getFrequency().getTimeUnit().toString(), + getFrequency().getTimeUnit().toString(), + "Process Frequency Unit is different"); + softAssert.assertEquals(newProcess.getParallel(), getParallel(), + "Process Parallel is different"); + softAssert.assertEquals(newProcess.getOrder(), getOrder(), + "Process Order is different"); + softAssert.assertEquals(newProcess.getRetry().getPolicy().value(), + getRetry().getPolicy().value(), + "Process Retry Policy is different"); + softAssert.assertEquals(newProcess.getRetry().getAttempts(), + getRetry().getAttempts(), + "Process Retry Attempts is different"); + softAssert.assertEquals(newProcess.getRetry().getDelay().getFrequency(), + getRetry().getDelay().getFrequency(), + "Process Delay Frequency is different"); + softAssert.assertEquals(newProcess.getRetry().getDelay().getTimeUnit().name(), + getRetry().getDelay().getTimeUnit().name(), + "Process Delay Unit is different"); + softAssert.assertAll(); + } + + /** + * Asserts equality of process inputs. + */ + public void assertInputValues(ProcessMerlin newProcess){ + Assert.assertEquals(newProcess.getInputs().getInputs().size(), getInputs().getInputs().size(), + "Processes have different number of inputs."); + SoftAssert softAssert = new SoftAssert(); + // Assert all the Input values + for (int i = 0; i < newProcess.getInputs().getInputs().size(); i++) { + softAssert.assertEquals(newProcess.getInputs().getInputs().get(i).getName(), + getInputs().getInputs().get(i).getName(), + "Process Input Name is different"); + softAssert.assertEquals(newProcess.getInputs().getInputs().get(i).getFeed(), + getInputs().getInputs().get(i).getFeed(), + "Process Input Feed is different"); + softAssert.assertEquals(newProcess.getInputs().getInputs().get(i).getStart(), + getInputs().getInputs().get(i).getStart(), + "Process Input Start is different"); + softAssert.assertEquals(newProcess.getInputs().getInputs().get(i).getEnd(), + getInputs().getInputs().get(i).getEnd(), + "Process Input End is different"); + } + softAssert.assertAll(); + } + + /** + * Asserts equality of process outputs. + */ + public void assertOutputValues(ProcessMerlin newProcess){ + SoftAssert softAssert = new SoftAssert(); + // Assert all the Output values + softAssert.assertEquals(newProcess.getOutputs().getOutputs().get(0).getName(), + getOutputs().getOutputs().get(0).getName(), + "Process Output Name is different"); + softAssert.assertEquals(newProcess.getOutputs().getOutputs().get(0).getFeed(), + getOutputs().getOutputs().get(0).getFeed(), + "Process Output Feed is different"); + softAssert.assertEquals(newProcess.getOutputs().getOutputs().get(0).getInstance(), + getOutputs().getOutputs().get(0).getInstance(), + "Process Output Instance is different"); + softAssert.assertAll(); + } + + /** + * Asserts equality of two processes. + */ + public void assertEquals(ProcessMerlin process) { + LOGGER.info(String.format("Comparing General Properties: source: %n%s%n and process: %n%n%s", + Util.prettyPrintXml(toString()), Util.prettyPrintXml(process.toString()))); + assertGeneralProperties(process); + assertInputValues(process); + assertOutputValues(process); + assertPropertiesInfo(process); + assertClustersEqual(getClusters().getClusters(), process.getClusters().getClusters()); + } + + /** + * Creates an empty process definition. + */ + public static ProcessMerlin getEmptyProcess(ProcessMerlin process) { + ProcessMerlin draft = new ProcessMerlin(process.toString()); + draft.setName(""); + draft.setTags(""); + draft.setACL(null); + draft.getInputs().getInputs().clear(); + draft.getOutputs().getOutputs().clear(); + draft.setRetry(null); + draft.clearProcessCluster(); + draft.getProperties().getProperties().clear(); + draft.setFrequency(null); + draft.setOrder(null); + draft.setTimezone(null); + draft.setParallel(0); + Workflow workflow = new Workflow(); + workflow.setName(null); + workflow.setPath(null); + workflow.setVersion(null); + workflow.setEngine(null); + draft.setWorkflow(null, null, null); + return draft; + } } http://git-wip-us.apache.org/repos/asf/falcon/blob/ff9c78e3/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/AbstractSearchPage.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/AbstractSearchPage.java b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/AbstractSearchPage.java index 7c1f7ad..a1e3e2e 100644 --- a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/AbstractSearchPage.java +++ b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/AbstractSearchPage.java @@ -33,6 +33,7 @@ import org.openqa.selenium.support.ui.Select; import java.util.ArrayList; import java.util.List; + /** Parent page object for all the search ui pages. */ public abstract class AbstractSearchPage extends Page { http://git-wip-us.apache.org/repos/asf/falcon/blob/ff9c78e3/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/ProcessWizardPage.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/ProcessWizardPage.java b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/ProcessWizardPage.java index e429a60..e796ba0 100644 --- a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/ProcessWizardPage.java +++ b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/ProcessWizardPage.java @@ -20,33 +20,79 @@ package org.apache.falcon.regression.ui.search; import com.google.common.collect.Lists; import org.apache.commons.lang.StringUtils; +import org.apache.falcon.entity.v0.Frequency; import org.apache.falcon.entity.v0.process.ACL; +import org.apache.falcon.entity.v0.process.Cluster; +import org.apache.falcon.entity.v0.process.Clusters; +import org.apache.falcon.entity.v0.process.EngineType; +import org.apache.falcon.entity.v0.process.ExecutionType; +import org.apache.falcon.entity.v0.process.Input; +import org.apache.falcon.entity.v0.process.Inputs; +import org.apache.falcon.entity.v0.process.Output; +import org.apache.falcon.entity.v0.process.Outputs; +import org.apache.falcon.entity.v0.process.PolicyType; +import org.apache.falcon.entity.v0.process.Retry; import org.apache.falcon.entity.v0.process.Workflow; +import org.apache.falcon.entity.v0.process.Validity; import org.apache.falcon.regression.Entities.ProcessMerlin; import org.apache.falcon.regression.core.util.UIAssert; +import org.apache.log4j.Logger; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; 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.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.Select; -import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; -import java.util.Arrays; +import java.text.SimpleDateFormat; import java.util.List; import java.util.TimeZone; /** Page object of the Process creation page. */ public class ProcessWizardPage extends AbstractSearchPage { + private static final Logger LOGGER = Logger.getLogger(ProcessWizardPage.class); + @FindBys({ @FindBy(className = "mainUIView"), @FindBy(className = "entityForm") }) private WebElement processBox; + @FindBy(xpath = "//textarea[@ng-model='prettyXml']") + private WebElement processXml; + + @FindBy(xpath = "//form[@name='processForm']/div[1]") + private WebElement summaryBox; + + @FindBys({ + @FindBy(className = "mainUIView"), + @FindBy(className = "entityForm"), + @FindBy(className = "nextBtn") + }) + private WebElement nextButton; + + @FindBys({ + @FindBy(className = "mainUIView"), + @FindBy(className = "entityForm"), + @FindBy(className = "prevBtn") + }) + private WebElement previousButton; + + @FindBys({ + @FindBy(id = "editXmlButton") + }) + private WebElement editXmlButton; + + @FindBy(xpath = "//a[contains(.,'Cancel')]") + private WebElement cancelButton; + + @FindBy(xpath = "//div[contains(@class,'formBoxContainer')]") + private WebElement formBox; + public ProcessWizardPage(WebDriver driver) { super(driver); } @@ -56,15 +102,40 @@ public class ProcessWizardPage extends AbstractSearchPage { UIAssert.assertDisplayed(processBox, "Process box"); } - private WebElement getNextButton() { - return driver.findElement(By.id("nextButton")); + /** + * Completes step 1 and clicks next. + */ + public void goToPropertiesStep(ProcessMerlin process) { + setProcessGeneralInfo(process); + clickNext(); + + } + + public void goToClustersStep(ProcessMerlin process) { + goToPropertiesStep(process); + + setProcessPropertiesInfo(process); + clickNext(); + } + + public void clickNext() { + nextButton.click(); } - public void pressNext() { - getNextButton().click(); + public void clickPrevious(){ + previousButton.click(); } - /*----- Step1 elements & operations ----*/ + public void clickCancel(){ + cancelButton.click(); + } + + public void clickEditXml(){ + editXmlButton.click(); + } + + /*----- Step1 General info ----*/ + private WebElement getName() { return driver.findElement(By.id("entityNameField")); } @@ -104,28 +175,51 @@ public class ProcessWizardPage extends AbstractSearchPage { } } - public void setTags(List<String> tags) { - deleteTags(); - //create enough number of tag fields - final int numTags = tags.size(); - for (int i = 0; i < numTags - 1; i++) { - getAddTagButton().click(); + private WebElement getTagKey(int index) { + return processBox.findElements(By.xpath("//input[@ng-model='tag.key']")).get(index); + } + private WebElement getTagValue(int index) { + return processBox.findElements(By.xpath("//input[@ng-model='tag.value']")).get(index); + } + + public void setTagKey(int index, String tagKey){ + getTagKey(index).sendKeys(tagKey); + } + public void setTagValue(int index, String tagValue){ + getTagValue(index).sendKeys(tagValue); + } + + public void setTags(String tagsStr){ + if (StringUtils.isEmpty(tagsStr)){ + return; } - final List<WebElement> tagTextFields = getTagTextFields(); - Assert.assertEquals(tagTextFields.size() % 2, 0, - "Number of text fields for tags should be even, found: " + tagTextFields.size()); - for (int i = 0; i < (tagTextFields.size() / 2); i++) { - final String oneTag = tags.get(i); - final String[] tagParts = oneTag.split("="); - Assert.assertEquals(tagParts.length, 2, - "Each tag is expected to be of form key=value, found: " + oneTag); - String key = tagParts[0]; - String val = tagParts[1]; - tagTextFields.get(2 * i).sendKeys(key); - tagTextFields.get(2 * i + 1).sendKeys(val); + String[] tags = tagsStr.split(","); + for (int i = 0; i < tags.length; i++){ + String[] keyValue = tags[i].split("="); + setTagKey(i, keyValue[0]); + setTagValue(i, keyValue[1]); + if (tags.length > i + 1){ + getAddTagButton().click(); + } } } + public String getTagKeyText(int index){ + return getTagKey(index).getAttribute("value"); + } + + public String getTagValueText(int index){ + return getTagValue(index).getAttribute("value"); + } + + public boolean isPigRadioSelected(){ + return getPigRadio().isSelected(); + } + + public String getEngineVersionText(){ + return getEngineVersion().getFirstSelectedOption().getAttribute("value"); + } + private WebElement getWfName() { return driver.findElement(By.id("workflowNameField")); } @@ -168,6 +262,7 @@ public class ProcessWizardPage extends AbstractSearchPage { Assert.fail("Unexpected workflow engine: " + processWf.getEngine()); } final String version = processWf.getVersion(); + // The getVersion() method returns '1.0' if its null, hence the hack below if (StringUtils.isNotEmpty(version) && !version.equals("1.0")) { getEngineVersion().selectByVisibleText(version); } @@ -200,24 +295,665 @@ public class ProcessWizardPage extends AbstractSearchPage { aclPerm.sendKeys(acl.getPermission()); } - public void doStep1(ProcessMerlin process) { + public void setProcessGeneralInfo(ProcessMerlin process) { setName(process.getName()); final String tags = StringUtils.trimToEmpty(process.getTags()); - setTags(Arrays.asList(tags.split(","))); + setTags(tags); setWorkflow(process.getWorkflow()); setAcl(process.getACL()); - final WebElement step1Element = getName(); - pressNext(); - new WebDriverWait(driver, AbstractSearchPage.PAGELOAD_TIMEOUT_THRESHOLD).until( - ExpectedConditions.stalenessOf(step1Element)); } - /*----- Step2 elements & operations ----*/ + public void isFrequencyQuantityDisplayed(boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getFrequencyQuantity(), "Frequency Quantity"); + }else { + try{ + getFrequencyQuantity(); + Assert.fail("Frequency Quantity found"); + } catch (Exception ex){ + LOGGER.info("Frequency Quantity not found"); + } + } + } + + public void isValidityStartDateDisplayed(boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getStartDate(), "Cluster Validity Start Date"); + }else { + try{ + getStartDate(); + Assert.fail("Cluster Validity Start Date found"); + } catch (Exception ex){ + LOGGER.info("Cluster Validity Start Date not found"); + } + } + } + + public void isAddInputButtonDisplayed(boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getAddInputButton(), "Add Input button."); + }else { + try{ + getAddInputButton(); + Assert.fail("Add Input Button found"); + } catch (Exception ex){ + LOGGER.info("Add Input Button not found"); + } + } + } + + public void isSaveButtonDisplayed(boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getSaveProcessButton(), "Save Button"); + }else { + try{ + getSaveProcessButton(); + Assert.fail("Save Process Button found"); + } catch (Exception ex){ + LOGGER.info("Save Process Button not found"); + } + } + } + + private WebElement getSaveProcessButton(){ + return formBox.findElement(By.xpath("//button[contains(.,'Save')]")); + } + + public void isTagsDisplayed(int index, boolean isDisplayed){ + if (isDisplayed){ + UIAssert.assertDisplayed(getTagKey(index), "Tag Key Index - " + index); + UIAssert.assertDisplayed(getTagValue(index), "Tag Value Index - " + index); + }else{ + try{ + getTagKey(index); + Assert.fail("Tag Key Index - " + index + " found"); + } catch (Exception ex){ + LOGGER.info("Tag Key Index - " + index + " not found"); + } + try{ + getTagValue(index); + Assert.fail("Tag Key Value - " + index + " found"); + } catch (Exception ex){ + LOGGER.info("Tag Key Value - " + index + " not found"); + } + } + } + + /*----- Step2 Properties ----*/ + private Select getTimezone() { - return new Select(driver.findElement(By.id("timeZoneSelect"))); + return new Select(formBox.findElement(By.xpath("//select[contains(@class, 'TZSelect')]"))); } public void setTimezone(TimeZone timezone) { - getTimezone().selectByValue(timezone.getDisplayName()); + if (timezone == null) { + return; + } + String timeZone = timezone.getID(); + getTimezone().selectByValue(timeZone); + } + + private WebElement getFrequencyQuantity() { + return processBox.findElement(By.xpath("//input[@ng-model='process.frequency.quantity']")); + } + private Select getFrequencyUnit() { + return new Select(processBox.findElement(By.xpath( + "//select[@ng-model='process.frequency.unit']"))); + } + + public String getFrequencyQuantityText(){ + return getFrequencyQuantity().getAttribute("value"); + } + + public String getMaxParallelInstancesText(){ + return getMaxParallelInstances().getFirstSelectedOption().getAttribute("value"); + } + + public String getTimezoneText(){ + return getTimezone().getFirstSelectedOption().getAttribute("value"); + } + + public String getOrderText(){ + return getOrder().getFirstSelectedOption().getAttribute("value"); + } + + public void setFrequencyQuantity(String frequencyQuantity){ + getFrequencyQuantity().sendKeys(frequencyQuantity); + } + public void setFrequencyUnit(String frequencyUnit){ + getFrequencyUnit().selectByVisibleText(frequencyUnit); + } + + public List<String> getTimezoneValues(){ + return getDropdownValues(getTimezone()); + } + + public List<String> getFrequencyUnitValues(){ + return getDropdownValues(getFrequencyUnit()); + } + + public List<String> getMaxParallelInstancesValues(){ + return getDropdownValues(getMaxParallelInstances()); + } + + public List<String> getOrderValues(){ + return getDropdownValues(getOrder()); + } + + public List<String> getRetryPolicyValues(){ + return getDropdownValues(getRetryPolicy()); + } + + public List<String> getRetryDelayUnitValues(){ + return getDropdownValues(getRetryDelayUnit()); + } + + private Select getMaxParallelInstances(){ + return new Select(formBox.findElement(By.xpath("//select[@ng-model='process.parallel']"))); + } + + public void setMaxParallelInstances(int quantity) { + getMaxParallelInstances().selectByValue(String.valueOf(quantity)); + } + + private Select getOrder(){ + return new Select(formBox.findElement(By.xpath("//select[@ng-model='process.order']"))); + } + + public void setOrder(ExecutionType order) { + getOrder().selectByValue(order.value()); + } + + private Select getRetryPolicy(){ + return new Select(formBox.findElement(By.xpath("//select[@ng-model='process.retry.policy']"))); + } + + private Select getRetryDelayUnit(){ + return new Select(formBox.findElement(By.xpath("//select[@ng-model='process.retry.delay.unit']"))); + } + + private WebElement getAttempts(){ + return formBox.findElement(By.id("attemptsField")); + } + + private WebElement getDelayQuantity(){ + return formBox.findElement(By.id("delayQuantity")); + } + + public void setRetry(Retry retry) { + getRetryPolicy().selectByValue(retry.getPolicy().value()); + getAttempts().sendKeys(String.valueOf(retry.getAttempts())); + getDelayQuantity().sendKeys(retry.getDelay().getFrequency()); + getRetryDelayUnit().selectByValue(retry.getDelay().getTimeUnit().name()); + } + + /** + * Enter process info on Page 2 of processSetup Wizard. + */ + public void setProcessPropertiesInfo(ProcessMerlin process) { + setTimezone(process.getTimezone()); + setFrequencyQuantity(process.getFrequency().getFrequency()); + setFrequencyUnit(process.getFrequency().getTimeUnit().toString()); + setMaxParallelInstances(process.getParallel()); + setOrder(process.getOrder()); + setRetry(process.getRetry()); + } + + /*-----Step3 Clusters-------*/ + + public WebElement getStartDate() { + List<WebElement> inputs = driver.findElements( + By.xpath("//input[contains(@ng-model, 'cluster.validity.start.date')]")); + return inputs.get(inputs.size() - 1); + } + + public WebElement getEndDate() { + List<WebElement> inputs = formBox.findElements( + By.xpath("//input[contains(@ng-model, 'cluster.validity.end.date')]")); + return inputs.get(inputs.size() - 1); + } + + public String getValidityEnd() { + return String.format("%s %s:%s", getEndDate().getAttribute("value"), getEndHours().getAttribute("value"), + getEndMinutes().getAttribute("value")); + } + + public WebElement getStartHours() { + List<WebElement> inputs = formBox.findElements(By.xpath("//input[contains(@ng-model, 'hours')]")); + return inputs.get(inputs.size() - 2); + } + + public WebElement getEndHours() { + List<WebElement> inputs = formBox.findElements(By.xpath("//input[contains(@ng-model, 'hours')]")); + return inputs.get(inputs.size() - 1); + } + + public WebElement getStartMinutes() { + List<WebElement> inputs = formBox.findElements(By.xpath("//input[contains(@ng-model, 'minutes')]")); + return inputs.get(inputs.size() - 2); + } + + public WebElement getEndMinutes() { + List<WebElement> inputs = formBox.findElements(By.xpath("//input[contains(@ng-model, 'minutes')]")); + return inputs.get(inputs.size() - 1); + } + + public WebElement getStartMeredian() { + List<WebElement> buttons = formBox.findElements(By.xpath("//td[@ng-show='showMeridian']/button")); + return buttons.get(buttons.size() - 2); + } + + public WebElement getEndMeredian() { + List<WebElement> buttons = formBox.findElements(By.xpath("//td[@ng-show='showMeridian']/button")); + return buttons.get(buttons.size() - 1); + } + + /** + * Retrieves the last cluster select. + */ + public Select getClusterSelect() { + List<WebElement> selects = formBox.findElements(By.xpath("//select[contains(@ng-model, 'cluster.name')]")); + return new Select(selects.get(selects.size() - 1)); + } + + public void clickAddClusterButton() { + int initialSize = getWizardClusterCount(); + formBox.findElement(By.xpath("//button[contains(., 'add cluster')]")).click(); + int finalSize = getWizardClusterCount(); + Assert.assertEquals(finalSize - initialSize, 1, "New cluster block should been added."); + } + + /** + * Removes last cluster on the form. + */ + public void deleteLastCluster() { + int initialSize = getWizardClusterCount(); + List<WebElement> buttons = formBox.findElements(By.xpath("//button[contains(., 'delete')]")); + Assert.assertTrue(buttons.size() > 0, + "Delete button should be present. There should be at least 2 cluster blocks"); + buttons.get(buttons.size() - 1).click(); + int finalSize = getWizardClusterCount(); + Assert.assertEquals(initialSize - finalSize, 1, "One cluster block should been removed."); + } + + /** + * Sets multiple clusters in process. + */ + public void setClusters(Clusters clusters) { + for (int i = 0; i < clusters.getClusters().size(); i++) { + if (i > 0) { + clickAddClusterButton(); + } + setCluster(clusters.getClusters().get(i)); + } + } + + /** + * Fills the last cluster on the form. + */ + public void setCluster(Cluster cluster) { + selectCluster(cluster.getName()); + setClusterValidity(cluster); + } + + /** + * Populates cluster form with values from process.Cluster object. + * @param cluster process process.Cluster object + */ + public void setClusterValidity(Cluster cluster) { + SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy-hh-mm-a"); + String start = format.format(cluster.getValidity().getStart()); + String [] parts = start.split("-"); + getStartDate().clear(); + sendKeysSlowly(getStartDate(), parts[0]); + getStartHours().clear(); + sendKeysSlowly(getStartHours(), parts[1]); + getStartMinutes().clear(); + sendKeysSlowly(getStartMinutes(), parts[2]); + String meredian = getStartMeredian().getText(); + if (!meredian.equals(parts[3])) { + getStartMeredian().click(); + } + String end = format.format(cluster.getValidity().getEnd()); + parts = end.split("-"); + getEndDate().clear(); + sendKeysSlowly(getEndDate(), parts[0]); + getEndHours().clear(); + sendKeysSlowly(getEndHours(), parts[1]); + getEndMinutes().clear(); + sendKeysSlowly(getEndMinutes(), parts[2]); + meredian = getEndMeredian().getText(); + if (!meredian.equals(parts[3])) { + getEndMeredian().click(); + } + } + + public void selectCluster(String clusterName) { + getClusterSelect().selectByValue(clusterName); + } + + public String getClusterName(int indx) { + List<WebElement> blocks = formBox.findElements(By.xpath("//div[contains(@class, 'processCluster')]")); + return new Select(blocks.get(indx).findElement(By.tagName("select"))) + .getFirstSelectedOption().getText(); + } + + public int getWizardClusterCount() { + return formBox.findElements(By.xpath("//div[contains(@class, 'processCluster')]")).size(); + } + + public void setProcessClustersInfo(ProcessMerlin process) { + for (int i = 0; i < process.getClusters().getClusters().size(); i++) { + if (i >= 1) { + clickAddClusterButton(); + } + setCluster(process.getClusters().getClusters().get(i)); + } + } + + public List<String> getClustersFromDropDown() { + return getDropdownValues(getClusterSelect()); + } + + public void clickOnValidityStart() { + getStartDate().click(); + List<WebElement> calendars = formBox.findElements(By.xpath("//ul[@ng-model='date']")); + waitForAngularToFinish(); + Assert.assertTrue(calendars.get(calendars.size() - 2).isDisplayed(), "Calendar should pop up."); + } + + public void clickOnValidityEnd() { + getEndDate().click(); + List<WebElement> calendars = formBox.findElements(By.xpath("//ul[@ng-model='date']")); + waitForAngularToFinish(); + Assert.assertTrue(calendars.get(calendars.size() - 1).isDisplayed(), "Calendar should pop up."); + } + + /* Step 4 - Inputs & Outputs*/ + + private WebElement getAddInputButton() { + return formBox.findElement(By.xpath("//button[contains(., 'add input')]")); + } + + private WebElement getAddOutputButton() { + return formBox.findElement(By.xpath("//button[contains(., 'add output')]")); + } + + private WebElement getDeleteInputButton() { + return formBox.findElement(By.xpath("//button[contains(., 'delete')]")); + } + + private WebElement getInputName(int index) { + return formBox.findElements(By.xpath("//input[@ng-model='input.name']")).get(index); + } + + private Select getInputFeed(int index) { + return new Select(formBox.findElements(By.xpath("//select[@ng-model='input.feed']")).get(index)); + } + + private WebElement getInputStart(int index) { + return formBox.findElements(By.xpath("//input[@ng-model='input.start']")).get(index); + } + + private WebElement getInputEnd(int index) { + return formBox.findElements(By.xpath("//input[@ng-model='input.end']")).get(index); + } + + public void setInputInfo(Inputs inputs){ + for (int i = 0; i < inputs.getInputs().size(); i++) { + clickAddInput(); + sendKeysSlowly(getInputName(i), inputs.getInputs().get(i).getName()); + getInputFeed(i).selectByVisibleText(inputs.getInputs().get(i).getFeed()); + sendKeysSlowly(getInputStart(i), inputs.getInputs().get(i).getStart()); + sendKeysSlowly(getInputEnd(i), inputs.getInputs().get(i).getEnd()); + } + } + + public void clickAddInput(){ + getAddInputButton().click(); + } + + public void clickAddOutput(){ + getAddOutputButton().click(); + } + + public void clickDeleteInput(){ + getDeleteInputButton().click(); + } + + private WebElement getDeleteOutputButton() { + return formBox.findElement(By.xpath("//button[contains(., 'delete')]")); + } + + private WebElement getOutputName(int index) { + return formBox.findElements(By.xpath("//input[@ng-model='output.name']")).get(index); + } + + private Select getOutputFeed(int index) { + return new Select(formBox.findElements(By.xpath("//select[@ng-model='output.feed']")).get(index)); + } + + private WebElement getOutputInstance(int index) { + return formBox.findElements(By.xpath("//input[@ng-model='output.outputInstance']")).get(index); + } + + public void clickDeleteOutput(){ + getDeleteOutputButton().click(); + } + + public void setOutputInfo(Outputs outputs){ + for (int i = 0; i < outputs.getOutputs().size(); i++) { + clickAddOutput(); + sendKeysSlowly(getOutputName(i), outputs.getOutputs().get(i).getName()); + getOutputFeed(i).selectByVisibleText(outputs.getOutputs().get(i).getFeed()); + sendKeysSlowly(getOutputInstance(i), outputs.getOutputs().get(i).getInstance()); + } + } + + public void setInputOutputInfo(ProcessMerlin process){ + setInputInfo(process.getInputs()); + setOutputInfo(process.getOutputs()); + } + + public List<String> getInputValues(int index){ + return getDropdownValues(getInputFeed(index)); + } + + public List<String> getOutputValues(int index){ + return getDropdownValues(getOutputFeed(index)); + } + + public String getInputNameText(int index){ + return getInputName(index).getAttribute("value"); + } + + public String getInputFeedText(int index){ + return getInputFeed(index).getFirstSelectedOption().getAttribute("value"); + } + + public String getInputStartText(int index){ + return getInputStart(index).getAttribute("value"); + } + + public String getInputEndText(int index){ + return getInputEnd(index).getAttribute("value"); + } + + public String getOutputNameText(int index){ + return getOutputName(index).getAttribute("value"); + } + + public String getOutputFeedText(int index){ + return getOutputFeed(index).getFirstSelectedOption().getAttribute("value"); + } + + public String getOutputInstanceText(int index){ + return getOutputInstance(index).getAttribute("value"); + } + + public void isInputNameDisplayed(int index, boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getInputName(index), "Input Name " + index); + }else { + try{ + getInputName(index); + Assert.fail("Input Name " + index + " found"); + } catch (Exception ex){ + LOGGER.info("Input Name " + index + " not found"); + } + } + } + + public void isOutputNameDisplayed(int index, boolean isDisplayed) { + if (isDisplayed){ + UIAssert.assertDisplayed(getOutputName(index), "Output Name " + index); + }else { + try{ + getOutputName(index); + Assert.fail("Output Name " + index + " found"); + } catch (Exception ex){ + LOGGER.info("Output Name " + index + " not found"); + } + } + } + + + /* Step 5 - Summary */ + + public void clickSave(){ + getSaveProcessButton().click(); + } + + /** + * Creates ProcessMerlin object from xml preview string. + */ + public ProcessMerlin getProcessMerlinFromProcessXml() throws Exception{ + waitForAngularToFinish(); + return new ProcessMerlin(processXml.getAttribute("value")); + } + + /** + * Pushes xml string to xml preview. + */ + public void setProcessXml(String xml) throws Exception{ + processXml.clear(); + processXml.sendKeys(xml); + } + + /** + * Method gets text from summary box and parses it to ProcessMerlin object. + * @param draft empty ProcessMerlin object + */ + public ProcessMerlin getProcessFromSummaryBox(ProcessMerlin draft) { + String text = summaryBox.getText().trim(); + draft.setName(getProperty(text, null, "Tags", 2)); + String currentBlock = text.substring(text.indexOf("Tags"), text.indexOf("Workflow")); + String [] parts; + parts = currentBlock.trim().split("\\n"); + String tags = ""; + for (int i = 1; i < parts.length; i++) { + String tag = parts[i]; + if (!tag.contains("No tags")) { + tag = tag.replace(" ", ""); + tags = tags + (tags.isEmpty() ? tag : "," + tag); + } + } + if (!tags.isEmpty()) { + draft.setTags(tags); + } + Workflow workflow = new Workflow(); + workflow.setName(getProperty(text, "Workflow", "Engine", 2)); + workflow.setEngine(EngineType.fromValue(getProperty(text, "Engine", "Version", 1))); + workflow.setVersion(getProperty(text, "Version", "Path", 1)); + workflow.setPath(getProperty(text, "Path", "Timing", 1)); + draft.setWorkflow(workflow); + + draft.setTimezone(TimeZone.getTimeZone(getProperty(text, "Timing", "Frequency", 2))); + parts = getProperty(text, "Frequency", "Max. parallel instances", 1).split(" "); + draft.setFrequency(new Frequency(parts[1], Frequency.TimeUnit.valueOf(parts[2]))); + draft.setParallel(Integer.parseInt(getProperty(text, "Max. parallel instances", "Order", 1))); + draft.setOrder(ExecutionType.fromValue(getProperty(text, "Order", "Retry", 1))); + + Retry retry = new Retry(); + retry.setPolicy(PolicyType.fromValue(getProperty(text, "Retry", "Attempts", 2))); + retry.setAttempts(Integer.parseInt(getProperty(text, "Attempts", "Delay", 1))); + parts = getProperty(text, "Delay", "Clusters", 1).split(" "); + retry.setDelay(new Frequency(parts[2], Frequency.TimeUnit.valueOf(parts[3]))); + draft.setRetry(retry); + + //get clusters + currentBlock = text.substring(text.indexOf("Clusters"), text.indexOf("Inputs")); + int last = 0; + while (last != -1) { + Cluster cluster = new Cluster(); + cluster.setName(getProperty(currentBlock, "Name", "Validity", 1)); + //remove the part which was used + currentBlock = currentBlock.substring(currentBlock.indexOf("Validity")); + //get validity + String start = getProperty(currentBlock, "Validity", "End", 2).split(" ")[1]; + //check if there are other clusters + last = currentBlock.indexOf("Name"); + String innerBlock = currentBlock.substring(currentBlock.indexOf("End"), + last != -1 ? last : currentBlock.length() - 1).trim(); + parts = innerBlock.trim().split("\\n"); + String end = parts[1].split(" ")[1]; + Validity validity = new Validity(); + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'"); + validity.setStart(formatter.parseDateTime(start.replaceAll("\"", "")).toDate()); + validity.setEnd(formatter.parseDateTime(end.replaceAll("\"", "")).toDate()); + cluster.setValidity(validity); + draft.getClusters().getClusters().add(cluster); + } + //get inputs + currentBlock = text.substring(text.indexOf("Inputs"), text.indexOf("Outputs")); + last = 0; + while (last != -1) { + Input input = new Input(); + //get input name + input.setName(getProperty(currentBlock, "Name", "Feed", 1)); + //remove the part which was used + currentBlock = currentBlock.substring(currentBlock.indexOf("Name") + 4); + //get input feed + input.setFeed(getProperty(currentBlock, "Feed", "Instance", 1)); + //get input start + input.setStart(getProperty(currentBlock, "Instance", "End", 2)); + //get input end + last = currentBlock.indexOf("Name"); + String innerBlock = currentBlock.substring(currentBlock.indexOf("End"), + last != -1 ? last : currentBlock.length() - 1).trim(); + parts = innerBlock.trim().split("\\n"); + input.setEnd(parts[1]); + draft.getInputs().getInputs().add(input); + //remove part which was parsed + currentBlock = currentBlock.substring(currentBlock.indexOf("End") + 4); + } + //get outputs + currentBlock = text.substring(text.indexOf("Outputs")); + last = 0; + while (last != -1) { + Output output = new Output(); + output.setName(getProperty(currentBlock, "Name", "Feed", 1)); + //remove the part which was used + currentBlock = currentBlock.substring(currentBlock.indexOf("Feed")); + //get feed + output.setFeed(getProperty(currentBlock, "Feed", "Instance", 1)); + last = currentBlock.indexOf("Name"); + output.setInstance(getProperty(currentBlock, "Instance", "Name", 2)); + draft.getOutputs().getOutputs().add(output); + } + return draft; + } + + /** + * Retrieves property from source text. + */ + private String getProperty(String block, String start, String end, int propertyIndex) { + int s = start != null ? block.indexOf(start) : 0; + s = s == -1 ? 0 : s; + int e = end != null ? block.indexOf(end) : block.length() - 1; + e = e == -1 ? block.length() : e; + String subBlock = block.substring(s, e).trim(); + String [] parts = subBlock.trim().split("\\n"); + return parts.length - 1 >= propertyIndex ? parts[propertyIndex].trim() : null; } }
