/*
* Copyright 2016 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.plugin.grails;
import java.io.File;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.ning.http.client.AsyncHttpClient;
import grails.artefact.Artefact;
import grails.boot.config.GrailsAutoConfiguration;
import org.apache.catalina.Context;
import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.startup.Tomcat;
import org.apache.naming.resources.VirtualDirContext;
import org.grails.boot.context.web.GrailsAppServletInitializer;
import org.grails.boot.internal.EnableAutoConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.glowroot.agent.it.harness.AppUnderTest;
import org.glowroot.agent.it.harness.Container;
import org.glowroot.agent.it.harness.Containers;
import org.glowroot.agent.it.harness.impl.JavaagentContainer;
import org.glowroot.wire.api.model.TraceOuterClass.Trace;
import static org.assertj.core.api.Assertions.assertThat;
public class GrailsIT {
private static Container container;
@BeforeClass
public static void setUp() throws Exception {
String javaVersion = StandardSystemProperty.JAVA_VERSION.value();
if (Containers.useJavaagent()
&& (javaVersion.startsWith("1.6") || javaVersion.startsWith("1.7"))) {
// grails loads lots of classes
container = JavaagentContainer
.createWithExtraJvmArgs(ImmutableList.of("-XX:MaxPermSize=128m"));
} else {
container = Containers.create();
}
}
@AfterClass
public static void tearDown() throws Exception {
container.close();
}
@After
public void afterEachTest() throws Exception {
container.checkAndReset();
}
@Test
public void shouldCaptureNonDefaultAction() throws Exception {
// when
Trace trace = container.execute(GetHelloAbc.class);
// then
assertThat(trace.getHeader().getTransactionName()).isEqualTo("Hello#abc");
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getDepth()).isEqualTo(0);
assertThat(entry.getMessage()).isEqualTo(
"grails controller: org.glowroot.agent.plugin.grails.HelloController.abc()");
assertThat(i.hasNext()).isFalse();
}
@Test
public void shouldCaptureDefaultAction() throws Exception {
// when
Trace trace = container.execute(GetHello.class);
// then
assertThat(trace.getHeader().getTransactionName()).isEqualTo("Hello#index");
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getDepth()).isEqualTo(0);
assertThat(entry.getMessage()).isEqualTo(
"grails controller: org.glowroot.agent.plugin.grails.HelloController.index()");
assertThat(i.hasNext()).isFalse();
}
public static class ApplicationLoader extends GrailsAppServletInitializer
implements WebApplicationInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.sources(Application.class);
return application;
}
}
@Artefact("Application")
@EnableWebMvc
@EnableAutoConfiguration
public static class Application extends GrailsAutoConfiguration {
@Override
public Collection<String> packageNames() {
return Lists.newArrayList("org.glowroot.agent.plugin.grails");
}
@Override
@SuppressWarnings("rawtypes")
public Collection<Class> classes() {
Collection<Class> classes = super.classes();
List<Class> classesInCorrectClassLoader = Lists.newArrayList();
for (Class clazz : classes) {
try {
classesInCorrectClassLoader.add(Class.forName(clazz.getName(), false,
Application.class.getClassLoader()));
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
return classesInCorrectClassLoader;
}
}
public static class GetHelloAbc extends RenderInTomcat {
@Override
protected void doTest(int port) throws Exception {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
int statusCode =
asyncHttpClient.prepareGet("http://localhost:" + port + "/hello/abc/xyz")
.execute().get().getStatusCode();
asyncHttpClient.close();
if (statusCode != 200) {
throw new IllegalStateException("Unexpected status code: " + statusCode);
}
}
}
public static class GetHello extends RenderInTomcat {
@Override
protected void doTest(int port) throws Exception {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
int statusCode = asyncHttpClient.prepareGet("http://localhost:" + port + "/hello")
.execute().get().getStatusCode();
asyncHttpClient.close();
if (statusCode != 200) {
throw new IllegalStateException("Unexpected status code: " + statusCode);
}
}
}
public abstract static class RenderInTomcat implements AppUnderTest {
@Override
public void executeApp() throws Exception {
int port = getAvailablePort();
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("target/tomcat");
tomcat.setPort(port);
Context context =
tomcat.addWebapp("", new File("src/test/resources").getAbsolutePath());
WebappLoader webappLoader = new WebappLoader(RenderInTomcat.class.getClassLoader());
context.setLoader(webappLoader);
// this is needed in order for Tomcat to find annotated classes
VirtualDirContext resources = new VirtualDirContext();
resources.setExtraResourcePaths("/WEB-INF/classes=target/test-classes");
context.setResources(resources);
tomcat.start();
doTest(port);
tomcat.stop();
tomcat.destroy();
}
protected abstract void doTest(int port) throws Exception;
private static int getAvailablePort() throws Exception {
ServerSocket serverSocket = new ServerSocket(0);
int port = serverSocket.getLocalPort();
serverSocket.close();
return port;
}
}
}