/* * Copyright © 2015-2016 Cask Data, Inc. * * Licensed 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 co.cask.cdap; import co.cask.cdap.api.artifact.ArtifactVersion; import co.cask.cdap.common.conf.CConfiguration; import co.cask.cdap.common.conf.Constants; import co.cask.cdap.common.utils.Networks; import co.cask.cdap.common.utils.Tasks; import co.cask.cdap.internal.app.runtime.artifact.ArtifactRepository; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.artifact.ArtifactRange; import com.google.common.base.Preconditions; import org.apache.hadoop.conf.Configuration; import org.junit.rules.ExternalResource; import org.junit.rules.TemporaryFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.URI; import java.net.URL; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; /** * This class helps writing tests that needs {@link StandaloneMain} up and running. */ public class StandaloneTester extends ExternalResource { private static final Logger LOG = LoggerFactory.getLogger(StandaloneTester.class); private final TemporaryFolder tmpFolder = new TemporaryFolder(); private final Object [] configs; private CConfiguration cConf; private StandaloneMain standaloneMain; public StandaloneTester(Object ... configs) { Preconditions.checkArgument(configs.length % 2 == 0, "Arguments must be in pair form like (k1, v1, k2, v2): %s", Arrays.toString(configs)); this.configs = configs; } @Override protected void before() throws Throwable { tmpFolder.create(); CConfiguration cConf = CConfiguration.create(); cConf.set(Constants.CFG_LOCAL_DATA_DIR, tmpFolder.newFolder().getAbsolutePath()); cConf.set(Constants.Router.ADDRESS, getLocalHostname()); cConf.setInt(Constants.Router.ROUTER_PORT, Networks.getRandomPort()); cConf.setBoolean(Constants.Dangerous.UNRECOVERABLE_RESET, true); cConf.setBoolean(Constants.Explore.EXPLORE_ENABLED, true); cConf.setBoolean(Constants.Explore.START_ON_DEMAND, true); cConf.setBoolean(StandaloneMain.DISABLE_UI, true); cConf.setBoolean(Constants.Audit.ENABLED, false); for (int i = 0; i < configs.length; i += 2) { cConf.set(configs[i].toString(), configs[i + 1].toString()); } this.cConf = cConf; // Start standalone standaloneMain = StandaloneMain.create(cConf, new Configuration()); standaloneMain.startUp(); try { waitForStandalone(); } catch (Throwable t) { standaloneMain.shutDown(); throw t; } } @Override protected void after() { try { if (standaloneMain != null) { standaloneMain.shutDown(); } } finally { tmpFolder.delete(); } } /** * Returns the {@link CConfiguration} used by the standalone instance. */ public CConfiguration getConfiguration() { Objects.requireNonNull(cConf, "StandaloneTester hasn't been initialized"); return cConf; } /** * Returns the base URI for making REST calls to the standalone instance. */ public URI getBaseURI() { return URI.create(String.format("http://%s:%d/", getConfiguration().get(Constants.Router.ADDRESS), getConfiguration().getInt(Constants.Router.ROUTER_PORT))); } /** * Adds a system artifact to CDAP instance that is used for testing. */ public void addSystemArtifact(String name, ArtifactVersion version, File artifactFile, @Nullable Set<ArtifactRange> parentArtifacts) throws Exception { ArtifactRepository artifactRepository = standaloneMain.getInjector().getInstance(ArtifactRepository.class); Id.Artifact artifactId = new Id.Artifact(Id.Namespace.SYSTEM, name, version); artifactRepository.addArtifact(artifactId, artifactFile, parentArtifacts); } private String getLocalHostname() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { LOG.warn("Unable to resolve localhost", e); return "127.0.0.1"; } } private void waitForStandalone() throws Exception { final URL url = getBaseURI().resolve("/ping").toURL(); Tasks.waitFor(true, new Callable<Boolean>() { @Override public Boolean call() throws Exception { HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); try { return urlConn.getResponseCode() == HttpURLConnection.HTTP_OK; } finally { urlConn.disconnect(); } } }, 30, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS); } }