Skip to content

Commit 264edb3

Browse files
committed
Improve initialization of Assume class
Prior to this commit, the org.springframework.tests.Assume class could fail to load resulting in a NoClassDefFoundError if parsing of the 'testGroups' system property failed. This is because the parsing took place while initializing a static field. This commit addresses this issue by moving the 'testGroups' system property lookup to a dedicated method that is lazily invoked upon demand instead of eagerly when loading the Assume class itself. In addition, when an error occurs, TestGroup.parse() now logs the complete original value of the supplied test groups string instead of potentially omitting the "all-" prefix. This results in more informative error messages similar to the following. java.lang.IllegalStateException: Failed to parse 'testGroups' system property: Unable to find test group 'bogus' when parsing testGroups value: 'all-bogus'. Available groups include: [LONG_RUNNING,PERFORMANCE,JMXMP,CI] Issue: SPR-15163
1 parent bb3b1f2 commit 264edb3

File tree

4 files changed

+193
-32
lines changed

4 files changed

+193
-32
lines changed

spring-core/src/test/java/org/springframework/tests/Assume.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,13 +28,14 @@
2828
* conditions hold {@code true}. If the assumption fails, it means the test should be
2929
* skipped.
3030
*
31-
* Tests can be categorized into {@link TestGroup}s. Active groups are enabled using
31+
* <p>Tests can be categorized into {@link TestGroup}s. Active groups are enabled using
3232
* the 'testGroups' system property, usually activated from the gradle command line:
33-
* <pre>
33+
*
34+
* <pre class="code">
3435
* gradle test -PtestGroups="performance"
3536
* </pre>
3637
*
37-
* Groups can be specified as a comma separated list of values, or using the pseudo group
38+
* <p>Groups can be specified as a comma separated list of values, or using the pseudo group
3839
* 'all'. See {@link TestGroup} for a list of valid groups.
3940
*
4041
* @author Rob Winch
@@ -46,7 +47,7 @@
4647
*/
4748
public abstract class Assume {
4849

49-
private static final Set<TestGroup> GROUPS = TestGroup.parse(System.getProperty("testGroups"));
50+
static final String TEST_GROUPS_SYSTEM_PROPERTY = "testGroups";
5051

5152

5253
/**
@@ -55,8 +56,9 @@ public abstract class Assume {
5556
* @throws AssumptionViolatedException if the assumption fails
5657
*/
5758
public static void group(TestGroup group) {
58-
if (!GROUPS.contains(group)) {
59-
throw new AssumptionViolatedException("Requires unspecified group " + group + " from " + GROUPS);
59+
Set<TestGroup> testGroups = loadTestGroups();
60+
if (!testGroups.contains(group)) {
61+
throw new AssumptionViolatedException("Requires unspecified group " + group + " from " + testGroups);
6062
}
6163
}
6264

@@ -70,7 +72,8 @@ public static void group(TestGroup group) {
7072
* @since 4.2
7173
*/
7274
public static void group(TestGroup group, Executable executable) throws Exception {
73-
if (GROUPS.contains(group)) {
75+
Set<TestGroup> testGroups = loadTestGroups();
76+
if (testGroups.contains(group)) {
7477
executable.execute();
7578
}
7679
}
@@ -85,6 +88,21 @@ public static void notLogging(Log log) {
8588
assumeFalse(log.isDebugEnabled());
8689
}
8790

91+
/**
92+
* Load test groups dynamically instead of during static
93+
* initialization in order to avoid a {@link NoClassDefFoundError}
94+
* being thrown while attempting to load the {@code Assume} class.
95+
*/
96+
private static Set<TestGroup> loadTestGroups() {
97+
try {
98+
return TestGroup.parse(System.getProperty(TEST_GROUPS_SYSTEM_PROPERTY));
99+
}
100+
catch (Exception ex) {
101+
throw new IllegalStateException("Failed to parse '" + TEST_GROUPS_SYSTEM_PROPERTY
102+
+ "' system property: " + ex.getMessage(), ex);
103+
}
104+
}
105+
88106

89107
/**
90108
* @since 4.2
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright 2002-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.tests;
18+
19+
import java.util.Arrays;
20+
21+
import org.junit.After;
22+
import org.junit.AssumptionViolatedException;
23+
import org.junit.Before;
24+
import org.junit.Test;
25+
26+
import static java.util.stream.Collectors.*;
27+
import static org.hamcrest.CoreMatchers.*;
28+
import static org.junit.Assert.*;
29+
import static org.springframework.tests.Assume.*;
30+
import static org.springframework.tests.TestGroup.*;
31+
32+
/**
33+
* Tests for {@link Assume}.
34+
*
35+
* @author Sam Brannen
36+
* @since 5.0
37+
*/
38+
public class AssumeTests {
39+
40+
private String originalTestGroups;
41+
42+
43+
@Before
44+
public void trackOriginalTestGroups() {
45+
this.originalTestGroups = System.getProperty(TEST_GROUPS_SYSTEM_PROPERTY);
46+
}
47+
48+
@After
49+
public void restoreOriginalTestGroups() {
50+
if (this.originalTestGroups != null) {
51+
setTestGroups(this.originalTestGroups);
52+
}
53+
else {
54+
setTestGroups("");
55+
}
56+
}
57+
58+
@Test
59+
public void assumeGroupWithNoActiveTestGroups() {
60+
setTestGroups("");
61+
Assume.group(JMXMP);
62+
fail("assumption should have failed");
63+
}
64+
65+
@Test
66+
public void assumeGroupWithNoMatchingActiveTestGroup() {
67+
setTestGroups(PERFORMANCE, CI);
68+
Assume.group(JMXMP);
69+
fail("assumption should have failed");
70+
}
71+
72+
@Test
73+
public void assumeGroupWithMatchingActiveTestGroup() {
74+
setTestGroups(JMXMP);
75+
try {
76+
Assume.group(JMXMP);
77+
}
78+
catch (AssumptionViolatedException ex) {
79+
fail("assumption should NOT have failed");
80+
}
81+
}
82+
83+
@Test
84+
public void assumeGroupWithBogusActiveTestGroup() {
85+
assertBogusActiveTestGroupBehavior("bogus");
86+
}
87+
88+
@Test
89+
public void assumeGroupWithAllMinusBogusActiveTestGroup() {
90+
assertBogusActiveTestGroupBehavior("all-bogus");
91+
}
92+
93+
private void assertBogusActiveTestGroupBehavior(String testGroups) {
94+
// Should result in something similar to the following:
95+
//
96+
// java.lang.IllegalStateException: Failed to parse 'testGroups' system property:
97+
// Unable to find test group 'bogus' when parsing testGroups value: 'all-bogus'.
98+
// Available groups include: [LONG_RUNNING,PERFORMANCE,JMXMP,CI]
99+
100+
setTestGroups(testGroups);
101+
try {
102+
Assume.group(JMXMP);
103+
fail("assumption should have failed");
104+
}
105+
catch (IllegalStateException ex) {
106+
assertThat(ex.getMessage(),
107+
startsWith("Failed to parse '" + TEST_GROUPS_SYSTEM_PROPERTY + "' system property: "));
108+
109+
assertThat(ex.getCause(), instanceOf(IllegalArgumentException.class));
110+
assertThat(ex.getCause().getMessage(),
111+
equalTo("Unable to find test group 'bogus' when parsing testGroups value: '" + testGroups
112+
+ "'. Available groups include: [LONG_RUNNING,PERFORMANCE,JMXMP,CI]"));
113+
}
114+
}
115+
116+
private void setTestGroups(TestGroup... testGroups) {
117+
setTestGroups(Arrays.stream(testGroups).map(TestGroup::name).collect(joining(", ")));
118+
}
119+
120+
private void setTestGroups(String testGroups) {
121+
System.setProperty(TEST_GROUPS_SYSTEM_PROPERTY, testGroups);
122+
}
123+
124+
}

spring-core/src/test/java/org/springframework/tests/TestGroup.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
* @see Assume#group(TestGroup)
3232
* @author Phillip Webb
3333
* @author Chris Beams
34+
* @author Sam Brannen
3435
*/
3536
public enum TestGroup {
3637

@@ -65,23 +66,27 @@ public enum TestGroup {
6566
* Parse the specified comma separated string of groups.
6667
* @param value the comma separated string of groups
6768
* @return a set of groups
69+
* @throws IllegalArgumentException if any specified group name is not a
70+
* valid {@link TestGroup}
6871
*/
69-
public static Set<TestGroup> parse(String value) {
70-
if (value == null || "".equals(value)) {
72+
public static Set<TestGroup> parse(String value) throws IllegalArgumentException {
73+
if (!StringUtils.hasText(value)) {
7174
return Collections.emptySet();
7275
}
76+
String originalValue = value;
77+
value = value.trim();
7378
if ("ALL".equalsIgnoreCase(value)) {
7479
return EnumSet.allOf(TestGroup.class);
7580
}
7681
if (value.toUpperCase().startsWith("ALL-")) {
77-
Set<TestGroup> groups = new HashSet<>(EnumSet.allOf(TestGroup.class));
78-
groups.removeAll(parseGroups(value.substring(4)));
82+
Set<TestGroup> groups = EnumSet.allOf(TestGroup.class);
83+
groups.removeAll(parseGroups(originalValue, value.substring(4)));
7984
return groups;
8085
}
81-
return parseGroups(value);
86+
return parseGroups(originalValue, value);
8287
}
8388

84-
private static Set<TestGroup> parseGroups(String value) {
89+
private static Set<TestGroup> parseGroups(String originalValue, String value) throws IllegalArgumentException {
8590
Set<TestGroup> groups = new HashSet<>();
8691
for (String group : value.split(",")) {
8792
try {
@@ -90,7 +95,7 @@ private static Set<TestGroup> parseGroups(String value) {
9095
catch (IllegalArgumentException ex) {
9196
throw new IllegalArgumentException(format(
9297
"Unable to find test group '%s' when parsing testGroups value: '%s'. " +
93-
"Available groups include: [%s]", group.trim(), value,
98+
"Available groups include: [%s]", group.trim(), originalValue,
9499
StringUtils.arrayToCommaDelimitedString(TestGroup.values())));
95100
}
96101
}

spring-core/src/test/java/org/springframework/tests/TestGroupTests.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818

1919
import java.util.Collections;
2020
import java.util.EnumSet;
21-
import java.util.HashSet;
2221
import java.util.Set;
2322

2423
import org.junit.Rule;
@@ -32,6 +31,7 @@
3231
* Tests for {@link TestGroup}.
3332
*
3433
* @author Phillip Webb
34+
* @author Sam Brannen
3535
*/
3636
public class TestGroupTests {
3737

@@ -40,29 +40,34 @@ public class TestGroupTests {
4040

4141

4242
@Test
43-
public void parseNull() throws Exception {
44-
assertThat(TestGroup.parse(null), equalTo(Collections.<TestGroup> emptySet()));
43+
public void parseNull() {
44+
assertThat(TestGroup.parse(null), equalTo(Collections.emptySet()));
4545
}
4646

4747
@Test
48-
public void parseEmptyString() throws Exception {
49-
assertThat(TestGroup.parse(""), equalTo(Collections.<TestGroup> emptySet()));
48+
public void parseEmptyString() {
49+
assertThat(TestGroup.parse(""), equalTo(Collections.emptySet()));
5050
}
5151

5252
@Test
53-
public void parseWithSpaces() throws Exception {
54-
assertThat(TestGroup.parse("PERFORMANCE, PERFORMANCE"),
55-
equalTo((Set<TestGroup>) EnumSet.of(TestGroup.PERFORMANCE)));
53+
public void parseBlankString() {
54+
assertThat(TestGroup.parse(" "), equalTo(Collections.emptySet()));
5655
}
5756

5857
@Test
59-
public void parseInMixedCase() throws Exception {
58+
public void parseWithSpaces() {
59+
assertThat(TestGroup.parse(" PERFORMANCE, PERFORMANCE "),
60+
equalTo(EnumSet.of(TestGroup.PERFORMANCE)));
61+
}
62+
63+
@Test
64+
public void parseInMixedCase() {
6065
assertThat(TestGroup.parse("performance, PERFormaNCE"),
61-
equalTo((Set<TestGroup>) EnumSet.of(TestGroup.PERFORMANCE)));
66+
equalTo(EnumSet.of(TestGroup.PERFORMANCE)));
6267
}
6368

6469
@Test
65-
public void parseMissing() throws Exception {
70+
public void parseMissing() {
6671
thrown.expect(IllegalArgumentException.class);
6772
thrown.expectMessage("Unable to find test group 'missing' when parsing " +
6873
"testGroups value: 'performance, missing'. Available groups include: " +
@@ -71,15 +76,24 @@ public void parseMissing() throws Exception {
7176
}
7277

7378
@Test
74-
public void parseAll() throws Exception {
75-
assertThat(TestGroup.parse("all"), equalTo((Set<TestGroup>)EnumSet.allOf(TestGroup.class)));
79+
public void parseAll() {
80+
assertThat(TestGroup.parse("all"), equalTo(EnumSet.allOf(TestGroup.class)));
7681
}
7782

7883
@Test
79-
public void parseAllExcept() throws Exception {
80-
Set<TestGroup> expected = new HashSet<>(EnumSet.allOf(TestGroup.class));
84+
public void parseAllExceptPerformance() {
85+
Set<TestGroup> expected = EnumSet.allOf(TestGroup.class);
8186
expected.remove(TestGroup.PERFORMANCE);
8287
assertThat(TestGroup.parse("all-performance"), equalTo(expected));
8388
}
8489

90+
@Test
91+
public void parseAllExceptMissing() {
92+
thrown.expect(IllegalArgumentException.class);
93+
thrown.expectMessage("Unable to find test group 'missing' when parsing " +
94+
"testGroups value: 'all-missing'. Available groups include: " +
95+
"[LONG_RUNNING,PERFORMANCE,JMXMP,CI]");
96+
TestGroup.parse("all-missing");
97+
}
98+
8599
}

0 commit comments

Comments
 (0)