// Copyright 2017 JanusGraph Authors // // 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 org.janusgraph.pkgtest; import static org.junit.Assert.assertEquals; import java.io.*; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.Writer; import java.util.Collections; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import org.janusgraph.core.JanusGraphFactory; public abstract class AbstractJanusGraphAssemblyIT { protected static final String BUILD_DIR; protected static final String EXPECT_DIR; protected static final String ZIPFILE_PATH; protected static final String ZIPFILE_EXTRACTED; static { Properties props; try { props = new Properties(); java.io.FileReader fr = new FileReader(Joiner.on(File.separator).join(new String[] { "target", "test-classes", "target.properties" }));; props.load(fr); fr.close(); } catch (IOException e) { throw new AssertionError(e); } BUILD_DIR = props.getProperty("build.dir"); EXPECT_DIR = props.getProperty("expect.dir"); ZIPFILE_PATH = props.getProperty("zipfile.path"); ZIPFILE_EXTRACTED = ZIPFILE_PATH.substring(0, ZIPFILE_PATH.length() - 4); Properties p = new Properties(); p.put("file.resource.loader.path", EXPECT_DIR); Velocity.init(p); } protected void testSimpleGremlinSession(String graphConfig, String graphToString) throws Exception { unzipAndRunExpect("single-vertex.expect.vm", graphConfig, graphToString); } protected void testGettingStartedGremlinSession(String graphConfig, String graphToString) throws Exception { unzipAndRunExpect("getting-started.expect.vm", graphConfig, graphToString); } protected void unzipAndRunExpect(String expectTemplateName, Map<String, String> contextVars) throws Exception { FileUtils.deleteQuietly(new File(ZIPFILE_EXTRACTED)); unzip(BUILD_DIR, ZIPFILE_PATH); parseTemplateAndRunExpect(expectTemplateName, contextVars); } protected void parseTemplateAndRunExpect(String expectTemplateName, Map<String, String> contextVars) throws IOException, InterruptedException { VelocityContext context = new VelocityContext(); for (Map.Entry<String, String> ent : contextVars.entrySet()) { context.put(ent.getKey(), ent.getValue()); } Template template = Velocity.getTemplate(expectTemplateName); String inputPath = EXPECT_DIR + File.separator + expectTemplateName; String outputPath = inputPath.substring(0, inputPath.length() - 3); Writer output = new FileWriter(outputPath); template.merge(context, output); output.close(); expect(ZIPFILE_EXTRACTED, outputPath); } protected void unzipAndRunExpect(String expectTemplateName) throws Exception { unzipAndRunExpect(expectTemplateName, Collections.<String, String>emptyMap()); } protected void unzipAndRunExpect(String expectTemplateName, String graphConfig, String graphToString) throws Exception { unzipAndRunExpect(expectTemplateName, ImmutableMap.of("graphConfig", graphConfig, "graphToString", graphToString)); } private static void expect(String dir, String expectScript) throws IOException, InterruptedException { command(new File(dir), "expect", expectScript); } protected static void unzip(String dir, String zipfile) throws IOException, InterruptedException { command(new File(dir), "unzip", "-q", zipfile); } protected static void command(File dir, String... command) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(command); pb.directory(dir); // pb.redirectInput(Redirect.PIPE); /* * Using Redirect.INHERIT with expect breaks maven-failsafe-plugin when * failsafe is configured to fork. The parent and child normally * communicate over stdout/stderr in fork mode. But after executing * expect, this failsafe communication starts appearing on the terminal. * The parent never sees it and assumes no tests ran. expect is probably * doing something nasty to its file descriptors and neglecting to clean * up after itself. Invoking unzip does not break failsafe+forks in this * way. So expect must be doing something unusual with its file * descriptors. * * Redirect.INHERIT works fine if failsafe is configured to never fork. */ // pb.redirectOutput(Redirect.INHERIT); // pb.redirectError(Redirect.INHERIT); // pb.redirectOutput(Redirect.PIPE); // pb.redirectError(Redirect.PIPE); final Process p = pb.start(); // Sense of "input" and "output" are reversed between ProcessBuilder and Process p.getOutputStream().close(); // Child process sees EOF on stdin (if it reads stdin at all) Thread outPrinter = new Thread(new SubprocessPipePrinter(p.getInputStream(), System.out)); Thread errPrinter = new Thread(new SubprocessPipePrinter(p.getErrorStream(), System.out)); outPrinter.start(); errPrinter.start(); int stat = p.waitFor(); outPrinter.join(); errPrinter.join(); assertEquals(0, stat); } private static class SubprocessPipePrinter implements Runnable { private final BufferedReader source; private final PrintStream sink; private SubprocessPipePrinter(InputStream source, PrintStream sink) { this.source = new BufferedReader(new InputStreamReader(source)); this.sink = sink; } @Override public void run() { try { runUnsafe(); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { // Exit silently } } private void runUnsafe() throws IOException, InterruptedException { String line = null; while (null != (line = source.readLine())) { synchronized (sink) { sink.println(line); } } } } }