Repository: falcon Updated Branches: refs/heads/master 637900145 -> 1afb51079
FALCON-1229 Tests for instance page on SearchUI. Contributed by Ruslan Ostafiychuk Project: http://git-wip-us.apache.org/repos/asf/falcon/repo Commit: http://git-wip-us.apache.org/repos/asf/falcon/commit/1afb5107 Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/1afb5107 Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/1afb5107 Branch: refs/heads/master Commit: 1afb51079a7ebfdaca1cddb39c0c555ea58fdbcd Parents: 6379001 Author: Ruslan Ostafiychuk <[email protected]> Authored: Thu May 21 17:31:19 2015 +0300 Committer: Ruslan Ostafiychuk <[email protected]> Committed: Fri May 22 13:32:09 2015 +0300 ---------------------------------------------------------------------- falcon-regression/CHANGES.txt | 2 + .../falcon/regression/ui/search/EntityPage.java | 7 + .../regression/ui/search/InstancePage.java | 114 +++++++++++ .../regression/searchUI/InstancePageTest.java | 193 +++++++++++++++++++ 4 files changed, 316 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/falcon/blob/1afb5107/falcon-regression/CHANGES.txt ---------------------------------------------------------------------- diff --git a/falcon-regression/CHANGES.txt b/falcon-regression/CHANGES.txt index c6da36d..b64f11e 100644 --- a/falcon-regression/CHANGES.txt +++ b/falcon-regression/CHANGES.txt @@ -5,6 +5,8 @@ Trunk (Unreleased) INCOMPATIBLE CHANGES NEW FEATURES + FALCON-1229 Tests for instance page on SearchUI (Ruslan Ostafiychuk) + FALCON-1216 Cluster setup wizard multiple tests (Paul Isaychuk via Ruslan Ostafiychuk) FALCON-1202 Add tests for EntityPage (Raghav Kumar Gautam) http://git-wip-us.apache.org/repos/asf/falcon/blob/1afb5107/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/EntityPage.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/EntityPage.java b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/EntityPage.java index 0b7057e..5dabc7c 100644 --- a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/EntityPage.java +++ b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/EntityPage.java @@ -38,6 +38,7 @@ 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.PageFactory; import org.openqa.selenium.support.ui.Select; import org.testng.asserts.SoftAssert; @@ -589,6 +590,12 @@ public class EntityPage extends AbstractSearchPage { } } + + public InstancePage openInstance(String nominalTime) { + instanceListBox.findElement(By.xpath("//button[contains(.,'" + nominalTime + "')]")).click(); + return PageFactory.initElements(driver, InstancePage.class); + } + /** * Class representing summary of one instance. */ http://git-wip-us.apache.org/repos/asf/falcon/blob/1afb5107/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/InstancePage.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/InstancePage.java b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/InstancePage.java new file mode 100644 index 0000000..1fce0a2 --- /dev/null +++ b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/InstancePage.java @@ -0,0 +1,114 @@ +/** + * 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.falcon.regression.core.util.UIAssert; +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.PageFactory; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + + +/** + * Class representation of Search UI entity page. + */ +public class InstancePage extends AbstractSearchPage { + private final String nominalTime; + + /** + * Possible instance actions available on instance page. + */ + public enum Button { + Resume, + Suspend, + Stop + } + + public InstancePage(WebDriver driver) { + super(driver); + nominalTime = driver.findElement(By.xpath("//h3")).getText().split("\\|")[1].trim(); + } + + + @FindBys({ + @FindBy(className = "detailsBox"), + @FindBy(className = "row") + }) + private WebElement detailsBox; + + @FindBys({ + @FindBy(xpath = "//h3/a") + }) + private WebElement entityLink; + + + + @Override + public void checkPage() { + UIAssert.assertDisplayed(detailsBox, "Dependency box"); + UIAssert.assertDisplayed(entityLink, "Link to parrent entity"); + } + + public InstancePage refreshPage() { + return backToEntityPage().openInstance(nominalTime); + } + + public String getStatus() { + return driver.findElement(By.xpath("//h4[@class='instance-title']/span")).getText(); + } + + public String getEntityName() { + return entityLink.getText(); + } + + public boolean isLineagePresent() { + List<WebElement> lineage = driver.findElements(By.className("lineage-graph")); + return !lineage.isEmpty() && lineage.get(0).isDisplayed(); + } + + + public Set<Button> getButtons(boolean active) { + List<WebElement> buttons = detailsBox.findElement(By.className("buttonCell")) + .findElements(By.className("btn")); + Set<Button> result = EnumSet.noneOf(Button.class); + for (WebElement button : buttons) { + if ((button.getAttribute("disabled") == null) == active) { + result.add(Button.valueOf(button.getText())); + } + } + return result; + } + + public void clickButton(Button button) { + detailsBox.findElement(By.className("buttonCell")) + .findElements(By.className("btn")).get(button.ordinal()).click(); + waitForAngularToFinish(); + } + + public EntityPage backToEntityPage() { + entityLink.click(); + return PageFactory.initElements(driver, EntityPage.class); + } +} http://git-wip-us.apache.org/repos/asf/falcon/blob/1afb5107/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/InstancePageTest.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/InstancePageTest.java b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/InstancePageTest.java new file mode 100644 index 0000000..0152b42 --- /dev/null +++ b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/InstancePageTest.java @@ -0,0 +1,193 @@ +/** + * 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.searchUI; + +import org.apache.falcon.entity.v0.EntityType; +import org.apache.falcon.entity.v0.Frequency; +import org.apache.falcon.regression.core.bundle.Bundle; +import org.apache.falcon.regression.core.helpers.ColoHelper; +import org.apache.falcon.regression.core.util.*; +import org.apache.falcon.regression.testHelper.BaseUITestClass; +import org.apache.falcon.regression.ui.search.EntityPage; +import org.apache.falcon.regression.ui.search.InstancePage; +import org.apache.falcon.regression.ui.search.LoginPage; +import org.apache.falcon.regression.ui.search.SearchPage; +import org.apache.falcon.resource.InstancesResult; +import org.apache.oozie.client.CoordinatorAction; +import org.apache.oozie.client.OozieClient; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.EnumSet; + +/** + * Tests for Search UI Instance Page. + */ +@Test(groups = "search-ui") +public class InstancePageTest extends BaseUITestClass { + + private final ColoHelper cluster = servers.get(0); + private final OozieClient clusterOC = serverOC.get(0); + private String baseTestHDFSDir = cleanAndGetTestDir(); + private String aggregateWorkflowDir = baseTestHDFSDir + "/aggregator"; + private String feedInputPath = baseTestHDFSDir + "/input" + MINUTE_DATE_PATTERN; + private String feedOutputPath = baseTestHDFSDir + "/output" + MINUTE_DATE_PATTERN; + private SearchPage searchPage; + private InstancePage instancePage; + private String instance = "2010-01-02T01:00Z"; + private String processName; + + @BeforeClass(alwaysRun = true) + public void setup() { + openBrowser(); + searchPage = LoginPage.open(getDriver()).doDefaultLogin(); + } + + @BeforeMethod(alwaysRun = true) + public void submitEntities() throws Exception { + cleanAndGetTestDir(); + HadoopUtil.uploadDir(serverFS.get(0), aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE); + bundles[0] = BundleUtil.readELBundle(); + bundles[0] = new Bundle(bundles[0], cluster); + bundles[0].generateUniqueBundle(this); + bundles[0].setInputFeedDataPath(feedInputPath); + bundles[0].setProcessWorkflow(aggregateWorkflowDir); + bundles[0].setProcessValidity("2010-01-02T01:00Z", "2010-01-02T01:01Z"); + bundles[0].setProcessInputStartEnd("now(0, 0)", "now(0, 0)"); + bundles[0].setProcessPeriodicity(5, Frequency.TimeUnit.minutes); + bundles[0].setOutputFeedPeriodicity(5, Frequency.TimeUnit.minutes); + bundles[0].setOutputFeedLocationData(feedOutputPath); + bundles[0].submitAndScheduleProcess(); + processName = bundles[0].getProcessName(); + searchPage.refresh(); + InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1, + CoordinatorAction.Status.WAITING, EntityType.PROCESS, 5); + } + + @Test + public void testInstancePageStatusWaitingRunning() throws Exception { + instancePage = searchPage.openEntityPage(processName).openInstance(instance); + checkInstanceStatuses(InstancesResult.WorkflowStatus.WAITING); + + Assert.assertEquals(instancePage.getButtons(false), EnumSet.allOf(InstancePage.Button.class), + "All buttons should be disabled for WAITING instance"); + + OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0); + + InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1, + CoordinatorAction.Status.RUNNING, EntityType.PROCESS, 5); + + instancePage = instancePage.refreshPage(); + checkInstanceStatuses(InstancesResult.WorkflowStatus.RUNNING); + Assert.assertEquals(instancePage.getButtons(false), EnumSet.of(InstancePage.Button.Resume), + "Only 'Resume' button should be disabled for RUNNING instance"); + } + + @Test + public void testInstancePagePauseResume() throws Exception { + OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0); + InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1, + CoordinatorAction.Status.RUNNING, EntityType.PROCESS, 5); + + instancePage = searchPage.openEntityPage(processName).openInstance(instance); + checkInstanceStatuses(InstancesResult.WorkflowStatus.RUNNING); + + instancePage.clickButton(InstancePage.Button.Suspend); + checkInstanceStatuses(InstancesResult.WorkflowStatus.SUSPENDED); + + Assert.assertEquals(instancePage.getButtons(false), EnumSet.of(InstancePage.Button.Suspend), + "Only 'Suspend' button should be disabled for SUSPENDED instance"); + + instancePage.clickButton(InstancePage.Button.Resume); + checkInstanceStatuses(InstancesResult.WorkflowStatus.RUNNING); + } + + @Test + public void testInstancePageKillRerun() throws Exception { + OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0); + InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1, + CoordinatorAction.Status.RUNNING, EntityType.PROCESS, 5); + + instancePage = searchPage.openEntityPage(processName).openInstance(instance); + checkInstanceStatuses(InstancesResult.WorkflowStatus.RUNNING); + + instancePage.clickButton(InstancePage.Button.Stop); + checkInstanceStatuses(InstancesResult.WorkflowStatus.KILLED); + + Assert.assertEquals(instancePage.getButtons(true), EnumSet.of(InstancePage.Button.Resume), + "Only 'Resume' button should be active for KILLED instance"); + + instancePage.clickButton(InstancePage.Button.Resume); + checkInstanceStatuses(InstancesResult.WorkflowStatus.RUNNING); + } + + @Test + public void testInstancePageInfo() throws Exception { + OozieUtil.createMissingDependencies(cluster, EntityType.PROCESS, processName, 0); + InstanceUtil.waitTillInstanceReachState(clusterOC, processName, 1, + CoordinatorAction.Status.SUCCEEDED, EntityType.PROCESS, 5); + + EntityPage entityPage = searchPage.openEntityPage(processName); + EntityPage.OneInstanceSummary summary = EntityPage.InstanceSummary + .getOneSummary(entityPage.getInstanceSummary().getSummary(), instance); + Assert.assertNotNull(summary, "Instance not found on entity page"); + Assert.assertEquals(summary.getStatus(), "SUCCEEDED", "Unexpected status on entity page"); + + instancePage = entityPage.openInstance(instance); + checkInstanceStatuses(InstancesResult.WorkflowStatus.SUCCEEDED); + + Assert.assertEquals(instancePage.getEntityName(), processName, "Process name isn't shown correctly"); + + Assert.assertTrue(instancePage.isLineagePresent(), "Lineage graph should be present"); + } + + @Test + public void testHeader() { + instancePage = searchPage.openEntityPage(processName).openInstance(instance); + instancePage.getPageHeader().checkHeader(); + + } + + + private void checkInstanceStatuses(InstancesResult.WorkflowStatus status) throws Exception { + InstancesResult.Instance[] instances = prism.getProcessHelper() + .listInstances(processName, "start=" + instance, null).getInstances(); + Assert.assertNotNull(instance, "Instances not found via API"); + Assert.assertEquals(instances.length, 1, "Only one instance expected via API"); + Assert.assertEquals(instances[0].getStatus(), status, "Unexpected status via API"); + + Assert.assertEquals(instancePage.getStatus(), status.toString(), "Unexpected status on UI"); + } + + + @AfterMethod(alwaysRun = true) + public void tearDown() throws IOException { + removeTestClassEntities(); + } + + @AfterClass(alwaysRun = true) + public void tearDownClass() { + closeBrowser(); + } +}
