com.mgmtp.perfload.agent.TransformerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.mgmtp.perfload.agent.TransformerTest.java

Source

/*
 * Copyright (c) 2013-2014 mgm technology partners GmbH
 *
 * 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 com.mgmtp.perfload.agent;

import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;

import java.io.File;
import java.io.IOException;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.UUID;

import javax.inject.Inject;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mgmtp.perfload.agent.util.ClassNameUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.util.Modules;
import com.mgmtp.perfload.agent.annotations.ConfigFile;
import com.mgmtp.perfload.agent.hook.ServletApiHook;

/**
 * @author rnaegele
 */
public class TransformerTest {

    private static final File MEASURING_LOG_FILE = new File("target",
            String.format("perfload-agent-measuring-%d.log", Agent.retrievePid()));

    @Inject
    private Transformer transformer;

    private Class<?> testClass;
    private Class<?> filterClass;
    private Class<?> servletClass;

    private HttpServletRequest request;
    private UUID execId;
    private UUID reqId;

    @BeforeClass
    public void init()
            throws MalformedURLException, IOException, IllegalClassFormatException, ClassNotFoundException {
        final File agentDir = new File("target");
        int pid = Agent.retrievePid();
        File agentLog = new File(agentDir, String.format("perfload-agent-%d.log", pid));
        AgentLogger logger = new AgentLogger(agentLog);

        Injector injector = InjectorHolder.INSTANCE
                .createInjector(Modules.override(new AgentModule(agentDir, logger, pid)).with(new AbstractModule() {
                    @Override
                    protected void configure() {
                        bind(File.class).annotatedWith(ConfigFile.class)
                                .toInstance(new File("src/test/resources/perfload-agent.json"));
                    }
                }));
        injector.injectMembers(this);

        testClass = loadClass("com.mgmtp.perfload.agent.Test");
        filterClass = loadClass("com.mgmtp.perfload.agent.TestFilter");
        servletClass = loadClass("com.mgmtp.perfload.agent.TestServlet");
    }

    @BeforeMethod
    public void beforeMethod() {
        request = mock(HttpServletRequest.class);
        execId = UUID.randomUUID();
        reqId = UUID.randomUUID();
        when(request.getHeader(ServletApiHook.EXECUTION_ID_HEADER)).thenReturn(execId.toString());
        when(request.getHeader(ServletApiHook.OPERATION_HEADER)).thenReturn("operation");
        when(request.getHeader(ServletApiHook.REQUEST_ID_HEADER)).thenReturn(reqId.toString());
    }

    @Test
    public void testMeasuringHook() throws Exception {
        Constructor<?> constructor = testClass.getConstructor(Boolean.class);

        Object object = constructor.newInstance(Boolean.TRUE);
        try {
            object.getClass().getMethod("check").invoke(object);
            fail();
        } catch (InvocationTargetException ex) {
            // expected
        }

        object = constructor.newInstance(Boolean.FALSE);
        testClass.getMethod("checkI", int.class).invoke(null, 1);
        testClass.getMethod("checkLL", long.class, long.class).invoke(object, 42L, 43L);
        testClass.getMethod("check").invoke(object);

        List<String> measuringLogContents = Files.readLines(MEASURING_LOG_FILE, Charsets.UTF_8);
        assertEquals(measuringLogContents.size(), 4);
        assertTrue(measuringLogContents.get(0).contains("ERROR"));
        assertTrue(measuringLogContents.get(1).contains("SUCCESS"));
        assertTrue(measuringLogContents.get(2).contains("SUCCESS"));
        assertTrue(measuringLogContents.get(3).contains("SUCCESS"));
    }

    @Test
    public void testServletApiHookWithFilter() throws Exception {
        Object filter = filterClass.newInstance();
        filterClass.getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class)
                .invoke(filter, request, null, null);

        String fileContents = Files.toString(MEASURING_LOG_FILE, Charsets.UTF_8);
        assertTrue(fileContents
                .matches(String.format("(?s).*%s[^\r\n]*?%s[^\r\n]*?%s.*", "operation", execId, reqId)));
    }

    @Test
    public void testServletApiHookWithServlet() throws Exception {
        Object servlet = servletClass.newInstance();
        servletClass.getMethod("service", HttpServletRequest.class, HttpServletResponse.class).invoke(servlet,
                request, mock(HttpServletResponse.class));

        String fileContents = Files.toString(MEASURING_LOG_FILE, Charsets.UTF_8);
        assertTrue(fileContents
                .matches(String.format("(?s).*%s[^\r\n]*?%s[^\r\n]*?%s.*", "operation", execId, reqId)));
        assertTrue(fileContents.contains(ClassNameUtils.abbreviatePackageName(servletClass.getName())));
    }

    private Class<?> loadClass(final String fqcn)
            throws IOException, IllegalClassFormatException, MalformedURLException, ClassNotFoundException {
        String internalName = fqcn.replace('.', '/');

        byte[] classBytes = Resources.toByteArray(Resources.getResource(internalName + ".class"));
        byte[] transformedClass = transformer.transform(null, internalName, null, null, classBytes);
        File classFile = new File("tmp/" + internalName + ".class");
        writeByteArrayToFile(classFile, transformedClass);

        URLClassLoader loader = new URLClassLoader(new URL[] { new File("tmp").toURI().toURL() }) {
            /**
             * Loads the class with the specified binary name trying to load it from the local
             * classpath first before delegating to the normal class loading mechanism.
             */
            @Override
            protected synchronized Class<?> loadClass(final String name, final boolean resolve)
                    throws ClassNotFoundException {
                // Check if the class has already been loaded
                Class<?> loadedClass = findLoadedClass(name);

                if (loadedClass == null) {
                    if (name.startsWith("com.mgmtp.perfload.agent.Test")) {
                        try {
                            // First try to find it locally
                            loadedClass = findClass(name);
                        } catch (ClassNotFoundException e) {
                            // Swallow exception --> the class does not exist locally
                        }
                    }
                    // If the class is not found locally we delegate to the normal class loading mechanism
                    if (loadedClass == null) {
                        loadedClass = super.loadClass(name, resolve);
                    }
                }

                if (resolve) {
                    resolveClass(loadedClass);
                }
                return loadedClass;
            }
        };
        return loader.loadClass(fqcn);
    }
}