Jira |
---|
server | ONAP JIRA |
---|
columns | key,summary,type,created,updated,due,assignee,reporter,priority,status,resolution |
---|
serverId | 425b2b0a-557c-3c0c-b515-579789cceedb |
---|
key | CPS-347 |
---|
|
We are proposing the introduction of automatic tools to support architecture and design quality during all application life cycle.
...
Code Block |
---|
|
/**
* Test class responsible for dependencies validations.
*/
@AnalyzeClasses(packages = "org.onap.cps", importOptions = { ImportOption.DoNotIncludeTests.class })
public class DependencyArchitectureTest {
@ArchTest
static final ArchRule noCyclesRule =
slices().matching("org.onap.cps.(**)..").should().beFreeOfCycles();
@ArchTest
static final ArchRule noUpperPackageDependencyRule = NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES;
}
/**
* Test class responsible for layered architecture.
*/
@AnalyzeClasses(packages = "org.onap.cps", importOptions = { ImportOption.DoNotIncludeTests.class })
public class LayeredArchitectureTest {
private static final String A_CONTROLLER_PACKAGE = "org.onap.cps.controller..";
private static final String A_SERVICE_PACKAGE = "org.onap.cps.service..";
private static final String A_REPOSITORY_PACKAGE = "org.onap.cps.repository..";
@ArchTest
public static final ArchRule layeredArchitectureRule =
layeredArchitecture()
.layer("Controller").definedBy(A_CONTROLLER_PACKAGE)
.layer("Service").definedBy(A_SERVICE_PACKAGE)
.layer("Repository").definedBy(A_REPOSITORY_PACKAGE)
.whereLayer("Controller").mayNotBeAccessedByAnyLayer()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
.whereLayer("Repository").mayOnlyBeAccessedByLayers("Service");
// 'access' catches only violations by real accesses,
// i.e. accessing a field, calling a method; compare 'dependOn' further down
@ArchTest
public static final ArchRule controllerAccessRule =
classes().that().resideInAPackage(A_CONTROLLER_PACKAGE)
.should().onlyBeAccessed().byAnyPackage(A_CONTROLLER_PACKAGE);
@ArchTest
public static final ArchRule serviceAccessRule =
classes().that().resideInAPackage(A_SERVICE_PACKAGE)
.should().onlyBeAccessed().byAnyPackage(A_CONTROLLER_PACKAGE, A_SERVICE_PACKAGE);
@ArchTest
public static final ArchRule repositoryAccessRule =
classes().that().resideInAPackage(A_REPOSITORY_PACKAGE)
.should().onlyBeAccessed().byAnyPackage(A_SERVICE_PACKAGE, A_REPOSITORY_PACKAGE);
// '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(A_CONTROLLER_PACKAGE)
.should().onlyHaveDependentClassesThat()
.resideInAPackage(A_CONTROLLER_PACKAGE);
@ArchTest
static final ArchRule serviceDependencyRule =
classes().that().resideInAPackage(A_SERVICE_PACKAGE)
.should().onlyHaveDependentClassesThat()
.resideInAnyPackage(A_CONTROLLER_PACKAGE, A_SERVICE_PACKAGE);
@ArchTest
static final ArchRule repositoryDependencyRule =
classes().that().resideInAPackage(A_REPOSITORY_PACKAGE)
.should().onlyHaveDependentClassesThat()
.resideInAnyPackage(A_SERVICE_PACKAGE, A_REPOSITORY_PACKAGE);
}
|
Finding example:
Code Block |
---|
|
[ERROR] Failures:
[ERROR] Architecture Violation [Priority: MEDIUM] - Rule 'slices matching 'org.onap.cps.(**)..' should be free of cycles' was violated (1 times):
Cycle detected: Slice spi.model -> Slice utils -> Slice spi.model
Dependencies of Slice spi.model
Method <org.onap.cps.spi.model.DataNodeBuilder.addYangContainer(org.onap.cps.spi.model.DataNode, org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode)> calls method <org.onap.cps.utils.YangUtils.buildXpath(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier$PathArgument)> in (DataNodeBuilder.java:175)
Dependencies of Slice utils
Method <org.onap.cps.utils.DataMapUtils.lambda$containerElementsAsMap$2(org.onap.cps.spi.model.DataNode)> has parameter of type <org.onap.cps.spi.model.DataNode> in (DataMapUtils.java:0)
Method <org.onap.cps.utils.DataMapUtils.lambda$containerElementsAsMap$3(org.onap.cps.spi.model.DataNode)> has parameter of type <org.onap.cps.spi.model.DataNode> in (DataMapUtils.java:0)
Method <org.onap.cps.utils.DataMapUtils.lambda$listElementsAsMap$0(org.onap.cps.spi.model.DataNode)> has parameter of type <org.onap.cps.spi.model.DataNode> in (DataMapUtils.java:0)
Method <org.onap.cps.utils.DataMapUtils.lambda$listElementsAsMap$1(org.onap.cps.spi.model.DataNode)> has parameter of type <org.onap.cps.spi.model.DataNode> in (DataMapUtils.java:0)
Method <org.onap.cps.utils.DataMapUtils.toDataMap(org.onap.cps.spi.model.DataNode)> has parameter of type <org.onap.cps.spi.model.DataNode> in (DataMapUtils.java:0)
Method <org.onap.cps.utils.DataMapUtils.toDataMap(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getLeaves()> in (DataMapUtils.java:48)
Method <org.onap.cps.utils.DataMapUtils.toDataMap(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getChildDataNodes()> in (DataMapUtils.java:49)
Method <org.onap.cps.utils.DataMapUtils.toDataMap(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getChildDataNodes()> in (DataMapUtils.java:50)
Method <org.onap.cps.utils.DataMapUtils.lambda$listElementsAsMap$0(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getXpath()> in (DataMapUtils.java:61)
Method <org.onap.cps.utils.DataMapUtils.lambda$listElementsAsMap$1(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getXpath()> in (DataMapUtils.java:63)
Method <org.onap.cps.utils.DataMapUtils.lambda$containerElementsAsMap$2(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getXpath()> in (DataMapUtils.java:74)
Method <org.onap.cps.utils.DataMapUtils.lambda$containerElementsAsMap$3(org.onap.cps.spi.model.DataNode)> calls method <org.onap.cps.spi.model.DataNode.getXpath()> in (DataMapUtils.java:77) |
...