You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@falcon.apache.org by ra...@apache.org on 2015/04/23 19:31:56 UTC
falcon git commit: FALCON-1171: Adding search API tests contributed
by Paul Isaychuk
Repository: falcon
Updated Branches:
refs/heads/master cecc3b427 -> 0232f1b6b
FALCON-1171: Adding search API tests contributed by Paul Isaychuk
Project: http://git-wip-us.apache.org/repos/asf/falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/falcon/commit/0232f1b6
Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/0232f1b6
Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/0232f1b6
Branch: refs/heads/master
Commit: 0232f1b6bddfc16762357cd0f70b9b89de0c308a
Parents: cecc3b4
Author: Raghav Kumar Gautam <ra...@apache.org>
Authored: Thu Apr 23 10:31:48 2015 -0700
Committer: Raghav Kumar Gautam <ra...@apache.org>
Committed: Thu Apr 23 10:31:48 2015 -0700
----------------------------------------------------------------------
falcon-regression/CHANGES.txt | 1 +
.../helpers/entity/AbstractEntityHelper.java | 14 +-
.../apache/falcon/regression/SearchApiTest.java | 497 +++++++++++++++++++
.../regression/entity/ListEntitiesTest.java | 6 +-
4 files changed, 509 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/falcon/blob/0232f1b6/falcon-regression/CHANGES.txt
----------------------------------------------------------------------
diff --git a/falcon-regression/CHANGES.txt b/falcon-regression/CHANGES.txt
index 7b56be8..104c01f 100644
--- a/falcon-regression/CHANGES.txt
+++ b/falcon-regression/CHANGES.txt
@@ -5,6 +5,7 @@ Trunk (Unreleased)
INCOMPATIBLE CHANGES
NEW FEATURES
+ 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)
http://git-wip-us.apache.org/repos/asf/falcon/blob/0232f1b6/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/core/helpers/entity/AbstractEntityHelper.java
----------------------------------------------------------------------
diff --git a/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/core/helpers/entity/AbstractEntityHelper.java b/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/core/helpers/entity/AbstractEntityHelper.java
index b899f1a..08e11a1 100644
--- a/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/core/helpers/entity/AbstractEntityHelper.java
+++ b/falcon-regression/merlin-core/src/main/java/org/apache/falcon/regression/core/helpers/entity/AbstractEntityHelper.java
@@ -252,14 +252,16 @@ public abstract class AbstractEntityHelper {
public ServiceResponse listEntities()
throws IOException, URISyntaxException, AuthenticationException, InterruptedException {
- return listEntities(null, null);
+ return listEntities(null, null, null);
}
- public ServiceResponse listEntities(String params, String user)
+ public ServiceResponse listEntities(String entityType, String params, String user)
throws IOException, URISyntaxException, AuthenticationException, InterruptedException {
- LOGGER.info("fetching " + getEntityType() + " list");
- String url = createUrl(this.hostname + URLS.LIST_URL.getValue(),
- getEntityType() + colo);
+ if (StringUtils.isEmpty(entityType)) {
+ entityType = getEntityType();
+ }
+ LOGGER.info("fetching " + entityType + " list");
+ String url = createUrl(this.hostname + URLS.LIST_URL.getValue(), entityType + colo);
if (StringUtils.isNotEmpty(params)){
url += colo.isEmpty() ? "?" + params : "&" + params;
}
@@ -268,7 +270,7 @@ public abstract class AbstractEntityHelper {
public ServiceResponse listAllEntities(String params, String user)
throws AuthenticationException, IOException, URISyntaxException, InterruptedException {
- return listEntities((params == null ? "" : params + '&')
+ return listEntities(null, (params == null ? "" : params + '&')
+ "numResults=" + Integer.MAX_VALUE, user);
}
http://git-wip-us.apache.org/repos/asf/falcon/blob/0232f1b6/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/SearchApiTest.java
----------------------------------------------------------------------
diff --git a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/SearchApiTest.java b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/SearchApiTest.java
new file mode 100644
index 0000000..b317944
--- /dev/null
+++ b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/SearchApiTest.java
@@ -0,0 +1,497 @@
+/**
+ * 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;
+
+import com.google.common.collect.Ordering;
+import org.apache.falcon.regression.Entities.FeedMerlin;
+import org.apache.falcon.regression.Entities.ProcessMerlin;
+import org.apache.falcon.regression.core.bundle.Bundle;
+import org.apache.falcon.regression.core.helpers.ColoHelper;
+import org.apache.falcon.regression.core.response.ServiceResponse;
+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.BaseTestClass;
+import org.apache.falcon.resource.EntityList.EntityElement;
+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.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Search api tests.
+ */
+@Test(groups = "search-api")
+public class SearchApiTest extends BaseTestClass {
+
+ private static final Logger LOGGER = Logger.getLogger(SearchApiTest.class);
+ private ColoHelper cluster = servers.get(0);
+ private String baseTestHDFSDir = cleanAndGetTestDir();
+ private String aggregateWorkflowDir = baseTestHDFSDir + "/aggregator";
+ private final String base = getClass().getSimpleName();
+ private static final Comparator<EntityElement> ASC = new Comparator<EntityElement>() {
+ @Override
+ public int compare(EntityElement o1, EntityElement o2) {
+ return o1.name.compareTo(o2.name);
+ }
+ };
+ private static final Comparator<EntityElement> DESC = Collections.reverseOrder(ASC);
+
+ /**
+ * Method creates a set of entities.
+ * |--------------------------------------------+-----------------------------+-----------------------------|
+ * | Basic input/output Feeds (without tags) | bundle0-input-feed | bundle0-output-feed |
+ * |--------------+-----------------------------+-----------------------------+-----------------------------|
+ * | Feed Name | bundle1-feed | bundle2-feed | bundle3-feed |
+ * | Tags | specific=bundle1 | specific=bundle2 | specific=bundle3 |
+ * | | common=common | common=common | common=common |
+ * | | partial=b1b2 | partial=b1b2 | |
+ * |--------------+-----------------------------+-----------------------------+-----------------------------|
+ * | Process Name | bundle1-process | bundle2-process | bundle3-process |
+ * | Tags | specific=bundle1 | specific=bundle2 | specific=bundle3 |
+ * | | partial=b1b2 | partial=b1b2 | common=common |
+ * | | common=common | common=common | |
+ * |--------------+-----------------------------+-----------------------------+-----------------------------|
+ * | Mirror Name | bundle1-mirror-process | bundle2-mirror-process | bundle3-mirror-process |
+ * | Tags | specific=bundle1 | specific=bundle2 | specific=bundle3 |
+ * | | common=common | common=common | common=common |
+ * | | partial=b1b2 | partial=b1b2 | _falcon_mirroring_type=HDFS |
+ * | | _falcon_mirroring_type=HDFS | _falcon_mirroring_type=HIVE | |
+ * |--------------+-----------------------------+-----------------------------+-----------------------------|
+ */
+ @BeforeClass(alwaysRun = true)
+ public void prepareData()
+ throws IOException, URISyntaxException, AuthenticationException, InterruptedException, JAXBException {
+ uploadDirToClusters(aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE);
+
+ /* Prepare bundle template*/
+ bundles[0] = BundleUtil.readELBundle();
+ bundles[0] = new Bundle(bundles[0], servers.get(0));
+ bundles[0].generateUniqueBundle(this);
+ bundles[0].submitClusters(cluster);
+ String prefix = getClass().getSimpleName() + "-bundle";
+
+ FeedMerlin basicFeed = new FeedMerlin(bundles[0].getInputFeedFromBundle());
+ basicFeed.setName(prefix + "0-input-feed");
+ AssertUtil.assertSucceeded(cluster.getFeedHelper().submitAndSchedule(basicFeed.toString()));
+ basicFeed = new FeedMerlin(bundles[0].getOutputFeedFromBundle());
+ basicFeed.setName(prefix + "0-output-feed");
+ AssertUtil.assertSucceeded(cluster.getFeedHelper().submitAndSchedule(basicFeed.toString()));
+
+ /* Submit 3 bundles of feeds */
+ FeedMerlin feed = new FeedMerlin(bundles[0].getInputFeedFromBundle());
+ for (int i = 1; i <= 3; i++) {
+ String feedName = prefix + i + "-feed";
+ feed.setName(feedName);
+ String tags = "specific=bundle" + i + ",common=common";
+ if (i <= 2) {
+ tags += ",partial=b1b2";
+ }
+ feed.setTags(tags);
+ AssertUtil.assertSucceeded(cluster.getFeedHelper().submitEntity(feed.toString()));
+ }
+
+ /* Submit 3 bundles of processes */
+ ProcessMerlin process = bundles[0].getProcessObject();
+
+ //replace input and output with feeds of bundle0
+ process.addInputFeed("input", prefix + "0-input-feed");
+ process.getInputs().getInputs().remove(0);
+ process.addOutputFeed("output", prefix + "0-output-feed");
+ process.getOutputs().getOutputs().remove(0);
+ process.setWorkflow(aggregateWorkflowDir, null, null);
+ for (int i = 1; i <= 3; i++) {
+ process.setName(prefix + i + "-process");
+ String tags = "specific=bundle" + i + ",common=common";
+ if (i <= 2) {
+ tags += ",partial=b1b2";
+ }
+ process.setTags(tags);
+ AssertUtil.assertSucceeded(cluster.getProcessHelper().submitEntity(process.toString()));
+
+ //submit a mirroring process
+ if (i % 2 == 1) {
+ tags += ",_falcon_mirroring_type=HDFS";
+ } else {
+ tags += ",_falcon_mirroring_type=HIVE";
+ }
+ process.setName(prefix + i + "-mirror-process");
+ process.setTags(tags);
+ AssertUtil.assertSucceeded(cluster.getProcessHelper().submitEntity(process.toString()));
+ }
+ }
+
+ /**
+ * Test hits API, retrieves entities and validates them based on set of expected conditions.
+ * @param params object which consists of test case parameters such as type, name sequence, tag keys etc.
+ * @param result object which contains set of expected conditions. Performs validations of entities.
+ */
+ @Test(dataProvider = "getSearchParams")
+ public void search(QueryParams params, Result result)
+ throws URISyntaxException, AuthenticationException, InterruptedException, IOException, JAXBException {
+ ServiceResponse serviceResponse = cluster.getClusterHelper()
+ .listEntities(params.getType(), params.getParams(), null);
+ if (result.getExpError() != null) {
+ AssertUtil.assertFailed(serviceResponse, result.getExpError());
+ } else {
+ String order = null;
+ if (params.getParams().contains("orderBy")) {
+ order = params.getParams().contains("sortOrder=desc") ? "desc" : "asc";
+ }
+ result.validateEntities(serviceResponse.getEntityList().getElements(), order);
+ }
+ }
+
+ @DataProvider
+ private Object[][] getSearchParams() {
+ return new Object[][]{
+
+ /*Nameseq test cases*/
+ {new QueryParams().withNumResults(12), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(11), },
+ {new QueryParams().withNameSeq(base + "-bundle1-feed"), new Result().withExpBundles(1)
+ .withExpTypes("feed").withExpTotal(1), },
+ {new QueryParams().withNameSeq(base + "-bundle2-mirror-process"), new Result().withExpBundles(2)
+ .withExpTypes("process", "mirror").withExpTotal(1), },
+ {new QueryParams().withNameSeq(base + "-bUnDlE1-fEeD"), new Result().withExpBundles(1)
+ .withExpTypes("feed").withExpTotal(1), },
+ {new QueryParams().withNameSeq(base + "-bundle1-feed-non"), new Result(), },
+ {new QueryParams().withNameSeq(base + "-bundle2-process-non"), new Result(), },
+ {new QueryParams().withNameSeq("-bundle2-"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withNameSeq(base).withNumResults(12), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(11), },
+ {new QueryParams().withNameSeq("bundleFeed"), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed").withExpTotal(5), },
+ {new QueryParams().withNameSeq("bundleProcess"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("process", "mirror").withExpTotal(6), },
+ {new QueryParams().withNameSeq("bUnDlEfeEd"), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed").withExpTotal(5), },
+ {new QueryParams().withNameSeq("bUnDlEprOCesS"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("process", "mirror").withExpTotal(6), },
+ {new QueryParams().withNameSeq(base + "-bundle-nonexistent"), new Result(), },
+ //unusual nameseq forms
+ {new QueryParams().withNameSeq("012345"), new Result(), },
+ {new QueryParams().withNameSeq("f€€d"), new Result(), },
+ {new QueryParams().withNameSeq("_-#$@"), new Result(), },
+ {new QueryParams().withNameSeq("").withNumResults(12), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(11), },
+
+ /*Tagkey test cases*/
+ /* Full tagkey name*/
+ {new QueryParams().withTagkey("bundle1"), new Result().withExpBundles(1)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("bundle2"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("bundle3"), new Result().withExpBundles(3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("bUnDlE1"), new Result().withExpBundles(1)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("_falcon_mirroring_type"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("process", "mirror").withExpTotal(3), },
+ /* Special, utf-8 symbols*/
+ {new QueryParams().withTagkey("bun@le#"), new Result()},
+ {new QueryParams().withTagkey("bundl€"), new Result()},
+ /* Common for a pair of bundles; use both tag and value as tagkey*/
+ {new QueryParams().withTagkey("b1b2"), new Result().withExpBundles(1, 2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(6), },
+ {new QueryParams().withTagkey("partial"), new Result().withExpBundles(1, 2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(6), },
+ /* Common for 1,2,3 bundles*/
+ {new QueryParams().withTagkey("common"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ {new QueryParams().withTagkey("bundle"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ {new QueryParams().withTagkey("undle"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ {new QueryParams().withTagkey("undle,undle"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ /* Multiple full tags*/
+ {new QueryParams().withTagkey("common,bundle1"), new Result().withExpBundles(1)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("common,bundle2"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("common,bundle3"), new Result().withExpBundles(3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("common,bundle1,b1b2"), new Result().withExpBundles(1)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("common,bundle2,b1b2"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ /* Multiple, diff case*/
+ {new QueryParams().withTagkey("cOmMoN,bUnDlE2,B1b2"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ /* Multiple partial tags*/
+ {new QueryParams().withTagkey("common,undle"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ {new QueryParams().withTagkey("ommo,undle"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(9), },
+ {new QueryParams().withTagkey("ommo,ndle1"), new Result().withExpBundles(1)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("oMMon,ndle2"), new Result().withExpBundles(2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ {new QueryParams().withTagkey("oMMon,b1b"), new Result().withExpBundles(1, 2)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(6), },
+ {new QueryParams().withTagkey("comm,ndle3"), new Result().withExpBundles(3)
+ .withExpTypes("feed", "process", "mirror").withExpTotal(3), },
+ /* Non existent*/
+ {new QueryParams().withTagkey("bundle9"), new Result(), },
+ {new QueryParams().withTagkey("common,undle,zero"), new Result(), },
+
+ /*Custom filter test cases*/
+ //different types
+ {new QueryParams().forType("process"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("process", "mirror").withExpTotal(6), },
+ {new QueryParams().forType("feed"), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed").withExpTotal(5), },
+ {new QueryParams().forType("FEED"), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed").withExpTotal(5), },
+ {new QueryParams().forType("MEGAFEED"), new Result()
+ .withExpError("Invalid entity type: MEGAFEED. Expected [feed, process, cluster]"), },
+ //custom filters
+ {new QueryParams().forType("process").withNameSeq("bundle").withTagkey("bundle,b1b2").withNumResults(3)
+ .withOrder(true).withSortOrder("desc"), new Result().withExpBundles(1, 2)
+ .withExpTypes("process", "mirror").withExpTotal(3), },
+ {new QueryParams().forType("schedulable").withNameSeq("bundle").withTagkey("partial,common")
+ .withOrder(true), new Result().withExpBundles(1, 2).withExpTypes("feed", "process", "mirror")
+ .withExpTotal(6), },
+ {new QueryParams().forType("feed").withNameSeq("bundlefeed").withNumResults(2).withOrder(true)
+ .withSortOrder("asc"), new Result().withExpBundles(0, 1, 2, 3)
+ .withExpTypes("feed").withExpTotal(2), },
+ {new QueryParams().forType("schedulable").withNameSeq("bundleproc").withTagkey("_falcon_mirroring_type")
+ .withOrder(true).withSortOrder("desc"), new Result().withExpBundles(1, 2, 3)
+ .withExpTypes("process", "mirror").withExpTotal(3), },
+ //one option excludes another
+ {new QueryParams().forType("process").withNameSeq("bundlefeed"), new Result(), },
+ {new QueryParams().forType("feed").withNameSeq("bundleprocess"), new Result(), },
+ {new QueryParams().forType("schedulable").withNameSeq("bundle3").withTagkey("b1b2").withOrder(true),
+ new Result(), },
+ };
+ }
+
+ /**
+ * Contains all required params for search api request.
+ */
+ private class QueryParams {
+ private String type = "schedulable";
+ private String nameSeq = null;
+ private String tagKey = null;
+ private String orderBy = null;
+ private String sortOrder = null;
+ private Integer numResults = null;
+ private String fields = "&fields=tags";
+
+ public QueryParams forType(String paramType) {
+ this.type = paramType;
+ return this;
+ }
+
+ public QueryParams withNameSeq(String paramNameSeq) {
+ this.nameSeq = paramNameSeq;
+ return this;
+ }
+
+ public QueryParams withTagkey(String paramTagkey) {
+ this.tagKey = paramTagkey;
+ return this;
+ }
+
+ public QueryParams withOrder(boolean ordered) {
+ if (ordered) {
+ this.orderBy = "&orderBy=name";
+ }
+ return this;
+ }
+
+ public QueryParams withSortOrder(String paramSortOrder) {
+ this.sortOrder = paramSortOrder;
+ return this;
+ }
+
+ public QueryParams withNumResults(Integer paramNumResults) {
+ this.numResults = paramNumResults;
+ return this;
+ }
+
+ /**
+ * @return url param string.
+ */
+ public String getParams() {
+ return (nameSeq != null ? "&nameseq=" + nameSeq : "")
+ + (tagKey != null ? "&tagkey=" + tagKey : "")
+ + (numResults != null ? "&numResults=" + numResults : "")
+ + (orderBy != null ? "&orderBy=name" + orderBy : "")
+ + (sortOrder != null ? "&sortOrder=" + sortOrder : "") + fields;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ /**
+ * Pretty prints params to param string.
+ */
+ @Override
+ public String toString() {
+ return "[type: " + type + (nameSeq != null ? "; nseq: " + nameSeq : "")
+ + (tagKey != null ? "; tagkey: " + tagKey : "")
+ + (numResults != null ? "; n:" + numResults : "")
+ + (orderBy != null ? "; ordered" : "")
+ + (sortOrder != null ? "; " + sortOrder : "") + "]";
+ }
+ }
+
+ /**
+ * Class for entities response validation.
+ */
+ private class Result {
+ private List<String> expectedTypes = null;
+ private String expectedError = null;
+ private List<String> expectedBundles = null;
+ private int expectedTotal = 0;
+ private final List<String> allBundles = Arrays.asList("bundle0", "bundle1", "bundle2", "bundle3");
+ private final List<String> allTypes = Arrays.asList("feed", "process", "mirror");
+
+ public Result withExpBundles(int... bundleNums) {
+ expectedBundles = new ArrayList<>();
+ for (int bundleNum : bundleNums) {
+ expectedBundles.add("bundle" + bundleNum);
+ }
+ return this;
+ }
+
+ public Result withExpTypes(String... types) {
+ expectedTypes = Arrays.asList(types);
+ return this;
+ }
+
+ public Result withExpError(String message) {
+ this.expectedError = message;
+ return this;
+ }
+
+ public Result withExpTotal(int total) {
+ this.expectedTotal = total;
+ return this;
+ }
+
+ public String getExpError() {
+ return expectedError;
+ }
+
+ /**
+ * Pretty prints params to param string.
+ */
+ @Override
+ public String toString() {
+ if (expectedError != null) {
+ return "Expected: error.";
+ } else {
+ return String.format("[Expected: %d %s%s]", expectedTotal,
+ (expectedTypes != null ? expectedTypes + "s": "entities"),
+ (expectedBundles != null ? " of " + expectedBundles : ""));
+ }
+ }
+
+ /**
+ * Validates entities number and order. Checks that each entity belongs to expected bundle and type.
+ * @param entities entities
+ * @param order expected order
+ */
+ public void validateEntities(EntityElement[] entities, String order) {
+ //validate number of entities
+ if (expectedTotal == 0) {
+ assertNull(entities, "Response shouldn't contain entities.");
+ } else {
+ List<EntityElement> entitiesList = new ArrayList<>(Arrays.asList(entities));
+ cleanUpResult(entitiesList);
+ LOGGER.info("Entities after clean up: \n" + entitiesList);
+ assertEquals(entitiesList.size(), expectedTotal, "Number of entities is not as expected.");
+
+ //Check that each entity belongs to expected bundle and type
+ for (EntityElement entity : entitiesList) {
+ assertTrue(matches(entity.name, allBundles, expectedBundles),
+ entity.name + " doesn't belong to expected bundles: " + expectedBundles);
+ assertTrue(matches(entity.name, allTypes, expectedTypes),
+ entity.name + " doesn't belong to expected types: " + expectedTypes);
+ }
+ //check the order
+ if (order != null) {
+ Assert.assertTrue(Ordering.from(order.equals("desc") ? DESC : ASC).isOrdered(entitiesList),
+ String.format("Entities are not ordered in %sending order", order));
+ }
+ }
+ }
+
+ /**
+ * Checks that entity name corresponds to expected bundle and type.
+ */
+ private boolean matches(String name, List<String> all, List<String> expectedParts) {
+ boolean matches = false;
+ for (String expectedPart : expectedParts) {
+ if (name.contains(expectedPart)) {
+ matches = true;
+ break;
+ }
+ }
+ List<String> unexpectedParts = new ArrayList<>(all);
+ unexpectedParts.removeAll(expectedParts);
+ for (String unexpectedPart : unexpectedParts) {
+ if (name.contains(unexpectedPart)) {
+ matches = false;
+ break;
+ }
+ }
+ return matches;
+ }
+ }
+
+ /**
+ * Cleans up a result list from items which belong to everything else than current test class.
+ * @param entityElements result array
+ */
+ private void cleanUpResult(List<EntityElement> entityElements) {
+ for (ListIterator<EntityElement> iterator = entityElements.listIterator(); iterator.hasNext();) {
+ String name = iterator.next().name;
+ if (!name.contains(base)) {
+ iterator.remove();
+ }
+ }
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDown() {
+ removeTestClassEntities();
+ }
+}
http://git-wip-us.apache.org/repos/asf/falcon/blob/0232f1b6/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/entity/ListEntitiesTest.java
----------------------------------------------------------------------
diff --git a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/entity/ListEntitiesTest.java b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/entity/ListEntitiesTest.java
index 3ae44e6..e3fcaf1 100644
--- a/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/entity/ListEntitiesTest.java
+++ b/falcon-regression/merlin/src/test/java/org/apache/falcon/regression/entity/ListEntitiesTest.java
@@ -178,7 +178,7 @@ public class ListEntitiesTest extends BaseTestClass {
for (int i = 0; i <= allEntitiesCount; i++) {
EntityElement[] entities =
- helper.listEntities("offset=" + i, null).getEntityList().getElements();
+ helper.listEntities(null, "offset=" + i, null).getEntityList().getElements();
LOGGER.info(String.format("%s entities with offset %d: %s",
helper.getEntityType(), i, Arrays.toString(entities)));
@@ -206,7 +206,7 @@ public class ListEntitiesTest extends BaseTestClass {
for (int i = 1; i <= allEntitiesCount; i++) {
EntityElement[] entities =
- helper.listEntities("numResults=" + i, null).getEntityList().getElements();
+ helper.listEntities(null, "numResults=" + i, null).getEntityList().getElements();
Assert.assertEquals(entities.length, i,
"Number of entities is not equal to numResults parameter");
for (int j = 0; j < i; j++) {
@@ -261,7 +261,7 @@ public class ListEntitiesTest extends BaseTestClass {
throws AuthenticationException, IOException, URISyntaxException, InterruptedException {
EntityElement[] entities = helper.listEntities(
- "numResults=2&fields=status,tags&filterBy=STATUS:SUBMITTED&orderBy=name&tags=" + tags[2],
+ null, "numResults=2&fields=status,tags&filterBy=STATUS:SUBMITTED&orderBy=name&tags=" + tags[2],
null).getEntityList().getElements();
if (entities != null) {
SoftAssert softAssert = new SoftAssert();