/* * The MIT License * * Copyright (c) 2014 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.olivergondza.dumpling.cli; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import org.junit.Rule; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; import com.github.olivergondza.dumpling.DisposeRule; import com.github.olivergondza.dumpling.TestThread; import com.github.olivergondza.dumpling.Util; import javax.annotation.Nonnull; /** * Test interoperability between groovy and groovysh command and main method invocation with uberjar invocation. * * @author ogondza */ @RunWith(Theories.class) public class GroovyRuntimeTest { @Rule public DisposeRule disposer = new DisposeRule(); @DataPoints public static String[] commands() { return new String[] { "groovy", "groovysh" }; } @DataPoints public static List<AbstractCliTest> invokers() { ArrayList<AbstractCliTest> callables = new ArrayList<AbstractCliTest>(); callables.add(new AbstractCliTest() {}); // Run command within the JVM callables.add(new AbstractCliTest() { // Run in sibling JDK testing the uberjar @Override protected int run(@Nonnull String... args) { ArrayList<String> procArgs = new ArrayList<String>(); procArgs.add("java"); procArgs.add("-jar"); procArgs.add(getUberjar()); procArgs.addAll(Arrays.asList(args)); try { Process process = new ProcessBuilder(procArgs).start(); PrintStream inStream = new PrintStream(process.getOutputStream()); Util.forwardStream(in, inStream); inStream.close(); exitValue = process.waitFor(); this.out = new ByteArrayOutputStream(); err = new ByteArrayOutputStream(); Util.forwardStream(process.getInputStream(), new PrintStream(this.out)); Util.forwardStream(process.getErrorStream(), new PrintStream(err)); return exitValue; } catch (IOException e) { throw new AssertionError(e); } catch (InterruptedException e) { throw new AssertionError(e); } } }); return callables; } private static String getUberjar() { File file = new File("./target"); try { if (!file.exists()) throw new AssertionError(file.getCanonicalPath()+ " does not exist"); List<File> files = Arrays.asList(file.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith("dumpling-cli") && name.endsWith("-shaded.jar"); } })); if (files.size() != 1) throw new AssertionError("One uberjar expected: " + files); return files.get(0).getCanonicalPath(); } catch (IOException e) { throw new AssertionError(e); } } @Theory public void executeScript(String command, AbstractCliTest i) { i.stdin("println D.load.jvm.threads.size() instanceof Integer;%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString().trim(), i.containsString("true")); assertThat(i, i.succeeded()); } @Theory public void filter(String command, AbstractCliTest i) throws Exception { i.stdin("D.load.threaddump(D.args[0]).threads.where(nameIs('owning_thread')).collect { it.name };%n"); i.run(command, Util.asFile(Util.resource("jstack/producer-consumer.log")).getAbsolutePath()); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString().trim(), i.containsString("[owning_thread]")); assertThat(i, i.succeeded()); } @Theory public void loadTreaddump(String command, AbstractCliTest i) throws Exception { assertLoadThreaddump(command, i, "D.load.threaddump(D.args[0]).threads.where(nameIs('blocked_thread'));%n"); } private void assertLoadThreaddump(String command, AbstractCliTest i, String script) throws Exception { File file = Util.asFile(Util.resource("jstack/producer-consumer.log")); i.stdin(script); i.run(command, file.getAbsolutePath()); assertThat(i.err.toString(), i.isEmptyString()); assertThat(i.out.toString(), i.containsString("\"blocked_thread\"")); assertThat(i.exitValue, equalTo(0)); } @Theory public void loadPid(String command, AbstractCliTest i) { assertLoadPid(command, i, "D.load.process(%d).threads.where(nameIs('remotely-observed-thread'));%n"); } private void assertLoadPid(String command, AbstractCliTest i, String script) { disposer.register(TestThread.runThread()); i.stdin(String.format(script, Util.currentPid())); i.run(command); assertThat(i.err.toString(), i.isEmptyString()); assertThat(i.out.toString(), i.containsString("\"remotely-observed-thread\"")); assertThat(i.exitValue, equalTo(0)); } @Theory public void loadPidOverJmx(String command, AbstractCliTest i) { assertLoadPidOverJmx(command, i, "D.load.jmx(%d).threads.where(nameIs('remotely-observed-thread'));%n"); } private void assertLoadPidOverJmx(String command, AbstractCliTest i, String script) { disposer.register(TestThread.runThread()); i.stdin(String.format(script, Util.currentPid())); i.run(command); assertThat(i.err.toString(), i.isEmptyString()); assertThat(i.out.toString(), i.containsString("\"remotely-observed-thread\"")); assertThat(i.exitValue, equalTo(0)); } @Theory public void loadJmx(String command, AbstractCliTest i) throws Exception { assertLoadJmx(command, i, "println D.load.jmx(D.args[0]).threads.where(nameIs('remotely-observed-thread'));%n"); } private void assertLoadJmx(String command, AbstractCliTest i, String script) throws Exception { TestThread.JMXProcess process = disposer.register(TestThread.runJmxObservableProcess(false)); i.stdin(script); i.run(command, process.JMX_CONNECTION); assertThat(i.err.toString(), i.isEmptyString()); assertThat(i.out.toString(), i.containsString("\"remotely-observed-thread\"")); assertThat(i.exitValue, equalTo(0)); } @Theory public void loadSymbolsFromOtherDumplingPackages(String command, AbstractCliTest i) { i.stdin("new Deadlocks(); ModelObject.Mode.HUMAN; new JvmRuntimeFactory(); new CommandFailedException('');%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i, i.succeeded()); } @Theory public void failTheScript(String command, AbstractCliTest i) { i.stdin("new ThereIsNoSuchClass();%n"); i.run(command); assertThat(i.err.toString(), i.containsString("unable to resolve class ThereIsNoSuchClass")); } @Theory public void printToOutAndErr(String command, AbstractCliTest i) { i.stdin("out.println('stdout content'); err.println('stderr content');%n"); i.run(command); assertThat(i.err.toString(), i.containsString("stderr content")); assertThat(i.out.toString(), i.containsString("stdout content")); assertThat(i.exitValue, equalTo(0)); } @Theory public void groovyGrep(String command, AbstractCliTest i) { i.stdin("def threads = D.load.jvm.threads; assert threads == threads.grep(); println threads.class;%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyGrepWithArg(String command, AbstractCliTest i) { final String name = Thread.currentThread().getName(); i.stdin("def threads = D.load.jvm.threads.grep { it.name == '" + name + "' }; assert threads.size() == 1; println threads.class%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyFindAll(String command, AbstractCliTest i) { i.stdin("def threads = D.load.jvm.threads; assert threads == threads.findAll(); println threads.getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyFindAllWithArg(String command, AbstractCliTest i) { final String name = Thread.currentThread().getName(); i.stdin("def threads = D.load.jvm.threads.findAll { it.name == '" + name + "' }; assert threads.size() == 1; println threads.getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyAsImmutable(String command, AbstractCliTest i) { i.stdin("def threads = D.load.jvm.threads; assert threads.asImmutable() == threads; print threads.getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyIntersect(String command, AbstractCliTest i) { i.stdin("def threads = D.load.jvm.threads; def intersected = threads.intersect(threads); assert threads == intersected; print intersected.getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyIntersectDifferentRuntime(String command, AbstractCliTest i) { i.stdin("D.load.jvm.threads.intersect(D.load.jvm.threads)%n"); i.run(command); assertThat(i.err.toString(), i.containsString("java.lang.IllegalArgumentException")); assertThat(i.err.toString(), i.containsString("Unable to intersect ThreadSets bound to different ProcessRuntimes")); } @Theory public void groovyPlus(String command, AbstractCliTest i) { i.stdin("rt = D.load.jvm; threadSum = rt.threads + rt.threads; print threadSum.getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void groovyPlusDifferentRuntime(String command, AbstractCliTest i) { i.stdin("D.load.jvm.threads + D.load.jvm.threads%n"); i.run(command); assertThat(i.err.toString(), i.containsString("java.lang.IllegalArgumentException")); assertThat(i.err.toString(), i.containsString("Unable to merge ThreadSets bound to different ProcessRuntimes")); } @Theory public void groovyToSet(String command, AbstractCliTest i) { i.stdin("print D.load.jvm.threads.toSet().getClass()%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("class com.github.olivergondza.dumpling.model.jvm.JvmThreadSet")); assertThat(i, i.succeeded()); } @Theory public void stateFilter(String command, AbstractCliTest i) { String choices = "it.status.new || it.status.runnable || it.status.sleeping || it.status.waiting || it.status.parked || it.status.blocked || it.status.terminated"; i.stdin("print D.load.jvm.threads.grep { " + choices + " }.empty%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("false")); assertThat(i, i.succeeded()); } @Theory public void cliArguments(String command, AbstractCliTest i) { i.stdin("print \"${D.args[1]} ${D.args[0]}!\"%n"); i.run(command, "World", "Hello"); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("Hello World!")); assertThat(i, i.succeeded()); } @Theory public void help(String command, AbstractCliTest i) { i.stdin("print D%n"); i.run(command); assertThat(i.err.toString(), equalTo("")); assertThat(i.out.toString(), i.containsString("D.args: java.util.List%n CLI arguments passed to the script")); assertThat(i.out.toString(), i.containsString("D.load.threaddump(String): com.github.olivergondza.dumpling.model.ProcessRuntime")); assertThat(i, i.succeeded()); } }