/*
* JBoss, Home of Professional Open Source
* Copyright 2016, Red Hat, Inc. and/or its affiliates,
* and individual contributors as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2016,
* @author JBoss, by Red Hat.
*/
package org.jboss.byteman.contrib.dtest;
import java.io.File;
import java.io.FileNotFoundException;
import java.rmi.RemoteException;
import java.util.Scanner;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class InstrumentorTest {
private static Instrumentor instrumentor;
private static final String lineSeparator = System.getProperty("line.separator");
private static final Class<?> clazz = InstrumentorTest.class;
private static final String clazzName = clazz.getName();
private static final String method = "method";
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
@BeforeClass
public static void beforeClass() throws RemoteException {
instrumentor = new Instrumentor();
}
@Before
public void startUp() throws Exception {
instrumentor.removeLocalState();
}
@Test
public void ruleCrashAtMethodExit() throws Exception {
File ruleFile = tmpDir.newFile("crashAtMethodExit.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
instrumentor.crashAtMethodExit(clazzName, method);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.atExit()
.ifTrue()
.doo("killJVM")
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleCrashAtInterfaceMethodEntry() throws Exception {
File ruleFile = tmpDir.newFile("crashAtInterfaceMethodEntry.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
instrumentor.crashAtMethodEntry(InstrumentorTestingInterface.class, method);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.interfaze(InstrumentorTestingInterface.class.getSimpleName())
.method(method)
.atEntry()
.ifTrue()
.doo("killJVM")
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleCrashAtMethodEntry() throws Exception {
File ruleFile = tmpDir.newFile("crashAtMethodEntry.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
instrumentor.crashAtMethodEntry(clazzName, method);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.atEntry()
.ifTrue()
.doo("killJVM")
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleCrashAtMethod() throws Exception {
File ruleFile = tmpDir.newFile("crashAtMethod.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
String atLine = "LINE 123";
instrumentor.crashAtMethod(clazzName, method, atLine);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.at(atLine)
.ifTrue()
.doo("killJVM")
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleInjectOnCall() throws Exception {
File ruleFile = tmpDir.newFile("injectOnCall.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
String action = "debug(\"here\");";
instrumentor.injectOnCall(clazz, method, action);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.atEntry()
.ifTrue()
.doo(action)
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleInjectOnExit() throws Exception {
File ruleFile = tmpDir.newFile("injectOnExit.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
String action = "debug(\"here\");";
instrumentor.injectOnExit(clazz, method, action);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.atExit()
.ifTrue()
.doo(action)
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleInjectOnMethod() throws Exception {
File ruleFile = tmpDir.newFile("injectOnMethod.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
String at = "AFTER READ i";
String action = "debug(\"here\");";
String iff = "recovered";
instrumentor.injectOnMethod(clazz, method, iff, action, at);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.at(at)
.iff(iff)
.doo(action)
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleInjectFault() throws Exception {
File ruleFile = tmpDir.newFile("injectFault.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
Class exception = NullPointerException.class;
Object[] args = {"hello"};
instrumentor.injectFault(clazz, method, exception, args);
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.atEntry()
.ifTrue()
.doo("throw new " + exception.getName() + "(\"" + args[0])
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
@Test
public void ruleInstall() throws Exception {
File ruleFile = tmpDir.newFile("installRule.btm");
instrumentor.setRedirectedSubmissionsFile(ruleFile);
Class exception = NullPointerException.class;
Object[] args = {"hello"};
instrumentor.installRule(RuleConstructor.createRule("install rule")
.onClass(clazz).inMethod(method).atEntry().helper(BytemanTestHelper.class).ifTrue()
.doAction("throw new " + exception.getName() + "(\"" + args[0] + "\")"));
String ruleString = readFileToString(ruleFile);
Pattern pattern = new RegexRuleBuilder()
.clazz(clazzName)
.method(method)
.ifTrue()
.atEntry()
.doo("throw new " + exception.getName() + "(\"" + args[0])
.build();
Assert.assertTrue("Pattern\n" + pattern.pattern() + "\ndoes not match rule\n" + ruleString,
pattern.matcher(ruleString).matches());
}
private String readFileToString(File file) throws FileNotFoundException {
Scanner in = null;
try {
in = new Scanner(file);
StringBuffer buffer = new StringBuffer();
while (in.hasNext()) {
buffer.append(in.nextLine() + lineSeparator);
}
return buffer.toString();
} finally {
in.close();
}
}
private static class RegexRuleBuilder {
private String clazz, interfaze, method, at, iff, doo;
public RegexRuleBuilder clazz(String clazz) {
this.clazz = clazz;
return this;
}
public RegexRuleBuilder interfaze(String interfaze) {
this.interfaze = interfaze;
return this;
}
public RegexRuleBuilder method(String method) {
this.method = method;
return this;
}
public RegexRuleBuilder at(String at) {
this.at = at;
return this;
}
public RegexRuleBuilder atEntry() {
this.at = "ENTRY";
return this;
}
public RegexRuleBuilder atExit() {
this.at = "EXIT";
return this;
}
public RegexRuleBuilder iff(String iff) {
this.iff = iff;
return this;
}
public RegexRuleBuilder ifTrue() {
this.iff = "true";
return this;
}
public RegexRuleBuilder doo(String doo) {
this.doo = doo;
return this;
}
private String cleanForRegexp(String str) {
return str
.replaceAll("\\.", "\\\\.")
.replaceAll("\\(", "\\\\(")
.replaceAll("\\)", "\\\\)");
}
public Pattern build() {
String regex = String.format(
"^RULE.*" +
"%s%s.*" +
"METHOD%s.*" +
"%s.*" + // AT
"HELPER " + BytemanTestHelper.class.getName() + ".*" +
"%s.*" + // IF
"%s.*" + // DO
"ENDRULE.*",
clazz == null ? "" : "CLASS.*" + cleanForRegexp(clazz),
interfaze == null ? "" : "INTERFACE.*" + cleanForRegexp(interfaze),
method == null ? "" : ".*" + cleanForRegexp(method),
at == null ? "" : "AT.*" + at,
iff == null ? "" : "IF.*" + iff,
doo == null ? "" : "DO.*" + cleanForRegexp(doo));
return Pattern.compile(regex, Pattern.DOTALL);
}
}
}