All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.instrumentation.test.harness.impl.LocalContainer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2011-2019 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.instrumentation.test.harness.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;

import org.glowroot.instrumentation.test.harness.shaded.com.google.common.io.Files;
import org.checkerframework.checker.nullness.qual.Nullable;

import org.glowroot.instrumentation.engine.weaving.IsolatedWeavingClassLoader;
import org.glowroot.instrumentation.test.harness.AppUnderTest;
import org.glowroot.instrumentation.test.harness.Container;
import org.glowroot.instrumentation.test.harness.IncomingSpan;
import org.glowroot.instrumentation.test.harness.agent.MainEntryPoint;

import static org.glowroot.instrumentation.test.harness.shaded.com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

public class LocalContainer implements Container {

    private final IsolatedWeavingClassLoader isolatedWeavingClassLoader;
    private final TraceCollector traceCollector;
    private final File tmpDir;

    private volatile @Nullable Thread executingAppThread;

    public static LocalContainer create() throws Exception {
        return new LocalContainer();
    }

    private LocalContainer() throws Exception {
        traceCollector = new TraceCollector();
        traceCollector.start();
        tmpDir = Files.createTempDir();
        isolatedWeavingClassLoader = new IsolatedWeavingClassLoader(AppUnderTest.class);
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(isolatedWeavingClassLoader);
        try {
            MainEntryPoint.start(null, tmpDir, traceCollector.getPort());
        } finally {
            Thread.currentThread().setContextClassLoader(loader);
        }
        MainEntryPoint.resetInstrumentationProperties();
    }

    @Override
    public void setInstrumentationProperty(String instrumentationId, String propertyName,
            boolean propertyValue) throws Exception {
        MainEntryPoint.setInstrumentationProperty(instrumentationId, propertyName, propertyValue);
    }

    @Override
    public void setInstrumentationProperty(String instrumentationId, String propertyName,
            @Nullable Double propertyValue) throws Exception {
        MainEntryPoint.setInstrumentationProperty(instrumentationId, propertyName, propertyValue);
    }

    @Override
    public void setInstrumentationProperty(String instrumentationId, String propertyName,
            String propertyValue) throws Exception {
        MainEntryPoint.setInstrumentationProperty(instrumentationId, propertyName, propertyValue);
    }

    @Override
    public void setInstrumentationProperty(String instrumentationId, String propertyName,
            List propertyValue) throws Exception {
        MainEntryPoint.setInstrumentationProperty(instrumentationId, propertyName, propertyValue);
    }

    @Override
    public IncomingSpan execute(Class appClass, Serializable... args)
            throws Exception {
        return executeInternal(appClass, null, null, args);
    }

    @Override
    public IncomingSpan executeForType(Class appClass,
            String transactionType, Serializable... args) throws Exception {
        return executeInternal(appClass, transactionType, null, args);
    }

    @Override
    public IncomingSpan executeForTypeAndName(Class appClass,
            String transactionType, String transactionName, Serializable... args) throws Exception {
        return executeInternal(appClass, transactionType, transactionName, args);
    }

    @Override
    public void executeNoExpectedTrace(Class appClass, Serializable... args)
            throws Exception {
        executeInternal(appClass, args);
        MILLISECONDS.sleep(10);
        if (traceCollector != null && traceCollector.hasIncomingSpan()) {
            throw new IllegalStateException("Trace was collected when none was expected");
        }
    }

    @Override
    public void resetAfterEachTest() throws Exception {
        MainEntryPoint.resetInstrumentationProperties();
    }

    @Override
    public void close() throws Exception {
        traceCollector.close();
    }

    public IncomingSpan executeInternal(Class appClass,
            @Nullable String transactionType, @Nullable String transactionName,
            Serializable... args) throws Exception {
        checkNotNull(traceCollector);
        executeInternal(appClass, args);
        IncomingSpan incomingSpan =
                traceCollector.getCompletedIncomingSpan(transactionType, transactionName, 10,
                        SECONDS);
        traceCollector.clearIncomingSpans();
        return incomingSpan;
    }

    private void executeInternal(Class appClass, Serializable[] args)
            throws Exception {
        ClassLoader previousContextClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(isolatedWeavingClassLoader);
        executingAppThread = Thread.currentThread();
        try {
            AppUnderTest app = isolatedWeavingClassLoader.newInstance(appClass, AppUnderTest.class);
            if (args.length > 0) {
                Serializable[] isoArgs = new Serializable[args.length];
                for (int i = 0; i < args.length; i++) {
                    isoArgs[i] = (Serializable) transfer(args[i], isolatedWeavingClassLoader);
                }
                app.executeApp(isoArgs);
            } else {
                app.executeApp();
            }
        } finally {
            executingAppThread = null;
            Thread.currentThread().setContextClassLoader(previousContextClassLoader);
        }
    }

    private static Object transfer(Object obj, ClassLoader loader) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(obj);
        ObjectInputStreamWithClassLoader in = new ObjectInputStreamWithClassLoader(
                new ByteArrayInputStream(baos.toByteArray()), loader);
        try {
            return in.readObject();
        } finally {
            in.close();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy