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.14.0-beta.3
Show 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.agent.it.harness.impl;

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

import org.glowroot.agent.it.harness.shaded.com.google.common.collect.ImmutableMap;
import org.glowroot.agent.it.harness.shaded.com.google.common.collect.Maps;
import org.checkerframework.checker.nullness.qual.Nullable;

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 org.glowroot.agent.it.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 File testDir;
    private final boolean deleteTestDirOnClose;

    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() throws Exception {
        return new LocalContainer(null, false, ImmutableMap.of());
    }

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

    public LocalContainer(@Nullable File testDir, boolean embedded,
            Map extraProperties) throws Exception {
        if (testDir == null) {
            this.testDir = TempDirs.createTempDir("glowroot-test-dir");
            deleteTestDirOnClose = true;
        } else {
            this.testDir = testDir;
            deleteTestDirOnClose = false;
        }

        boolean pointingToCentral = extraProperties.containsKey("glowroot.collector.address");
        final Map properties = Maps.newHashMap();
        properties.put("glowroot.test.dir", this.testDir.getAbsolutePath());
        if (embedded || pointingToCentral) {
            traceCollector = null;
            server = null;
        } else {
            int collectorPort = getAvailablePort();
            traceCollector = new TraceCollector();
            server = new GrpcServerWrapper(traceCollector, collectorPort);
            properties.put("glowroot.collector.address",
                    "localhost:" + Integer.toString(collectorPort));
        }
        isolatedWeavingClassLoader = new IsolatedWeavingClassLoader(AppUnderTest.class);
        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 {
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(isolatedWeavingClassLoader);
                try {
                    MainEntryPoint.start(properties);
                } finally {
                    Thread.currentThread().setContextClassLoader(loader);
                }
                return null;
            }
        }).get();
        glowrootAgentInit = checkNotNull(MainEntryPoint.getGlowrootAgentInit());
        if (server == null) {
            configService = null;
            glowrootAgentInit.initConfigForTests();
        } else {
            configService = new ConfigServiceImpl(server, false);
            // need to set through config service so config service can keep track of changes,
            // otherwise it will clobber slow threshold value on next update through config service
            configService.initConfigForTests();
        }
    }

    @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 {
        return executeInternal(appClass, null, null);
    }

    @Override
    public Trace execute(Class appClass, String transactionType)
            throws Exception {
        return executeInternal(appClass, transactionType, null);
    }

    @Override
    public Trace execute(Class appClass, String transactionType,
            String transactionName) throws Exception {
        return executeInternal(appClass, transactionType, transactionName);
    }

    @Override
    public void executeNoExpectedTrace(Class appClass) throws Exception {
        executeInternal(appClass);
        MILLISECONDS.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.resetConfigForTests();
        } else {
            // need to reset through config service so config service can keep track of changes,
            // otherwise it will clobber the reset config on next update through config service
            configService.resetConfigForTests();
        }
        if (traceCollector != null) {
            traceCollector.checkAndResetLogMessages();
        }
    }

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

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

    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 Exception {
        ServerSocket serverSocket = new ServerSocket(0);
        int port = serverSocket.getLocalPort();
        serverSocket.close();
        return port;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy