/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.cli; import alluxio.AlluxioURI; import alluxio.Configuration; import alluxio.Constants; import alluxio.PropertyKey; import alluxio.client.block.BlockMasterClient; import alluxio.client.file.FileInStream; import alluxio.client.file.FileOutStream; import alluxio.client.file.FileSystem; import alluxio.exception.status.UnavailableException; import alluxio.util.CommonUtils; import alluxio.util.WaitForOptions; import alluxio.util.io.PathUtils; import alluxio.util.network.NetworkAddressUtils; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.util.Map; import java.util.Map.Entry; /** * Integration tests for AlluxioFramework. These tests assume that a Mesos cluster is * running locally. */ public final class AlluxioFrameworkIntegrationTest { private static final Logger LOG = LoggerFactory.getLogger(AlluxioFrameworkIntegrationTest.class); private static final String JDK_URL = "https://s3-us-west-2.amazonaws.com/alluxio-mesos/jdk-7u79-macosx-x64.tar.gz"; private static final String JDK_PATH = "jdk1.7.0_79.jdk/Contents/Home"; @Parameter(names = {"-m", "--mesos"}, required = true, description = "Address for locally-running Mesos, e.g. localhost:5050") private String mMesosAddress; @Parameter(names = {"-a", "--alluxio"}, description = "URL of an Alluxio tarball to test. Otherwise only test local Alluxio") private String mAlluxioUrl; @Parameter(names = {"-h", "--help"}, help = true) private boolean mHelp = false; private AlluxioFrameworkIntegrationTest() {} private void run() throws Exception { checkMesosRunning(); stopAlluxio(); stopAlluxioFramework(); runTests(); LOG.info("All tests passed!"); } private void runTests() throws Exception { LOG.info("Testing deployment with preinstalled alluxio and jdk"); testMesosDeploy(ImmutableMap.of( PropertyKey.INTEGRATION_MESOS_JDK_URL, Constants.MESOS_LOCAL_INSTALL, PropertyKey.INTEGRATION_MESOS_ALLUXIO_JAR_URL, Constants.MESOS_LOCAL_INSTALL)); LOG.info("Testing deployment with downloaded jdk"); testMesosDeploy(ImmutableMap.of( PropertyKey.INTEGRATION_MESOS_JDK_URL, JDK_URL, PropertyKey.INTEGRATION_MESOS_ALLUXIO_JAR_URL, Constants.MESOS_LOCAL_INSTALL, PropertyKey.INTEGRATION_MESOS_JDK_PATH, JDK_PATH)); if (mAlluxioUrl != null) { LOG.info("Testing deployment with downloaded Alluxio"); testMesosDeploy(ImmutableMap.of( PropertyKey.INTEGRATION_MESOS_JDK_URL, Constants.MESOS_LOCAL_INSTALL, PropertyKey.INTEGRATION_MESOS_ALLUXIO_JAR_URL, mAlluxioUrl)); } } private void testMesosDeploy(Map<PropertyKey, String> properties) throws Exception { StringBuilder alluxioJavaOpts = new StringBuilder(System.getProperty("ALLUXIO_JAVA_OPTS", "")); for (Entry<PropertyKey, String> entry : properties.entrySet()) { alluxioJavaOpts .append(String.format(" -D%s=%s", entry.getKey().toString(), entry.getValue())); } Map<String, String> env = ImmutableMap.of("ALLUXIO_JAVA_OPTS", alluxioJavaOpts.toString()); try { startAlluxioFramework(env); LOG.info("Launched Alluxio cluster, waiting for worker to register with master"); String masterHostName = NetworkAddressUtils.getLocalHostName(); int masterPort = Configuration.getInt(PropertyKey.MASTER_RPC_PORT); InetSocketAddress masterAddress = new InetSocketAddress(masterHostName, masterPort); try (final BlockMasterClient client = BlockMasterClient.Factory.create(masterAddress)) { CommonUtils.waitFor("Alluxio worker to register with master", new Function<Void, Boolean>() { @Override public Boolean apply(Void input) { try { try { return !client.getWorkerInfoList().isEmpty(); } catch (UnavailableException e) { // block master isn't up yet, keep waiting return false; } } catch (Exception e) { throw new RuntimeException(e); } } }, WaitForOptions.defaults().setTimeout(15 * Constants.MINUTE_MS)); } LOG.info("Worker registered"); basicAlluxioTests(); } finally { stopAlluxioFramework(); } } private void startAlluxioFramework(Map<String, String> extraEnv) { String startScript = PathUtils.concatPath(Configuration.get(PropertyKey.HOME), "integration", "mesos", "bin", "alluxio-mesos-start.sh"); ProcessBuilder pb = new ProcessBuilder(startScript, mMesosAddress); Map<String, String> env = pb.environment(); env.putAll(extraEnv); try { pb.start().waitFor(); } catch (Exception e) { LOG.info("Failed to launch Alluxio on Mesos. Note that this test requires that " + "Mesos is currently running."); throw new RuntimeException(e); } } private static void basicAlluxioTests() throws Exception { LOG.info("Running tests"); FileSystem fs = FileSystem.Factory.get(); int listSize = fs.listStatus(new AlluxioURI("/")).size(); if (listSize != 1) { throw new RuntimeException("Expected 1 path to exist at the root, but found " + listSize); } FileOutStream outStream = fs.createFile(new AlluxioURI("/test")); outStream.write("abc".getBytes()); outStream.close(); FileInStream inStream = fs.openFile(new AlluxioURI("/test")); String result = IOUtils.toString(inStream); if (!result.equals("abc")) { throw new RuntimeException("Expected abc but got " + result); } LOG.info("Tests passed"); } private static void checkMesosRunning() throws Exception { for (String processName : new String[]{"mesos-master", "mesos-slave"}) { if (!processExists(processName)) { throw new IllegalStateException(String.format( "Couldn't find local '%s' process. Mesos must be running locally to use this test", processName)); } } } private static boolean processExists(String processName) throws Exception { Process ps = Runtime.getRuntime().exec(new String[] {"ps", "ax"}); InputStream psOutput = ps.getInputStream(); Process processGrep = Runtime.getRuntime().exec(new String[] {"grep", processName}); OutputStream processGrepInput = processGrep.getOutputStream(); IOUtils.copy(psOutput, processGrepInput); InputStream processGrepOutput = processGrep.getInputStream(); processGrepInput.close(); // Filter out the grep process itself. Process filterGrep = Runtime.getRuntime().exec(new String[] {"grep", "-v", "grep"}); OutputStream filterGrepInput = filterGrep.getOutputStream(); IOUtils.copy(processGrepOutput, filterGrepInput); filterGrepInput.close(); return IOUtils.readLines(filterGrep.getInputStream()).size() >= 1; } private static void stopAlluxioFramework() throws Exception { String stopScript = PathUtils.concatPath(Configuration.get(PropertyKey.HOME), "integration", "mesos", "bin", "alluxio-mesos-stop.sh"); ProcessBuilder pb = new ProcessBuilder(stopScript); pb.start().waitFor(); // Wait for Mesos to unregister and shut down the Alluxio Framework. CommonUtils.sleepMs(5000); } private static void stopAlluxio() throws Exception { String stopScript = PathUtils.concatPath(Configuration.get(PropertyKey.HOME), "bin", "alluxio-stop.sh"); ProcessBuilder pb = new ProcessBuilder(stopScript, "all"); pb.start().waitFor(); } /** * @param args arguments */ public static void main(String[] args) throws Exception { AlluxioFrameworkIntegrationTest test = new AlluxioFrameworkIntegrationTest(); JCommander jc = new JCommander(test); jc.setProgramName(AlluxioFrameworkIntegrationTest.class.getName()); try { jc.parse(args); } catch (Exception e) { LOG.error(e.getMessage()); jc.usage(); System.exit(1); } if (test.mHelp) { jc.usage(); } else { test.run(); } } }