blob: 46fb450ffc03b6214a2be2fd2f4e3a4008774eb0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.shardingsphere.agent.plugin.tracing;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.ResettableClassFileTransformer;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.shardingsphere.agent.api.advice.AdviceTargetObject;
import org.apache.shardingsphere.agent.plugin.tracing.advice.AdviceTestBase;
import org.apache.shardingsphere.agent.plugin.tracing.rule.CollectorRule;
import org.junit.rules.TestRule;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public final class AgentRunner extends BlockJUnit4ClassRunner {
private static final String EXTRA_DATA = "_$EXTRA_DATA$_";
private static ResettableClassFileTransformer byteBuddyAgent;
private static final String[] ENHANCEMENT_CLASSES = {
"org.apache.shardingsphere.proxy.frontend.command.CommandExecutorTask",
"org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutorCallback",
"org.apache.shardingsphere.infra.parser.ShardingSphereSQLParserEngine",
};
private CollectorRule collectorRule;
public AgentRunner(final Class<?> testClass) throws InitializationError {
super(testClass);
}
@Override
protected Statement withBeforeClasses(final Statement statement) {
ByteBuddyAgent.install();
Collection<String> classes = new HashSet<>(Arrays.asList(ENHANCEMENT_CLASSES));
byteBuddyAgent = new AgentBuilder.Default()
.with(new ByteBuddy().with(TypeValidation.ENABLED))
.type(ElementMatchers.namedOneOf(ENHANCEMENT_CLASSES))
.transform((builder, typeDescription, classLoader, module) -> {
if (classes.contains(typeDescription.getTypeName())) {
return builder.defineField(EXTRA_DATA, Object.class, Opcodes.ACC_PRIVATE | Opcodes.ACC_VOLATILE)
.implement(AdviceTargetObject.class)
.intercept(FieldAccessor.ofField(EXTRA_DATA));
}
return builder;
}).installOnByteBuddyAgent();
// load them into current classloader
classes.forEach(each -> {
try {
Class<?> klass = Class.forName(each);
} catch (final ClassNotFoundException ignored) {
}
});
return super.withBeforeClasses(statement);
}
@Override
protected List<TestRule> classRules() {
List<TestRule> result = super.classRules();
collectorRule = result.stream().filter(each -> each instanceof CollectorRule).findFirst().map(optional -> (CollectorRule) optional).orElse(() -> {
});
return result;
}
@Override
protected Statement withBefores(final FrameworkMethod method, final Object target, final Statement statement) {
if (target instanceof AdviceTestBase) {
((AdviceTestBase) target).prepare();
}
return super.withBefores(method, target, statement);
}
@Override
protected Statement withAfters(final FrameworkMethod method, final Object target, final Statement statement) {
return super.withAfters(method, target, new Statement() {
@Override
public void evaluate() throws Throwable {
try {
statement.evaluate();
} finally {
collectorRule.cleanup();
}
}
});
}
@Override
protected Statement withAfterClasses(final Statement statement) {
byteBuddyAgent.reset(ByteBuddyAgent.getInstrumentation(), AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
return super.withAfterClasses(statement);
}
}