Repository: falcon Updated Branches: refs/heads/master a6298f8a7 -> 9124f0152
FALCON-1173 Tests for entities table of search-ui. 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/9124f015 Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/9124f015 Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/9124f015 Branch: refs/heads/master Commit: 9124f015275a780480aa256b8538191ccc96d6e7 Parents: a6298f8 Author: Ruslan Ostafiychuk <[email protected]> Authored: Wed Apr 22 18:45:36 2015 +0300 Committer: Ruslan Ostafiychuk <[email protected]> Committed: Mon Apr 27 17:00:29 2015 +0300 ---------------------------------------------------------------------- falcon-regression/CHANGES.txt | 4 +- .../falcon/regression/ui/search/SearchPage.java | 143 +++++++++++++---- .../falcon/regression/TestngListener.java | 7 +- .../regression/searchUI/EntitiesTableTest.java | 155 +++++++++++++++++++ 4 files changed, 279 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/falcon/blob/9124f015/falcon-regression/CHANGES.txt ---------------------------------------------------------------------- diff --git a/falcon-regression/CHANGES.txt b/falcon-regression/CHANGES.txt index 104c01f..884acfc 100644 --- a/falcon-regression/CHANGES.txt +++ b/falcon-regression/CHANGES.txt @@ -5,6 +5,8 @@ Trunk (Unreleased) INCOMPATIBLE CHANGES NEW FEATURES + FALCON-1173 Tests for entities table of search-ui (Ruslan Ostafiychuk) + FALCON-1171 Adding search API tests (Paul Isaychuk via Raghav Kumar Gautam) FALCON-1167 Homepage & Login test for search-ui (Raghav Kumar Gautam via Ruslan Ostafiychuk) @@ -66,7 +68,7 @@ Trunk (Unreleased) via Samarth Gupta) IMPROVEMENTS - + FALCON-1131 Fixing FeedClusterUpdateTest and name confilcts in FALCON-1113(Pragya M via Samarth Gupta) http://git-wip-us.apache.org/repos/asf/falcon/blob/9124f015/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/SearchPage.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/SearchPage.java b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/SearchPage.java index 8c3ae71..5d3febf 100644 --- a/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/SearchPage.java +++ b/falcon-regression/merlin/src/main/java/org/apache/falcon/regression/ui/search/SearchPage.java @@ -19,7 +19,9 @@ package org.apache.falcon.regression.ui.search; import org.apache.falcon.regression.core.util.UIAssert; +import org.apache.log4j.Logger; import org.openqa.selenium.By; +import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -28,6 +30,7 @@ import org.testng.Assert; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** Page object for the Search Page. */ @@ -106,53 +109,110 @@ public class SearchPage extends AbstractSearchPage { } public List<SearchResult> doSearch(String searchString) { - getSearchBox().sendKeys(searchString + "\n"); + clearSearch(); + return appendAndSearch(searchString); + } + + public List<SearchResult> appendAndSearch(String appendedPart) { + for(String queryParam : appendedPart.split("\\s+")) { + getSearchBox().sendKeys(queryParam); + getSearchBox().sendKeys(Keys.SPACE); + } + String activeAlert = getActiveAlertText(); + if (activeAlert != null) { + Assert.assertEquals(activeAlert.trim(), "No results matched the search criteria."); + return Collections.emptyList(); + } UIAssert.assertDisplayed(resultBlock, "Search result block"); return getSearchResults(); + } - public SearchQuery getSearchQuery() { - final WebElement queryGroup = searchBlock.findElement(By.className("tag-list")); - final List<WebElement> queryParts = queryGroup.findElements(By.tagName("li")); - if (queryParts.size() == 0) { - return SearchQuery.create(null); - } else { - final WebElement namePart = queryParts.remove(0); - final WebElement nameLabel = namePart.findElement(By.tagName("strong")); - Assert.assertEquals(nameLabel.getText(), "NAME: ", "Name label of query"); - final WebElement nameElem = namePart.findElement(By.tagName("span")); - SearchQuery searchQuery = SearchQuery.create(nameElem.getText()); - for (WebElement tagPart : queryParts) { - final WebElement tagLabel = tagPart.findElement(By.tagName("strong")); - Assert.assertEquals(tagLabel.getText(), "TAG: ", "Tag label of query"); - final WebElement tagElem = tagPart.findElement(By.tagName("span")); - searchQuery.withTag(tagElem.getText()); + private String getActiveAlertText() { + List<WebElement> alerts = driver.findElements(By.className("ng-animate")); + if (!alerts.isEmpty()) { + WebElement last = alerts.get(alerts.size() - 1); + if (last.isDisplayed()) { + return last.getText(); } - return searchQuery; } + return null; } + public SearchQuery getSearchQuery() { + return new SearchQuery(searchBlock); + } + + public void clearSearch() { + getSearchBox().clear(); + SearchQuery query = getSearchQuery(); + for (int i = 0; i < query.getElementsNumber(); i++) { + removeLastParam(); + } + } + + public void removeLastParam() { + getSearchBox().sendKeys(Keys.BACK_SPACE); + getSearchBox().sendKeys(Keys.BACK_SPACE); + } + + public void checkNoResult() { UIAssert.assertNotDisplayed(resultBlock, "Search result block"); } /** Class representing search query displayed in the search box. */ public static final class SearchQuery { - private final String name; - + private WebElement searchBlock; + private String name; + private String type; + private int elementsNumber; private final List<String> tags = new ArrayList<>(); + private static final Logger LOGGER = Logger.getLogger(SearchQuery.class); - private SearchQuery(String name) { - this.name = name; + public SearchQuery(WebElement searchBlock) { + this.searchBlock = searchBlock; + updateElements(); } - public static SearchQuery create(String name) { - return new SearchQuery(name); + private SearchQuery updateElements() { + name = null; + type = null; + tags.clear(); + final WebElement queryGroup = searchBlock.findElement(By.className("tag-list")); + final List<WebElement> queryParts = queryGroup.findElements(By.tagName("li")); + elementsNumber = queryParts.size(); + for (WebElement queryPart : queryParts) { + final WebElement queryLabel = queryPart.findElement(By.tagName("strong")); + final String queryText = queryPart.findElement(By.tagName("span")).getText(); + switch (queryLabel.getText().trim()) { + case "NAME:": + if (name != null) { + LOGGER.warn(String.format("NAME block is already added: '%s' => '%s'", + name, queryText)); + } + name = queryText; + break; + case "TAG:": + tags.add(queryText); + break; + case "TYPE:": + if (type != null) { + LOGGER.warn(String.format("TYPE block is already added: '%s' => '%s'", + type, queryText)); + } + type = queryText; + break; + default: + Assert.fail("There should be only TAGs or TYPE"); + } + } + return this; } - public SearchQuery withTag(String tag) { - tags.add(tag); - return this; + + public String getType() { + return type; } public String getName() { @@ -162,6 +222,35 @@ public class SearchPage extends AbstractSearchPage { public List<String> getTags() { return tags; } + + public int getElementsNumber() { + return elementsNumber; + } + + /** + * Delete element by index (1, 2, 3,..). + * @param index of element in search query. + * @return true if deletion was successful + */ + public boolean deleteByIndex(int index) { + if (index > elementsNumber || index < 1) { + LOGGER.warn("There is no element with index=" + index); + return false; + } + int oldElementsNumber = elementsNumber; + final WebElement queryGroup = searchBlock.findElement(By.className("tag-list")); + final List<WebElement> queryParts = queryGroup.findElements(By.tagName("li")); + queryParts.get(index - 1).findElement(By.className("remove-button")).click(); + this.updateElements(); + boolean result = oldElementsNumber == elementsNumber + 1; + LOGGER.info(String.format( + "Element with index=%d was%s deleted", index, result ? "" : "n't")); + return result; + } + + public boolean deleteLast() { + return deleteByIndex(elementsNumber); + } } /** Class representing search result displayed on the entity table page. */ http://git-wip-us.apache.org/repos/asf/falcon/blob/9124f015/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/TestngListener.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/TestngListener.java b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/TestngListener.java index e3aac1d..8d8677c 100644 --- a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/TestngListener.java +++ b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/TestngListener.java @@ -116,8 +116,11 @@ public class TestngListener implements ITestListener, IExecutionListener { byte[] scrFile = ((TakesScreenshot)BaseUITestClass.getDriver()).getScreenshotAs(OutputType.BYTES); try { - String filename = OSUtil.getPath("target", "surefire-reports", "screenshots", String.format("%s.%s.png", - result.getTestClass().getRealClass().getSimpleName(), result.getName())); + String params = Arrays.toString(result.getParameters()); + params = params.replaceAll("[<>\":\\\\/\\|\\?\\*]", ""); //remove <>:"/\|?* + String filename = OSUtil.getPath("target", "surefire-reports", "screenshots", + String.format("%s.%s.(%s).png", result.getTestClass().getRealClass() + .getSimpleName(), result.getName(), params)); FileUtils.writeByteArrayToFile(new File(filename), scrFile); } catch (IOException e) { LOGGER.info("Saving screenshot FAILED: " + e.getCause()); http://git-wip-us.apache.org/repos/asf/falcon/blob/9124f015/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/EntitiesTableTest.java ---------------------------------------------------------------------- diff --git a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/EntitiesTableTest.java b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/EntitiesTableTest.java new file mode 100644 index 0000000..88db7fe --- /dev/null +++ b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/searchUI/EntitiesTableTest.java @@ -0,0 +1,155 @@ +/** + * 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.commons.lang3.StringUtils; +import org.apache.falcon.regression.Entities.ProcessMerlin; +import org.apache.falcon.regression.core.bundle.Bundle; +import org.apache.falcon.regression.core.util.AssertUtil; +import org.apache.falcon.regression.core.util.BundleUtil; +import org.apache.falcon.regression.core.util.OSUtil; +import org.apache.falcon.regression.testHelper.BaseUITestClass; +import org.apache.falcon.regression.ui.search.LoginPage; +import org.apache.falcon.regression.ui.search.SearchPage; +import org.apache.hadoop.security.authentication.client.AuthenticationException; +import org.apache.log4j.Logger; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import javax.xml.bind.JAXBException; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; + +/** UI tests for entities table with search results. */ +@Test(groups = "search-ui") +public class EntitiesTableTest extends BaseUITestClass { + private static final Logger LOGGER = Logger.getLogger(EntitiesTableTest.class); + private String baseTestDir = cleanAndGetTestDir(); + private String aggregateWorkflowDir = baseTestDir + "/aggregator"; + + private SearchPage searchPage = null; + private String[] tags = {"first=correctvalue", "second=one", "third=one", "fourth=one", + "fifth=one", "sixth=one", "seventh=one", "eighth=one", "ninth=one", "tenth=one", }; + private String baseProcessName; + + /** + * Submit one cluster, 2 feeds and 10 processes with 1 to 10 tags (1st process has 1 tag, + * 2nd - two tags.. 10th has 10 tags). + * @throws URISyntaxException + * @throws IOException + * @throws AuthenticationException + * @throws InterruptedException + * @throws JAXBException + */ + @BeforeClass(alwaysRun = true) + public void setup() + throws URISyntaxException, IOException, AuthenticationException, InterruptedException, + JAXBException { + uploadDirToClusters(aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE); + openBrowser(); + searchPage = LoginPage.open(getDriver()).doDefaultLogin(); + bundles[0] = BundleUtil.readELBundle(); + bundles[0] = new Bundle(bundles[0], servers.get(0)); + bundles[0].generateUniqueBundle(this); + bundles[0].submitClusters(prism); + bundles[0].submitFeeds(prism); + bundles[0].setProcessWorkflow(aggregateWorkflowDir); + ProcessMerlin process = bundles[0].getProcessObject(); + baseProcessName = process.getName(); + for (int i = 1; i <= 10; i++) { + process.setName(baseProcessName + '-' + i); + process.setTags(StringUtils.join(Arrays.copyOfRange(tags, 0, i), ',')); + AssertUtil.assertSucceeded(prism.getProcessHelper().submitEntity(process.toString())); + } + + } + + @AfterClass(alwaysRun = true) + public void tearDown() throws IOException { + removeTestClassEntities(); + closeBrowser(); + } + + /** + * Search entities with invalid params. Zero entities should be shown. + */ + @Test(dataProvider = "getInvalidFilters") + public void testSearchBoxInvalidFilter(String invalidSearch) { + Assert.assertEquals(searchPage.doSearch(invalidSearch).size(), 0, + "There should be 0 results with query='" + invalidSearch + "'"); + } + + + @DataProvider + public Object[][] getInvalidFilters() { + return new String[][]{ + {"notnameofentity"}, + {"* othertag=sometag"}, + {"* first=other"}, + {"XX" + bundles[0].getProcessName().substring(2)}, + }; + } + + /** + * All processes should be found with first tag. Add tags one by one. Only one process + * should be found with all tags. + */ + @Test + public void testSearchBoxManyParams() { + searchPage.doSearch(baseProcessName); + for (int i = 0; i < 10; i++) { + Assert.assertEquals(searchPage.appendAndSearch(tags[i]).size(), 10 - i, + "There should be " + (10 - i) + " results"); + } + } + + /** + * Only one process should be found with all tags. Delete tags one by one. All processes + * should be found with first tag. Zero entities should be shown after cleaning all params. + */ + @Test(dataProvider = "getBoolean") + public void testSearchBoxCleanSingleParam(boolean deleteByClick) { + searchPage.doSearch(this.getClass().getSimpleName() + ' ' + StringUtils.join(tags, ' ')); + for (int i = 1; i <= 10; i++) { + Assert.assertEquals(searchPage.getSearchResults().size(), i, + "There should be " + i + " results"); + if (deleteByClick) { + searchPage.getSearchQuery().deleteLast(); + } else { + searchPage.removeLastParam(); + } + } + if (deleteByClick) { + searchPage.getSearchQuery().deleteLast(); + } else { + searchPage.removeLastParam(); + } + Assert.assertEquals(searchPage.getSearchResults().size(), 0, + "There should be 0 results"); + } + + @DataProvider + public Object[][] getBoolean() { + return new Boolean[][]{{Boolean.TRUE}, {Boolean.FALSE}}; + } +}
