diff --git a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java
index f72dce31da..5212a04071 100644
--- a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java
+++ b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -19,9 +19,8 @@ package org.springframework.test.context;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
@@ -49,8 +48,9 @@ import org.springframework.util.StringUtils;
*
A {@link SmartContextLoader} uses {@code MergedContextConfiguration}
* to load an {@link org.springframework.context.ApplicationContext ApplicationContext}.
*
- *
{@code MergedContextConfiguration} is also used by the {@link TestContext}
- * as the context cache key for caching an
+ *
{@code MergedContextConfiguration} is also used by the
+ * {@link org.springframework.test.context.cache.ContextCache ContextCache}
+ * as the key for caching an
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* that was loaded using properties of this {@code MergedContextConfiguration}.
*
@@ -116,11 +116,9 @@ public class MergedContextConfiguration implements Serializable {
return EMPTY_STRING_ARRAY;
}
- // Active profiles must be unique and sorted in order to support proper
- // cache key generation. Specifically, profile sets {foo,bar} and
- // {bar,foo} must both result in the same array (e.g., [bar,foo]).
- SortedSet sortedProfilesSet = new TreeSet(Arrays.asList(activeProfiles));
- return StringUtils.toStringArray(sortedProfilesSet);
+ // Active profiles must be unique
+ Set profilesSet = new LinkedHashSet(Arrays.asList(activeProfiles));
+ return StringUtils.toStringArray(profilesSet);
}
/**
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java
index 15a281a4de..c2025424c5 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java
@@ -16,7 +16,10 @@
package org.springframework.test.context.support;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -72,7 +75,7 @@ abstract class ActiveProfilesUtils {
static String[] resolveActiveProfiles(Class> testClass) {
Assert.notNull(testClass, "Class must not be null");
- final Set activeProfiles = new HashSet();
+ final List profileArrays = new ArrayList();
Class annotationType = ActiveProfiles.class;
AnnotationDescriptor descriptor = MetaAnnotationUtils.findAnnotationDescriptor(testClass,
@@ -118,14 +121,22 @@ abstract class ActiveProfilesUtils {
throw new IllegalStateException(msg);
}
+ profileArrays.add(profiles);
+
+ descriptor = (annotation.inheritProfiles() ? MetaAnnotationUtils.findAnnotationDescriptor(
+ rootDeclaringClass.getSuperclass(), annotationType) : null);
+ }
+
+ // Reverse the list so that we can traverse "down" the hierarchy.
+ Collections.reverse(profileArrays);
+
+ final Set activeProfiles = new LinkedHashSet();
+ for (String[] profiles : profileArrays) {
for (String profile : profiles) {
if (StringUtils.hasText(profile)) {
activeProfiles.add(profile.trim());
}
}
-
- descriptor = (annotation.inheritProfiles() ? MetaAnnotationUtils.findAnnotationDescriptor(
- rootDeclaringClass.getSuperclass(), annotationType) : null);
}
return StringUtils.toStringArray(activeProfiles);
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DefaultActiveProfilesResolver.java b/spring-test/src/main/java/org/springframework/test/context/support/DefaultActiveProfilesResolver.java
index d03f0f1c1a..e1de32a8cc 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/DefaultActiveProfilesResolver.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/DefaultActiveProfilesResolver.java
@@ -16,7 +16,7 @@
package org.springframework.test.context.support;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -59,7 +59,7 @@ public class DefaultActiveProfilesResolver implements ActiveProfilesResolver {
public String[] resolve(Class> testClass) {
Assert.notNull(testClass, "Class must not be null");
- final Set activeProfiles = new HashSet();
+ final Set activeProfiles = new LinkedHashSet();
Class annotationType = ActiveProfiles.class;
AnnotationDescriptor descriptor = findAnnotationDescriptor(testClass, annotationType);
diff --git a/spring-test/src/test/java/org/springframework/test/context/MergedContextConfigurationTests.java b/spring-test/src/test/java/org/springframework/test/context/MergedContextConfigurationTests.java
index ea0521afc3..bf8eba0403 100644
--- a/spring-test/src/test/java/org/springframework/test/context/MergedContextConfigurationTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/MergedContextConfigurationTests.java
@@ -141,7 +141,7 @@ public class MergedContextConfigurationTests {
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, activeProfiles1, loader);
MergedContextConfiguration mergedConfig2 = new MergedContextConfiguration(getClass(),
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, activeProfiles2, loader);
- assertEquals(mergedConfig1.hashCode(), mergedConfig2.hashCode());
+ assertNotEquals(mergedConfig1.hashCode(), mergedConfig2.hashCode());
}
@Test
@@ -337,7 +337,7 @@ public class MergedContextConfigurationTests {
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, activeProfiles1, loader);
MergedContextConfiguration mergedConfig2 = new MergedContextConfiguration(getClass(),
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, activeProfiles2, loader);
- assertEquals(mergedConfig1, mergedConfig2);
+ assertNotEquals(mergedConfig1, mergedConfig2);
}
@Test
diff --git a/spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java b/spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java
index be0440a504..5d518d3c8f 100644
--- a/spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java
@@ -86,14 +86,15 @@ public class ContextCacheTests {
@Test
public void verifyCacheKeyIsBasedOnActiveProfiles() {
- loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 0, 1);
- loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 1, 1);
- // Profiles {foo, bar} should hash to the same as {bar,foo}
- loadCtxAndAssertStats(BarFooProfilesTestCase.class, 1, 2, 1);
- loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 3, 1);
- loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 4, 1);
- loadCtxAndAssertStats(BarFooProfilesTestCase.class, 1, 5, 1);
- loadCtxAndAssertStats(FooBarActiveProfilesResolverTestCase.class, 1, 6, 1);
+ int size = 0, hit = 0, miss = 0;
+ loadCtxAndAssertStats(FooBarProfilesTestCase.class, ++size, hit, ++miss);
+ loadCtxAndAssertStats(FooBarProfilesTestCase.class, size, ++hit, miss);
+ // Profiles {foo, bar} should not hash to the same as {bar,foo}
+ loadCtxAndAssertStats(BarFooProfilesTestCase.class, ++size, hit, ++miss);
+ loadCtxAndAssertStats(FooBarProfilesTestCase.class, size, ++hit, miss);
+ loadCtxAndAssertStats(FooBarProfilesTestCase.class, size, ++hit, miss);
+ loadCtxAndAssertStats(BarFooProfilesTestCase.class, size, ++hit, miss);
+ loadCtxAndAssertStats(FooBarActiveProfilesResolverTestCase.class, size, ++hit, miss);
}
@Test
diff --git a/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java
index 6663128e8b..23eade78e0 100644
--- a/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -164,12 +164,12 @@ abstract class AbstractContextConfigurationUtilsTests {
}
@ContextConfiguration(locations = "/foo.xml", inheritLocations = false)
- @ActiveProfiles(profiles = "foo")
+ @ActiveProfiles("foo")
static class LocationsFoo {
}
@ContextConfiguration(classes = FooConfig.class, inheritLocations = false)
- @ActiveProfiles(profiles = "foo")
+ @ActiveProfiles("foo")
static class ClassesFoo {
}
@@ -198,14 +198,14 @@ abstract class AbstractContextConfigurationUtilsTests {
}
@ContextConfiguration(locations = "/foo.properties", loader = GenericPropertiesContextLoader.class)
- @ActiveProfiles(profiles = "foo")
+ @ActiveProfiles("foo")
static class PropertiesLocationsFoo {
}
// Combining @Configuration classes with a Properties based loader doesn't really make
// sense, but that's OK for unit testing purposes.
@ContextConfiguration(classes = FooConfig.class, loader = GenericPropertiesContextLoader.class)
- @ActiveProfiles(profiles = "foo")
+ @ActiveProfiles("foo")
static class PropertiesClassesFoo {
}
diff --git a/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java
index ceb19dde6d..f9f4013c39 100644
--- a/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java
@@ -22,9 +22,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import org.junit.Test;
@@ -47,27 +45,22 @@ import static org.springframework.test.context.support.ActiveProfilesUtils.*;
public class ActiveProfilesUtilsTests extends AbstractContextConfigurationUtilsTests {
private void assertResolvedProfiles(Class> testClass, String... expected) {
- assertNotNull(testClass);
- assertNotNull(expected);
- String[] actual = resolveActiveProfiles(testClass);
- Set expectedSet = new HashSet(Arrays.asList(expected));
- Set actualSet = new HashSet(Arrays.asList(actual));
- assertEquals(expectedSet, actualSet);
+ assertArrayEquals(expected, resolveActiveProfiles(testClass));
}
@Test
public void resolveActiveProfilesWithoutAnnotation() {
- assertArrayEquals(EMPTY_STRING_ARRAY, resolveActiveProfiles(Enigma.class));
+ assertResolvedProfiles(Enigma.class, EMPTY_STRING_ARRAY);
}
@Test
public void resolveActiveProfilesWithNoProfilesDeclared() {
- assertArrayEquals(EMPTY_STRING_ARRAY, resolveActiveProfiles(BareAnnotations.class));
+ assertResolvedProfiles(BareAnnotations.class, EMPTY_STRING_ARRAY);
}
@Test
public void resolveActiveProfilesWithEmptyProfiles() {
- assertArrayEquals(EMPTY_STRING_ARRAY, resolveActiveProfiles(EmptyProfiles.class));
+ assertResolvedProfiles(EmptyProfiles.class, EMPTY_STRING_ARRAY);
}
@Test
@@ -75,6 +68,11 @@ public class ActiveProfilesUtilsTests extends AbstractContextConfigurationUtilsT
assertResolvedProfiles(DuplicatedProfiles.class, "foo", "bar", "baz");
}
+ @Test
+ public void resolveActiveProfilesWithLocalAndInheritedDuplicatedProfiles() {
+ assertResolvedProfiles(ExtendedDuplicatedProfiles.class, "foo", "bar", "baz", "cat", "dog");
+ }
+
@Test
public void resolveActiveProfilesWithLocalAnnotation() {
assertResolvedProfiles(LocationsFoo.class, "foo");
@@ -252,6 +250,10 @@ public class ActiveProfilesUtilsTests extends AbstractContextConfigurationUtilsT
private static class DuplicatedProfiles {
}
+ @ActiveProfiles({ "cat", "dog", " foo", "bar ", "cat" })
+ private static class ExtendedDuplicatedProfiles extends DuplicatedProfiles {
+ }
+
@ActiveProfiles(profiles = { "dog", "cat" }, inheritProfiles = false)
private static class Animals extends LocationsBar {
}