Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrates DependencyTests to ArchUnit. #4315

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
9 changes: 5 additions & 4 deletions spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.0-archunit-dependency-tests-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand All @@ -23,6 +23,7 @@
<java-module-name>spring.data.mongodb</java-module-name>
<project.root>${basedir}/..</project.root>
<multithreadedtc>1.01</multithreadedtc>
<archunit.version>1.0.1</archunit.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -250,9 +251,9 @@
</dependency>

<dependency>
<groupId>de.schauderhaft.degraph</groupId>
<artifactId>degraph-check</artifactId>
<version>0.1.4</version>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit</artifactId>
<version>${archunit.version}</version>
<scope>test</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
*/
package org.springframework.data.mongodb;

import static de.schauderhaft.degraph.check.JCheck.*;
import static org.hamcrest.MatcherAssert.*;

import de.schauderhaft.degraph.configuration.NamedPattern;

import org.junit.jupiter.api.Disabled;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.dependencies.SliceAssignment;
import com.tngtech.archunit.library.dependencies.SliceIdentifier;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;

/**
Expand All @@ -29,49 +33,138 @@
* @author Jens Schauder
* @author Oliver Gierke
*/
@Disabled("Needs to be tansitioned to ArchUnit")
class DependencyTests {

@Test
void noInternalPackageCycles() {

assertThat(classpath() //
.noJars() //
.including("org.springframework.data.mongodb.**") //
.filterClasspath("*target/classes") //
.printOnFailure("degraph.graphml"), //
violationFree() //
);
void cycleFree() {

JavaClasses importedClasses = new ClassFileImporter() //
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) //
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) // we just analyze the code of this module.
.importPackages("org.springframework.data.mongodb").that( //
onlySpringData() //
);

ArchRule rule = SlicesRuleDefinition.slices() //
.matching("org.springframework.data.mongodb.(**)") //
.should() //
.beFreeOfCycles();

rule.check(importedClasses);
}

@Test
void acrossModules() {

JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages( //
"org.springframework.data.mongodb", // Spring Data Relational
"org.springframework.data" // Spring Data Commons
).that(onlySpringData());

ArchRule rule = SlicesRuleDefinition.slices() //
.assignedFrom(subModuleSlicing()) //
.should().beFreeOfCycles();

rule.check(importedClasses);
}

@Test
void onlyConfigMayUseRepository() {

assertThat(classpath() //
.including("org.springframework.data.**") //
.filterClasspath("*target/classes") //
.printOnFailure("onlyConfigMayUseRepository.graphml") //
.withSlicing("slices", //
"**.(config).**", //
new NamedPattern("**.cdi.**", "config"), //
"**.(repository).**", //
new NamedPattern("**", "other"))
.allow("config", "repository", "other"), //
violationFree() //
);
// GH-1058
void testGetFirstPackagePart() {

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(getFirstPackagePart("a.b.c")).isEqualTo("a");
softly.assertThat(getFirstPackagePart("a")).isEqualTo("a");
});
}

@Test
void commonsInternaly() {

assertThat(classpath() //
.noJars() //
.including("org.springframework.data.**") //
.excluding("org.springframework.data.mongodb.**") //
.filterClasspath("*target/classes") //
.printTo("commons.graphml"), //
violationFree() //
);
// GH-1058
void testSubModule() {

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(subModule("a.b", "a.b.c.d")).isEqualTo("c");
softly.assertThat(subModule("a.b", "a.b.c")).isEqualTo("c");
softly.assertThat(subModule("a.b", "a.b")).isEqualTo("");
});
}

private DescribedPredicate<JavaClass> onlySpringData() {

return new DescribedPredicate<>("Spring Data Classes") {
@Override
public boolean test(JavaClass input) {
return input.getPackageName().startsWith("org.springframework.data");
}
};
}

private DescribedPredicate<JavaClass> ignore(Class<?> type) {

return new DescribedPredicate<>("ignored class " + type.getName()) {
@Override
public boolean test(JavaClass input) {
return !input.getFullName().startsWith(type.getName());
}
};
}

private DescribedPredicate<JavaClass> ignorePackage(String type) {

return new DescribedPredicate<>("ignored class " + type) {
@Override
public boolean test(JavaClass input) {
return !input.getPackageName().equals(type);
}
};
}

private String getFirstPackagePart(String subpackage) {

int index = subpackage.indexOf(".");
if (index < 0) {
return subpackage;
}
return subpackage.substring(0, index);
}

private String subModule(String basePackage, String packageName) {

if (packageName.startsWith(basePackage) && packageName.length() > basePackage.length()) {

final int index = basePackage.length() + 1;
String subpackage = packageName.substring(index);
return getFirstPackagePart(subpackage);
}
return "";
}

private SliceAssignment subModuleSlicing() {
return new SliceAssignment() {

@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {

String packageName = javaClass.getPackageName();

String subModule = subModule("org.springframework.data.mongodb", packageName);
if (!subModule.isEmpty()) {
return SliceIdentifier.of(subModule);
}

subModule = subModule("org.springframework.data", packageName);
if (!subModule.isEmpty()) {
return SliceIdentifier.of(subModule);
}

return SliceIdentifier.ignore();
}

@Override
public String getDescription() {
return "Submodule";
}
};
}
}