/** * 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.entity; import com.google.common.collect.Ordering; import org.apache.commons.lang.StringUtils; import org.apache.falcon.regression.Entities.ClusterMerlin; 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.entity.AbstractEntityHelper; 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 org.testng.asserts.SoftAssert; import javax.xml.bind.JAXBException; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Random; /** * Testing the list entities API. */ @Test(groups = { "distributed", "embedded" }) public class ListEntitiesTest extends BaseTestClass { private static final Logger LOGGER = Logger.getLogger(ListEntitiesTest.class); private String baseTestHDFSDir = cleanAndGetTestDir(); private String aggregateWorkflowDir = baseTestHDFSDir + "/aggregator"; private String[] tags = {"first=yes", "second=yes", "third=yes", "wrong=no"}; private static final Comparator<EntityElement> NAME_COMPARATOR = new Comparator<EntityElement>() { @Override public int compare(EntityElement o1, EntityElement o2) { return o1.name.compareTo(o2.name); } }; /** * Upload 10+ feeds, processes and clusters with different statuses and tags. */ @BeforeClass(alwaysRun = true) public void prepareData() throws IOException, AuthenticationException, JAXBException, URISyntaxException, InterruptedException { uploadDirToClusters(aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE); removeTestClassEntities(); bundles[0] = BundleUtil.readELBundle(); bundles[0] = new Bundle(bundles[0], servers.get(0)); bundles[0].generateUniqueBundle(this); bundles[0].setProcessWorkflow(aggregateWorkflowDir); bundles[0].submitBundle(prism); //submit 10 different clusters, feeds and processes FeedMerlin feed = new FeedMerlin(bundles[0].getInputFeedFromBundle()); ProcessMerlin process = bundles[0].getProcessObject(); ClusterMerlin cluster = bundles[0].getClusterElement(); String clusterNamePrefix = bundles[0].getClusterElement().getName() + '-'; String processNamePrefix = bundles[0].getProcessName() + '-'; String feedNamePrefix = bundles[0].getInputFeedNameFromBundle() + '-'; for (int i = 0; i < 10; i++) { process.setName(processNamePrefix + i); process.setTags(getRandomTags()); if (i % 2 == 0) { AssertUtil.assertSucceeded(prism.getProcessHelper().submitEntity(process.toString())); } else { AssertUtil.assertSucceeded(prism.getProcessHelper().submitAndSchedule(process.toString())); } feed.setName(feedNamePrefix + i); feed.setTags(getRandomTags()); if (i % 2 == 0) { AssertUtil.assertSucceeded(prism.getFeedHelper().submitEntity(feed.toString())); } else { AssertUtil.assertSucceeded(prism.getFeedHelper().submitAndSchedule(feed.toString())); } cluster.setName(clusterNamePrefix + i); cluster.setTags(getRandomTags()); AssertUtil.assertSucceeded(prism.getClusterHelper().submitEntity(cluster.toString())); } } @AfterClass(alwaysRun = true) public void tearDown() throws IOException { removeTestClassEntities(); } /** * Testing orderBy parameter. Entities should be ordered by name when orderBy=name. */ @Test(dataProvider = "getHelpers") public void listEntitiesWithOrderBy(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { EntityElement[] entities = helper.listAllEntities("orderBy=name", null).getEntityList().getElements(); LOGGER.info(helper.getEntityType() + " entities: " + Arrays.toString(entities)); Assert.assertTrue(Ordering.from(NAME_COMPARATOR).isOrdered(Arrays.asList(entities)), helper.getEntityType() + " entities are not ordered by name: " + Arrays.toString(entities)); } /** * Filter entities by status (SUBMITTED or RUNNING). */ @Test(dataProvider = "getHelpers") public void listEntitiesWithFilterByStatus(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { String[] statuses = helper.getEntityType().equalsIgnoreCase("cluster") ? new String[]{"SUBMITTED"} : new String[]{"SUBMITTED", "RUNNING"}; EntityElement[] allEntities = helper.listAllEntities("fields=status", null).getEntityList().getElements(); int[] counters = new int[statuses.length]; for (EntityElement entity : allEntities) { for (int i = 0; i < statuses.length; i++) { if (statuses[i].equals(entity.status)) { counters[i]++; } } } for (int i = 0; i < statuses.length; i++) { EntityElement[] entities = helper.listAllEntities("fields=status&filterBy=STATUS:" + statuses[i], null).getEntityList().getElements(); Assert.assertEquals(entities.length, counters[i], "Number of entities is not correct with status=" + statuses[i]); for (EntityElement entity : entities) { Assert.assertEquals(entity.status, statuses[i], "Entity should has status " + statuses[i] + ". Entity: " + entity); } } } /** * Testing offset parameter. Checking number of entities and order. */ @Test(dataProvider = "getHelpers") public void listEntitiesWithOffset(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { EntityElement[] allEntities = helper.listAllEntities().getEntityList().getElements(); LOGGER.info(helper.getEntityType() + " entities: " + Arrays.toString(allEntities)); int allEntitiesCount = allEntities.length; for (int i = 0; i <= allEntitiesCount; i++) { EntityElement[] entities = helper.listEntities(null, "offset=" + i, null).getEntityList().getElements(); LOGGER.info(String.format("%s entities with offset %d: %s", helper.getEntityType(), i, Arrays.toString(entities))); Assert.assertEquals(entities != null ? entities.length : 0, allEntitiesCount - i < 10 ? allEntitiesCount - i : 10, "Number of entities is not correct."); for (int j = 0; entities != null && j < entities.length; j++) { Assert.assertEquals(entities[j].name, allEntities[j + i].name, "Order of entities is not correct"); } } } /** * Testing numResults parameter. Checking number of entities and order. */ @Test(dataProvider = "getHelpers") public void listEntitiesWithNumResults(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { EntityElement[] allEntities = helper.listAllEntities().getEntityList().getElements(); int allEntitiesCount = allEntities.length; for (int i = 1; i <= allEntitiesCount; i++) { EntityElement[] entities = 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++) { Assert.assertEquals(entities[j].name, allEntities[j].name, "Order of entities is not correct"); } } } /** * Get list of entities with tag. */ @Test(dataProvider = "getHelpers") public void listEntitiesWithTags(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { EntityElement[] allEntities = helper.listAllEntities("fields=tags", null).getEntityList().getElements(); int[] counters = new int[tags.length]; for (EntityElement entity : allEntities) { for (int i = 0; i < tags.length; i++) { if (entity.tag != null && entity.tag.contains(tags[i])) { counters[i]++; } } } for (int i = 0; i < tags.length; i++) { EntityElement[] entities = helper.listAllEntities("fields=tags&tags=" + tags[i], null).getEntityList().getElements(); Assert.assertEquals(entities != null ? entities.length : 0, counters[i], "Number of entities is not correct with tag=" + tags[i]); for (int j = 0; entities != null && j < entities.length; j++) { Assert.assertNotNull(entities[j].tag, "Entity should have tags. Entity: " + entities[j]); Assert.assertTrue(entities[j].tag.contains(tags[i]), "Entity should contain tag " + tags[i] + ". Entity: " + entities[j]); } } } /** * Testing list entities API with custom filter. */ @Test(dataProvider = "getHelpers") public void listEntitiesWithCustomFilter(AbstractEntityHelper helper) throws AuthenticationException, IOException, URISyntaxException, InterruptedException { EntityElement[] entities = helper.listEntities( null, "numResults=2&fields=status,tags&filterBy=STATUS:SUBMITTED&orderBy=name&tags=" + tags[2], null).getEntityList().getElements(); if (entities != null) { SoftAssert softAssert = new SoftAssert(); for (EntityElement entity : entities) { softAssert.assertEquals(entity.status, "SUBMITTED", "Entities should have status 'SUBMITTED'"); softAssert.assertTrue(entity.tag.contains(tags[2]), "There is entity without tag=" + tags[2] + " Entity: " + entity); } softAssert.assertTrue(entities.length <= 2, "Number of results should be 2 or less"); softAssert.assertTrue(Ordering.from(NAME_COMPARATOR).isOrdered(Arrays.asList(entities)), helper.getEntityType() + " entities are not ordered by name: " + Arrays.toString(entities)); softAssert.assertAll(); } } @DataProvider public Object[][] getHelpers(){ return new Object[][]{ {prism.getProcessHelper()}, {prism.getClusterHelper()}, {prism.getFeedHelper()}, }; } private String getRandomTags() { List<String> tagsList = new ArrayList<>(); Random r = new Random(); if (r.nextInt(4) == 0) { tagsList.add(tags[0]); } if (r.nextInt(3) == 0) { tagsList.add(tags[1]); } if (r.nextInt(2) == 0) { tagsList.add(tags[2]); } return StringUtils.join(tagsList, ','); } }