/*
* 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.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.Ordered;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link AutoConfigurationSorter}.
*
* @author Phillip Webb
*/
public class AutoConfigurationSorterTests {
private static final String LOWEST = OrderLowest.class.getName();
private static final String HIGHEST = OrderHighest.class.getName();
private static final String A = AutoConfigureA.class.getName();
private static final String B = AutoConfigureB.class.getName();
private static final String C = AutoConfigureC.class.getName();
private static final String D = AutoConfigureD.class.getName();
private static final String E = AutoConfigureE.class.getName();
private static final String W = AutoConfigureW.class.getName();
private static final String X = AutoConfigureX.class.getName();
private static final String Y = AutoConfigureY.class.getName();
private static final String Z = AutoConfigureZ.class.getName();
private static final String A2 = AutoConfigureA2.class.getName();
private static final String W2 = AutoConfigureW2.class.getName();
@Rule
public ExpectedException thrown = ExpectedException.none();
private AutoConfigurationSorter sorter;
private AutoConfigurationMetadata autoConfigurationMetadata = mock(
AutoConfigurationMetadata.class);
@Before
public void setup() {
this.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory(),
this.autoConfigurationMetadata);
}
@Test
public void byOrderAnnotation() throws Exception {
List<String> actual = this.sorter
.getInPriorityOrder(Arrays.asList(LOWEST, HIGHEST));
assertThat(actual).containsExactly(HIGHEST, LOWEST);
}
@Test
public void byAutoConfigureAfter() throws Exception {
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B, C));
assertThat(actual).containsExactly(C, B, A);
}
@Test
public void byAutoConfigureBefore() throws Exception {
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(X, Y, Z));
assertThat(actual).containsExactly(Z, Y, X);
}
@Test
public void byAutoConfigureAfterDoubles() throws Exception {
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, E));
assertThat(actual).containsExactly(C, E, B, A);
}
@Test
public void byAutoConfigureMixedBeforeAndAfter() throws Exception {
List<String> actual = this.sorter
.getInPriorityOrder(Arrays.asList(A, B, C, W, X));
assertThat(actual).containsExactly(C, W, B, A, X);
}
@Test
public void byAutoConfigureMixedBeforeAndAfterWithClassNames() throws Exception {
List<String> actual = this.sorter
.getInPriorityOrder(Arrays.asList(A2, B, C, W2, X));
assertThat(actual).containsExactly(C, W2, B, A2, X);
}
@Test
public void byAutoConfigureMixedBeforeAndAfterWithDifferentInputOrder()
throws Exception {
List<String> actual = this.sorter
.getInPriorityOrder(Arrays.asList(W, X, A, B, C));
assertThat(actual).containsExactly(C, W, B, A, X);
}
@Test
public void byAutoConfigureAfterWithMissing() throws Exception {
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B));
assertThat(actual).containsExactly(B, A);
}
@Test
public void byAutoConfigureAfterWithCycle() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("AutoConfigure cycle detected");
this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, D));
}
@Test
public void usesAnnotationPropertiesWhenPossible() throws Exception {
MetadataReaderFactory readerFactory = mock(MetadataReaderFactory.class);
this.autoConfigurationMetadata = getAutoConfigurationMetadata(A2, B, C, W2, X);
this.sorter = new AutoConfigurationSorter(readerFactory,
this.autoConfigurationMetadata);
List<String> actual = this.sorter
.getInPriorityOrder(Arrays.asList(A2, B, C, W2, X));
assertThat(actual).containsExactly(C, W2, B, A2, X);
}
private AutoConfigurationMetadata getAutoConfigurationMetadata(String... classNames)
throws Exception {
Properties properties = new Properties();
for (String className : classNames) {
Class<?> type = ClassUtils.forName(className, null);
properties.put(type.getName(), "");
AutoConfigureOrder order = type
.getDeclaredAnnotation(AutoConfigureOrder.class);
if (order != null) {
properties.put(className + ".AutoConfigureOrder",
String.valueOf(order.value()));
}
AutoConfigureBefore autoConfigureBefore = type
.getDeclaredAnnotation(AutoConfigureBefore.class);
if (autoConfigureBefore != null) {
properties.put(className + ".AutoConfigureBefore",
merge(autoConfigureBefore.value(), autoConfigureBefore.name()));
}
AutoConfigureAfter autoConfigureAfter = type
.getDeclaredAnnotation(AutoConfigureAfter.class);
if (autoConfigureAfter != null) {
properties.put(className + ".AutoConfigureAfter",
merge(autoConfigureAfter.value(), autoConfigureAfter.name()));
}
}
return AutoConfigurationMetadataLoader.loadMetadata(properties);
}
private String merge(Class<?>[] value, String[] name) {
Set<String> items = new LinkedHashSet<>();
for (Class<?> type : value) {
items.add(type.getName());
}
for (String type : name) {
items.add(type);
}
return StringUtils.collectionToCommaDelimitedString(items);
}
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public static class OrderLowest {
}
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public static class OrderHighest {
}
@AutoConfigureAfter(AutoConfigureB.class)
public static class AutoConfigureA {
}
@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureB")
public static class AutoConfigureA2 {
}
@AutoConfigureAfter({ AutoConfigureC.class, AutoConfigureD.class,
AutoConfigureE.class })
public static class AutoConfigureB {
}
public static class AutoConfigureC {
}
@AutoConfigureAfter(AutoConfigureA.class)
public static class AutoConfigureD {
}
public static class AutoConfigureE {
}
@AutoConfigureBefore(AutoConfigureB.class)
public static class AutoConfigureW {
}
@AutoConfigureBefore(name = "org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureB")
public static class AutoConfigureW2 {
}
public static class AutoConfigureX {
}
@AutoConfigureBefore(AutoConfigureX.class)
public static class AutoConfigureY {
}
@AutoConfigureBefore(AutoConfigureY.class)
public static class AutoConfigureZ {
}
}