diff options
author | Bruno Sakoto <bruno.sakoto@bell.ca> | 2021-05-12 08:37:16 -0400 |
---|---|---|
committer | Bruno Sakoto <bruno.sakoto@bell.ca> | 2021-05-17 11:11:37 -0400 |
commit | 25050c117a6e69946de4f70503afa74cdef78aa7 (patch) | |
tree | b3d6e11fba894ed91af7357daf3b1a60b91321c7 | |
parent | 2d88ad8115c4f618275490e58c584f9b0c01c477 (diff) |
Add automatic architecture verification
Introduce verification for dependencies and layers.
Issue-ID: CPS-381
Signed-off-by: Bruno Sakoto <bruno.sakoto@bell.ca>
Change-Id: I948439ee5bcba2d41ccba3028d62a728babc83da
3 files changed, 148 insertions, 14 deletions
@@ -37,21 +37,34 @@ <properties> <app>org.onap.cps.temporal.Application</app> - <cps.checkstyle.version>1.0.1</cps.checkstyle.version> - <cps.spotbugs.version>1.0.1</cps.spotbugs.version> <docker.repository.pull>nexus3.onap.org:10001/</docker.repository.pull> <docker.repository.push>nexus3.onap.org:10003/</docker.repository.push> <image.base>${docker.repository.pull}onap/integration-java11:8.0.0</image.base> <image.name>${docker.repository.push}onap/cps-temporal</image.name> - <hibernate-types.version>2.10.0</hibernate-types.version> <java.version>11</java.version> - <jib-maven-plugin.version>3.0.0</jib-maven-plugin.version> <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format> <minimum-coverage>0.8</minimum-coverage> + <!-- Application dependencies versions --> + <spring-boot-dependencies.version>2.3.8.RELEASE</spring-boot-dependencies.version> + <hibernate-types.version>2.10.0</hibernate-types.version> + <liquibase-core.version>4.3.2</liquibase-core.version> + <!-- Tests dependencies versions --> + <spock-bom.version>2.0-M4-groovy-3.0</spock-bom.version> + <groovy.version>3.0.7</groovy.version> + <junit-jupiter.version>1.15.2</junit-jupiter.version> + <testcontainers-postgresql.version>1.15.2</testcontainers-postgresql.version> + <archunit-junit5.version>0.18.0</archunit-junit5.version> + <!-- Plugins and plugins dependencies versions --> + <spring-boot-maven-plugin.version>2.3.3.RELEASE</spring-boot-maven-plugin.version> + <gmavenplus-plugin.version>1.12.1</gmavenplus-plugin.version> + <jib-maven-plugin.version>3.0.0</jib-maven-plugin.version> <oparent.version>3.2.0</oparent.version> + <cps.checkstyle.version>1.0.1</cps.checkstyle.version> + <cps.spotbugs.version>1.0.1</cps.spotbugs.version> <spotbugs-maven-plugin.version>4.1.3</spotbugs-maven-plugin.version> - <spotbugs.slf4j.version>1.8.0-beta4</spotbugs.slf4j.version> <spotbugs.version>4.2.0</spotbugs.version> + <spotbugs.slf4j.version>1.8.0-beta4</spotbugs.slf4j.version> + <bug-pattern.version>1.5.0</bug-pattern.version> </properties> <dependencyManagement> @@ -59,14 +72,14 @@ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> - <version>2.3.8.RELEASE</version> + <version>${spring-boot-dependencies.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-bom</artifactId> - <version>2.0-M4-groovy-3.0</version> + <version>${spock-bom.version}</version> <type>pom</type> <scope>import</scope> </dependency> @@ -94,7 +107,7 @@ <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> - <version>4.3.2</version> + <version>${liquibase-core.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> @@ -114,7 +127,7 @@ <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> - <version>3.0.7</version> + <version>${groovy.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> @@ -140,13 +153,19 @@ <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> - <version>1.15.2</version> + <version>${junit-jupiter.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> - <version>1.15.2</version> + <version>${testcontainers-postgresql.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.tngtech.archunit</groupId> + <artifactId>archunit-junit5</artifactId> + <version>${archunit-junit5.version}</version> <scope>test</scope> </dependency> </dependencies> @@ -156,14 +175,14 @@ <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> - <version>2.3.3.RELEASE</version> + <version>${spring-boot-maven-plugin.version}</version> </plugin> <plugin> <!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin, visit https://github.com/groovy/GMavenPlus/wiki --> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> - <version>1.12.1</version> + <version>${gmavenplus-plugin.version}</version> <executions> <execution> <goals> @@ -275,7 +294,7 @@ <plugin> <groupId>jp.skypencil.findbugs.slf4j</groupId> <artifactId>bug-pattern</artifactId> - <version>1.5.0</version> + <version>${bug-pattern.version}</version> </plugin> </plugins> <!-- diff --git a/src/test/java/org/onap/cps/temporal/architecture/DependencyArchitectureTest.java b/src/test/java/org/onap/cps/temporal/architecture/DependencyArchitectureTest.java new file mode 100644 index 0000000..8e4cfd5 --- /dev/null +++ b/src/test/java/org/onap/cps/temporal/architecture/DependencyArchitectureTest.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2021 Bell Canada. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.temporal.architecture; + +import static com.tngtech.archunit.library.DependencyRules.NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES; +import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; + +/** + * Test class responsible for dependencies validations. + */ +@AnalyzeClasses(packages = "org.onap.cps.temporal", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class DependencyArchitectureTest { + + @ArchTest + static final ArchRule noCyclesRule = + slices().matching("org.onap.cps.temporal.(**)..").should().beFreeOfCycles(); + + @ArchTest + static final ArchRule noUpperPackageDependencyRule = NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES; + +} diff --git a/src/test/java/org/onap/cps/temporal/architecture/LayeredArchitectureTest.java b/src/test/java/org/onap/cps/temporal/architecture/LayeredArchitectureTest.java new file mode 100644 index 0000000..d47e8a5 --- /dev/null +++ b/src/test/java/org/onap/cps/temporal/architecture/LayeredArchitectureTest.java @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2021 Bell Canada. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.temporal.architecture; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.library.Architectures.layeredArchitecture; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; + +/** + * Test class responsible for layered architecture. + */ +@AnalyzeClasses(packages = "org.onap.cps.temporal", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class LayeredArchitectureTest { + + private static final String CONTROLLER_PACKAGE = "org.onap.cps.temporal.controller.."; + private static final String SERVICE_PACKAGE = "org.onap.cps.temporal.service.."; + private static final String REPOSITORY_PACKAGE = "org.onap.cps.temporal.repository.."; + + // 'access' catches only violations by real accesses, + // i.e. accessing a field, calling a method; compare 'dependOn' further down + + @ArchTest + public static final ArchRule layeredArchitectureRule = + layeredArchitecture() + .layer("Controller").definedBy(CONTROLLER_PACKAGE) + .layer("Service").definedBy(SERVICE_PACKAGE) + .layer("Repository").definedBy(REPOSITORY_PACKAGE) + .whereLayer("Controller").mayNotBeAccessedByAnyLayer() + .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller") + .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service"); + + // 'dependOn' catches a wider variety of violations, + // e.g. having fields of type, having method parameters of type, extending type ... + + @ArchTest + static final ArchRule controllerDependencyRule = + classes().that().resideInAPackage(CONTROLLER_PACKAGE) + .should().onlyHaveDependentClassesThat() + .resideInAPackage(CONTROLLER_PACKAGE); + + @ArchTest + static final ArchRule serviceDependencyRule = + classes().that().resideInAPackage(SERVICE_PACKAGE) + .should().onlyHaveDependentClassesThat() + .resideInAnyPackage(CONTROLLER_PACKAGE, SERVICE_PACKAGE); + + @ArchTest + static final ArchRule repositoryDependencyRule = + classes().that().resideInAPackage(REPOSITORY_PACKAGE) + .should().onlyHaveDependentClassesThat() + .resideInAnyPackage(SERVICE_PACKAGE, REPOSITORY_PACKAGE); + +}
\ No newline at end of file |