/** * 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.helpers; import com.google.gson.GsonBuilder; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.falcon.regression.core.response.lineage.Direction; import org.apache.falcon.regression.core.response.lineage.EdgeResult; import org.apache.falcon.regression.core.response.lineage.EdgesResult; import org.apache.falcon.regression.core.response.lineage.Vertex; import org.apache.falcon.regression.core.response.lineage.VertexIdsResult; import org.apache.falcon.regression.core.response.lineage.VertexResult; import org.apache.falcon.regression.core.response.lineage.VerticesResult; import org.apache.falcon.regression.core.util.AssertUtil; import org.apache.falcon.regression.core.util.GraphAssert; import org.apache.falcon.regression.core.util.Util; import org.apache.falcon.request.BaseRequest; import org.apache.hadoop.security.authentication.client.AuthenticationException; import org.apache.http.HttpResponse; import org.apache.log4j.Logger; import org.testng.Assert; import java.io.IOException; import java.net.URISyntaxException; import java.util.EnumSet; import java.util.Map; import java.util.TreeMap; /** * Class with helper functions to test lineage feature. */ public class LineageHelper { private static final Logger LOGGER = Logger.getLogger(LineageHelper.class); private final String hostname; /** * Lineage related REST endpoints. */ public enum URL { SERIALIZE("/api/metadata/lineage/serialize"), VERTICES("/api/metadata/lineage/vertices"), VERTICES_ALL("/api/metadata/lineage/vertices/all"), VERTICES_PROPERTIES("/api/metadata/lineage/vertices/properties"), EDGES("/api/metadata/lineage/edges"), EDGES_ALL("/api/metadata/lineage/edges/all"); private final String url; URL(String url) { this.url = url; } public String getValue() { return this.url; } } /** * Create a LineageHelper to use with a specified hostname. * @param hostname hostname */ public LineageHelper(String hostname) { this.hostname = hostname.trim().replaceAll("/$", ""); } /** * Create a LineageHelper to use with a specified prismHelper. * @param prismHelper prismHelper */ public LineageHelper(ColoHelper prismHelper) { this(prismHelper.getClusterHelper().getHostname()); } /** * Extract response string from the response object. * @param response the response object * @return the response string * @throws IOException */ public String getResponseString(HttpResponse response) throws IOException { return IOUtils.toString(response.getEntity().getContent(), "UTF-8"); } /** * Run a get request on the specified url. * @param url url * @return response of the request * @throws URISyntaxException * @throws IOException * @throws AuthenticationException */ public HttpResponse runGetRequest(String url) throws URISyntaxException, IOException, AuthenticationException, InterruptedException { final BaseRequest request = new BaseRequest(url, "get", null); return request.run(); } /** * Successfully run a get request on the specified url. * @param url url * @return string response of the request * @throws URISyntaxException * @throws IOException * @throws AuthenticationException */ public String runGetRequestSuccessfully(String url) throws URISyntaxException, IOException, AuthenticationException, InterruptedException { HttpResponse response = runGetRequest(url); String responseString = getResponseString(response); LOGGER.info(Util.prettyPrintXmlOrJson(responseString)); Assert.assertEquals(response.getStatusLine().getStatusCode(), 200, "The get request was expected to be successfully"); return responseString; } /** * Create a full url for the given lineage endpoint, urlPath and parameter. * @param url lineage endpoint * @param urlPath url path to be added to lineage endpoint * @param paramPairs parameters to be passed * @return url string */ public String getUrl(final URL url, final String urlPath, final Map<String, String> paramPairs) { Assert.assertNotNull(hostname, "Hostname can't be null."); String hostAndPath = hostname + url.getValue(); if (urlPath != null) { hostAndPath += "/" + urlPath; } if (paramPairs != null && paramPairs.size() > 0) { String[] params = new String[paramPairs.size()]; int i = 0; for (Map.Entry<String, String> entry : paramPairs.entrySet()) { params[i++] = entry.getKey() + '=' + entry.getValue(); } return hostAndPath + "/?" + StringUtils.join(params, "&"); } return hostAndPath; } /** * Create a full url for the given lineage endpoint, urlPath and parameter. * @param url lineage endpoint * @param urlPath url path to be added to lineage endpoint * @return url string */ public String getUrl(final URL url, final String urlPath) { return getUrl(url, urlPath, null); } /** * Create a full url for the given lineage endpoint and parameter. * @param url lineage endpoint * @param paramPairs parameters to be passed * @return url string */ public String getUrl(final URL url, final Map<String, String> paramPairs) { return getUrl(url, null, paramPairs); } /** * Create a full url for the given lineage endpoint and parameter. * @param url lineage endpoint * @return url string */ public String getUrl(final URL url) { return getUrl(url, null, null); } /** * Create url path from parts. * @param pathParts parts of the path * @return url path */ public String getUrlPath(String... pathParts) { return StringUtils.join(pathParts, "/"); } /** * Create url path from parts. * @param oneInt part of the path * @param pathParts parts of the path * @return url path */ public String getUrlPath(int oneInt, String... pathParts) { return oneInt + "/" + getUrlPath(pathParts); } /** * Get result of the supplied type for the given url. * @param url url * @return result of the REST request */ public <T> T getResultOfType(String url, Class<T> clazz) { String responseString = null; try { responseString = runGetRequestSuccessfully(url); } catch (URISyntaxException | InterruptedException | AuthenticationException | IOException e) { AssertUtil.fail(e); } return new GsonBuilder().create().fromJson(responseString, clazz); } /** * Get vertices result for the url. * @param url url * @return result of the REST request */ public VerticesResult getVerticesResult(String url) { return getResultOfType(url, VerticesResult.class); } /** * Get vertex result for the url. * @param url url * @return result of the REST request */ private VertexResult getVertexResult(String url) { return getResultOfType(url, VertexResult.class); } /** * Get vertex id result for the url. * @param url url * @return result of the REST request */ private VertexIdsResult getVertexIdsResult(String url) { return getResultOfType(url, VertexIdsResult.class); } /** * Get all the vertices. * @return all the vertices */ public VerticesResult getAllVertices() { return getVerticesResult(getUrl(URL.VERTICES_ALL)); } public VerticesResult getVertices(Vertex.FilterKey key, String value) { Map<String, String> params = new TreeMap<>(); params.put("key", key.toString()); params.put("value", value); return getVerticesResult(getUrl(URL.VERTICES, params)); } public VertexResult getVertexById(int vertexId) { return getVertexResult(getUrl(URL.VERTICES, getUrlPath(vertexId))); } public VertexResult getVertexProperties(int vertexId) { return getVertexResult(getUrl(URL.VERTICES_PROPERTIES, getUrlPath(vertexId))); } public VerticesResult getVerticesByType(Vertex.VERTEX_TYPE vertexType) { return getVertices(Vertex.FilterKey.type, vertexType.getValue()); } public VerticesResult getVerticesByName(String name) { return getVertices(Vertex.FilterKey.name, name); } public VerticesResult getVerticesByDirection(int vertexId, Direction direction) { Assert.assertTrue((EnumSet.of(Direction.bothCount, Direction.inCount, Direction.outCount, Direction.bothVertices, Direction.inComingVertices, Direction.outgoingVertices).contains(direction)), "Vertices requested."); return getVerticesResult(getUrl(URL.VERTICES, getUrlPath(vertexId, direction.getValue()))); } public VertexIdsResult getVertexIdsByDirection(int vertexId, Direction direction) { Assert.assertTrue((EnumSet.of(Direction.bothVerticesIds, Direction.incomingVerticesIds, Direction.outgoingVerticesIds).contains(direction)), "Vertex Ids requested."); return getVertexIdsResult(getUrl(URL.VERTICES, getUrlPath(vertexId, direction.getValue()))); } public Vertex getVertex(String vertexName) { final VerticesResult clusterResult = getVerticesByName(vertexName); GraphAssert.assertVertexSanity(clusterResult); Assert.assertEquals(clusterResult.getTotalSize(), 1, "Expected one node for vertex name:" + vertexName); return clusterResult.getResults().get(0); } /** * Get edges result for the url. * @param url url * @return result of the REST request */ private EdgesResult getEdgesResult(String url) { return getResultOfType(url, EdgesResult.class); } private EdgeResult getEdgeResult(String url) { return getResultOfType(url, EdgeResult.class); } public EdgesResult getEdgesByDirection(int vertexId, Direction direction) { Assert.assertTrue((EnumSet.of(Direction.bothEdges, Direction.inComingEdges, Direction.outGoingEdges).contains(direction)), "Vertices requested."); return getEdgesResult(getUrl(URL.VERTICES, getUrlPath(vertexId, direction.getValue()))); } public EdgesResult getAllEdges() { return getEdgesResult(getUrl(URL.EDGES_ALL)); } public EdgeResult getEdgeById(String edgeId) { return getEdgeResult(getUrl(URL.EDGES, getUrlPath(edgeId))); } }