Skip to content

Commit

Permalink
Do not allow a secondary to call its own context's primary
Browse files Browse the repository at this point in the history
  • Loading branch information
onepunchmagne committed Sep 14, 2022
1 parent df5962f commit 430c60f
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package {{packageName}};

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.*;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
Expand All @@ -15,7 +16,6 @@ import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Component;
Expand All @@ -31,23 +31,19 @@ class HexagonalArchTest {
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages(ROOT_PACKAGE);
private static final Collection<String> businessContexts = buildBusinessContexts();
private static final Collection<String> sharedKernels = buildSharedKernels();
// the empty package is related to: https://github.com/TNG/ArchUnit/issues/191#issuecomment-507964792
private static final Collection<String> vanillaPackages = Arrays.asList("java..", "");
private static final Collection<String> commonToolsAndUtilsPackages = Arrays.asList("org.slf4j..", "org.apache.commons..", "com.google.guava..");
private static final Collection<String> businessContexts = getPackageAnnotatedBy(BusinessContext.class);
private static final Collection<String> businessContextsPackages = toPackages(businessContexts);
private static final Collection<String> sharedKernelsPackages = toPackages(sharedKernels);
private static Collection<String> buildBusinessContexts() {
return getPackageAnnotatedBy(BusinessContext.class);
}
private static final Collection<String> sharedKernels = getPackageAnnotatedBy(SharedKernel.class);
private static final Collection<String> sharedKernelsPackages = toPackages(sharedKernels);
private static Collection<String> buildSharedKernels() {
return getPackageAnnotatedBy(SharedKernel.class);
}
// the empty package is related to: https://github.com/TNG/ArchUnit/issues/191#issuecomment-507964792
private static final Collection<String> vanillaPackages = Arrays.asList("java..", "");
private static final Collection<String> commonToolsAndUtilsPackages = Arrays.asList(
"org.slf4j..",
"org.apache.commons..",
"com.google.guava.."
);
private static Collection<String> toPackages(Collection<String> packages) {
return packages.stream().map(path -> path + "..").toList();
Expand Down Expand Up @@ -121,6 +117,7 @@ class HexagonalArchTest {
.onlyBeAccessed()
.byClassesThat()
.resideInAPackage("..secondary..")
.because("To interact between two contexts, secondary from context A should call a primary Java adapter (naming convention starting with 'Java') from context B")
.check(classes);
}

Expand All @@ -137,11 +134,11 @@ class HexagonalArchTest {
sharedKernelsPackages.forEach(kernel ->
noClasses()
.that()
.resideInAnyPackage(kernel)
.resideInAPackage(kernel)
.should()
.dependOnClassesThat()
.resideInAnyPackage(businessContextsPackages.toArray(String[]::new))
.because("Shared kernels should not have dependencies to bounded contexts")
.because("Shared kernels should not have dependencies to bounded contexts, only the opposite is allowed")
.check(classes)
);
}
Expand All @@ -154,7 +151,7 @@ class HexagonalArchTest {
void shouldNotDependOnOutside() {
classes()
.that()
.resideInAnyPackage(".domain..")
.resideInAPackage(".domain..")
.should()
.onlyDependOnClassesThat()
.resideInAnyPackage(authorizedContextPackages(".domain.."))
Expand All @@ -163,7 +160,10 @@ class HexagonalArchTest {
}

private String[] authorizedContextPackages(String packageName) {
return Stream.of(List.of(packageName), vanillaPackages, commonToolsAndUtilsPackages, sharedKernelsPackages).flatMap(Collection::stream).toArray(String[]::new);
return Stream
.of(List.of(packageName), vanillaPackages, commonToolsAndUtilsPackages, sharedKernelsPackages)
.flatMap(Collection::stream)
.toArray(String[]::new);
}
}

Expand All @@ -174,10 +174,10 @@ class HexagonalArchTest {
void shouldNotDependOnInfrastructure() {
noClasses()
.that()
.resideInAnyPackage("..application..")
.resideInAPackage("..application..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..infrastructure..")
.resideInAPackage("..infrastructure..")
.because("Application should only depend on domain, not on infrastructure")
.check(classes);
}
Expand All @@ -190,10 +190,10 @@ class HexagonalArchTest {
void shouldNotDependOnSecondary() {
noClasses()
.that()
.resideInAnyPackage("..primary..")
.resideInAPackage("..primary..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..secondary..")
.resideInAPackage("..secondary..")
.because("Primary should not interact with secondary")
.check(classes);
}
Expand All @@ -211,12 +211,26 @@ class HexagonalArchTest {
void shouldNotDependOnApplication() {
noClasses()
.that()
.resideInAnyPackage("..infrastructure.secondary..")
.resideInAPackage("..infrastructure.secondary..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..application..")
.resideInAPackage("..application..")
.because("Secondary should not depend on application")
.check(classes);
}

@Test
void shouldNotDependOnSameContextPrimary() {
Stream.concat(businessContexts.stream(), sharedKernels.stream()).forEach(context -> {
noClasses()
.that()
.resideInAPackage(context + ".infrastructure.secondary..")
.should()
.dependOnClassesThat()
.resideInAPackage(context + ".infrastructure.primary")
.because("Secondary should not loop to its own context's primary")
.check(classes);
});
}
}
}
55 changes: 33 additions & 22 deletions src/test/java/tech/jhipster/lite/HexagonalArchTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ class HexagonalArchTest {
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages(ROOT_PACKAGE);

private static final Collection<String> businessContexts = buildBusinessContexts();
private static final Collection<String> sharedKernels = buildSharedKernels();
private static final Collection<String> businessContexts = getPackageAnnotatedBy(BusinessContext.class);
private static final Collection<String> businessContextsPackages = toPackages(businessContexts);

private static final Collection<String> sharedKernels = getPackageAnnotatedBy(SharedKernel.class);
private static final Collection<String> sharedKernelsPackages = toPackages(sharedKernels);

// the empty package is related to: https://github.com/TNG/ArchUnit/issues/191#issuecomment-507964792
private static final Collection<String> vanillaPackages = Arrays.asList("java..", "");
Expand All @@ -42,17 +45,6 @@ class HexagonalArchTest {
"com.google.guava.."
);

private static final Collection<String> businessContextsPackages = toPackages(businessContexts);
private static final Collection<String> sharedKernelsPackages = toPackages(sharedKernels);

private static Collection<String> buildBusinessContexts() {
return getPackageAnnotatedBy(BusinessContext.class);
}

private static Collection<String> buildSharedKernels() {
return getPackageAnnotatedBy(SharedKernel.class);
}

private static Collection<String> toPackages(Collection<String> packages) {
return packages.stream().map(path -> path + "..").toList();
}
Expand Down Expand Up @@ -125,6 +117,9 @@ void primaryJavaAdaptersShouldOnlyBeCalledFromSecondaries() {
.onlyBeAccessed()
.byClassesThat()
.resideInAPackage("..secondary..")
.because(
"To interact between two contexts, secondary from context A should call a primary Java adapter (naming convention starting with 'Java') from context B"
)
.check(classes);
}

Expand All @@ -141,11 +136,11 @@ void shouldNotDependOnBoundedContexts() {
sharedKernelsPackages.forEach(kernel ->
noClasses()
.that()
.resideInAnyPackage(kernel)
.resideInAPackage(kernel)
.should()
.dependOnClassesThat()
.resideInAnyPackage(businessContextsPackages.toArray(String[]::new))
.because("Shared kernels should not have dependencies to bounded contexts")
.because("Shared kernels should not have dependencies to bounded contexts, only the opposite is allowed")
.check(classes)
);
}
Expand All @@ -158,7 +153,7 @@ class Domain {
void shouldNotDependOnOutside() {
classes()
.that()
.resideInAnyPackage(".domain..")
.resideInAPackage(".domain..")
.should()
.onlyDependOnClassesThat()
.resideInAnyPackage(authorizedContextPackages(".domain.."))
Expand All @@ -181,10 +176,10 @@ class Application {
void shouldNotDependOnInfrastructure() {
noClasses()
.that()
.resideInAnyPackage("..application..")
.resideInAPackage("..application..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..infrastructure..")
.resideInAPackage("..infrastructure..")
.because("Application should only depend on domain, not on infrastructure")
.check(classes);
}
Expand All @@ -197,10 +192,10 @@ class Primary {
void shouldNotDependOnSecondary() {
noClasses()
.that()
.resideInAnyPackage("..primary..")
.resideInAPackage("..primary..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..secondary..")
.resideInAPackage("..secondary..")
.because("Primary should not interact with secondary")
.check(classes);
}
Expand All @@ -218,12 +213,28 @@ class Secondary {
void shouldNotDependOnApplication() {
noClasses()
.that()
.resideInAnyPackage("..infrastructure.secondary..")
.resideInAPackage("..infrastructure.secondary..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("..application..")
.resideInAPackage("..application..")
.because("Secondary should not depend on application")
.check(classes);
}

@Test
void shouldNotDependOnSameContextPrimary() {
Stream
.concat(businessContexts.stream(), sharedKernels.stream())
.forEach(context -> {
noClasses()
.that()
.resideInAPackage(context + ".infrastructure.secondary..")
.should()
.dependOnClassesThat()
.resideInAPackage(context + ".infrastructure.primary")
.because("Secondary should not loop to its own context's primary")
.check(classes);
});
}
}
}

0 comments on commit 430c60f

Please sign in to comment.