/* * Copyright 2012-2017 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.springframework.boot.diagnostics; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import org.junit.Before; import org.junit.Test; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; /** * Tests for {@link FailureAnalyzers}. * * @author Andy Wilkinson */ public class FailureAnalyzersTests { private static BeanFactoryAwareFailureAnalyzer failureAnalyzer; @Before public void configureMock() { failureAnalyzer = mock(BeanFactoryAwareFailureAnalyzer.class); } @Test public void analyzersAreLoadedAndCalled() { RuntimeException failure = new RuntimeException(); analyzeAndReport("basic.factories", failure); verify(failureAnalyzer, times(2)).analyze(failure); } @Test public void beanFactoryIsInjectedIntoBeanFactoryAwareFailureAnalyzers() { RuntimeException failure = new RuntimeException(); analyzeAndReport("basic.factories", failure); verify(failureAnalyzer).setBeanFactory(any(BeanFactory.class)); } @Test public void analyzerThatFailsDuringInitializationDoesNotPreventOtherAnalyzersFromBeingCalled() { RuntimeException failure = new RuntimeException(); analyzeAndReport("broken-initialization.factories", failure); verify(failureAnalyzer, times(1)).analyze(failure); } @Test public void analyzerThatFailsDuringAnalysisDoesNotPreventOtherAnalyzersFromBeingCalled() { RuntimeException failure = new RuntimeException(); analyzeAndReport("broken-analysis.factories", failure); verify(failureAnalyzer, times(1)).analyze(failure); } private void analyzeAndReport(String factoriesName, Throwable failure) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); ClassLoader classLoader = new CustomSpringFactoriesClassLoader(factoriesName); new FailureAnalyzers(context, classLoader).reportException(failure); } static class BasicFailureAnalyzer implements FailureAnalyzer { @Override public FailureAnalysis analyze(Throwable failure) { return failureAnalyzer.analyze(failure); } } static class BrokenInitializationFailureAnalyzer implements FailureAnalyzer { static { Object foo = null; foo.toString(); } @Override public FailureAnalysis analyze(Throwable failure) { return null; } } static class BrokenAnalysisFailureAnalyzer implements FailureAnalyzer { @Override public FailureAnalysis analyze(Throwable failure) { throw new NoClassDefFoundError(); } } interface BeanFactoryAwareFailureAnalyzer extends BeanFactoryAware, FailureAnalyzer { } static class StandardBeanFactoryAwareFailureAnalyzer extends BasicFailureAnalyzer implements BeanFactoryAwareFailureAnalyzer { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { failureAnalyzer.setBeanFactory(beanFactory); } } static class CustomSpringFactoriesClassLoader extends ClassLoader { private final String factoriesName; CustomSpringFactoriesClassLoader(String factoriesName) { super(CustomSpringFactoriesClassLoader.class.getClassLoader()); this.factoriesName = factoriesName; } @Override public Enumeration<URL> getResources(String name) throws IOException { if ("META-INF/spring.factories".equals(name)) { return super.getResources( "failure-analyzers-tests/" + this.factoriesName); } return super.getResources(name); } } }