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

org.glowroot.agent.it.harness.impl.LocalContainer Maven / Gradle / Ivy

There is a newer version: 0.9.24
Show newest version
/*
 * Copyright 2011-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.it.harness.impl;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import javax.annotation.Nullable;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.reflect.Reflection;

import org.glowroot.agent.MainEntryPoint;
import org.glowroot.agent.init.GlowrootAgentInit;
import org.glowroot.agent.it.harness.AppUnderTest;
import org.glowroot.agent.it.harness.ConfigService;
import org.glowroot.agent.it.harness.Container;
import org.glowroot.agent.it.harness.TempDirs;
import org.glowroot.agent.weaving.IsolatedWeavingClassLoader;
import org.glowroot.wire.api.model.TraceOuterClass.Trace;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.SECONDS;

public class LocalContainer implements Container {

    static {
        Reflection.initialize(InitLogging.class);
    }

    private final File baseDir;
    private final boolean deleteBaseDirOnClose;

    private volatile @Nullable IsolatedWeavingClassLoader isolatedWeavingClassLoader;
    private final @Nullable GrpcServerWrapper server;
    private final @Nullable TraceCollector traceCollector;
    private final GlowrootAgentInit glowrootAgentInit;
    private final @Nullable ConfigServiceImpl configService;

    private volatile @Nullable Thread executingAppThread;

    public static LocalContainer create(File baseDir) throws Exception {
        return new LocalContainer(baseDir, false, ImmutableMap.of());
    }

    public LocalContainer(@Nullable File baseDir, boolean fat, Map extraProperties)
            throws Exception {
        if (baseDir == null) {
            this.baseDir = TempDirs.createTempDir("glowroot-test-basedir");
            deleteBaseDirOnClose = true;
        } else {
            this.baseDir = baseDir;
            deleteBaseDirOnClose = false;
        }

        int collectorPort;
        if (fat) {
            collectorPort = 0;
            traceCollector = null;
            server = null;
        } else {
            collectorPort = getAvailablePort();
            traceCollector = new TraceCollector();
            server = new GrpcServerWrapper(traceCollector, collectorPort);
        }
        isolatedWeavingClassLoader = new IsolatedWeavingClassLoader(AppUnderTest.class);
        final Map properties = Maps.newHashMap();
        properties.put("glowroot.base.dir", this.baseDir.getAbsolutePath());
        if (collectorPort != 0) {
            properties.put("glowroot.collector.host", "localhost");
            properties.put("glowroot.collector.port", Integer.toString(collectorPort));
        }
        properties.putAll(extraProperties);
        // start up in separate thread to avoid the main thread from being capture by netty
        // ThreadDeathWatcher, which then causes PermGen OOM during maven test
        Executors.newSingleThreadExecutor().submit(new Callable() {
            @Override
            public @Nullable Void call() throws Exception {
                Thread.currentThread().setContextClassLoader(isolatedWeavingClassLoader);
                MainEntryPoint.start(properties);
                return null;
            }
        }).get();
        glowrootAgentInit = checkNotNull(MainEntryPoint.getGlowrootAgentInit());
        if (server == null) {
            configService = null;
        } else {
            configService = new ConfigServiceImpl(server, false);
            configService.resetConfig();
        }
    }

    @Override
    public ConfigService getConfigService() {
        checkNotNull(configService);
        return configService;
    }

    @Override
    public void addExpectedLogMessage(String loggerName, String partialMessage) {
        checkNotNull(traceCollector);
        traceCollector.addExpectedLogMessage(loggerName, partialMessage);
    }

    @Override
    public Trace execute(Class appClass) throws Exception {
        checkNotNull(traceCollector);
        executeInternal(appClass);
        Trace trace = traceCollector.getCompletedTrace(10, SECONDS);
        traceCollector.clearTrace();
        return trace;
    }

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

    @Override
    public void interruptAppUnderTest() throws Exception {
        Thread thread = executingAppThread;
        if (thread == null) {
            throw new IllegalStateException("No app currently executing");
        }
        thread.interrupt();
    }

    @Override
    public Trace getCollectedPartialTrace() throws InterruptedException {
        checkNotNull(traceCollector);
        return traceCollector.getPartialTrace(10, SECONDS);
    }

    @Override
    public void checkAndReset() throws Exception {
        if (configService == null) {
            glowrootAgentInit.getAgentModule().getConfigService().resetAllConfig();
        } else {
            configService.resetConfig();
        }
        if (traceCollector != null) {
            traceCollector.checkAndResetLogMessages();
        }
    }

    @Override
    public void close() throws Exception {
        glowrootAgentInit.close();
        if (server != null) {
            server.close();
        }
        glowrootAgentInit.awaitClose();
        if (deleteBaseDirOnClose) {
            TempDirs.deleteRecursively(baseDir);
        }
        // release class loader to prevent PermGen OOM during maven test
        isolatedWeavingClassLoader = null;
    }

    public boolean isClosed() {
        return isolatedWeavingClassLoader == null;
    }

    private void executeInternal(Class appClass) throws Exception {
        IsolatedWeavingClassLoader isolatedWeavingClassLoader = this.isolatedWeavingClassLoader;
        checkNotNull(isolatedWeavingClassLoader);
        ClassLoader previousContextClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(isolatedWeavingClassLoader);
        executingAppThread = Thread.currentThread();
        try {
            AppUnderTest app = isolatedWeavingClassLoader.newInstance(appClass, AppUnderTest.class);
            app.executeApp();
        } finally {
            executingAppThread = null;
            Thread.currentThread().setContextClassLoader(previousContextClassLoader);
        }
    }

    static int getAvailablePort() throws IOException {
        ServerSocket serverSocket = new ServerSocket(0);
        int port = serverSocket.getLocalPort();
        serverSocket.close();
        return port;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy