From 99d4ccc78c83424ffc4ee8e6e4b8e0238ee3b8ae Mon Sep 17 00:00:00 2001 From: Simon Brown Date: Tue, 9 Jan 2024 17:25:24 +0000 Subject: [PATCH] Removes the `Workspace.countAndLogWarnings()` method with an initial version of something more flexible. --- settings.gradle | 1 + structurizr-assistant/README.md | 3 + structurizr-assistant/build.gradle | 7 ++ .../com/structurizr/assistant/Assistant.java | 20 +++++ .../assistant/DefaultAssistant.java | 65 +++++++++++++++ .../com/structurizr/assistant/Inspection.java | 50 ++++++++++++ .../com/structurizr/assistant/Priority.java | 9 +++ .../structurizr/assistant/Recommendation.java | 32 ++++++++ .../model/ComponentDescriptionInspection.java | 16 ++++ .../assistant/model/ComponentInspection.java | 21 +++++ .../model/ComponentTechnologyInspection.java | 28 +++++++ .../model/ContainerDescriptionInspection.java | 16 ++++ .../assistant/model/ContainerInspection.java | 21 +++++ .../model/ContainerTechnologyInspection.java | 28 +++++++ .../DeploymentNodeDescriptionInspection.java | 16 ++++ .../model/DeploymentNodeInspection.java | 21 +++++ .../DeploymentNodeTechnologyInspection.java | 28 +++++++ .../model/ElementDescriptionInspection.java | 23 ++++++ .../assistant/model/ElementInspection.java | 30 +++++++ ...lementNotIncludedInAnyViewsInspection.java | 44 +++++++++++ .../model/EmptyDeploymentNodeInspection.java | 27 +++++++ .../assistant/model/EmptyModelInspection.java | 26 ++++++ ...frastructureNodeDescriptionInspection.java | 15 ++++ .../model/InfrastructureNodeInspection.java | 21 +++++ ...nfrastructureNodeTechnologyInspection.java | 28 +++++++ .../assistant/model/ModelInspection.java | 24 ++++++ ...ipleSoftwareSystemsDetailedInspection.java | 34 ++++++++ .../model/OrphanedElementInspection.java | 44 +++++++++++ .../model/PersonDescriptionInspection.java | 16 ++++ .../RelationshipDescriptionInspection.java | 37 +++++++++ .../model/RelationshipInspection.java | 36 +++++++++ .../RelationshipTechnologyInspection.java | 37 +++++++++ .../SoftwareSystemDescriptionInspection.java | 16 ++++ ...sForMultipleSoftwareSystemsInspection.java | 34 ++++++++ .../assistant/view/EmptyViewsInspection.java | 26 ++++++ ...sForMultipleSoftwareSystemsInspection.java | 34 ++++++++ .../assistant/view/ViewsInspection.java | 23 ++++++ .../workspace/WorkspaceInspection.java | 23 ++++++ .../workspace/WorkspaceScopeInspection.java | 26 ++++++ .../ComponentDescriptionInspectionTests.java | 41 ++++++++++ .../ComponentTechnologyInspectionTests.java | 41 ++++++++++ .../ContainerDescriptionInspectionTests.java | 38 +++++++++ .../ContainerTechnologyInspectionTests.java | 38 +++++++++ ...loymentNodeDescriptionInspectionTests.java | 35 ++++++++ ...ploymentNodeTechnologyInspectionTests.java | 35 ++++++++ ...tNotIncludedInAnyViewsInspectionTests.java | 36 +++++++++ .../model/EmptyDeploymentNodeCheckTests.java | 71 +++++++++++++++++ .../model/EmptyModelInspectionTests.java | 33 ++++++++ ...ructureNodeDescriptionInspectionTests.java | 37 +++++++++ ...tructureNodeTechnologyInspectionTests.java | 37 +++++++++ ...oftwareSystemsDetailedInspectionTests.java | 79 +++++++++++++++++++ .../model/OrphanedElementInspectionTests.java | 40 ++++++++++ .../PersonDescriptionInspectionTests.java | 35 ++++++++ ...elationshipDescriptionInspectionTests.java | 57 +++++++++++++ ...RelationshipTechnologyInspectionTests.java | 55 +++++++++++++ ...twareSystemDescriptionInspectionTests.java | 35 ++++++++ ...ultipleSoftwareSystemsInspectionTests.java | 40 ++++++++++ .../view/EmptyViewsInspectionTests.java | 33 ++++++++ ...ultipleSoftwareSystemsInspectionTests.java | 40 ++++++++++ .../WorkspaceScopeInspectionTests.java | 34 ++++++++ .../structurizr/api/WorkspaceApiClient.java | 2 - .../main/java/com/structurizr/Workspace.java | 68 ---------------- .../java/com/structurizr/WorkspaceTests.java | 20 ----- 63 files changed, 1896 insertions(+), 90 deletions(-) create mode 100644 structurizr-assistant/README.md create mode 100644 structurizr-assistant/build.gradle create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/Assistant.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/DefaultAssistant.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/Inspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/Priority.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/Recommendation.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentTechnologyInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerTechnologyInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyDeploymentNodeInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyModelInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/ModelInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/OrphanedElementInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/PersonDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipTechnologyInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/view/EmptyViewsInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/view/ViewsInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceInspection.java create mode 100644 structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceScopeInspection.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentTechnologyInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerTechnologyInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyDeploymentNodeCheckTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyModelInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/OrphanedElementInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/PersonDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipTechnologyInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/view/EmptyViewsInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspectionTests.java create mode 100644 structurizr-assistant/src/test/java/com/structurizr/assistant/workspace/WorkspaceScopeInspectionTests.java diff --git a/settings.gradle b/settings.gradle index 3b97826d..e06f2f88 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ rootProject.name = 'structurizr-java' +include 'structurizr-assistant' include 'structurizr-client' include 'structurizr-core' include 'structurizr-dsl' diff --git a/structurizr-assistant/README.md b/structurizr-assistant/README.md new file mode 100644 index 00000000..790b286e --- /dev/null +++ b/structurizr-assistant/README.md @@ -0,0 +1,3 @@ +# structurizr-assistant + +[![Maven Central](https://img.shields.io/maven-central/v/com.structurizr/structurizr-assistant.svg?label=Maven%20Central)](https://search.maven.org/artifact/com.structurizr/structurizr-assistant) diff --git a/structurizr-assistant/build.gradle b/structurizr-assistant/build.gradle new file mode 100644 index 00000000..b6bde77a --- /dev/null +++ b/structurizr-assistant/build.gradle @@ -0,0 +1,7 @@ +dependencies { + + api project(':structurizr-core') + + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/Assistant.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/Assistant.java new file mode 100644 index 00000000..aba2a552 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/Assistant.java @@ -0,0 +1,20 @@ +package com.structurizr.assistant; + +import java.util.ArrayList; +import java.util.Collection; + +abstract class Assistant { + + private final Collection recommendations = new ArrayList<>(); + + public Collection getRecommendations() { + return new ArrayList<>(recommendations); + } + + protected void add(Recommendation recommendation) { + if (recommendation != null) { + recommendations.add(recommendation); + } + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/DefaultAssistant.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/DefaultAssistant.java new file mode 100644 index 00000000..ec111448 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/DefaultAssistant.java @@ -0,0 +1,65 @@ +package com.structurizr.assistant; + +import com.structurizr.Workspace; +import com.structurizr.assistant.model.*; +import com.structurizr.assistant.view.ContainerViewsForMultipleSoftwareSystemsInspection; +import com.structurizr.assistant.view.EmptyViewsInspection; +import com.structurizr.assistant.view.SystemContextViewsForMultipleSoftwareSystemsInspection; +import com.structurizr.assistant.workspace.WorkspaceScopeInspection; +import com.structurizr.model.*; + +public class DefaultAssistant extends Assistant { + + private static final String ALL_RECOMMENDATIONS = "structurizr.recommendations"; + + public DefaultAssistant(Workspace workspace) { + if (workspace.getProperties().getOrDefault(ALL_RECOMMENDATIONS, "true").equalsIgnoreCase("false")) { + // skip all inspections + return; + } + + runWorkspaceInspections(workspace); + runModelInspections(workspace); + runViewInspections(workspace); + } + + private void runWorkspaceInspections(Workspace workspace) { + add(new WorkspaceScopeInspection(workspace).run()); + } + + private void runModelInspections(Workspace workspace) { + add(new EmptyModelInspection(workspace).run()); + add(new MultipleSoftwareSystemsDetailedInspection(workspace).run()); + ElementNotIncludedInAnyViewsInspection elementNotIncludedInAnyViewsCheck = new ElementNotIncludedInAnyViewsInspection(workspace); + OrphanedElementInspection orphanedElementCheck = new OrphanedElementInspection(workspace); + for (Element element : workspace.getModel().getElements()) { + add(elementNotIncludedInAnyViewsCheck.run(element)); + add(orphanedElementCheck.run(element)); + + if (element instanceof Person) { + add(new PersonDescriptionInspection(workspace).run(element)); + } + + if (element instanceof SoftwareSystem) { + add(new SoftwareSystemDescriptionInspection(workspace).run(element)); + } + + if (element instanceof Container) { + add(new ContainerDescriptionInspection(workspace).run(element)); + add(new ContainerTechnologyInspection(workspace).run(element)); + } + + if (element instanceof Component) { + add(new ComponentDescriptionInspection(workspace).run(element)); + add(new ComponentTechnologyInspection(workspace).run(element)); + } + } + } + + private void runViewInspections(Workspace workspace) { + add(new EmptyViewsInspection(workspace).run()); + add(new SystemContextViewsForMultipleSoftwareSystemsInspection(workspace).run()); + add(new ContainerViewsForMultipleSoftwareSystemsInspection(workspace).run()); + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/Inspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/Inspection.java new file mode 100644 index 00000000..22458a13 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/Inspection.java @@ -0,0 +1,50 @@ +package com.structurizr.assistant; + +import com.structurizr.PropertyHolder; +import com.structurizr.Workspace; + +public abstract class Inspection { + + private static final String STRUCTURIZR_RECOMMENDATIONS_PREFIX = "structurizr.recommendations."; + + private final Workspace workspace; + + protected Inspection(Workspace workspace) { + this.workspace = workspace; + } + + protected abstract String getType(); + + protected Workspace getWorkspace() { + return workspace; + } + + protected boolean isEnabled(String type, PropertyHolder... propertyHolders) { + String value = "true"; + + for (PropertyHolder propertyHolder : propertyHolders) { + if (propertyHolder != null) { + value = propertyHolder.getProperties().getOrDefault(STRUCTURIZR_RECOMMENDATIONS_PREFIX + type, value); + } + } + + return !value.equalsIgnoreCase("false"); + } + + protected Recommendation noRecommendation() { + return null; + } + + protected Recommendation lowPriorityRecommendation(String description) { + return new Recommendation(STRUCTURIZR_RECOMMENDATIONS_PREFIX + getType(), Priority.Low, description); + } + + protected Recommendation mediumPriorityRecommendation(String description) { + return new Recommendation(STRUCTURIZR_RECOMMENDATIONS_PREFIX + getType(), Priority.Medium, description); + } + + protected Recommendation highPriorityRecommendation(String description) { + return new Recommendation(STRUCTURIZR_RECOMMENDATIONS_PREFIX + getType(), Priority.High, description); + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/Priority.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/Priority.java new file mode 100644 index 00000000..5a2c3085 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/Priority.java @@ -0,0 +1,9 @@ +package com.structurizr.assistant; + +public enum Priority { + + Low, + Medium, + High + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/Recommendation.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/Recommendation.java new file mode 100644 index 00000000..1e35b3c6 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/Recommendation.java @@ -0,0 +1,32 @@ +package com.structurizr.assistant; + +public final class Recommendation { + + private final String type; + private final Priority priority; + private final String description; + + Recommendation(String type, Priority priority, String description) { + this.type = type; + this.priority = priority; + this.description = description; + } + + public String getType() { + return type; + } + + public Priority getPriority() { + return priority; + } + + public String getDescription() { + return description; + } + + @Override + public String toString() { + return type + " | " + priority + " | " + description; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentDescriptionInspection.java new file mode 100644 index 00000000..ccacdefb --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentDescriptionInspection.java @@ -0,0 +1,16 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class ComponentDescriptionInspection extends ElementDescriptionInspection { + + public ComponentDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected String getType() { + return "model.component.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentInspection.java new file mode 100644 index 00000000..4c64146f --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentInspection.java @@ -0,0 +1,21 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.model.Element; + +abstract class ComponentInspection extends ElementInspection { + + public ComponentInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Element element) { + return inspect((Component)element); + } + + protected abstract Recommendation inspect(Component component); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentTechnologyInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentTechnologyInspection.java new file mode 100644 index 00000000..780acd97 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ComponentTechnologyInspection.java @@ -0,0 +1,28 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.util.StringUtils; + +public class ComponentTechnologyInspection extends ComponentInspection { + + public ComponentTechnologyInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Component component) { + if (StringUtils.isNullOrEmpty(component.getDescription())) { + return lowPriorityRecommendation("Add a technology to the " + terminologyFor(component).toLowerCase() + " named \"" + component.getName() + "\"."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.component.technology"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerDescriptionInspection.java new file mode 100644 index 00000000..ac4d59f8 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerDescriptionInspection.java @@ -0,0 +1,16 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class ContainerDescriptionInspection extends ElementDescriptionInspection { + + public ContainerDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected String getType() { + return "model.container.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerInspection.java new file mode 100644 index 00000000..4c7dea0f --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerInspection.java @@ -0,0 +1,21 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.Element; + +abstract class ContainerInspection extends ElementInspection { + + public ContainerInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Element element) { + return inspect((Container)element); + } + + protected abstract Recommendation inspect(Container container); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerTechnologyInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerTechnologyInspection.java new file mode 100644 index 00000000..34baaa0f --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ContainerTechnologyInspection.java @@ -0,0 +1,28 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.util.StringUtils; + +public class ContainerTechnologyInspection extends ContainerInspection { + + public ContainerTechnologyInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Container container) { + if (StringUtils.isNullOrEmpty(container.getTechnology())) { + return mediumPriorityRecommendation("Add a technology to the " + terminologyFor(container).toLowerCase() + " named \"" + container.getName() + "\"."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.container.technology"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspection.java new file mode 100644 index 00000000..5dfccec4 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspection.java @@ -0,0 +1,16 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class DeploymentNodeDescriptionInspection extends ElementDescriptionInspection { + + public DeploymentNodeDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected String getType() { + return "model.deploymentnode.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeInspection.java new file mode 100644 index 00000000..bd87be41 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeInspection.java @@ -0,0 +1,21 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; +import com.structurizr.model.Element; + +abstract class DeploymentNodeInspection extends ElementInspection { + + public DeploymentNodeInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Element element) { + return inspect((DeploymentNode)element); + } + + protected abstract Recommendation inspect(DeploymentNode deploymentNode); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspection.java new file mode 100644 index 00000000..eeb76882 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspection.java @@ -0,0 +1,28 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; +import com.structurizr.util.StringUtils; + +public class DeploymentNodeTechnologyInspection extends DeploymentNodeInspection { + + public DeploymentNodeTechnologyInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(DeploymentNode deploymentNode) { + if (StringUtils.isNullOrEmpty(deploymentNode.getDescription())) { + return mediumPriorityRecommendation("Add a technology to the " + terminologyFor(deploymentNode).toLowerCase() + " named \"" + deploymentNode.getName() + "\"."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.deploymentnode.technology"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementDescriptionInspection.java new file mode 100644 index 00000000..85b024d8 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementDescriptionInspection.java @@ -0,0 +1,23 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; +import com.structurizr.util.StringUtils; + +abstract class ElementDescriptionInspection extends ElementInspection { + + public ElementDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Element element) { + if (StringUtils.isNullOrEmpty(element.getDescription())) { + return mediumPriorityRecommendation("Add a description to the " + terminologyFor(element).toLowerCase() + " named \"" + element.getName() + "\"."); + } + + return noRecommendation(); + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementInspection.java new file mode 100644 index 00000000..475b7121 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementInspection.java @@ -0,0 +1,30 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Inspection; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; + +abstract class ElementInspection extends Inspection { + + public ElementInspection(Workspace workspace) { + super(workspace); + } + + public final Recommendation run(Element element) { + Element parentElement = element.getParent(); + + if (isEnabled(getType(), getWorkspace(), getWorkspace().getModel(), parentElement, element)) { + return inspect(element); + } + + return noRecommendation(); + } + + protected String terminologyFor(Element element) { + return getWorkspace().getViews().getConfiguration().getTerminology().findTerminology(element).toLowerCase(); + } + + protected abstract Recommendation inspect(Element element); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspection.java new file mode 100644 index 00000000..930d1374 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspection.java @@ -0,0 +1,44 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; +import com.structurizr.view.ElementView; +import com.structurizr.view.ModelView; +import com.structurizr.view.View; + +import java.util.HashSet; +import java.util.Set; + +public class ElementNotIncludedInAnyViewsInspection extends ElementInspection { + + private final Set elementsInViews = new HashSet<>(); + + public ElementNotIncludedInAnyViewsInspection(Workspace workspace) { + super(workspace); + + for (View view : workspace.getViews().getViews()) { + if (view instanceof ModelView) { + ModelView modelView = (ModelView)view; + for (ElementView elementView : modelView.getElements()) { + elementsInViews.add(elementView.getId()); + } + } + } + } + + @Override + protected Recommendation inspect(Element element) { + if (!elementsInViews.contains(element.getId())) { + return lowPriorityRecommendation("The " + terminologyFor(element) + " named \"" + element.getName() + "\" is not included on any views - add it to a view."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.element.noview"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyDeploymentNodeInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyDeploymentNodeInspection.java new file mode 100644 index 00000000..b3c46582 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyDeploymentNodeInspection.java @@ -0,0 +1,27 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; + +public class EmptyDeploymentNodeInspection extends DeploymentNodeInspection { + + public EmptyDeploymentNodeInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(DeploymentNode deploymentNode) { + if (!deploymentNode.hasChildren() && !deploymentNode.hasSoftwareSystemInstances() && !deploymentNode.hasContainerInstances() && !deploymentNode.hasInfrastructureNodes()) { + return lowPriorityRecommendation("The " + terminologyFor(deploymentNode).toLowerCase() + " named \"" + deploymentNode.getName() + "\" is empty."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.deploymentnode.empty"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyModelInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyModelInspection.java new file mode 100644 index 00000000..d31042e8 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/EmptyModelInspection.java @@ -0,0 +1,26 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; + +public class EmptyModelInspection extends ModelInspection { + + public EmptyModelInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Workspace workspace) { + if (workspace.getModel().isEmpty()) { + return highPriorityRecommendation("Add some elements to the model."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.empty"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspection.java new file mode 100644 index 00000000..265b961a --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspection.java @@ -0,0 +1,15 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class InfrastructureNodeDescriptionInspection extends ElementDescriptionInspection { + + public InfrastructureNodeDescriptionInspection(Workspace workspace) { + super(workspace); + } + + protected String getType() { + return "model.infrastructurenode.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeInspection.java new file mode 100644 index 00000000..62097ea0 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeInspection.java @@ -0,0 +1,21 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; +import com.structurizr.model.InfrastructureNode; + +abstract class InfrastructureNodeInspection extends ElementInspection { + + public InfrastructureNodeInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Element element) { + return inspect((InfrastructureNode)element); + } + + protected abstract Recommendation inspect(InfrastructureNode infrastructureNode); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspection.java new file mode 100644 index 00000000..951dc0fb --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspection.java @@ -0,0 +1,28 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.InfrastructureNode; +import com.structurizr.util.StringUtils; + +public class InfrastructureNodeTechnologyInspection extends InfrastructureNodeInspection { + + public InfrastructureNodeTechnologyInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(InfrastructureNode infrastructureNode) { + if (StringUtils.isNullOrEmpty(infrastructureNode.getTechnology())) { + return mediumPriorityRecommendation("Add a technology to the " + terminologyFor(infrastructureNode).toLowerCase() + " named \"" + infrastructureNode.getName() + "\"."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.infrastructurenode.technology"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ModelInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ModelInspection.java new file mode 100644 index 00000000..4b8ab75a --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/ModelInspection.java @@ -0,0 +1,24 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Inspection; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; + +abstract class ModelInspection extends Inspection { + + public ModelInspection(Workspace workspace) { + super(workspace); + } + + public final Recommendation run() { + if (isEnabled(getType(), getWorkspace(), getWorkspace().getModel())) { + return inspect(getWorkspace()); + } + + return noRecommendation(); + } + + protected abstract Recommendation inspect(Workspace workspace); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspection.java new file mode 100644 index 00000000..34fc04be --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspection.java @@ -0,0 +1,34 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; + +public class MultipleSoftwareSystemsDetailedInspection extends ModelInspection { + + public MultipleSoftwareSystemsDetailedInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Workspace workspace) { + int softwareSystemsWithDetails = 0; + for (SoftwareSystem softwareSystem : workspace.getModel().getSoftwareSystems()) { + if (softwareSystem.hasContainers() || !softwareSystem.getDocumentation().isEmpty()) { + softwareSystemsWithDetails++; + } + } + + if (softwareSystemsWithDetails > 1) { + return highPriorityRecommendation("This workspace describes the internal details of " + softwareSystemsWithDetails + " software systems. It is recommended that a workspace contains the model, views, and documentation for a single software system only."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "workspace.scope"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/OrphanedElementInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/OrphanedElementInspection.java new file mode 100644 index 00000000..7cc09eb5 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/OrphanedElementInspection.java @@ -0,0 +1,44 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; +import com.structurizr.model.Element; +import com.structurizr.model.Relationship; + +import java.util.HashSet; +import java.util.Set; + +public class OrphanedElementInspection extends ElementInspection { + + private final Set elementsWithRelationships = new HashSet<>(); + + public OrphanedElementInspection(Workspace workspace) { + super(workspace); + + for (Relationship relationship : workspace.getModel().getRelationships()) { + elementsWithRelationships.add(relationship.getSourceId()); + elementsWithRelationships.add(relationship.getDestinationId()); + } + } + + @Override + protected Recommendation inspect(Element element) { + if (element instanceof DeploymentNode) { + // deployment nodes typically won't have relationships to/from them + return noRecommendation(); + } + + if (!elementsWithRelationships.contains(element.getId())) { + return mediumPriorityRecommendation("The " + terminologyFor(element).toLowerCase() + " named \"" + element.getName() + "\" is orphaned - add a relationship to/from it, or consider removing it from the model."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.element.orphaned"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/PersonDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/PersonDescriptionInspection.java new file mode 100644 index 00000000..9f88eca2 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/PersonDescriptionInspection.java @@ -0,0 +1,16 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class PersonDescriptionInspection extends ElementDescriptionInspection { + + public PersonDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected String getType() { + return "model.person.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipDescriptionInspection.java new file mode 100644 index 00000000..7c8bb9aa --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipDescriptionInspection.java @@ -0,0 +1,37 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.model.Element; +import com.structurizr.model.Relationship; +import com.structurizr.util.StringUtils; + +public class RelationshipDescriptionInspection extends RelationshipInspection { + + public RelationshipDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Relationship relationship) { + Element source = relationship.getSource(); + Element destination = relationship.getDestination(); + + if (StringUtils.isNullOrEmpty(relationship.getDescription())) { + if (source instanceof Component && destination instanceof Component) { + return lowPriorityRecommendation("Add a description to the relationship between the " + terminologyFor(source) + " named \"" + source.getName() + "\" and the " + terminologyFor(destination) + " named \"" + destination.getName() + "\"."); + } else { + return mediumPriorityRecommendation("Add a description to the relationship between the " + terminologyFor(source) + " named \"" + source.getName() + "\" and the " + terminologyFor(destination) + " named \"" + destination.getName() + "\"."); + } + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.relationship.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipInspection.java new file mode 100644 index 00000000..406d80b4 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipInspection.java @@ -0,0 +1,36 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Inspection; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Element; +import com.structurizr.model.Relationship; +import com.structurizr.util.StringUtils; + +public abstract class RelationshipInspection extends Inspection { + + public RelationshipInspection(Workspace workspace) { + super(workspace); + } + + public final Recommendation run(Relationship relationship) { + Element source = relationship.getSource(); + Relationship linkedRelationship = null; + if (!StringUtils.isNullOrEmpty(relationship.getLinkedRelationshipId())) { + getWorkspace().getModel().getRelationship(relationship.getLinkedRelationshipId()); + } + + if (isEnabled(getType(), getWorkspace(), getWorkspace().getModel(), source.getParent(), source, linkedRelationship, relationship)) { + return inspect(relationship); + } + + return noRecommendation(); + } + + protected String terminologyFor(Element element) { + return getWorkspace().getViews().getConfiguration().getTerminology().findTerminology(element).toLowerCase(); + } + + protected abstract Recommendation inspect(Relationship relationship); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipTechnologyInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipTechnologyInspection.java new file mode 100644 index 00000000..b563a70c --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/RelationshipTechnologyInspection.java @@ -0,0 +1,37 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.Element; +import com.structurizr.model.Relationship; +import com.structurizr.util.StringUtils; + +public class RelationshipTechnologyInspection extends RelationshipInspection { + + public RelationshipTechnologyInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected Recommendation inspect(Relationship relationship) { + Element source = relationship.getSource(); + Element destination = relationship.getDestination(); + + if (StringUtils.isNullOrEmpty(relationship.getTechnology())) { + if (source instanceof Container && destination instanceof Container) { + return mediumPriorityRecommendation("Add a technology to the relationship between the " + terminologyFor(source) + " named \"" + source.getName() + "\" and the " + terminologyFor(destination) + " named \"" + destination.getName() + "\"."); + } else { + return lowPriorityRecommendation("Add a technology to the relationship between the " + terminologyFor(source) + " named \"" + source.getName() + "\" and the " + terminologyFor(destination) + " named \"" + destination.getName() + "\"."); + } + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "model.relationship.technology"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspection.java new file mode 100644 index 00000000..abc505cc --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspection.java @@ -0,0 +1,16 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; + +public class SoftwareSystemDescriptionInspection extends ElementDescriptionInspection { + + public SoftwareSystemDescriptionInspection(Workspace workspace) { + super(workspace); + } + + @Override + protected String getType() { + return "model.softwaresystem.description"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspection.java new file mode 100644 index 00000000..2e33015c --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspection.java @@ -0,0 +1,34 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.view.ContainerView; + +import java.util.HashSet; +import java.util.Set; + +public class ContainerViewsForMultipleSoftwareSystemsInspection extends ViewsInspection { + + public ContainerViewsForMultipleSoftwareSystemsInspection(Workspace workspace) { + super(workspace); + } + + @Override + public Recommendation inspect(Workspace workspace) { + Set softwareSystemsWithContainerViews = new HashSet<>(); + for (ContainerView view : workspace.getViews().getContainerViews()) { + softwareSystemsWithContainerViews.add(view.getSoftwareSystemId()); + } + if (softwareSystemsWithContainerViews.size() > 1) { + return highPriorityRecommendation("Container views exist for " + softwareSystemsWithContainerViews.size() + " software systems. It is recommended that a workspace includes container views for a single software system only."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "workspace.scope"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/view/EmptyViewsInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/EmptyViewsInspection.java new file mode 100644 index 00000000..b00c8ad4 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/EmptyViewsInspection.java @@ -0,0 +1,26 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; + +public class EmptyViewsInspection extends ViewsInspection { + + public EmptyViewsInspection(Workspace workspace) { + super(workspace); + } + + @Override + public Recommendation inspect(Workspace workspace) { + if (workspace.getViews().isEmpty()) { + return highPriorityRecommendation("Add some views to the workspace."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "views.empty"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspection.java new file mode 100644 index 00000000..4e7c926a --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspection.java @@ -0,0 +1,34 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; +import com.structurizr.view.SystemContextView; + +import java.util.HashSet; +import java.util.Set; + +public class SystemContextViewsForMultipleSoftwareSystemsInspection extends ViewsInspection { + + public SystemContextViewsForMultipleSoftwareSystemsInspection(Workspace workspace) { + super(workspace); + } + + @Override + public Recommendation inspect(Workspace workspace) { + Set softwareSystemsWithSystemContextViews = new HashSet<>(); + for (SystemContextView view : workspace.getViews().getSystemContextViews()) { + softwareSystemsWithSystemContextViews.add(view.getSoftwareSystemId()); + } + if (softwareSystemsWithSystemContextViews.size() > 1) { + return highPriorityRecommendation("System context views exist for " + softwareSystemsWithSystemContextViews.size() + " software systems. It is recommended that a workspace includes system context views for a single software system only."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "workspace.scope"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ViewsInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ViewsInspection.java new file mode 100644 index 00000000..bd7af5b0 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/view/ViewsInspection.java @@ -0,0 +1,23 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Inspection; +import com.structurizr.assistant.Recommendation; + +abstract class ViewsInspection extends Inspection { + + public ViewsInspection(Workspace workspace) { + super(workspace); + } + + public final Recommendation run() { + if (isEnabled(getType(), getWorkspace(), getWorkspace().getViews().getConfiguration())) { + return inspect(getWorkspace()); + } + + return noRecommendation(); + } + + protected abstract Recommendation inspect(Workspace workspace); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceInspection.java new file mode 100644 index 00000000..1e6e5c63 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceInspection.java @@ -0,0 +1,23 @@ +package com.structurizr.assistant.workspace; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Inspection; +import com.structurizr.assistant.Recommendation; + +abstract class WorkspaceInspection extends Inspection { + + public WorkspaceInspection(Workspace workspace) { + super(workspace); + } + + public final Recommendation run() { + if (isEnabled(getType(), getWorkspace())) { + return inspect(getWorkspace()); + } + + return null; + } + + protected abstract Recommendation inspect(Workspace workspace); + +} \ No newline at end of file diff --git a/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceScopeInspection.java b/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceScopeInspection.java new file mode 100644 index 00000000..076edf60 --- /dev/null +++ b/structurizr-assistant/src/main/java/com/structurizr/assistant/workspace/WorkspaceScopeInspection.java @@ -0,0 +1,26 @@ +package com.structurizr.assistant.workspace; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Recommendation; + +public class WorkspaceScopeInspection extends WorkspaceInspection { + + public WorkspaceScopeInspection(Workspace workspace) { + super(workspace); + } + + @Override + public Recommendation inspect(Workspace workspace) { + if (workspace.getConfiguration().getScope() == null) { + return highPriorityRecommendation("This workspace has no defined scope. It is recommended that the workspace scope is set to \"Landscape\" or \"SoftwareSystem\"."); + } + + return noRecommendation(); + } + + @Override + protected String getType() { + return "workspace.scope"; + } + +} \ No newline at end of file diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentDescriptionInspectionTests.java new file mode 100644 index 00000000..eb17e0c0 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentDescriptionInspectionTests.java @@ -0,0 +1,41 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.model.Container; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ComponentDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Name"); + + Recommendation recommendation = new ComponentDescriptionInspection(workspace).run(component); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.component.description", recommendation.getType()); + assertEquals("Add a description to the component named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Name", "Description"); + + Recommendation recommendation = new ComponentDescriptionInspection(workspace).run(component); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentTechnologyInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentTechnologyInspectionTests.java new file mode 100644 index 00000000..f5f1826a --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ComponentTechnologyInspectionTests.java @@ -0,0 +1,41 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.model.Container; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ComponentTechnologyInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Name"); + + Recommendation recommendation = new ComponentTechnologyInspection(workspace).run(component); + Assertions.assertEquals(Priority.Low, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.component.technology", recommendation.getType()); + assertEquals("Add a technology to the component named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Name", "Description", "Technology"); + + Recommendation recommendation = new ComponentTechnologyInspection(workspace).run(component); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerDescriptionInspectionTests.java new file mode 100644 index 00000000..9b0655c0 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerDescriptionInspectionTests.java @@ -0,0 +1,38 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ContainerDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Name"); + + Recommendation recommendation = new ContainerDescriptionInspection(workspace).run(container); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.container.description", recommendation.getType()); + assertEquals("Add a description to the container named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Name", "Description"); + + Recommendation recommendation = new ContainerDescriptionInspection(workspace).run(container); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerTechnologyInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerTechnologyInspectionTests.java new file mode 100644 index 00000000..3f2e0885 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ContainerTechnologyInspectionTests.java @@ -0,0 +1,38 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ContainerTechnologyInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Name"); + + Recommendation recommendation = new ContainerTechnologyInspection(workspace).run(container); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.container.technology", recommendation.getType()); + assertEquals("Add a technology to the container named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Name", "Description", "Technology"); + + Recommendation recommendation = new ContainerTechnologyInspection(workspace).run(container); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspectionTests.java new file mode 100644 index 00000000..e495234e --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeDescriptionInspectionTests.java @@ -0,0 +1,35 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class DeploymentNodeDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Name"); + + Recommendation recommendation = new DeploymentNodeDescriptionInspection(workspace).run(deploymentNode); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.deploymentnode.description", recommendation.getType()); + assertEquals("Add a description to the deployment node named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Name", "Description", "Technology"); + + Recommendation recommendation = new DeploymentNodeDescriptionInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspectionTests.java new file mode 100644 index 00000000..5c0aa566 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/DeploymentNodeTechnologyInspectionTests.java @@ -0,0 +1,35 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.DeploymentNode; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class DeploymentNodeTechnologyInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Name"); + + Recommendation recommendation = new DeploymentNodeTechnologyInspection(workspace).run(deploymentNode); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.deploymentnode.technology", recommendation.getType()); + assertEquals("Add a technology to the deployment node named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Name", "Description", "Technology"); + + Recommendation recommendation = new DeploymentNodeTechnologyInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspectionTests.java new file mode 100644 index 00000000..d92e2913 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/ElementNotIncludedInAnyViewsInspectionTests.java @@ -0,0 +1,36 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ElementNotIncludedInAnyViewsInspectionTests { + + @Test + public void run_NotInViews() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Name"); + + Recommendation recommendation = new ElementNotIncludedInAnyViewsInspection(workspace).run(softwareSystem); + Assertions.assertEquals(Priority.Low, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.element.noview", recommendation.getType()); + assertEquals("The software system named \"Name\" is not included on any views - add it to a view.", recommendation.getDescription()); + } + + @Test + public void run_InViews() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Name"); + workspace.getViews().createSystemLandscapeView("key", "Description").addAllElements(); + + Recommendation recommendation = new ElementNotIncludedInAnyViewsInspection(workspace).run(softwareSystem); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyDeploymentNodeCheckTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyDeploymentNodeCheckTests.java new file mode 100644 index 00000000..2bde3561 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyDeploymentNodeCheckTests.java @@ -0,0 +1,71 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.DeploymentNode; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class EmptyDeploymentNodeCheckTests { + + @Test + public void run_Empty() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Name"); + + Recommendation recommendation = new EmptyDeploymentNodeInspection(workspace).run(deploymentNode); + Assertions.assertEquals(Priority.Low, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.deploymentnode.empty", recommendation.getType()); + assertEquals("The deployment node named \"Name\" is empty.", recommendation.getDescription()); + } + + @Test + public void run_WithDeploymentNode() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Deployment Node", "Description", "Technology"); + deploymentNode.addDeploymentNode("Deployment Node"); + + Recommendation recommendation = new EmptyDeploymentNodeInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + + @Test + public void run_WithInfrastructureNode() { + Workspace workspace = new Workspace("Name", "Description"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Deployment Node", "Description", "Technology"); + deploymentNode.addInfrastructureNode("Infrastructure Node"); + + Recommendation recommendation = new EmptyDeploymentNodeInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + + @Test + public void run_WithSoftwareSystemInstance() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Deployment Node", "Description", "Technology"); + deploymentNode.add(softwareSystem); + + Recommendation recommendation = new EmptyDeploymentNodeInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + + @Test + public void run_WithContainerInstance() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + DeploymentNode deploymentNode = workspace.getModel().addDeploymentNode("Deployment Node", "Description", "Technology"); + deploymentNode.add(container); + + Recommendation recommendation = new EmptyDeploymentNodeInspection(workspace).run(deploymentNode); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyModelInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyModelInspectionTests.java new file mode 100644 index 00000000..e022667e --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/EmptyModelInspectionTests.java @@ -0,0 +1,33 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class EmptyModelInspectionTests { + + @Test + public void run_WhenThereAreNoElements() { + Workspace workspace = new Workspace("Name", "Description"); + + Recommendation recommendation = new EmptyModelInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.empty", recommendation.getType()); + assertEquals("Add some elements to the model.", recommendation.getDescription()); + } + + @Test + public void run_WhenThereAreElements() { + Workspace workspace = new Workspace("Name", "Description"); + workspace.getModel().addSoftwareSystem("Name"); + + Recommendation recommendation = new EmptyModelInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspectionTests.java new file mode 100644 index 00000000..b9257dd0 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeDescriptionInspectionTests.java @@ -0,0 +1,37 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.InfrastructureNode; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class InfrastructureNodeDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + InfrastructureNode infrastructureNode = workspace.getModel().addDeploymentNode("Deployment Node") + .addInfrastructureNode("Name"); + + Recommendation recommendation = new InfrastructureNodeDescriptionInspection(workspace).run(infrastructureNode); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.infrastructurenode.description", recommendation.getType()); + assertEquals("Add a description to the infrastructure node named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + InfrastructureNode infrastructureNode = workspace.getModel().addDeploymentNode("Deployment Node") + .addInfrastructureNode("Name", "Description", "Technology"); + + Recommendation recommendation = new InfrastructureNodeDescriptionInspection(workspace).run(infrastructureNode); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspectionTests.java new file mode 100644 index 00000000..fd990cda --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/InfrastructureNodeTechnologyInspectionTests.java @@ -0,0 +1,37 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.InfrastructureNode; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class InfrastructureNodeTechnologyInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + InfrastructureNode infrastructureNode = workspace.getModel().addDeploymentNode("Deployment Node") + .addInfrastructureNode("Name"); + + Recommendation recommendation = new InfrastructureNodeTechnologyInspection(workspace).run(infrastructureNode); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.infrastructurenode.technology", recommendation.getType()); + assertEquals("Add a technology to the infrastructure node named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + InfrastructureNode infrastructureNode = workspace.getModel().addDeploymentNode("Deployment Node") + .addInfrastructureNode("Name", "Description", "Technology"); + + Recommendation recommendation = new InfrastructureNodeTechnologyInspection(workspace).run(infrastructureNode); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspectionTests.java new file mode 100644 index 00000000..3dcce3c0 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/MultipleSoftwareSystemsDetailedInspectionTests.java @@ -0,0 +1,79 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.documentation.Decision; +import com.structurizr.documentation.Format; +import com.structurizr.documentation.Section; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class MultipleSoftwareSystemsDetailedInspectionTests { + + @Test + public void run_MultipleSoftwareSystemsWithContainers() { + Workspace workspace = new Workspace("Name", "Description"); + workspace.getModel().addSoftwareSystem("A").addContainer("Container"); + workspace.getModel().addSoftwareSystem("B").addContainer("Container"); + + Recommendation recommendation = new MultipleSoftwareSystemsDetailedInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("This workspace describes the internal details of 2 software systems. It is recommended that a workspace contains the model, views, and documentation for a single software system only.", recommendation.getDescription()); + } + + @Test + public void run_MultipleSoftwareSystemsWithDocumentation() { + Workspace workspace = new Workspace("Name", "Description"); + workspace.getModel().addSoftwareSystem("A").getDocumentation().addSection(new Section(Format.Markdown, "# Section 1")); + workspace.getModel().addSoftwareSystem("B").getDocumentation().addSection(new Section(Format.Markdown, "# Section 1")); + + Recommendation recommendation = new MultipleSoftwareSystemsDetailedInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("This workspace describes the internal details of 2 software systems. It is recommended that a workspace contains the model, views, and documentation for a single software system only.", recommendation.getDescription()); + } + + @Test + public void run_MultipleSoftwareSystemsWithDecisions() { + Workspace workspace = new Workspace("Name", "Description"); + Decision decision = new Decision("1"); + decision.setTitle("Decision 1"); + decision.setFormat(Format.Markdown); + decision.setContent("Content"); + decision.setStatus("Accepted"); + workspace.getModel().addSoftwareSystem("A").getDocumentation().addDecision(decision); + workspace.getModel().addSoftwareSystem("B").getDocumentation().addDecision(decision); + + Recommendation recommendation = new MultipleSoftwareSystemsDetailedInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("This workspace describes the internal details of 2 software systems. It is recommended that a workspace contains the model, views, and documentation for a single software system only.", recommendation.getDescription()); + } + + @Test + public void run_SingleSoftwareSystem() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + a.addContainer("Container"); + + a.getDocumentation().addSection(new Section(Format.Markdown, "# Section 1")); + + Decision decision = new Decision("1"); + decision.setTitle("Decision 1"); + decision.setFormat(Format.Markdown); + decision.setContent("Content"); + decision.setStatus("Accepted"); + + a.getDocumentation().addDecision(decision); + + Recommendation recommendation = new MultipleSoftwareSystemsDetailedInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/OrphanedElementInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/OrphanedElementInspectionTests.java new file mode 100644 index 00000000..a92153de --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/OrphanedElementInspectionTests.java @@ -0,0 +1,40 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class OrphanedElementInspectionTests { + + @Test + public void run_WithOrphan() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + + Recommendation recommendation = new OrphanedElementInspection(workspace).run(a); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.element.orphaned", recommendation.getType()); + assertEquals("The software system named \"A\" is orphaned - add a relationship to/from it, or consider removing it from the model.", recommendation.getDescription()); + } + + @Test + public void run_WithoutOrphan() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + a.uses(b, "Uses"); + + Recommendation recommendation = new OrphanedElementInspection(workspace).run(a); + assertNull(recommendation); + + recommendation = new OrphanedElementInspection(workspace).run(b); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/PersonDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/PersonDescriptionInspectionTests.java new file mode 100644 index 00000000..03a4b07e --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/PersonDescriptionInspectionTests.java @@ -0,0 +1,35 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Person; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class PersonDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + Person person = workspace.getModel().addPerson("Name"); + + Recommendation recommendation = new PersonDescriptionInspection(workspace).run(person); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.person.description", recommendation.getType()); + assertEquals("Add a description to the person named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + Person person = workspace.getModel().addPerson("Name", "Description"); + + Recommendation recommendation = new PersonDescriptionInspection(workspace).run(person); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipDescriptionInspectionTests.java new file mode 100644 index 00000000..69b46f4a --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipDescriptionInspectionTests.java @@ -0,0 +1,57 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Component; +import com.structurizr.model.Container; +import com.structurizr.model.Relationship; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class RelationshipDescriptionInspectionTests { + + @Test + public void run_WithoutDescription_MediumPriority() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + Relationship relationship = a.uses(b, ""); + + Recommendation recommendation = new RelationshipDescriptionInspection(workspace).run(relationship); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.relationship.description", recommendation.getType()); + assertEquals("Add a description to the relationship between the software system named \"A\" and the software system named \"B\".", recommendation.getDescription()); + } + + @Test + public void run_WithoutDescription_LowPriority() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component a = container.addComponent("A"); + Component b = container.addComponent("B"); + Relationship relationship = a.uses(b, ""); + + Recommendation recommendation = new RelationshipDescriptionInspection(workspace).run(relationship); + Assertions.assertEquals(Priority.Low, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.relationship.description", recommendation.getType()); + assertEquals("Add a description to the relationship between the component named \"A\" and the component named \"B\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + Relationship relationship = a.uses(b, "Description"); + + Recommendation recommendation = new RelationshipDescriptionInspection(workspace).run(relationship); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipTechnologyInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipTechnologyInspectionTests.java new file mode 100644 index 00000000..2fe68d6c --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/RelationshipTechnologyInspectionTests.java @@ -0,0 +1,55 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.Container; +import com.structurizr.model.Relationship; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class RelationshipTechnologyInspectionTests { + + @Test + public void run_WithoutDescription_LowPriority() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + Relationship relationship = a.uses(b, "Description"); + + Recommendation recommendation = new RelationshipTechnologyInspection(workspace).run(relationship); + Assertions.assertEquals(Priority.Low, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.relationship.technology", recommendation.getType()); + assertEquals("Add a technology to the relationship between the software system named \"A\" and the software system named \"B\".", recommendation.getDescription()); + } + + @Test + public void run_WithoutDescription_MediumPriority() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Software System"); + Container a = softwareSystem.addContainer("A"); + Container b = softwareSystem.addContainer("B"); + Relationship relationship = a.uses(b, "Description"); + + Recommendation recommendation = new RelationshipTechnologyInspection(workspace).run(relationship); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.relationship.technology", recommendation.getType()); + assertEquals("Add a technology to the relationship between the container named \"A\" and the container named \"B\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + Relationship relationship = a.uses(b, "Description", "Technology"); + + Recommendation recommendation = new RelationshipTechnologyInspection(workspace).run(relationship); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspectionTests.java new file mode 100644 index 00000000..49389b30 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/model/SoftwareSystemDescriptionInspectionTests.java @@ -0,0 +1,35 @@ +package com.structurizr.assistant.model; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class SoftwareSystemDescriptionInspectionTests { + + @Test + public void run_WithoutDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Name"); + + Recommendation recommendation = new SoftwareSystemDescriptionInspection(workspace).run(softwareSystem); + Assertions.assertEquals(Priority.Medium, recommendation.getPriority()); + assertEquals("structurizr.recommendations.model.softwaresystem.description", recommendation.getType()); + assertEquals("Add a description to the software system named \"Name\".", recommendation.getDescription()); + } + + @Test + public void run_WithDescription() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem softwareSystem = workspace.getModel().addSoftwareSystem("Name", "Description"); + + Recommendation recommendation = new SoftwareSystemDescriptionInspection(workspace).run(softwareSystem); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspectionTests.java new file mode 100644 index 00000000..8b389b48 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/ContainerViewsForMultipleSoftwareSystemsInspectionTests.java @@ -0,0 +1,40 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ContainerViewsForMultipleSoftwareSystemsInspectionTests { + + @Test + public void run_MultipleSoftwareSystems() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + workspace.getViews().createContainerView(a, "Containers-A", "Description"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + workspace.getViews().createContainerView(b, "Containers-B", "Description"); + + Recommendation recommendation = new ContainerViewsForMultipleSoftwareSystemsInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("Container views exist for 2 software systems. It is recommended that a workspace includes container views for a single software system only.", recommendation.getDescription()); + } + + @Test + public void run_SingleSoftwareSystem() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + workspace.getViews().createContainerView(a, "Containers-A", "Description"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + + Recommendation recommendation = new ContainerViewsForMultipleSoftwareSystemsInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/view/EmptyViewsInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/EmptyViewsInspectionTests.java new file mode 100644 index 00000000..2d5c9b40 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/EmptyViewsInspectionTests.java @@ -0,0 +1,33 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class EmptyViewsInspectionTests { + + @Test + public void run_WhenThereAreNoViews() { + Workspace workspace = new Workspace("Name", "Description"); + + Recommendation recommendation = new EmptyViewsInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.views.empty", recommendation.getType()); + assertEquals("Add some views to the workspace.", recommendation.getDescription()); + } + + @Test + public void run_WhenThereAreViews() { + Workspace workspace = new Workspace("Name", "Description"); + workspace.getViews().createSystemLandscapeView("key", "Description"); + + Recommendation recommendation = new EmptyViewsInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspectionTests.java new file mode 100644 index 00000000..48ec2117 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/view/SystemContextViewsForMultipleSoftwareSystemsInspectionTests.java @@ -0,0 +1,40 @@ +package com.structurizr.assistant.view; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.model.SoftwareSystem; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class SystemContextViewsForMultipleSoftwareSystemsInspectionTests { + + @Test + public void run_MultipleSoftwareSystems() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + workspace.getViews().createSystemContextView(a, "SystemContext-A", "Description"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + workspace.getViews().createSystemContextView(b, "SystemContext-B", "Description"); + + Recommendation recommendation = new SystemContextViewsForMultipleSoftwareSystemsInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("System context views exist for 2 software systems. It is recommended that a workspace includes system context views for a single software system only.", recommendation.getDescription()); + } + + @Test + public void run_SingleSoftwareSystem() { + Workspace workspace = new Workspace("Name", "Description"); + SoftwareSystem a = workspace.getModel().addSoftwareSystem("A"); + workspace.getViews().createSystemContextView(a, "SystemContext-A", "Description"); + SoftwareSystem b = workspace.getModel().addSoftwareSystem("B"); + + Recommendation recommendation = new SystemContextViewsForMultipleSoftwareSystemsInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-assistant/src/test/java/com/structurizr/assistant/workspace/WorkspaceScopeInspectionTests.java b/structurizr-assistant/src/test/java/com/structurizr/assistant/workspace/WorkspaceScopeInspectionTests.java new file mode 100644 index 00000000..d48e93c7 --- /dev/null +++ b/structurizr-assistant/src/test/java/com/structurizr/assistant/workspace/WorkspaceScopeInspectionTests.java @@ -0,0 +1,34 @@ +package com.structurizr.assistant.workspace; + +import com.structurizr.Workspace; +import com.structurizr.assistant.Priority; +import com.structurizr.assistant.Recommendation; +import com.structurizr.configuration.WorkspaceScope; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class WorkspaceScopeInspectionTests { + + @Test + public void run_WithUnscopedWorkspace() { + Workspace workspace = new Workspace("Name", "Description"); + + Recommendation recommendation = new WorkspaceScopeInspection(workspace).run(); + Assertions.assertEquals(Priority.High, recommendation.getPriority()); + assertEquals("structurizr.recommendations.workspace.scope", recommendation.getType()); + assertEquals("This workspace has no defined scope. It is recommended that the workspace scope is set to \"Landscape\" or \"SoftwareSystem\".", recommendation.getDescription()); + } + + @Test + public void run_WithScopedWorkspace() { + Workspace workspace = new Workspace("Name", "Description"); + workspace.getConfiguration().setScope(WorkspaceScope.SoftwareSystem); + + Recommendation recommendation = new WorkspaceScopeInspection(workspace).run(); + assertNull(recommendation); + } + +} diff --git a/structurizr-client/src/main/java/com/structurizr/api/WorkspaceApiClient.java b/structurizr-client/src/main/java/com/structurizr/api/WorkspaceApiClient.java index 29bbb833..d12adf3a 100644 --- a/structurizr-client/src/main/java/com/structurizr/api/WorkspaceApiClient.java +++ b/structurizr-client/src/main/java/com/structurizr/api/WorkspaceApiClient.java @@ -296,8 +296,6 @@ public void putWorkspace(long workspaceId, Workspace workspace) throws Structuri workspace.setLastModifiedAgent(agent); workspace.setLastModifiedUser(getUser()); - workspace.countAndLogWarnings(); - HttpPut httpPut = new HttpPut(url + WORKSPACE_PATH + "/" + workspaceId); StringWriter stringWriter = new StringWriter(); diff --git a/structurizr-core/src/main/java/com/structurizr/Workspace.java b/structurizr-core/src/main/java/com/structurizr/Workspace.java index 8dd320eb..d48ead6e 100644 --- a/structurizr-core/src/main/java/com/structurizr/Workspace.java +++ b/structurizr-core/src/main/java/com/structurizr/Workspace.java @@ -163,74 +163,6 @@ public boolean isEmpty() { return model.isEmpty() && viewSet.isEmpty() && documentation.isEmpty(); } - /** - * Counts and logs any warnings within the workspace (e.g. missing element descriptions). - * - * @return the number of warnings - */ - public int countAndLogWarnings() { - final List warnings = new LinkedList<>(); - - // find elements with a missing description - getModel().getElements().stream() - .filter(e -> !(e instanceof SoftwareSystemInstance) && !(e instanceof ContainerInstance) && !(e instanceof DeploymentNode) && !(e instanceof InfrastructureNode)) - .filter(e -> e.getDescription() == null || e.getDescription().trim().length() == 0) - .forEach(e -> warnings.add(e.getCanonicalName() + " is missing a description.")); - - // find containers with a missing technology - getModel().getElements().stream() - .filter(e -> e instanceof Container) - .map(e -> (Container)e) - .filter(c -> c.getTechnology() == null || c.getTechnology().trim().length() == 0) - .forEach(c -> warnings.add(c.getCanonicalName() + " is missing a technology.")); - - // find components with a missing technology - getModel().getElements().stream() - .filter(e -> e instanceof Component) - .map(e -> (Component)e) - .filter(c -> c.getTechnology() == null || c.getTechnology().trim().length() == 0) - .forEach(c -> warnings.add(c.getCanonicalName() + " is missing a technology.")); - - // find component relationships with a missing description - for (Relationship relationship : getModel().getRelationships()) { - if (relationship.getSource() instanceof Component && relationship.getDestination() instanceof Component && - relationship.getSource().getParent().equals(relationship.getDestination().getParent())) { - // ignore component-component relationships inside the same container because these are - // often identified using reflection and won't have a description - // (i.e. let's not flood the user with warnings) - } else { - if (relationship.getDescription() == null || relationship.getDescription().trim().length() == 0) { - warnings.add("The relationship between " + relationship.getSource().getCanonicalName() + " and " + relationship.getDestination().getCanonicalName() + " is missing a description."); - } - } - } - - // diagram keys have not been specified - this is only applicable to - // workspaces created with the early versions of Structurizr for Java - getViews().getSystemLandscapeViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("System Landscape view \"" + v.getName() + "\": Missing key")); - getViews().getSystemContextViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("System Context view \"" + v.getName() + "\": Missing key")); - getViews().getContainerViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("Container view \"" + v.getName() + "\": Missing key")); - getViews().getComponentViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("Component view \"" + v.getName() + "\": Missing key")); - getViews().getDynamicViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("Dynamic view \"" + v.getName() + "\": Missing key")); - getViews().getDeploymentViews().stream() - .filter(v -> v.getKey() == null) - .forEach(v -> warnings.add("Deployment view \"" + v.getName() + "\": Missing key")); - - warnings.forEach(log::warn); - - return warnings.size(); - } - /** * Trims the workspace by removing all unused elements. */ diff --git a/structurizr-core/src/test/java/com/structurizr/WorkspaceTests.java b/structurizr-core/src/test/java/com/structurizr/WorkspaceTests.java index 4a523033..d0f5f979 100644 --- a/structurizr-core/src/test/java/com/structurizr/WorkspaceTests.java +++ b/structurizr-core/src/test/java/com/structurizr/WorkspaceTests.java @@ -1,10 +1,8 @@ package com.structurizr; -import com.structurizr.configuration.WorkspaceScope; import com.structurizr.documentation.Decision; import com.structurizr.documentation.Format; import com.structurizr.model.*; -import com.structurizr.view.SystemContextView; import com.structurizr.view.SystemLandscapeView; import org.junit.jupiter.api.Test; @@ -46,24 +44,6 @@ void isEmpty_ReturnsFalse_WhenThereIsDocumentation() throws Exception { assertFalse(workspace.isEmpty()); } - @Test - void countAndLogWarnings() { - Workspace workspace = new Workspace("Name", "Description"); - SoftwareSystem softwareSystem1 = workspace.getModel().addSoftwareSystem("Software System 1", null); - SoftwareSystem softwareSystem2 = workspace.getModel().addSoftwareSystem("Software System 2", " "); - Container container1 = softwareSystem1.addContainer("Name", "Description", null); - Container container2 = softwareSystem2.addContainer("Name", "Description", " "); - container1.uses(container2, null, null); - container2.uses(container1, " ", " "); - - Component component1A = container1.addComponent("A", null, null); - Component component1B = container1.addComponent("B", "", ""); - component1A.uses(component1B, null); - component1B.uses(component1A, ""); - - assertEquals(10, workspace.countAndLogWarnings()); - } - @Test void hydrate_DoesNotCrash() { Workspace workspace = new Workspace("Name", "Description");