/*
* Copyright 2013-2017 the original author or 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.glowroot.agent.tests;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.glowroot.agent.it.harness.AppUnderTest;
import org.glowroot.agent.it.harness.Container;
import org.glowroot.agent.it.harness.TempDirs;
import org.glowroot.agent.it.harness.TransactionMarker;
import org.glowroot.agent.it.harness.impl.LocalContainer;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.InstrumentationConfig;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.InstrumentationConfig.CaptureKind;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.InstrumentationConfig.MethodModifier;
import org.glowroot.wire.api.model.AgentConfigOuterClass.AgentConfig.TransactionConfig;
import org.glowroot.wire.api.model.TraceOuterClass.Trace;
import static org.assertj.core.api.Assertions.assertThat;
public class ConfiguredInstrumentationIT {
protected static Container container;
private static File testDir;
@BeforeClass
public static void setUp() throws Exception {
testDir = TempDirs.createTempDir("glowroot-test-dir");
// see subclass (ReweavePointcutsTest) for JavaagentContainer test
container = LocalContainer.create(testDir);
List<InstrumentationConfig> instrumentationConfigs = Lists.newArrayList();
instrumentationConfigs.add(buildInstrumentationForExecute1());
instrumentationConfigs.add(buildInstrumentationForExecute1TimerOnly());
instrumentationConfigs.add(buildInstrumentationForExecuteWithReturn());
instrumentationConfigs.add(buildInstrumentationForExecuteWithArgs());
container.getConfigService().updateInstrumentationConfigs(instrumentationConfigs);
// TODO this sleep currently resolves sporadic grpc related failure, try without sleep after
// next grpc update
Thread.sleep(1000);
// re-start now with pointcut configs
container.close();
// see subclass (ReweavePointcutsTest) for JavaagentContainer test
container = LocalContainer.create(testDir);
}
@AfterClass
public static void tearDown() throws Exception {
container.close();
TempDirs.deleteRecursively(testDir);
}
@After
public void afterEachTest() throws Exception {
container.checkAndReset();
}
@Test
public void shouldExecute1() throws Exception {
// given
container.getConfigService().updateTransactionConfig(
TransactionConfig.newBuilder()
.setSlowThresholdMillis(ProtoOptional.of(Integer.MAX_VALUE))
.build());
// when
Trace trace = container.execute(ShouldExecute1.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getTransactionType()).isEqualTo("test override type");
assertThat(header.getTransactionName()).isEqualTo("test override name");
Trace.Timer rootTimer = header.getMainThreadRootTimer();
assertThat(rootTimer.getName()).isEqualTo("mock trace marker");
assertThat(rootTimer.getChildTimerList()).hasSize(1);
assertThat(rootTimer.getChildTimerList().get(0).getName()).isEqualTo("execute one");
assertThat(rootTimer.getChildTimerList().get(0).getChildTimerList()).hasSize(1);
assertThat(rootTimer.getChildTimerList().get(0).getChildTimerList().get(0).getName())
.isEqualTo("execute one timer only");
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getDepth()).isEqualTo(0);
assertThat(entry.getMessage()).isEqualTo("execute1() => void");
assertThat(entry.getLocationStackTraceElementList()).isNotEmpty();
assertThat(i.hasNext()).isFalse();
}
@Test
public void shouldRenderTraceEntryMessageTemplateWithReturnValue() throws Exception {
// when
Trace trace = container.execute(ShouldExecuteWithReturn.class);
// then
Trace.Timer rootTimer = trace.getHeader().getMainThreadRootTimer();
assertThat(rootTimer.getName()).isEqualTo("mock trace marker");
assertThat(rootTimer.getChildTimerList()).hasSize(1);
assertThat(rootTimer.getChildTimerList().get(0).getName()).isEqualTo("execute with return");
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getDepth()).isEqualTo(0);
assertThat(entry.getMessage()).isEqualTo("executeWithReturn() => xyz");
assertThat(i.hasNext()).isFalse();
}
@Test
public void shouldRenderTraceHeadline() throws Exception {
// when
Trace trace = container.execute(ShouldExecuteWithArgs.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getHeadline()).isEqualTo("executeWithArgs(): abc, 123, the name");
assertThat(header.getTransactionType()).isEqualTo("Pointcut config test");
assertThat(header.getTransactionName()).isEqualTo("Misc / executeWithArgs");
Trace.Timer rootTimer = header.getMainThreadRootTimer();
assertThat(rootTimer.getName()).isEqualTo("execute with args");
assertThat(rootTimer.getChildTimerList()).isEmpty();
assertThat(header.getEntryCount()).isZero();
}
protected static InstrumentationConfig buildInstrumentationForExecute1() throws Exception {
return InstrumentationConfig.newBuilder()
.setClassName("org.glowroot.agent.tests.ConfiguredInstrumentationIT$Misc")
.setMethodName("execute1")
.setMethodReturnType("")
.addMethodModifier(MethodModifier.PUBLIC)
.setCaptureKind(CaptureKind.TRACE_ENTRY)
.setTimerName("execute one")
.setTraceEntryMessageTemplate("execute1() => {{_}}")
.setTraceEntryStackThresholdMillis(ProtoOptional.of(0))
.setTransactionType("test override type")
.setTransactionNameTemplate("test override name")
.setTransactionSlowThresholdMillis(ProtoOptional.of(0))
.build();
}
protected static InstrumentationConfig buildInstrumentationForExecute1TimerOnly()
throws Exception {
return InstrumentationConfig.newBuilder()
.setClassName("org.glowroot.agent.tests.ConfiguredInstrumentationIT$Misc")
.setMethodName("execute1")
.setMethodReturnType("")
.addMethodModifier(MethodModifier.PUBLIC)
.setCaptureKind(CaptureKind.TIMER)
.setTimerName("execute one timer only")
.build();
}
protected static InstrumentationConfig buildInstrumentationForExecuteWithReturn()
throws Exception {
return InstrumentationConfig.newBuilder()
.setClassName("org.glowroot.agent.tests.ConfiguredInstrumentationIT$Misc")
.setMethodName("executeWithReturn")
.setMethodReturnType("")
.addMethodModifier(MethodModifier.PUBLIC)
.setCaptureKind(CaptureKind.TRACE_ENTRY)
.setTimerName("execute with return")
.setTraceEntryMessageTemplate("executeWithReturn() => {{_}}")
.build();
}
protected static InstrumentationConfig buildInstrumentationForExecuteWithArgs()
throws Exception {
return InstrumentationConfig.newBuilder()
.setClassName("org.glowroot.agent.tests.ConfiguredInstrumentationIT$Misc")
.setMethodName("executeWithArgs")
.addMethodParameterType("java.lang.String")
.addMethodParameterType("int")
.addMethodParameterType(
"org.glowroot.agent.tests.ConfiguredInstrumentationIT$BasicMisc")
.setMethodReturnType("void")
.addMethodModifier(MethodModifier.PUBLIC)
.setCaptureKind(CaptureKind.TRANSACTION)
.setTimerName("execute with args")
.setTraceEntryMessageTemplate("executeWithArgs(): {{0}}, {{1}}, {{2.name}}")
.setTransactionType("Pointcut config test")
.setTransactionNameTemplate("Misc / {{methodName}}")
.build();
}
public interface Misc {
public void execute1();
public CharSequence executeWithReturn();
public void executeWithArgs(String one, int two, BasicMisc anotherMisc);
}
public static class BasicMisc implements Misc {
String getName() {
return "the name";
}
@Override
public void execute1() {}
@Override
public String executeWithReturn() {
return "xyz";
}
@Override
public void executeWithArgs(String one, int two, BasicMisc anotherMisc) {}
}
public static class ShouldExecute1 implements AppUnderTest, TransactionMarker {
@Override
public void executeApp() {
transactionMarker();
}
@Override
public void transactionMarker() {
new BasicMisc().execute1();
}
}
public static class ShouldExecuteWithReturn implements AppUnderTest, TransactionMarker {
@Override
public void executeApp() {
transactionMarker();
}
@Override
public void transactionMarker() {
new BasicMisc().executeWithReturn();
}
}
public static class ShouldExecuteWithArgs implements AppUnderTest {
@Override
public void executeApp() {
new BasicMisc().executeWithArgs("abc", 123, new BasicMisc());
}
}
}