/** * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.hadoop.gateway; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.hadoop.gateway.services.DefaultGatewayServices; import org.apache.hadoop.gateway.services.GatewayServices; import org.apache.hadoop.gateway.services.ServiceLifecycleException; import org.apache.hadoop.gateway.services.topology.TopologyService; import org.apache.hadoop.test.TestUtils; import org.apache.hadoop.test.mock.MockServer; import org.apache.http.HttpStatus; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.hamcrest.MatcherAssert; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.StringWriter; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.UUID; import static com.jayway.restassured.RestAssured.given; import static org.apache.hadoop.test.TestUtils.LOG_ENTER; import static org.apache.hadoop.test.TestUtils.LOG_EXIT; import static org.hamcrest.CoreMatchers.notNullValue; import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; public class AmbariServiceDefinitionTest { private static Logger LOG = LoggerFactory.getLogger( AmbariServiceDefinitionTest.class ); private static Class DAT = AmbariServiceDefinitionTest.class; private static GatewayTestConfig config; private static DefaultGatewayServices services; private static GatewayServer gateway; private static int gatewayPort; private static String gatewayUrl; private static String clusterUrl; private static String clusterPath; private static Properties params; private static TopologyService topos; private static MockServer mockAmbari; private static VelocityEngine velocity; private static VelocityContext context; @BeforeClass public static void setupSuite() throws Exception { LOG_ENTER(); setupGateway(); String topoStr = TestUtils.merge( DAT, "test-topology.xml", params ); File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); FileUtils.writeStringToFile( topoFile, topoStr ); topos.reloadTopologies(); LOG_EXIT(); } @AfterClass public static void cleanupSuite() throws Exception { LOG_ENTER(); gateway.stop(); FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) ); LOG_EXIT(); } @After public void cleanupTest() throws Exception { FileUtils.cleanDirectory( new File( config.getGatewayTopologyDir() ) ); FileUtils.cleanDirectory( new File( config.getGatewayDeploymentDir() ) ); } public static void setupGateway() throws Exception { File targetDir = new File( System.getProperty( "user.dir" ), "target" ); File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); gatewayDir.mkdirs(); config = new GatewayTestConfig(); config.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); URL svcsFileUrl = TestUtils.getResourceUrl( DAT, "test-svcs/readme.txt" ); File svcsFile = new File( svcsFileUrl.getFile() ); File svcsDir = svcsFile.getParentFile(); config.setGatewayServicesDir( svcsDir.getAbsolutePath() ); String pathToStacksSource = "gateway-service-definitions/src/main/resources/services"; File stacksSourceDir = new File( targetDir.getParent(), pathToStacksSource); if (!stacksSourceDir.exists()) { stacksSourceDir = new File( targetDir.getParentFile().getParent(), pathToStacksSource); } if (stacksSourceDir.exists()) { FileUtils.copyDirectoryToDirectory(stacksSourceDir, svcsDir); } File topoDir = new File( config.getGatewayTopologyDir() ); topoDir.mkdirs(); File deployDir = new File( config.getGatewayDeploymentDir() ); deployDir.mkdirs(); setupMockServers(); startGatewayServer(); } public static void setupMockServers() throws Exception { mockAmbari = new MockServer( "AMBARI", true ); } public static void startGatewayServer() throws Exception { services = new DefaultGatewayServices(); Map<String,String> options = new HashMap<String,String>(); options.put( "persist-master", "false" ); options.put( "master", "password" ); try { services.init( config, options ); } catch ( ServiceLifecycleException e ) { e.printStackTrace(); // I18N not required. } topos = services.getService(GatewayServices.TOPOLOGY_SERVICE); gateway = GatewayServer.startGateway( config, services ); MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() ); gatewayPort = gateway.getAddresses()[0].getPort(); gatewayUrl = "http://localhost:" + gatewayPort + "/" + config.getGatewayPath(); String topologyPath = "/test-topology"; clusterPath = "/" + config.getGatewayPath() + topologyPath; clusterUrl = gatewayUrl + topologyPath; LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); params = new Properties(); params.put( "AMBARI_URL", "http://localhost:" + mockAmbari.getPort() ); velocity = new VelocityEngine(); velocity.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem" ); velocity.setProperty( RuntimeConstants.RESOURCE_LOADER, "classpath" ); velocity.setProperty( "classpath.resource.loader.class", ClasspathResourceLoader.class.getName() ); velocity.init(); context = new VelocityContext(); context.put( "cluster_url", clusterUrl ); context.put( "cluster_path", clusterPath ); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void clusters() throws Exception { LOG_ENTER(); String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/clusters"; mockAmbari.expect() .method( "GET" ) .pathInfo( "/api/v1/clusters" ) .respond() .status( HttpStatus.SC_OK ) .content( TestUtils.getResourceStream( DAT, "clusters-response.json" ) ) .contentType( "text/plain" ); String body = given() // .log().all() .auth().preemptive().basic( username, password ) .expect() // .log().all() .statusCode( HttpStatus.SC_OK ) .contentType( "text/plain" ) .when().get( serviceUrl ).asString(); String name = TestUtils.getResourceName( this.getClass(), "clusters-response-expected.json" ); Template template = velocity.getTemplate( name ); StringWriter sw = new StringWriter(); template.merge( context, sw ); String expected = sw.toString(); MatcherAssert.assertThat(body, sameJSONAs(expected)); LOG_EXIT(); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void historyServer() throws Exception { LOG_ENTER(); String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/clusters/test/hosts/c6401.ambari.apache.org/host_components/HISTORYSERVER"; mockAmbari.expect() .method( "GET" ) .pathInfo( "/api/v1/clusters/test/hosts/c6401.ambari.apache.org/host_components/HISTORYSERVER" ) .respond() .status( HttpStatus.SC_OK ) .content( TestUtils.getResourceStream( DAT, "history-server-response.json" ) ) .contentType( "text/plain" ); String body = given() .auth().preemptive().basic( username, password ) .expect() .statusCode( HttpStatus.SC_OK ) .contentType( "text/plain" ) .when().get( serviceUrl ).asString(); String name = TestUtils.getResourceName( this.getClass(), "history-server-response-expected.json" ); Template template = velocity.getTemplate( name ); StringWriter sw = new StringWriter(); template.merge( context, sw ); String expected = sw.toString(); MatcherAssert.assertThat(body, sameJSONAs(expected)); LOG_EXIT(); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void unwiseCharacterRequest() throws Exception { String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/clusters/test/components"; mockAmbari.expect() .method( "GET" ) .pathInfo( "/api/v1/clusters/test/components" ) .queryParam("ServiceComponentInfo/component_name", "APP_TIMELINE_SERVER|ServiceComponentInfo/category=MASTER") .respond() .status( HttpStatus.SC_OK ) .content( TestUtils.getResourceStream( DAT, "unwise-character-response.json" ) ) .contentType( "text/plain" ); //only assertion here is to make sure the request can be made successfully with the unwise characters present //in the request url given() .auth().preemptive().basic( username, password ) .queryParam("ServiceComponentInfo/component_name", "APP_TIMELINE_SERVER|ServiceComponentInfo/category=MASTER") .expect() .statusCode( HttpStatus.SC_OK ) .contentType( "text/plain" ) .when().get( serviceUrl ).asString(); LOG_EXIT(); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void encryptedResponse() throws Exception { LOG_ENTER(); String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/persist/CLUSTER_CURRENT_STATUS?_=1457977721091"; mockAmbari.expect() .method( "GET" ) .pathInfo( "/api/v1/persist/CLUSTER_CURRENT_STATUS" ) .queryParam("_","1457977721091") .respond() .status( HttpStatus.SC_OK ) .content( TestUtils.getResourceStream( DAT, "encrypted-response.txt" ) ) .contentType( "text/plain" ); String body = given() .auth().preemptive().basic( username, password ) .expect() .statusCode( HttpStatus.SC_OK ) .contentType( "text/plain" ) .when().get( serviceUrl ).asString(); Assert.assertNotNull(body); LOG_EXIT(); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void postDataWithWrongContentType() throws Exception { LOG_ENTER(); String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/stacks/HDP/versions/2.3/recommendations"; mockAmbari.expect() .method( "POST" ) .pathInfo( "/api/v1/stacks/HDP/versions/2.3/recommendations" ) .content( TestUtils.getResourceStream( DAT, "post-data-wrong-type.json" ) ) .respond() .status( HttpStatus.SC_OK ) .contentType( "application/x-www-form-urlencoded" ); String body = given() .auth().preemptive().basic( username, password ) .content(IOUtils.toByteArray(TestUtils.getResourceStream( DAT, "post-data-wrong-type.json"))) .expect() .statusCode( HttpStatus.SC_OK ) .contentType( "application/x-www-form-urlencoded" ) .when().post( serviceUrl ).asString(); Assert.assertNotNull(body); LOG_EXIT(); } @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) public void contextPathInViewsResponse() throws Exception { LOG_ENTER(); String username = "guest"; String password = "guest-password"; String serviceUrl = clusterUrl + "/ambari/api/v1/views?fields=versions/instances/ViewInstanceInfo,versions/" + "ViewVersionInfo/label&versions/ViewVersionInfo/system=false&_=1461186937589"; mockAmbari.expect() .method( "GET" ) .pathInfo( "/api/v1/views" ) .queryParam("_", "1461186937589") .queryParam("versions/ViewVersionInfo/system", "false") .queryParam("fields", "versions/instances/ViewInstanceInfo,versions/ViewVersionInfo/label") .respond() .status( HttpStatus.SC_OK ) .content( TestUtils.getResourceStream( DAT, "views-response.json" ) ) .contentType( "text/plain" ); String body = given() .auth().preemptive().basic( username, password ) .expect() .statusCode( HttpStatus.SC_OK ) .contentType( "text/plain" ) .when().get( serviceUrl ).asString(); String name = TestUtils.getResourceName( this.getClass(), "views-response-expected.json" ); Template template = velocity.getTemplate( name ); StringWriter sw = new StringWriter(); template.merge( context, sw ); String expected = sw.toString(); MatcherAssert.assertThat(body, sameJSONAs(expected)); LOG_EXIT(); } }