Skip to content

Commit 58bf556

Browse files
committed
Dependency tests are now based on ArchUnit.
Replaced ignored tests with exclusion of packages and classes. Upgraded ArchUnit dependency to 1.0.0. Closes #1354
1 parent 6bdc7db commit 58bf556

File tree

5 files changed

+174
-57
lines changed

5 files changed

+174
-57
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
<!-- test utilities-->
4343
<awaitility.version>4.2.0</awaitility.version>
44-
<archunit.version>0.23.1</archunit.version>
44+
<archunit.version>1.0.0</archunit.version>
4545
</properties>
4646

4747
<inceptionYear>2017</inceptionYear>

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package org.springframework.data.jdbc;
1717

1818
import org.assertj.core.api.SoftAssertions;
19-
import org.junit.jupiter.api.Disabled;
2019
import org.junit.jupiter.api.Test;
2120
import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser;
2221

@@ -43,10 +42,9 @@ void cycleFree() {
4342
JavaClasses importedClasses = new ClassFileImporter() //
4443
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) //
4544
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) // we just analyze the code of this module.
46-
.importPackages("org.springframework.data.jdbc")
47-
.that( //
48-
onlySpringData() //
49-
);
45+
.importPackages("org.springframework.data.jdbc").that( //
46+
onlySpringData() //
47+
);
5048

5149
ArchRule rule = SlicesRuleDefinition.slices() //
5250
.matching("org.springframework.data.jdbc.(**)") //
@@ -57,17 +55,17 @@ void cycleFree() {
5755
}
5856

5957
@Test
60-
@Disabled("Cycle in Spring Data Commons")
6158
void acrossModules() {
6259

63-
JavaClasses importedClasses = new ClassFileImporter()
64-
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
60+
JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
6561
.importPackages( //
6662
"org.springframework.data.jdbc", // Spring Data Relational
6763
"org.springframework.data.relational", // Spring Data Relational
6864
"org.springframework.data" // Spring Data Commons
6965
).that(onlySpringData()) //
70-
.that(ignore(AuditingHandlerBeanDefinitionParser.class));
66+
.that(ignore(AuditingHandlerBeanDefinitionParser.class)) //
67+
.that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
68+
.that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons
7169

7270
ArchRule rule = SlicesRuleDefinition.slices() //
7371
.assignedFrom(subModuleSlicing()) //
@@ -99,7 +97,7 @@ private DescribedPredicate<JavaClass> onlySpringData() {
9997

10098
return new DescribedPredicate<>("Spring Data Classes") {
10199
@Override
102-
public boolean apply(JavaClass input) {
100+
public boolean test(JavaClass input) {
103101
return input.getPackageName().startsWith("org.springframework.data");
104102
}
105103
};
@@ -109,12 +107,22 @@ private DescribedPredicate<JavaClass> ignore(Class<?> type) {
109107

110108
return new DescribedPredicate<>("ignored class " + type.getName()) {
111109
@Override
112-
public boolean apply(JavaClass input) {
110+
public boolean test(JavaClass input) {
113111
return !input.getFullName().startsWith(type.getName());
114112
}
115113
};
116114
}
117115

116+
private DescribedPredicate<JavaClass> ignorePackage(String type) {
117+
118+
return new DescribedPredicate<>("ignored class " + type) {
119+
@Override
120+
public boolean test(JavaClass input) {
121+
return !input.getPackageName().equals(type);
122+
}
123+
};
124+
}
125+
118126
private String getFirstPackagePart(String subpackage) {
119127

120128
int index = subpackage.indexOf(".");

spring-data-r2dbc/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@
306306
<scope>test</scope>
307307
</dependency>
308308

309+
<dependency>
310+
<groupId>com.tngtech.archunit</groupId>
311+
<artifactId>archunit</artifactId>
312+
<version>${archunit.version}</version>
313+
<scope>test</scope>
314+
</dependency>
309315
</dependencies>
310316

311317
<build>

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/DependencyTests.java

Lines changed: 133 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
*/
1616
package org.springframework.data.r2dbc;
1717

18-
import static de.schauderhaft.degraph.check.JCheck.*;
19-
import static org.junit.Assert.*;
20-
21-
import de.schauderhaft.degraph.check.JCheck;
22-
import de.schauderhaft.degraph.configuration.NamedPattern;
23-
import scala.runtime.AbstractFunction1;
24-
25-
import org.junit.Assume;
18+
import org.assertj.core.api.SoftAssertions;
2619
import org.junit.jupiter.api.Disabled;
2720
import org.junit.jupiter.api.Test;
2821

22+
import com.tngtech.archunit.base.DescribedPredicate;
23+
import com.tngtech.archunit.core.domain.JavaClass;
24+
import com.tngtech.archunit.core.domain.JavaClasses;
25+
import com.tngtech.archunit.core.importer.ClassFileImporter;
26+
import com.tngtech.archunit.core.importer.ImportOption;
27+
import com.tngtech.archunit.lang.ArchRule;
28+
import com.tngtech.archunit.library.dependencies.SliceAssignment;
29+
import com.tngtech.archunit.library.dependencies.SliceIdentifier;
30+
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
31+
2932
/**
3033
* Test package dependencies for violations.
3134
*
@@ -35,40 +38,131 @@
3538
public class DependencyTests {
3639

3740
@Test // DATAJDBC-114
38-
public void cycleFree() {
39-
40-
Assume.assumeThat( //
41-
classpath() //
42-
.noJars() //
43-
.including("org.springframework.data.jdbc.**") //
44-
.including("org.springframework.data.relational.**") //
45-
.including("org.springframework.data.r2dbc.**") //
46-
.filterClasspath("*target/classes") // exclude test code
47-
.withSlicing("modules", "org.springframework.data.(*).**").printOnFailure("degraph.graphml"),
48-
JCheck.violationFree());
41+
void cycleFree() {
42+
43+
JavaClasses importedClasses = new ClassFileImporter() //
44+
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) //
45+
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) // we just analyze the code of this module.
46+
.importPackages("org.springframework.data.r2dbc").that( //
47+
onlySpringData() //
48+
);
49+
50+
ArchRule rule = SlicesRuleDefinition.slices() //
51+
.matching("org.springframework.data.r2dbc.(**)") //
52+
.should() //
53+
.beFreeOfCycles();
54+
55+
rule.check(importedClasses);
4956
}
5057

5158
@Test // DATAJDBC-220
52-
public void acrossModules() {
53-
54-
assertThat( //
55-
classpath() //
56-
// include only Spring Data related classes (for example no JDK code)
57-
.including("org.springframework.data.**") //
58-
.filterClasspath(new AbstractFunction1<String, Object>() {
59-
@Override
60-
public Object apply(String s) { //
61-
// only the current module + commons
62-
return s.endsWith("target/classes") || s.contains("spring-data-commons");
63-
}
64-
}) // exclude test code
65-
.withSlicing("sub-modules", // sub-modules are defined by any of the following pattern.
66-
"org.springframework.data.jdbc.(**).*", //
67-
"org.springframework.data.relational.(**).*", //
68-
new NamedPattern("org.springframework.data.r2dbc.**", "repository.reactive"), //
69-
"org.springframework.data.(**).*") //
70-
.printTo("degraph-across-modules.graphml"), // writes a graphml to this location
71-
JCheck.violationFree());
59+
void acrossModules() {
60+
61+
JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
62+
.importPackages( //
63+
"org.springframework.data.r2dbc", // Spring Data Relational
64+
"org.springframework.data.relational", // Spring Data Relational
65+
"org.springframework.data" // Spring Data Commons
66+
).that(onlySpringData()) //
67+
.that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
68+
.that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons
69+
70+
ArchRule rule = SlicesRuleDefinition.slices() //
71+
.assignedFrom(subModuleSlicing()) //
72+
.should().beFreeOfCycles();
73+
74+
rule.check(importedClasses);
75+
}
76+
77+
@Test // GH-1058
78+
void testGetFirstPackagePart() {
79+
80+
SoftAssertions.assertSoftly(softly -> {
81+
softly.assertThat(getFirstPackagePart("a.b.c")).isEqualTo("a");
82+
softly.assertThat(getFirstPackagePart("a")).isEqualTo("a");
83+
});
84+
}
85+
86+
private DescribedPredicate<JavaClass> onlySpringData() {
87+
88+
return new DescribedPredicate<>("Spring Data Classes") {
89+
@Override
90+
public boolean test(JavaClass input) {
91+
return input.getPackageName().startsWith("org.springframework.data");
92+
}
93+
};
94+
}
95+
96+
private DescribedPredicate<JavaClass> ignore(Class<?> type) {
97+
98+
return new DescribedPredicate<>("ignored class " + type.getName()) {
99+
@Override
100+
public boolean test(JavaClass input) {
101+
return !input.getFullName().startsWith(type.getName());
102+
}
103+
};
72104
}
73105

106+
private DescribedPredicate<JavaClass> ignorePackage(String type) {
107+
108+
return new DescribedPredicate<>("ignored class " + type) {
109+
@Override
110+
public boolean test(JavaClass input) {
111+
return !input.getPackageName().equals(type);
112+
}
113+
};
114+
}
115+
116+
private String getFirstPackagePart(String subpackage) {
117+
118+
int index = subpackage.indexOf(".");
119+
if (index < 0) {
120+
return subpackage;
121+
}
122+
return subpackage.substring(0, index);
123+
}
124+
125+
private String subModule(String basePackage, String packageName) {
126+
127+
if (packageName.startsWith(basePackage) && packageName.length() > basePackage.length()) {
128+
129+
final int index = basePackage.length() + 1;
130+
String subpackage = packageName.substring(index);
131+
return getFirstPackagePart(subpackage);
132+
}
133+
return "";
134+
}
135+
136+
private SliceAssignment subModuleSlicing() {
137+
return new SliceAssignment() {
138+
139+
@Override
140+
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
141+
142+
String packageName = javaClass.getPackageName();
143+
144+
String subModule = subModule("org.springframework.data.jdbc", packageName);
145+
if (!subModule.isEmpty()) {
146+
return SliceIdentifier.of(subModule);
147+
}
148+
149+
subModule = subModule("org.springframework.data.relational", packageName);
150+
if (!subModule.isEmpty()) {
151+
return SliceIdentifier.of(subModule);
152+
}
153+
154+
subModule = subModule("org.springframework.data", packageName);
155+
if (!subModule.isEmpty()) {
156+
return SliceIdentifier.of(subModule);
157+
}
158+
159+
return SliceIdentifier.ignore();
160+
}
161+
162+
@Override
163+
public String getDescription() {
164+
return "Submodule";
165+
}
166+
};
167+
}
74168
}

spring-data-relational/src/test/java/org/springframework/data/relational/DependencyTests.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package org.springframework.data.relational;
1717

1818
import org.assertj.core.api.SoftAssertions;
19-
import org.junit.jupiter.api.Disabled;
2019
import org.junit.jupiter.api.Test;
2120
import org.springframework.data.relational.core.dialect.RenderContextFactory;
2221
import org.springframework.data.relational.core.sql.render.SelectRenderContext;
@@ -59,16 +58,16 @@ void cycleFree() {
5958
}
6059

6160
@Test
62-
@Disabled("Cycle in Spring Data Commons")
6361
void acrossModules() {
6462

6563
JavaClasses importedClasses = new ClassFileImporter() //
6664
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) //
6765
.importPackages( //
6866
"org.springframework.data.relational", // Spring Data Relational
6967
"org.springframework.data" // Spring Data Commons
70-
).that(onlySpringData());
71-
68+
).that(onlySpringData()) //
69+
.that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
70+
.that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons;
7271

7372
ArchRule rule = SlicesRuleDefinition.slices() //
7473
.assignedFrom(subModuleSlicing()) //
@@ -100,7 +99,7 @@ private DescribedPredicate<JavaClass> onlySpringData() {
10099

101100
return new DescribedPredicate<>("Spring Data Classes") {
102101
@Override
103-
public boolean apply(JavaClass input) {
102+
public boolean test(JavaClass input) {
104103
return input.getPackageName().startsWith("org.springframework.data");
105104
}
106105
};
@@ -110,12 +109,22 @@ private DescribedPredicate<JavaClass> ignore(Class<?> type) {
110109

111110
return new DescribedPredicate<>("ignored class " + type.getName()) {
112111
@Override
113-
public boolean apply(JavaClass input) {
112+
public boolean test(JavaClass input) {
114113
return !input.getFullName().startsWith(type.getName());
115114
}
116115
};
117116
}
118117

118+
private DescribedPredicate<JavaClass> ignorePackage(String type) {
119+
120+
return new DescribedPredicate<>("ignored class " + type) {
121+
@Override
122+
public boolean test(JavaClass input) {
123+
return !input.getPackageName().equals(type);
124+
}
125+
};
126+
}
127+
119128
private String getFirstPackagePart(String subpackage) {
120129

121130
int index = subpackage.indexOf(".");

0 commit comments

Comments
 (0)