/** * 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.core.util; import org.apache.falcon.regression.core.enumsAndConstants.ResponseErrors; import org.apache.falcon.resource.LineageGraphResult; import org.apache.falcon.resource.TriageResult; import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.testng.Assert; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** *Util function related to entity lineage. */ public final class EntityLineageUtil{ private static final Logger LOGGER = Logger.getLogger(EntityLineageUtil.class); /** * Enum to represent entity role in pipeline. */ public enum PipelineEntityType { PROCESS, INPUT_FEED, OUTPUT_FEED } private EntityLineageUtil() { throw new AssertionError("Instantiating utility class..."); } /** * Validates entity lineage results. * @param lineageGraphResult entity lineage result * @param expectedVertices array of expected vertices * @param expectedEdgeArray array of expected edges */ public static void validateLineageGraphResult(LineageGraphResult lineageGraphResult, String[] expectedVertices, LineageGraphResult.Edge[] expectedEdgeArray) { String[] actualVertices; LineageGraphResult.Edge[] actualEdgeArray; Set<String> actualVerticesSet = new HashSet<>(); Set<LineageGraphResult.Edge> actualEdgeSet = new HashSet<>(); try { actualVertices = lineageGraphResult.getVertices(); actualVerticesSet = new HashSet<>(Arrays.asList(actualVertices)); } catch (NullPointerException e) { Assert.assertEquals(expectedVertices.length, 0); } try { actualEdgeArray = lineageGraphResult.getEdges(); actualEdgeSet = new HashSet<>(Arrays.asList(actualEdgeArray)); } catch (NullPointerException e) { Assert.assertEquals(expectedEdgeArray.length, 0); } Set<LineageGraphResult.Edge> expectedEdgeSet = new HashSet<>(Arrays.asList(expectedEdgeArray)); Set<String> expectedVerticesSet = new HashSet<>(Arrays.asList(expectedVertices)); Assert.assertEquals(actualEdgeSet, expectedEdgeSet, "Edges dont match"); Assert.assertEquals(actualVerticesSet, expectedVerticesSet, "Vertices dont match"); } /** * Validates that failed response contains specific error message. * @param triageResult response * @param error expected error */ public static void validateError(TriageResult triageResult, ResponseErrors error) { AssertUtil.assertFailed(triageResult); Assert.assertTrue(triageResult.getMessage().contains(error.getError()), "Error should contain '" + error + "'"); } /** * Produces list of expected vertices and edges in triage result. */ public static LineageGraphResult getExpectedResult(int bundleIndx, Map<PipelineEntityType, List<String>> entityNamesMap, List<Integer> inputFeedFrequencies, String entityName, String clusterName, String startTime) { List<String> processNames = entityNamesMap.get(PipelineEntityType.PROCESS); List<String> inputFeedNames = entityNamesMap.get(PipelineEntityType.INPUT_FEED); List<String> outputFeedNames = entityNamesMap.get(PipelineEntityType.OUTPUT_FEED); List<String> vertices = new ArrayList<>(); List<LineageGraphResult.Edge> edges = new ArrayList<>(); final String startTimeMinus20 = TimeUtil.addMinsToTime(startTime, -20); String vertexTemplate = "name: %s, type: %s, cluster: %s, instanceTime: %s, tags: %s"; for (int i = 0; i <= bundleIndx; ++i) { //add vertex of i-th bundle process boolean isTerminalInstance = processNames.contains(entityName) && i == bundleIndx; String tag = isTerminalInstance ? "[WAITING]" : "Output[WAITING]"; final String processVertex = String.format(vertexTemplate, processNames.get(i), "PROCESS", clusterName, startTime, tag); vertices.add(processVertex); //add all input feed vertices & edges for i-th bundle LineageGraphResult.Edge edge; String feedVertex; for (DateTime dt = new DateTime(startTime); !dt.isBefore(new DateTime(startTimeMinus20)); dt = dt.minusMinutes(inputFeedFrequencies.get(i))) { feedVertex = String.format(vertexTemplate, inputFeedNames.get(i), "FEED", clusterName, TimeUtil.dateToOozieDate(dt.toDate()), "Input[MISSING]"); edge = new LineageGraphResult.Edge(feedVertex, processVertex, "consumed by"); vertices.add(feedVertex); edges.add(edge); } //add output feed edge for i-th bundle tag = (outputFeedNames.contains(entityName) && i == bundleIndx) ? "[MISSING]" : "Input[MISSING]"; feedVertex = String.format(vertexTemplate, outputFeedNames.get(i), "FEED", clusterName, startTime, tag); isTerminalInstance = i == bundleIndx && outputFeedNames.contains(entityName); if (i < bundleIndx || isTerminalInstance) { edge = new LineageGraphResult.Edge(processVertex, feedVertex, "produces"); edges.add(edge); } //add output feed vertex only if it is terminal; it will be added as the input for next bundle otherwise if (isTerminalInstance) { vertices.add(feedVertex); } } LineageGraphResult lineageGraphResult = new LineageGraphResult(); lineageGraphResult.setVertices(vertices.toArray(new String[vertices.size()])); lineageGraphResult.setEdges(edges.toArray(new LineageGraphResult.Edge[edges.size()])); return lineageGraphResult; } }