/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.brooklyn.test.support; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.ITestContext; import org.testng.TestListenerAdapter; public class BrooklynLeakListener extends TestListenerAdapter { private static final Logger TEST_RESOURCE_LOG = LoggerFactory.getLogger("test.resource.usage"); @Override public void onStart(ITestContext testContext) { super.onStart(testContext); tryTerminateAll("BrooklynLeakListener.onStart", testContext); } @Override public void onFinish(ITestContext testContext) { super.onFinish(testContext); tryTerminateAll("BrooklynLeakListener.onFinish", testContext); } /** * Tries to reflectively invoke {@code LocalManagementContext.logAll(TEST_RESOURCE_LOG); LocalManagementContext.terminateAll()}. * * It does this reflectively because the listener is executed for all projects, included those that don't * depend on brooklyn-core, so LocalManagementContext may not be on the classpath. */ private void tryTerminateAll(String context, ITestContext testContext) { String clazzName = "org.apache.brooklyn.core.management.internal.LocalManagementContext"; String message; int level; try { Class<?> clazz = BrooklynLeakListener.class.getClassLoader().loadClass(clazzName); clazz.getMethod("logAll", new Class[] {Logger.class}).invoke(null, TEST_RESOURCE_LOG); Integer count = (Integer)clazz.getMethod("terminateAll").invoke(null); if (count>0) { level = 0; message = ""+count+" ManagementContexts terminated"; } else if (count<0) { level = 1; message = ""+(-count)+" ManagementContexts left dangling"; } else { level = -1; message = ""+count+" ManagementContexts terminated"; } } catch (ClassNotFoundException e) { TEST_RESOURCE_LOG.debug("Class {} not found in testng listener, so not attempting to terminate all extant ManagementContexts; continuing", clazzName); level = 0; message = "no "+clazzName+" available, so skipped"; } catch (Throwable e) { TEST_RESOURCE_LOG.error("ERROR in testng listener, attempting to terminate all extant ManagementContexts", e); level = 1; message = "ERROR: "+e; } String logMessage = context+" attempting to terminate all extant ManagementContexts: " + "name=" + testContext.getName() + "; includedGroups="+Arrays.toString(testContext.getIncludedGroups()) + "; excludedGroups="+Arrays.toString(testContext.getExcludedGroups()) + "; suiteName="+testContext.getSuite().getName() + "; outDir="+testContext.getOutputDirectory() + ": "+message; if (level<0) TEST_RESOURCE_LOG.debug(logMessage); else if (level>0) TEST_RESOURCE_LOG.warn(logMessage); else TEST_RESOURCE_LOG.info(logMessage); } }