/*
* 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.autoconfigure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AutoConfigurationImportSelector}
*
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Madhura Bhave
*/
public class AutoConfigurationImportSelectorTests {
private final TestAutoConfigurationImportSelector importSelector = new TestAutoConfigurationImportSelector();
private final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private final MockEnvironment environment = new MockEnvironment();
private List<AutoConfigurationImportFilter> filters = new ArrayList<>();
@Rule
public ExpectedException expected = ExpectedException.none();
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.importSelector.setBeanFactory(this.beanFactory);
this.importSelector.setEnvironment(this.environment);
this.importSelector.setResourceLoader(new DefaultResourceLoader());
}
@Test
public void importsAreSelectedWhenUsingEnableAutoConfiguration() {
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSameSizeAs(SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, getClass().getClassLoader()));
assertThat(this.importSelector.getLastEvent().getExclusions()).isEmpty();
}
@Test
public void classExclusionsAreApplied() {
String[] imports = selectImports(
EnableAutoConfigurationWithClassExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(FreeMarkerAutoConfiguration.class.getName());
}
@Test
public void classExclusionsAreAppliedWhenUsingSpringBootApplication() {
String[] imports = selectImports(SpringBootApplicationWithClassExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(FreeMarkerAutoConfiguration.class.getName());
}
@Test
public void classNamesExclusionsAreApplied() {
String[] imports = selectImports(
EnableAutoConfigurationWithClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(MustacheAutoConfiguration.class.getName());
}
@Test
public void classNamesExclusionsAreAppliedWhenUsingSpringBootApplication() {
String[] imports = selectImports(
SpringBootApplicationWithClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(MustacheAutoConfiguration.class.getName());
}
@Test
public void propertyExclusionsAreApplied() {
this.environment.setProperty("spring.autoconfigure.exclude",
FreeMarkerAutoConfiguration.class.getName());
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(FreeMarkerAutoConfiguration.class.getName());
}
@Test
public void severalPropertyExclusionsAreApplied() {
this.environment.setProperty("spring.autoconfigure.exclude",
FreeMarkerAutoConfiguration.class.getName() + ","
+ MustacheAutoConfiguration.class.getName());
testSeveralPropertyExclusionsAreApplied();
}
@Test
public void severalPropertyExclusionsAreAppliedWithExtraSpaces() {
this.environment.setProperty("spring.autoconfigure.exclude",
FreeMarkerAutoConfiguration.class.getName() + " , "
+ MustacheAutoConfiguration.class.getName() + " ");
testSeveralPropertyExclusionsAreApplied();
}
@Test
public void severalPropertyYamlExclusionsAreApplied() {
this.environment.setProperty("spring.autoconfigure.exclude[0]",
FreeMarkerAutoConfiguration.class.getName());
this.environment.setProperty("spring.autoconfigure.exclude[1]",
MustacheAutoConfiguration.class.getName());
testSeveralPropertyExclusionsAreApplied();
}
private void testSeveralPropertyExclusionsAreApplied() {
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 2);
assertThat(this.importSelector.getLastEvent().getExclusions()).contains(
FreeMarkerAutoConfiguration.class.getName(),
MustacheAutoConfiguration.class.getName());
}
@Test
public void combinedExclusionsAreApplied() {
this.environment.setProperty("spring.autoconfigure.exclude",
ThymeleafAutoConfiguration.class.getName());
String[] imports = selectImports(
EnableAutoConfigurationWithClassAndClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 3);
assertThat(this.importSelector.getLastEvent().getExclusions()).contains(
FreeMarkerAutoConfiguration.class.getName(),
MustacheAutoConfiguration.class.getName(),
ThymeleafAutoConfiguration.class.getName());
}
@Test
public void nonAutoConfigurationClassExclusionsShouldThrowException()
throws Exception {
this.expected.expect(IllegalStateException.class);
selectImports(EnableAutoConfigurationWithFaultyClassExclude.class);
}
@Test
public void nonAutoConfigurationClassNameExclusionsWhenPresentOnClassPathShouldThrowException()
throws Exception {
this.expected.expect(IllegalStateException.class);
selectImports(EnableAutoConfigurationWithFaultyClassNameExclude.class);
}
@Test
public void nonAutoConfigurationPropertyExclusionsWhenPresentOnClassPathShouldThrowException()
throws Exception {
this.environment.setProperty("spring.autoconfigure.exclude",
"org.springframework.boot.autoconfigure."
+ "AutoConfigurationImportSelectorTests.TestConfiguration");
this.expected.expect(IllegalStateException.class);
selectImports(BasicEnableAutoConfiguration.class);
}
@Test
public void nameAndPropertyExclusionsWhenNotPresentOnClasspathShouldNotThrowException()
throws Exception {
this.environment.setProperty("spring.autoconfigure.exclude",
"org.springframework.boot.autoconfigure.DoesNotExist2");
selectImports(EnableAutoConfigurationWithAbsentClassNameExclude.class);
assertThat(this.importSelector.getLastEvent().getExclusions())
.containsExactlyInAnyOrder(
"org.springframework.boot.autoconfigure.DoesNotExist1",
"org.springframework.boot.autoconfigure.DoesNotExist2");
}
@Test
public void filterShouldFilterImports() throws Exception {
String[] defaultImports = selectImports(BasicEnableAutoConfiguration.class);
this.filters.add(new TestAutoConfigurationImportFilter(defaultImports, 1));
this.filters.add(new TestAutoConfigurationImportFilter(defaultImports, 3, 4));
String[] filtered = selectImports(BasicEnableAutoConfiguration.class);
assertThat(filtered).hasSize(defaultImports.length - 3);
assertThat(filtered).doesNotContain(defaultImports[1], defaultImports[3],
defaultImports[4]);
}
@Test
public void filterShouldSupportAware() throws Exception {
TestAutoConfigurationImportFilter filter = new TestAutoConfigurationImportFilter(
new String[] {});
this.filters.add(filter);
selectImports(BasicEnableAutoConfiguration.class);
assertThat(filter.getBeanFactory()).isEqualTo(this.beanFactory);
}
private String[] selectImports(Class<?> source) {
return this.importSelector.selectImports(new StandardAnnotationMetadata(source));
}
private List<String> getAutoConfigurationClassNames() {
return SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
getClass().getClassLoader());
}
private class TestAutoConfigurationImportSelector
extends AutoConfigurationImportSelector {
private AutoConfigurationImportEvent lastEvent;
@Override
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return AutoConfigurationImportSelectorTests.this.filters;
}
@Override
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return Collections.<AutoConfigurationImportListener>singletonList(
new AutoConfigurationImportListener() {
@Override
public void onAutoConfigurationImportEvent(
AutoConfigurationImportEvent event) {
TestAutoConfigurationImportSelector.this.lastEvent = event;
}
});
}
public AutoConfigurationImportEvent getLastEvent() {
return this.lastEvent;
}
}
private static class TestAutoConfigurationImportFilter
implements AutoConfigurationImportFilter, BeanFactoryAware {
private final Set<String> nonMatching = new HashSet<>();
private BeanFactory beanFactory;
TestAutoConfigurationImportFilter(String[] configurations, int... nonMatching) {
for (int i : nonMatching) {
this.nonMatching.add(configurations[i]);
}
}
@Override
public boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] result = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < result.length; i++) {
result[i] = !this.nonMatching.contains(autoConfigurationClasses[i]);
}
return result;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public BeanFactory getBeanFactory() {
return this.beanFactory;
}
}
@Configuration
private class TestConfiguration {
}
@EnableAutoConfiguration
private class BasicEnableAutoConfiguration {
}
@EnableAutoConfiguration(exclude = FreeMarkerAutoConfiguration.class)
private class EnableAutoConfigurationWithClassExclusions {
}
@SpringBootApplication(exclude = FreeMarkerAutoConfiguration.class)
private class SpringBootApplicationWithClassExclusions {
}
@EnableAutoConfiguration(excludeName = "org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration")
private class EnableAutoConfigurationWithClassNameExclusions {
}
@EnableAutoConfiguration(exclude = MustacheAutoConfiguration.class, excludeName = "org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration")
private class EnableAutoConfigurationWithClassAndClassNameExclusions {
}
@EnableAutoConfiguration(exclude = TestConfiguration.class)
private class EnableAutoConfigurationWithFaultyClassExclude {
}
@EnableAutoConfiguration(excludeName = "org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests.TestConfiguration")
private class EnableAutoConfigurationWithFaultyClassNameExclude {
}
@EnableAutoConfiguration(excludeName = "org.springframework.boot.autoconfigure.DoesNotExist1")
private class EnableAutoConfigurationWithAbsentClassNameExclude {
}
@SpringBootApplication(excludeName = "org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration")
private class SpringBootApplicationWithClassNameExclusions {
}
}