test: add architecture and OpenAPI validation tooling

This commit is contained in:
2026-08-25 12:22:14 +08:00
parent 24df851acf
commit 0e0b6f8264
13 changed files with 544 additions and 17 deletions
@@ -0,0 +1,80 @@
package com.baiyue.firstleg.customerstatistics;
import com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader;
import com.baiyue.firstleg.service.FirstlegScopeGuard;
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 org.junit.jupiter.api.Test;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideOutsideOfPackage;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
class CustomerStatisticsArchitectureTest {
private static final String FIRSTLEG = "com.baiyue.firstleg..";
private static final String CUSTOMER_STATISTICS = "com.baiyue.firstleg.customerstatistics..";
private static final String APPLICATION = "com.baiyue.firstleg.customerstatistics.application..";
private static final String OUTPUT_PORT = "com.baiyue.firstleg.customerstatistics.application.port.out..";
private static final String PERSISTENCE = "com.baiyue.firstleg.customerstatistics.adapter.out.persistence..";
private static final String WEB = "com.baiyue.firstleg.customerstatistics.adapter.in.web..";
private static final JavaClasses PRODUCTION_CLASSES = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS)
.importPackages("com.baiyue.firstleg");
@Test
void applicationModelAndPortsStayFreeOfWebAndPersistenceFrameworks() {
noClasses().that().resideInAPackage(APPLICATION)
.should().dependOnClassesThat().resideInAnyPackage(
"org.springframework.web..",
"org.apache.ibatis..",
"com.baomidou.mybatisplus..")
.check(PRODUCTION_CLASSES);
}
@Test
void applicationOnlyDependsOnItsOwnSliceWithinFirstleg() {
classes().that().resideInAPackage(APPLICATION)
.should().onlyDependOnClassesThat(
resideOutsideOfPackage(FIRSTLEG).or(resideInAPackage(APPLICATION)))
.check(PRODUCTION_CLASSES);
}
@Test
void persistenceAdapterCollaboratesThroughTheApplicationOutputPort() {
classes().that().resideInAPackage(PERSISTENCE)
.should().onlyDependOnClassesThat(
resideOutsideOfPackage(CUSTOMER_STATISTICS).or(resideInAPackage(OUTPUT_PORT)))
.andShould().beAssignableTo(CustomerTransitStatisticsReader.class)
.check(PRODUCTION_CLASSES);
}
@Test
void webAdapterOnlyUsesApplicationAndScopeGuardWithinFirstleg() {
DescribedPredicate<JavaClass> scopeGuard = new DescribedPredicate<>("FirstlegScopeGuard") {
@Override
public boolean test(JavaClass javaClass) {
return javaClass.getName().equals(FirstlegScopeGuard.class.getName());
}
};
classes().that().resideInAPackage(WEB)
.should().onlyDependOnClassesThat(
resideOutsideOfPackage(FIRSTLEG)
.or(resideInAPackage(APPLICATION))
.or(resideInAPackage(WEB))
.or(scopeGuard))
.check(PRODUCTION_CLASSES);
}
@Test
void otherFirstlegProductionPackagesDoNotDependOnCustomerStatistics() {
noClasses().that().resideOutsideOfPackage(CUSTOMER_STATISTICS)
.should().dependOnClassesThat().resideInAPackage(CUSTOMER_STATISTICS)
.check(PRODUCTION_CLASSES);
}
}
@@ -39,6 +39,22 @@
"split-loading->outbound",
"split-loading->shared-technical"
],
"requiredClassLocations": {
"com.baiyue.firstleg.customerstatistics.adapter.in.web.PlatformCustomerTransitStatisticsController": "src/main/java/com/baiyue/firstleg/customerstatistics/adapter/in/web/PlatformCustomerTransitStatisticsController.java",
"com.baiyue.firstleg.customerstatistics.adapter.out.persistence.CustomerTransitStatisticsMapper": "src/main/java/com/baiyue/firstleg/customerstatistics/adapter/out/persistence/CustomerTransitStatisticsMapper.java",
"com.baiyue.firstleg.customerstatistics.application.CustomerTransitStatisticsService": "src/main/java/com/baiyue/firstleg/customerstatistics/application/CustomerTransitStatisticsService.java",
"com.baiyue.firstleg.customerstatistics.application.model.CustomerTransitStatisticsDtos": "src/main/java/com/baiyue/firstleg/customerstatistics/application/model/CustomerTransitStatisticsDtos.java",
"com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader": "src/main/java/com/baiyue/firstleg/customerstatistics/application/port/out/CustomerTransitStatisticsReader.java"
},
"applicationDependencyRule": {
"packagePrefix": "com.baiyue.firstleg.customerstatistics.application",
"allowedInternalPrefix": "com.baiyue.firstleg.customerstatistics.application",
"forbiddenImportPrefixes": [
"org.springframework.web",
"org.apache.ibatis",
"com.baomidou.mybatisplus"
]
},
"sliceSpecificRules": {
"customer-statistics": {
"allowedOutgoing": ["shared-technical"],