From dc83cd12b2096c1b97391fb298cd75e453774bde Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 13 Nov 2024 19:45:50 +0100 Subject: [PATCH 01/28] First commit: migrating the resource identifier with the entities + test cases - Includes new module with: - Most of the model entities - Code-functionality of the resource identification - Test cases that validate the above functionality - Necesary changes in the pipelining code (actions) to make all pass-work --- .github/workflows/build.yml | 4 +- .github/workflows/release.yml | 2 +- pom.xml | 22 +- retorch-orchestration/.classpath | 40 ++ retorch-orchestration/.project | 23 ++ .../org.eclipse.core.resources.prefs | 6 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../.settings/org.eclipse.m2e.core.prefs | 4 + retorch-orchestration/pom.xml | 90 +++++ .../ClassifierUnitTestsSystemResources.json | 70 ++++ .../configurations/retorchCI.properties | 8 + .../orchestration/model/AccessModeEntity.java | 78 ++++ .../model/AccessModeTypesEntity.java | 66 +++ .../orchestration/model/CapacityEntity.java | 76 ++++ .../model/ElasticityModelEntity.java | 65 +++ .../orchestration/model/ResourceEntity.java | 142 +++++++ .../model/ResourceInstanceEntity.java | 18 + .../orchestration/model/SystemEntity.java | 80 ++++ .../orchestration/model/TJobEntity.java | 274 +++++++++++++ .../orchestration/model/TestCaseEntity.java | 61 +++ .../EmptyInputException.java | 22 + .../RetorchClassifier.java | 382 ++++++++++++++++++ .../RetorchClassifierUtils.java | 136 +++++++ .../unitary/components/ClassifierTests.java | 87 ++++ .../unitary/entities/TJobsEntityTests.java | 87 ++++ .../SyntheticInvalidClassTests.java | 138 +++++++ .../SyntheticClassTwoTests.java | 25 ++ .../insidepackage/SyntheticClassOneTests.java | 49 +++ .../orchestration/utils/ClassifierUtils.java | 107 +++++ .../orchestration/utils/GenericUtils.java | 115 ++++++ .../src/test/resources/log4j2.xml | 21 + sonar-project.properties | 2 +- 32 files changed, 2301 insertions(+), 7 deletions(-) create mode 100644 retorch-orchestration/.classpath create mode 100644 retorch-orchestration/.project create mode 100644 retorch-orchestration/.settings/org.eclipse.core.resources.prefs create mode 100644 retorch-orchestration/.settings/org.eclipse.jdt.core.prefs create mode 100644 retorch-orchestration/.settings/org.eclipse.m2e.core.prefs create mode 100644 retorch-orchestration/pom.xml create mode 100644 retorch-orchestration/retorchfiles/configurations/ClassifierUnitTestsSystemResources.json create mode 100644 retorch-orchestration/retorchfiles/configurations/retorchCI.properties create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java create mode 100644 retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java create mode 100644 retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java create mode 100644 retorch-orchestration/src/test/resources/log4j2.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc1aaa1..2829dc1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '8' + java-version: '16' cache: 'maven' - name: Build Annotation project @@ -50,7 +50,7 @@ jobs: - uses: javiertuya/branch-snapshots-action@v1.2.3 with: token: ${{ secrets.GITHUB_TOKEN }} - java-version: '8' + java-version: '16' mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' delete-old-snapshots: true min-snapshots-to-keep: 2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d511cb..2570c32 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: uses: actions/setup-java@v4 with: # running setup-java again overwrites the settings.xml distribution: 'temurin' - java-version: '8' + java-version: '16' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy diff --git a/pom.xml b/pom.xml index be45d20..a0ded23 100644 --- a/pom.xml +++ b/pom.xml @@ -16,17 +16,29 @@ - 1.8 - 1.8 + 16 + 16 UTF-8 retorch-annotations + retorch-orchestration + + junit + junit + 4.13.2 + test + + + org.slf4j + slf4j-api + 2.0.16 + @@ -71,7 +83,7 @@ Cristian Augusto - http://giis.uniovi.es + http://www.augustocristian.es Claudio de la Riva @@ -81,6 +93,10 @@ Javier Tuya http://giis.uniovi.es + + Jesús Morán + http://giis.uniovi.es + diff --git a/retorch-orchestration/.classpath b/retorch-orchestration/.classpath new file mode 100644 index 0000000..f7e4a1d --- /dev/null +++ b/retorch-orchestration/.classpath @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/retorch-orchestration/.project b/retorch-orchestration/.project new file mode 100644 index 0000000..dece056 --- /dev/null +++ b/retorch-orchestration/.project @@ -0,0 +1,23 @@ + + + retorch-orchestration + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/retorch-orchestration/.settings/org.eclipse.core.resources.prefs b/retorch-orchestration/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/retorch-orchestration/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/retorch-orchestration/.settings/org.eclipse.jdt.core.prefs b/retorch-orchestration/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/retorch-orchestration/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/retorch-orchestration/.settings/org.eclipse.m2e.core.prefs b/retorch-orchestration/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/retorch-orchestration/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml new file mode 100644 index 0000000..e1e08e6 --- /dev/null +++ b/retorch-orchestration/pom.xml @@ -0,0 +1,90 @@ + + 4.0.0 + + io.github.giis-uniovi + retorch + 1.1.1-SNAPSHOT + + retorch-orchestration + jar + retorch-orchestration + Multimodule maven project template, module without dependencies + http://github.com/giis-uniovi/samples-giis-template + + Software Engineering Research Group (GIIS) - Universidad de Oviedo, ES + http://giis.uniovi.es/ + + + + 2.18.1 + + 5.14.2 + + 1.5.12 + + + + + org.slf4j + slf4j-api + + + junit + junit + + + com.fasterxml.jackson.core + jackson-databind + ${jacksonjson.version} + + + org.mockito + mockito-core + ${mockito.version} + test + + + ch.qos.logback + logback-classic + ${logback-classic.version} + test + + + io.github.giis-uniovi + retorch-annotations + 1.1.1-SNAPSHOT + + + + + + org.jacoco + jacoco-maven-plugin + + + org.apache.maven.plugins + maven-surefire-report-plugin + + + org.apache.maven.plugins + maven-antrun-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + + \ No newline at end of file diff --git a/retorch-orchestration/retorchfiles/configurations/ClassifierUnitTestsSystemResources.json b/retorch-orchestration/retorchfiles/configurations/ClassifierUnitTestsSystemResources.json new file mode 100644 index 0000000..7ffd8e5 --- /dev/null +++ b/retorch-orchestration/retorchfiles/configurations/ClassifierUnitTestsSystemResources.json @@ -0,0 +1,70 @@ +{ + "mockElasticResource": { + "hierarchyParent": [], + "replaceable": ["lightElasticResource","heavyInElasRest"], + "elasticityModel": { + "elasticityID": "elasModelmockElasticResource", + "elasticity": 50, + "elasticityCost": 0.0 + }, + "resourceType": "LOGICAL", + "resourceID": "mockElasticResource", + "minimalCapacities": [ + { + "name": "memory", + "quantity": 0.5 + }, + { + "name": "processor", + "quantity": 2 + } + ], + "dockerImage": "someplaceholder1[IMG:]docker.someImage" + }, + "heavyInElasRest": { + "hierarchyParent": [ + "parentAllInelastic" + ], + "replaceable": [], + "elasticityModel": { + "elasticityID": "elasModelHeavyInElasRest", + "elasticity": 1, + "elasticityCost": 50.0 + }, + "resourceType": "LOGICAL", + "resourceID": "heavyInElasRest", + "minimalCapacities": [ + { + "name": "memory", + "quantity": 4 + }, + { + "name": "processor", + "quantity": 0.6 + } + ], + "dockerImage": "someplaceholder2[IMG:]docker.someImage" + }, + "lightElasticResource": { + "hierarchyParent": [], + "replaceable": [], + "elasticityModel": { + "elasticityID": "elasModelLightElasticResource", + "elasticity": 35, + "elasticityCost": 15.0 + }, + "resourceType": "LOGICAL", + "resourceID": "lightElasticResource", + "minimalCapacities": [ + { + "name": "memory", + "quantity": 1 + }, + { + "name": "processor", + "quantity": 0.5 + } + ], + "dockerImage": "someplaceholder3[IMG:]docker.someImage" + } +} \ No newline at end of file diff --git a/retorch-orchestration/retorchfiles/configurations/retorchCI.properties b/retorch-orchestration/retorchfiles/configurations/retorchCI.properties new file mode 100644 index 0000000..dadcf41 --- /dev/null +++ b/retorch-orchestration/retorchfiles/configurations/retorchCI.properties @@ -0,0 +1,8 @@ +agentCIName=any +sut-wait-html=FullTeaching +sut-location=$WORKSPACE +docker-frontend-name=https://full-teaching- +docker-frontend-port=5000 +external-binded-port= +external-frontend-url= +testsBasePath=somepath/somedir/ \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java new file mode 100644 index 0000000..e0cf7fe --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java @@ -0,0 +1,78 @@ +package giis.retorch.orchestration.model; + +public class AccessModeEntity { + + private AccessModeTypesEntity accessMode; + private boolean sharing = false; + private int concurrency = 1; + private ResourceEntity resource; + + public AccessModeEntity() {} + + public AccessModeEntity(AccessModeEntity accessMode) { + this.accessMode = accessMode.getAccessMode(); + this.concurrency = accessMode.getConcurrency(); + this.resource = accessMode.getResource(); + this.sharing = accessMode.getSharing(); + } + + /** + * Access mode constructor + * @param accessMode {@link AccessModeTypesEntity} that could be READONLY,WRITEONLY,READWRITE,DYNAMIC or NOACCESS + * @param sharing Boolean that represents if the resource can be shared or not + * @param concurrency Integer with the max number of concurrent access + * @param resource Resource on which the access mode is performed + */ + public AccessModeEntity(AccessModeTypesEntity accessMode, boolean sharing, int concurrency, ResourceEntity resource) { + this.accessMode = accessMode; + this.sharing = sharing; + this.concurrency = concurrency; + this.resource = resource; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; + AccessModeEntity objToCompare = ((AccessModeEntity) obj); + + return objToCompare.getSharing() == this.sharing && objToCompare.getConcurrency() == this.concurrency + && objToCompare.getAccessMode().equals(this.accessMode) && objToCompare.getResource().equals(this.resource); + } + + @Override + public String toString() { + return "a.m.{" + accessMode + ", " + sharing + ", " + concurrency + ",'" + resource + '\'' + '}'; + } + + public AccessModeTypesEntity getAccessMode() { + return accessMode; + } + public int getConcurrency() { + return concurrency; + } + public ResourceEntity getResource() { + return resource; + } + public boolean getSharing() { + return sharing; + } + + public void setSharing(boolean sharing) { + this.sharing = sharing; + } + public void setResource(ResourceEntity resource) { + this.resource = resource; + } + public void setConcurrency(int concurrency) { + this.concurrency = concurrency; + } + public void setAccessMode(AccessModeTypesEntity accessMode) { + this.accessMode = accessMode; + } + +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java new file mode 100644 index 0000000..13c9f56 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java @@ -0,0 +1,66 @@ +package giis.retorch.orchestration.model; + +/** + * This class is used as AccessMode parser for given a string representation of a RETORCH access mode (i.e: + * READONLY,READWRITE...) convert it into the proper enumeration. Also provides + */ +public class AccessModeTypesEntity { + + public enum type {READONLY, READWRITE, WRITEONLY, DYNAMIC, NOACCESS} + + private final String accessStringType; + + private type accessModeType; + + public AccessModeTypesEntity(String typeOfAccess) { + this.accessStringType = typeOfAccess; + switch (typeOfAccess) { + case "READONLY": + this.accessModeType = type.READONLY; + break; + case "READWRITE": + this.accessModeType = type.READWRITE; + break; + case "WRITEONLY": + this.accessModeType = type.WRITEONLY; + break; + case "DYNAMIC": + this.accessModeType = type.DYNAMIC; + break; + case "NOACCESS": + this.accessModeType = type.NOACCESS; + break; + default: + break; + } + } + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return this.accessStringType; + } + + @Override + public boolean equals(Object obj) { + if ((obj == null)||(!obj.getClass().equals(this.getClass()))) return false; + AccessModeTypesEntity currentType = ((AccessModeTypesEntity) obj); + return currentType.getAccessModeType() == this.getAccessModeType(); + } + + public type getAccessModeType() { + return accessModeType; + } + + /** + * Support method that checks if the given String is valid access mode + * @param accessMode String with the access mode: READONLY,READWRITE,WRITEONLY,DYNAMIC or NOACESS + */ + public static boolean isValidAccessMode(String accessMode) { + return accessMode.equals("READONLY") || accessMode.equals("READWRITE") || accessMode.equals("WRITEONLY") + || accessMode.equals("DYNAMIC") || accessMode.equals("NOACCESS"); + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java new file mode 100644 index 0000000..e04dd42 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java @@ -0,0 +1,76 @@ +package giis.retorch.orchestration.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * The {@code Capacity} class represents a capacity of with a name and a quantity. + * It provides methods to add to the quantity and to get and set the name and quantity. The capacity names that + * are supported are specified in {@code CapacityTypes}: memory, processor,slots and storage. + * If the provided name is not in the list of valid capacities, it defaults to "Wrong Capacity". + */ +public class CapacityEntity { + + private static final Logger log = LoggerFactory.getLogger(CapacityEntity.class); + public static final String MEMORY_NAME = "memory"; + public static final String PROCESSOR_NAME = "processor"; + public static final String SLOTS_NAME = "slots"; + public static final String STORAGE_NAME = "storage"; + + private String name; + private double quantity; + + protected static final Set LIST_CAPACITIES = new HashSet<>(); + static {Collections.addAll(LIST_CAPACITIES, MEMORY_NAME, PROCESSOR_NAME, SLOTS_NAME, STORAGE_NAME);} + + public CapacityEntity(@JsonProperty("name") String name, @JsonProperty("quantity") double quantity) { + if (LIST_CAPACITIES.contains(name)) { + setName(name); + } else { + log.error("The capacity: {} is not valid", name); + setName("Wrong Capacity"); + } + setQuantity(quantity); + } + + @Override + public int hashCode() { + return Objects.hash(name, quantity); + } + + @Override + public String toString() { + return "{"+"name:"+ getName() + ", "+"quantity:" + getQuantity() + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CapacityEntity that = (CapacityEntity) o; + return Objects.equals(this.getName(), that.getName()) && Objects.equals(this.getQuantity(), that.getQuantity()); + } + + public String getName() { + return name; + } + public double getQuantity() {return quantity;} + public static Set getCapacityNames(){return LIST_CAPACITIES;} + + public void setName(String name) { + this.name = name; + } + public void setQuantity(double quantity) { + this.quantity = quantity; + } + + public void addQuantity(double number) { + this.quantity += number; + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java new file mode 100644 index 0000000..9d8e2ac --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java @@ -0,0 +1,65 @@ +package giis.retorch.orchestration.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ElasticityModelEntity { + + private String elasticityID; + private int elasticity; + private double elasticityCost; + + public ElasticityModelEntity(String idElasticity) {this.elasticityID = idElasticity;} + + /** + * Elasticity model constructor + * @param elasticity Integer with the maximum amount of resources that can be deployed + * @param elasticityCost Double with the cost of one instance deployment + * @param elasticityID String with the ElasticityID + */ + public ElasticityModelEntity(@JsonProperty("elasticityID") String elasticityID, + @JsonProperty("elasticity") int elasticity, + @JsonProperty("elasticityCost") double elasticityCost) { + this.elasticityID = elasticityID; + this.elasticity = elasticity; + this.elasticityCost = elasticityCost; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "elas{" + "'" + elasticityID + '\'' + ", e=" + elasticity + ", cost=" + elasticityCost + '}'; + } + + @Override + public boolean equals(Object obj) { + if ((obj == null) ||(!obj.getClass().equals(this.getClass()))) return false; + ElasticityModelEntity currentType = ((ElasticityModelEntity) obj); + return currentType.getElasticity() == this.elasticity && currentType.getElasticityCost() == this.elasticityCost && + currentType.getElasticityID().equals(this.getElasticityID()); + } + + public int getElasticity() { + return elasticity; + } + public double getElasticityCost() { + return elasticityCost; + } + public String getElasticityID() { + return elasticityID; + } + + public void setElasticityID(String elasticityID) { + this.elasticityID = elasticityID; + } + public void setElasticityCost(double elasticityCost) { + this.elasticityCost = elasticityCost; + } + public void setElasticity(int elasticity) { + this.elasticity = elasticity; + } + +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java new file mode 100644 index 0000000..6ff9778 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java @@ -0,0 +1,142 @@ +package giis.retorch.orchestration.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +public class ResourceEntity { + + public enum type {PHYSICAL, LOGICAL, COMPUTATIONAL} + + private final Logger logResourceClass=LoggerFactory.getLogger(ResourceEntity.class); + + Marker errorMarker = MarkerFactory.getMarker("Error"); + private String resourceID; + private List hierarchyParent; + private List replaceable; + private List minimalCapacities; + private ElasticityModelEntity elasticityModel; + private type resourceType = type.LOGICAL; + private String dockerImage; + + public ResourceEntity(String resourceID) { + super(); + this.resourceID = resourceID; + this.replaceable = new LinkedList<>(); + this.hierarchyParent = new LinkedList<>(); + } + + public ResourceEntity() {} + + /** + * Resource constructor + * @param resourceID String with the resource identifier + * @param elasticityModel Resource Elasticity model + * @param replaceable List with the ids of those resources that could replace the resource + * @param resourceType type of the resource (LOGICAL, PHYSICAL or COMPUTATIONAL) + * @param hierarchyParent String with the resource hierarchical parent + * @param minimalCapacities List with the minimal {@link CapacityEntity} required by the resource + * @param dockerImage String with the Resource docker image name + */ + public ResourceEntity(@JsonProperty("resourceId") String resourceID, + @JsonProperty("hierarchyParent") List hierarchyParent, + @JsonProperty("replaceable") List replaceable, + @JsonProperty("elasticityModel") ElasticityModelEntity elasticityModel, + @JsonProperty("resourceType") type resourceType, + @JsonProperty("minimalCapacities")List minimalCapacities, + @JsonProperty("dockerImage") String dockerImage) { + this.resourceID = resourceID; + this.hierarchyParent = hierarchyParent; + this.replaceable = replaceable; + this.elasticityModel = elasticityModel; + this.resourceType = resourceType; + this.minimalCapacities = minimalCapacities; + this.dockerImage=dockerImage; + } + + public ResourceEntity(ResourceEntity resourceEntity) { + this.dockerImage = resourceEntity.dockerImage; + this.elasticityModel = resourceEntity.getElasticityModel(); + this.errorMarker = resourceEntity.errorMarker; + this.hierarchyParent = new LinkedList<>(); + this.hierarchyParent.addAll(resourceEntity.getHierarchyParent()); + this.minimalCapacities = resourceEntity.getMinimalCapacities(); + this.replaceable = new LinkedList<>(); + this.replaceable.addAll(resourceEntity.getReplaceable()); + this.resourceID = resourceEntity.getResourceID(); + this.resourceType = resourceEntity.getResourceType(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "res{" + this.getResourceID() + '\'' + ", p=" + this.getHierarchyParent() + ", r=" + this.getReplaceable() + ", " + this.getElasticityModel() + ", " + + this.getResourceType()+","+this.getMinimalCapacities()+ "}"; + } + + @Override + public boolean equals(Object obj) { + String message; + if (obj == null || !obj.getClass().equals(this.getClass())) return false; + ResourceEntity resClass = (ResourceEntity) obj; + if (!this.elasticityModel.equals(resClass.elasticityModel)) { + if (this.elasticityModel.getElasticityID().equals(resClass.elasticityModel.getElasticityID())){ + message=String.format("The elasticityModel of the resources with the same identifier " + "%s differ", resClass.getResourceID()); + logResourceClass.error(message);} + return false; + } + if ((!containsAllReplaceableElements(this.replaceable, resClass.getReplaceable())) || + (!this.hierarchyParent.equals(resClass.hierarchyParent)) || + (!this.getResourceType().equals(resClass.getResourceType()))) return false; + return this.getResourceID().equals(resClass.getResourceID()); + } + + public String getDockerImage() {return dockerImage;} + public ElasticityModelEntity getElasticityModel() {return elasticityModel;} + public List getHierarchyParent() {return hierarchyParent;} + public List getMinimalCapacities() {return minimalCapacities;} + public String getResourceID() {return resourceID;} + public type getResourceType() {return resourceType;} + public List getReplaceable() { + this.replaceable.sort(String::compareToIgnoreCase); + return replaceable; + } + + public void setDockerImage(String dockerImage) {this.dockerImage = dockerImage;} + public void setElasticityModel(ElasticityModelEntity elasticityModel) {this.elasticityModel = elasticityModel;} + public void setHierarchyParent(List hierarchyParent) {this.hierarchyParent = hierarchyParent;} + public void setMinimalCapacities(List minimalCapacities) { + minimalCapacities.sort(Comparator.comparing(CapacityEntity::getName)); + this.minimalCapacities = minimalCapacities; + } + public void setReplaceable(List replaceable) {this.replaceable = replaceable;} + public void setResourceID(String resourceID) {this.resourceID = resourceID;} + public void setResourceType(type resourceType) {this.resourceType = resourceType;} + + public void addHierarchyParent(String idResource) { + this.hierarchyParent.add(idResource); + } + + public void addReplaceableResource(String resourceID) { + this.replaceable.add(resourceID); + } + + public boolean containsAllReplaceableElements(List listOne, List listTwo) { + if (listOne.size() != listTwo.size()) return false; + for (String currentRes : listOne) { + if (!listTwo.contains(currentRes)) return false; + } + return true; + } + +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java new file mode 100644 index 0000000..e9d66bb --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java @@ -0,0 +1,18 @@ +package giis.retorch.orchestration.model; + +import java.util.List; + +/** + * The {@code ResourceInstance} class represents a resource with a name and a list of {@code Capacity} that requires + * for its instantiation.This class is used during the profile generation to calculate the overall {@code Capacity} that + * are used-required. + * It provides methods to get and set the name and capacities, and overrides the {@code equals}, {@code hashCode}, + * and {@code toString} methods for comparison and representation purposes taking into account the list of capacities. + */ +public class ResourceInstanceEntity extends ResourceEntity { + + public ResourceInstanceEntity(String name, List capacities) { + this.setMinimalCapacities(capacities); + this.setResourceID(name); + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java new file mode 100644 index 0000000..9e834c0 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java @@ -0,0 +1,80 @@ +package giis.retorch.orchestration.model; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +public class SystemEntity { + + private static final Logger logSystemClass = LoggerFactory.getLogger(SystemEntity.class); + + private final String name; + private final LinkedList resources; + private final List testCases; + + public SystemEntity(String name) { + this.name = name; + this.testCases = new LinkedList<>(); + this.resources = new LinkedList<>(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj == null)||(!obj.getClass().equals(this.getClass()))) return false; + SystemEntity objectToCompare = ((SystemEntity) obj); + if (!objectToCompare.getName().equals(this.name)) return false; + boolean containAllResources = new HashSet<>(objectToCompare.getResources()).containsAll(this.getResources()); + boolean containsAllTestCases = new HashSet<>(objectToCompare.getTestCases()).containsAll(this.getTestCases()); + return containAllResources && containsAllTestCases; + } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("System ID: ").append(getName()).append("\n"); + sb.append("Resources:\n"); + for (ResourceEntity res : getResources()){ + sb.append("\t").append(res).append("\n"); + } + sb.append("TestCases:\n"); + for (TestCaseEntity tc : getTestCases()){ + sb.append("\t").append(tc).append("\n"); + } + return sb.toString(); + } + + public String getName() {return name;} + public List getResources() {return resources;} + public List getTestCases() {return testCases;} + + public void addTestCase(TestCaseEntity test) { + this.testCases.add(test); + this.testCases.sort(Comparator.comparing(TestCaseEntity::getName)); + } + + public void addListOfResources(List listResources) { + this.resources.addAll(listResources); + this.resources.sort(Comparator.comparing(ResourceEntity::getResourceID)); + } + + public void addResourceClass(ResourceEntity resource) { + if (!this.resources.contains(resource)) { + this.resources.add(resource); + } else logSystemClass.info("The resource {} is contained in the system", resource.getResourceID()); + this.resources.sort(Comparator.comparing(ResourceEntity::getResourceID)); + } + + public void addListTestCases(List listTestCases) { + this.testCases.addAll(listTestCases); + this.testCases.sort(Comparator.comparing(TestCaseEntity::getName)); + } + +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java new file mode 100644 index 0000000..a207ab7 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java @@ -0,0 +1,274 @@ +package giis.retorch.orchestration.model; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +/** + * The {@code TJobClass} class represents a TJob with a name, stage, and a set of {@code ResourceClass}. + * When the TJob is created, it calculates the total amount of {@code Capacity} that is used by the list of + * {@code ResourceClass} required + */ +public class TJobEntity { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private Set totalCapacities; + private int stage; + private double startSetUp; + private double endSetUp; + private double startExec; + private double endExec; + private double startTearDown; + private double endTearDown; + private List listTestCases; + private List listResourceEntities; + private String idTJob = "Default"; + private String intraTJobSchedule = "SequentialScheduling"; + private Integer tJobConcurrency=50; + private double elasticityCostResources; + + public static final String LIFECYCLE_SETUP_NAME = "setup"; + public static final String LIFECYCLE_TESTEXECUTION_NAME = "testexec"; + public static final String LIFECYCLE_TEARDOWN_NAME = "teardown"; + + protected static final Set LIST_TJOB_LIFECYCLE; + static { + LIST_TJOB_LIFECYCLE = new HashSet<>(); + LIST_TJOB_LIFECYCLE.add(LIFECYCLE_SETUP_NAME); + LIST_TJOB_LIFECYCLE.add(LIFECYCLE_TESTEXECUTION_NAME); + LIST_TJOB_LIFECYCLE.add(LIFECYCLE_TEARDOWN_NAME); + } + + /** + * Default constructor of the TJob. The list of test cases and resources are instantiated and the concurrency + * is set to a default value. By default, the intra-schedule is set to Sequential, and is being checked when a + * new test + * case is added. + */ + public TJobEntity() { + this.listResourceEntities = new LinkedList<>(); + this.listTestCases = new LinkedList<>(); + } + public TJobEntity(String idTJob, int stage, List resourceInstances) { + //Attributes required by the tool + this.listTestCases=new LinkedList<>(); + //Attributes required for the cost model + this.idTJob = idTJob; + this.listResourceEntities = resourceInstances; + this.stage = stage; + CapacityEntity memory = new CapacityEntity(CapacityEntity.MEMORY_NAME, 0); + CapacityEntity processors = new CapacityEntity(CapacityEntity.PROCESSOR_NAME, 0); + CapacityEntity slots = new CapacityEntity(CapacityEntity.SLOTS_NAME, 0); + CapacityEntity storage = new CapacityEntity(CapacityEntity.STORAGE_NAME, 0); + for (ResourceEntity resource : resourceInstances) { + for (CapacityEntity capacityEntity : resource.getMinimalCapacities()) + switch (capacityEntity.getName()) { + case CapacityEntity.PROCESSOR_NAME: + processors.addQuantity(capacityEntity.getQuantity()); + break; + case CapacityEntity.MEMORY_NAME: + memory.addQuantity(capacityEntity.getQuantity()); + break; + case CapacityEntity.STORAGE_NAME: + storage.addQuantity(capacityEntity.getQuantity()); + break; + case CapacityEntity.SLOTS_NAME: + slots.addQuantity(capacityEntity.getQuantity()); + break; + default: + log.warn("Capacity {} not found", capacityEntity.getName()); + break; + } + } + totalCapacities = new HashSet<>(); + totalCapacities.add(memory); + totalCapacities.add(processors); + totalCapacities.add(slots); + totalCapacities.add(storage); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; + + TJobEntity objectToCompare = ((TJobEntity) obj); + for (TestCaseEntity tc : objectToCompare.getListTestCases()) { + if (!this.getListTestCases().contains(tc)) {return false;} + } + return this.getListResourceClasses().equals(objectToCompare.getListResourceClasses()) && + this.getIntraTJobSchedule().equals(objectToCompare.getIntraTJobSchedule()); + } + + @Override + public String toString() { + List testCasesNames = listTestCases.stream().map(TestCaseEntity::getName).toList(); + List resourceNames = + listResourceEntities.stream().map(ResourceEntity::getResourceID).toList(); + return "TJobClass [\n" + "listTc:{\n" + testCasesNames + "}, listRes " + resourceNames + ", intraSchedule '" + + intraTJobSchedule + '\'' + ", con " + tJobConcurrency + ']'; + } + + public static Set getListTJobLifecyclesNames() {return LIST_TJOB_LIFECYCLE;} + public static List getListTJobLifecyclesWithDesiredOrder() { + LinkedList desiredDataOrder = new LinkedList<>(); + desiredDataOrder.add(TJobEntity.LIFECYCLE_SETUP_NAME); + desiredDataOrder.add(TJobEntity.LIFECYCLE_TESTEXECUTION_NAME); + desiredDataOrder.add(TJobEntity.LIFECYCLE_TEARDOWN_NAME); + return desiredDataOrder; + } + + public Set getTotalCapacities() {return totalCapacities;} + public List getCapacityNames() {return this.getTotalCapacities().stream().map(CapacityEntity::getName).toList();} + public double getElasticityCostResources() {return elasticityCostResources;} + public double getEndExec() {return endExec;} + public double getEndSetUp() {return endSetUp;} + public double getEndTearDown() {return endTearDown;} + public String getIdTJob() {return idTJob.toLowerCase(Locale.ENGLISH);} + public String getIntraTJobSchedule() {return intraTJobSchedule;} + public List getListResourceClasses() {return listResourceEntities;} + public List getListTestCases() { + return listTestCases; + } + public int getStage() {return stage;} + public double getStartExec() {return startExec;} + public double getStartSetUp() {return startSetUp;} + public double getStartTearDown() {return startTearDown;} + + public void setEndExec(double endExec) {this.endExec = endExec;} + public void setEndSetUp(double endSetUp) {this.endSetUp = endSetUp;} + public void setEndTearDown(double endTearDown) {this.endTearDown = endTearDown;} + public void setIdTJob(String id) {this.idTJob = id;} + public void setStage(int stage) {this.stage = stage;} + public void setStartExec(double startExec) {this.startExec = startExec;} + public void setStartSetUp(double startSetUp) {this.startSetUp = startSetUp;} + public void setStartTearDown(double startTearDown) {this.startTearDown = startTearDown;} + public void setAvgTime(double stSetUp, double endSetUp, double stExec, double endExec, double stTearDown, + double endTearDown) { + if (stSetUp <= endSetUp && stExec <= endExec && stTearDown <= endTearDown && stSetUp < stExec && stExec < stTearDown) { + log.debug("The times provided are correct, setting the start and end of each phase"); + this.setStartSetUp(stSetUp); + this.setStartExec(stExec); + this.setStartTearDown(stTearDown); + + this.setEndSetUp(endSetUp); + this.setEndExec(endExec); + this.setEndTearDown(endTearDown); + } else { + throw new IllegalArgumentException("One or more times provided are not correct, please review that each " + + "phase starts before the end, and are continuous"); + } + } + + public Map.Entry> getCapacitiesGivenTime(double currentTime, double startExecutionTime) { + double adjustedStartSetUp = this.getStartSetUp() + startExecutionTime; + double adjustedEndSetUp = this.getEndSetUp() + startExecutionTime; + double adjustedStartExec = this.getStartExec() + startExecutionTime; + double adjustedEndExec = this.getEndExec() + startExecutionTime; + double adjustedStartTearDown = this.getStartTearDown() + startExecutionTime; + double adjustedEndTearDown = this.getEndTearDown() + startExecutionTime; + + if (currentTime >= adjustedStartSetUp && currentTime < adjustedEndSetUp) { + return new AbstractMap.SimpleEntry<>(LIFECYCLE_SETUP_NAME, this.getTotalCapacities()); + } + if (currentTime >= adjustedStartExec && currentTime < adjustedEndExec) { + return new AbstractMap.SimpleEntry<>(LIFECYCLE_TESTEXECUTION_NAME, this.getTotalCapacities()); + } + if (currentTime >= adjustedStartTearDown && currentTime < adjustedEndTearDown) { + return new AbstractMap.SimpleEntry<>(LIFECYCLE_TEARDOWN_NAME, this.getTotalCapacities()); + } + + return new AbstractMap.SimpleEntry<>("noexec", Collections.emptySet()); + } + + public boolean addTestCase(TestCaseEntity subject) { + if (listTestCases.contains(subject)) return false; + listTestCases.add(subject); + this.updateIntraTestCaseSchedule(); + + return true; + } + + /** + * Support method that updates the intra-Schedule of the given TJob. Iterates over all the TJob test cases in order + * to check if any of the test case requires a sequential access mode. In the case that this kind of test case exist + * the TJob is updated with a sequential scheduling and a single concurrency. If there are no sequential test cases + * the schedule remains as parallel and the concurrency is setter to the lower access mode value. + */ + public void updateIntraTestCaseSchedule() { + boolean thereAreAtLeastOneSequential = false; + for (TestCaseEntity subject : this.listTestCases) { + for (AccessModeEntity subjectAccessMode : subject.getAccessMode()) { + if (!subjectAccessMode.getSharing()) thereAreAtLeastOneSequential = true; + // Checks if the given concurrency is lower than stored (if its lower overwrite the value) + if (subjectAccessMode.getConcurrency() < this.tJobConcurrency) this.tJobConcurrency = subjectAccessMode.getConcurrency(); + } + if (thereAreAtLeastOneSequential) {this.intraTJobSchedule = "SequentialScheduling";} + else {this.intraTJobSchedule = "ParallelScheduling";} + } + } + + /** + * This method add a lis of test cases updating the intra- schedule after it. + * @param testCases List with the test cases to be added + */ + public void addListTestCases(List testCases) { + this.listTestCases.addAll(testCases); + this.updateIntraTestCaseSchedule(); + } + + public void addListResources(List listResources) { + for (ResourceEntity res : listResources) this.addResource(res); + } + /** + * This method add a new resource to the current TJob. First check that the resource is not contained in the + * TJob for after add it and increase the total elasticity cost of the TJob. + */ + public boolean addResource(ResourceEntity subject) { + if (listResourceEntities.contains(subject)) { + return false; + } + listResourceEntities.add(subject); + elasticityCostResources += subject.getElasticityModel().getElasticityCost(); + + return true; + } + + public void removeTestCase(TestCaseEntity tc) { + this.listTestCases.remove(tc); + this.updateIntraTestCaseSchedule(); + } + /** + * Support method, search between the elasticities of the Resources and returns the minimal value + */ + public int getMinimalElasticity() { + int minimalElasticity = 50; + for (ResourceEntity res : this.getListResourceClasses()) { + int currentElasticity = res.getElasticityModel().getElasticity(); + if (currentElasticity < minimalElasticity) minimalElasticity = currentElasticity; + } + + return minimalElasticity; + } + + /** + * Gets the minimal concurrency of the given TJob + */ + public int getMinimalConcurrency() { + int minimalConcurrency = 50; + for (TestCaseEntity tc : this.getListTestCases()) { + for (AccessModeEntity acc : tc.getAccessMode()) { + int concurrency = acc.getConcurrency(); + if (concurrency < minimalConcurrency) minimalConcurrency = concurrency; + } + } + + return minimalConcurrency; + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java new file mode 100644 index 0000000..bcebaf9 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java @@ -0,0 +1,61 @@ +package giis.retorch.orchestration.model; + +import java.util.LinkedList; +import java.util.List; + +public class TestCaseEntity { + + private final String name; + private final Class testClass; + private List accessMode; //List with the access modes (one access mode for each resource) + + /** + * RETORCH Test Case has the test name, its class and the access mode that performs over the resource + * @param nameTestCase String with the test case name + * @param classTestCase Class that contains the test case + */ + public TestCaseEntity(String nameTestCase, Class classTestCase) { + this.name = nameTestCase; + this.testClass = classTestCase; + this.accessMode = new LinkedList<>(); + } + + public Class getTestClass() { + return testClass; + } + public void addAccessMode(AccessModeEntity accessMode) { + this.accessMode.add(accessMode); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; + + TestCaseEntity objectToCompare = ((TestCaseEntity) obj); + boolean conditionOne = objectToCompare.getAccessMode().equals(this.accessMode); + boolean conditionTwo = objectToCompare.getName().equals(this.name); + return conditionOne && conditionTwo; + } + + @Override + public String toString() { + return "tc{" + "'" + name + '\'' + ", " + accessMode + '}'; + } + + public List getAccessMode() { + return accessMode; + } + public String getName() { + return name; + } + + public void setAccessMode(List accessMode) { + this.accessMode = accessMode; + } + +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java new file mode 100644 index 0000000..2652eb1 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java @@ -0,0 +1,22 @@ +package giis.retorch.orchestration.resourceidentification; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serial; + +/** + * This exception is thrown when the classifier receives an input that is empty or its invalid i.e: null, no exist + * directories... + */ +public class EmptyInputException extends Exception { + + @Serial + private static final long serialVersionUID = -6473170362328956807L; + private static final Logger logEmptyInputException = LoggerFactory.getLogger(EmptyInputException.class); + + public EmptyInputException(String errorMessage) { + super(errorMessage); + logEmptyInputException.error(errorMessage); + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java new file mode 100644 index 0000000..c0cff55 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java @@ -0,0 +1,382 @@ +package giis.retorch.orchestration.resourceidentification; + +import giis.retorch.annotations.AccessModes; +import giis.retorch.orchestration.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import giis.retorch.annotations.AccessMode; + +public class RetorchClassifier { + + private static final Logger log = LoggerFactory.getLogger(RetorchClassifier.class); + + private static final String CHORUS_ATTRIBUTES = " is not present"; + private static final String NO_EXIST = " doesn't exist"; + private final RetorchClassifierUtils deserializer; //Serializer employed to deserialize the resources info + + private Map listAllResources; + + /** + * Empty constructor used to validate RETORCH in the test case + */ + public RetorchClassifier() { + deserializer = new RetorchClassifierUtils(); + } + /** + * This method gets the file specified as package, in order to do this, instantiates the classLoader + * and gets from it the File, replacing the dots by the slash. If the file exist returns it, otherwise + * returns two types of exception + * @param packageName String with the package name + * @throws IllegalStateException if the classLoader couldn't be found + * @throws EmptyInputException if the Package is not in the Classpath + */ + + private static File getPackageSourceDirectory(String packageName) throws EmptyInputException, URISyntaxException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) { + throw new IllegalStateException("ClassLoader could not be Loaded"); + } + URL resourceURL = classLoader.getResource(packageName.replace('.', '/')); + if (resourceURL == null) { + throw new EmptyInputException("Package " + packageName + " not found on classpath."); + } + URI uri = resourceURL.toURI(); + Path path = Paths.get(uri); + return path.toFile(); + } + + /** + * This method retrieves given one packageName the different classes contained on it + * @param packageName String with the package name + * @param directory File with the directory required + * @return List with the different Class methods. + * This solution is inspired by the answer of this StackOverflow thread: + * ...... + */ + private static List> findClasses(File directory, String packageName) throws ClassNotFoundException { + List> classes = new ArrayList<>(); + if (!directory.exists()) { + return classes; + } + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + classes.addAll(findClasses(file, packageName + "." + file.getName())); + } else if (file.getName().endsWith(".class") && !file.getName().contains("$")) { + classes.add(Class.forName(packageName + '.' + file.getName().replace(".class", ""))); + } + } + } else { + log.error("Classes of the specified package {} not found", packageName); + } + return classes; + } + + /** + * This method deserializes the information related to the Resources Attributes, gets the package as a file + * Object, and use it to retrieve + * the different Classes of the package. Once the classes are retrieved, are used to retrieve the different + * Annotated Methods, resources and + * Access Modes that conforms que system. Finally, the system created is validated in order to check if the + * resources and test cases list are + * correct + * @param packageName String with the name of the package + * @param systemName String with the system name (must be the same as specified in the resource attributes JSON + * file + */ + public SystemEntity getSystemFromPackage(String systemName, String packageName) throws EmptyInputException, + IOException, ClassNotFoundException, URISyntaxException { + this.listAllResources= new HashMap<>(); + for (ResourceEntity res:deserializer.deserializeResources(systemName).values()){ + if (resourceChecker(res)){ + this.listAllResources.put(res.getResourceID(),res); + } + } + SystemEntity systemRetorch = new SystemEntity(systemName); + File directory = getPackageSourceDirectory(packageName); + List> listClassesPackage = findClasses(directory, packageName); + for (Class currentClass : listClassesPackage) { + SystemEntity temporalSystem = getSystemFromClass(systemName, currentClass); + addUniqueResources(systemRetorch, temporalSystem); + systemRetorch.addListTestCases(temporalSystem.getTestCases()); + } + sortSystemClass(systemRetorch); + return checkSystemClass(systemRetorch); + } + + private void addUniqueResources(SystemEntity systemRetorch, SystemEntity temporalSystem) { + temporalSystem.getResources().stream() + .filter(res -> !systemRetorch.getResources().contains(res)) + .forEach(systemRetorch::addResourceClass); + } + + private void sortSystemClass(SystemEntity systemRetorch) { + systemRetorch.getTestCases().sort(Comparator.comparing(TestCaseEntity::getName)); + systemRetorch.getResources().sort(Comparator.comparing(ResourceEntity::toString)); + } + + /** + * This method given a Class file and a System name, retrieves the System that is on it. In order to accomplish + * with it first + * retrieve the class methods.With these methods, iterate over them retrieving (1)The test method ant its access + * mode + * (2) The resources annotated to then validate it. The test method and resources are added to the returned system + * @param systemName String with the system name + * @param testCaseClass Class with the test cases annotated + */ + public SystemEntity getSystemFromClass(String systemName, Class testCaseClass) throws EmptyInputException, + IOException { + this.listAllResources = deserializer.deserializeResources(systemName); + SystemEntity systemRetorch = new SystemEntity(systemName); + List listMethods = this.getClassMethods(testCaseClass); + systemRetorch.addListOfResources(new ArrayList<>(listAllResources.values())); + for (Method m : listMethods) { + TestCaseEntity testCase = getTestCasesFromMethod(m, testCaseClass); + if (validateTestCase(testCase)) { + systemRetorch.addTestCase(testCase); + } + } + if (listMethods.isEmpty()) + throw new EmptyInputException(String.format("No annotated methods found in class %s", + testCaseClass.getName())); + return checkSystemClass(systemRetorch); + } + + /** + * Validation method for the test cases it checks : (1) Each resource has annotated its own access mode (2) The + * access modes + * remains to the annotated resources (3) The access mode is not empty + * @param testCase testCase to be validated + */ + public boolean validateTestCase(TestCaseEntity testCase) { + boolean output = true; + String message; + if (testCase.getAccessMode().isEmpty()) { + output = false; + message=String.format("The test method %s has no access mode",testCase.getName()); + log.error(message); + } + return output; + } + + /** + * Support method that retrieves the test cases of a given method. In order to accomplish it first, calls the + * support method that retrieves + * the access modes, for later create a new TestCaseClass object with the method name and its access modes* + * @param currentClass Class that belongs the method + * @param currentMethod Test case Method + */ + public TestCaseEntity getTestCasesFromMethod(Method currentMethod, Class currentClass) { + String methodName = currentMethod.getName(); + // Directly assign the result of getAccessModesFromMethod to listAccessModesMethod + List listAccessModesMethod = this.getAccessModesFromMethod(currentMethod); + TestCaseEntity newTestCase = new TestCaseEntity(methodName, currentClass); + newTestCase.setAccessMode(listAccessModesMethod); + return newTestCase; + } + + /** + * Support method that given one testMethod, retrieves all the Access modes annotated on it.In order to + * accomplish with + * it, checks if the resource and Access mode RETORCH annotations are present, retrieving a list with them.Then + * creates + * the accessModes with all the information retrieved from the annotations ( resource,elasticity,sharing...) + * @param testMethod Method to retrieve the annotations. + */ + public List getAccessModesFromMethod(Method testMethod) { + List listAccessModes = new ArrayList<>(); // Use ArrayList instead of LinkedList for better + + List listAccessModesTag = new ArrayList<>(); // random access performance + + if (testMethod.isAnnotationPresent(AccessMode.class)) { // Check for single annotation presence + listAccessModesTag.add(testMethod.getAnnotation(AccessMode.class)); + } + if (testMethod.isAnnotationPresent(AccessModes.class) ) { // Check for multiple annotations presence + listAccessModesTag.addAll(Arrays.asList(testMethod.getAnnotation(AccessModes.class).value())); // Use + // addAll instead of assignment to avoid overwriting previous values + } + for (AccessMode accessTag : listAccessModesTag) { + if (this.accessModeTagChecker(accessTag, testMethod.getName())) { + AccessModeEntity currentAccessMode = new AccessModeEntity(); + currentAccessMode.setConcurrency(accessTag.concurrency()); + ResourceEntity requiredResource = getRequiredResource(accessTag.resID()); + currentAccessMode.setResource(requiredResource); + currentAccessMode.setSharing(accessTag.sharing()); + currentAccessMode.setAccessMode(new AccessModeTypesEntity(accessTag.accessMode())); + listAccessModes.add(currentAccessMode); + } + } + return listAccessModes; + } + + /** + * Support method that checks the resources annotated with the access mode + */ + public ResourceEntity getRequiredResource(String idResource) { + String message; + if (listAllResources.containsKey(idResource)) { + return listAllResources.get(idResource); + } else { + message=String.format("The resource %s is not tagged", idResource); + log.info(message); + return new ResourceEntity("Resource Not valid"); + } + } + + /** + * Support method that retrieves the methods from a given class. This method filters the Jacoco Test method used + * to instrument the system and gets the coverage + * @param testClass Class to retrieve the methods + */ + public List getClassMethods(Class testClass) { + List methods = Arrays.stream(testClass.getDeclaredMethods()) + .sorted(Comparator.comparing(Method::toString)) // Sort methods + .filter(meth -> !meth.getName().equals("$jacocoInit")) // Filter out methods with name "$jacocoInit" + .toList(); // Collect results to a list + methods.forEach(meth -> log.info("The method name its : {}", meth.getName())); + return methods; + } + + /** + * Support method that validates que resources tagged checking: (1) Validates the elasticityTag (2) Checks if in + * the non + * serialized annotation is specified: (2.1)The hierarchy parent, (2.2)The replaceable resource and (2.3) The + * resource id + * for finally (3) check if there is only there are one Hierarchy Parent + * @param resource ResourceClass with the resource to check + */ + private boolean resourceChecker(ResourceEntity resource) { + List listMessages = new LinkedList<>(); + if (resource.getHierarchyParent().contains("None")) { + listMessages.add(String.format("The Hierarchy Parent Attribute in resource %s%s",resource.getResourceID(), CHORUS_ATTRIBUTES)); + } + if (resource.getReplaceable().size() == 1 && resource.getReplaceable().get(0).equals("None")) { + listMessages.add(String.format("The Replaceable Attribute in resource %s%s",resource.getResourceID(), CHORUS_ATTRIBUTES)); + } + if (resource.getResourceID().equals("None")) { + listMessages.add(String.format("The ResourceID Attribute in the res:%s %s", resource.getResourceID(),CHORUS_ATTRIBUTES)); + } + if (resource.getHierarchyParent().size() > 1) { + listMessages.add(String.format("There are more than 2 HierarchyParents in resource %s and is mandatory provide " + + "only one ",resource.getResourceID())); + } + if(listMessages.isEmpty()) log.debug("No errors produced during the Resource checking"); + else{for (String message : listMessages) {log.error(message);}} + + return elasticityChecker(resource) && listMessages.isEmpty(); + } + + /** + * Support method that checks the elasticity Model of the resource. It checks : (1) If the Resource omits one + * of the attributes : id,elasticity or cost, (2) If the elasticity or the cost is invalid (negative) + * @param resource Resource with all the attributes + */ + private boolean elasticityChecker(ResourceEntity resource) { + boolean isOutElasticityID = resource.getElasticityModel().getElasticityID().equals("None"); + boolean isOutElasticity = resource.getElasticityModel().getElasticity() == -1; + boolean isOutElasticityCost = resource.getElasticityModel().getElasticityCost() == -1; + List listMessages = new LinkedList<>(); + if (isOutElasticity && isOutElasticityCost && isOutElasticityID) { + listMessages.add(String.format("No Elasticity Annotation Specified in the resource %s", resource.getResourceID())); + return false; + } + if (isOutElasticityID) { + listMessages.add(String.format("The ElasticityId Attribute in the resource %s %s", resource.getResourceID(), CHORUS_ATTRIBUTES)); + } + if (isOutElasticity) { + listMessages.add(String.format("The Elasticity Attribute in the resource %s%s",resource.getResourceID(), CHORUS_ATTRIBUTES)); + } else { + if (resource.getElasticityModel().getElasticity() <= 0) { + listMessages.add(String.format("The Specified Elasticity in resource %s is not valid", resource.getResourceID())); + } + } + if (isOutElasticityCost) { + listMessages.add(String.format("The Elasticity Cost Attribute in resource %s%s", resource.getResourceID(), CHORUS_ATTRIBUTES)); + } else { + if (resource.getElasticityModel().getElasticityCost() < 0) { + listMessages.add(String.format("The Specified Elasticity Cost in resource %s is not valid", resource.getResourceID())); + } + } + if(listMessages.isEmpty()) log.debug("No errors produced during the ElasticityMode checking"); + else{for (String message : listMessages) {log.error(message);}} + + return listMessages.isEmpty(); + } + + /** + * Support method that checks the Access mode of the resource. It checks : (1) If the Tag doesn't have + * one of the attributes: IdResource, concurrency,Access Mode Type or sharing, + * (2) If the sharing attribute its contradictory with the concurrency + * @param accessModeTag AccessMode tag + * @param methodName String with the method name + */ + private boolean accessModeTagChecker(AccessMode accessModeTag, String methodName) { + List listMessages = new LinkedList<>(); + + checkConcurrency(accessModeTag, methodName, listMessages); + if ("None".equals(accessModeTag.resID())) { + listMessages.add(String.format("The ResourceID Attribute in method %s%s", methodName, CHORUS_ATTRIBUTES)); + } + checkAccessModeType(accessModeTag, methodName, listMessages); + + if (listMessages.isEmpty()) { + log.debug("No errors produced during the AccessModeTag checking"); + } else { + for (String message: listMessages) {log.error(message);} + } + + return listMessages.isEmpty(); + } + + private void checkConcurrency(AccessMode accessModeTag, String methodName, List listMessages) { + if (accessModeTag.concurrency() == -1) { + listMessages.add(String.format("The Concurrency Attribute in method %s%s", methodName, CHORUS_ATTRIBUTES)); + } + + if (accessModeTag.sharing() && accessModeTag.concurrency() < 2) { + listMessages.add(String.format("Invalid Concurrency in method %s: shareable resource with concurrency < 2", methodName)); + } else if (!accessModeTag.sharing() && accessModeTag.concurrency() > 1) { + listMessages.add(String.format("Invalid Concurrency in method %s: non-shareable resource with concurrency > 1", methodName)); + } + } + + private void checkAccessModeType(AccessMode accessModeTag, String methodName, List listMessages) { + if (!AccessModeTypesEntity.isValidAccessMode(accessModeTag.accessMode())) { + String message = accessModeTag.accessMode().equals("NOASSIGNED") + ? String.format("The AccessModeType in method %s is not specified", methodName) + : String.format("The AccessModeType in method %s%s", methodName, NO_EXIST); + listMessages.add(message); + } + } + + /** + * Support method that validates the System provided as parameter. It checks that the replaceable resources exists + * @param systemToCheck System to check tag + */ + private SystemEntity checkSystemClass(SystemEntity systemToCheck) { + SystemEntity systemEntityOutput = new SystemEntity(systemToCheck.getName()); + List idResourcesList = listAllResources.values().stream() + .map(ResourceEntity::getResourceID) + .toList(); + systemToCheck.getResources().stream() + .filter(res -> idResourcesList.containsAll(res.getReplaceable())) + .forEach(systemEntityOutput::addResourceClass); + systemToCheck.getResources().stream() + .filter(res -> !idResourcesList.containsAll(res.getReplaceable())) + .forEach(res -> log.error("The Replaceable of resource {}{}", res.getResourceID(), NO_EXIST)); + systemEntityOutput.addListTestCases(systemToCheck.getTestCases()); + + return systemEntityOutput; + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java new file mode 100644 index 0000000..760dbf3 --- /dev/null +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java @@ -0,0 +1,136 @@ +package giis.retorch.orchestration.resourceidentification; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import giis.retorch.orchestration.model.ElasticityModelEntity; +import giis.retorch.orchestration.model.ResourceEntity; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +public class RetorchClassifierUtils { + + private final Logger logSerializer = LoggerFactory.getLogger(RetorchClassifierUtils.class); + private static final String FOLDER_RESOURCES = "retorchfiles/configurations/";//Base path of the resource files + + final HashMap resourcesToSerialize;//Map with the dictionary of resources to serialize + final ObjectMapper mapper; + + /** + * RETORCH Serializer provides utils to deserialize the configuration files, and create them from scratch with the + * RETORCH entities that they want to serialize in these files. + */ + public RetorchClassifierUtils() { + resourcesToSerialize = new HashMap<>(); + mapper = new ObjectMapper(); + } + + /** + * Support method that given an identification, elasticity cost, elasticity, type and hierarchy parent, adds to + * the mapper + * this resource in order to after that serialize it into a resources file + * + * @param hierarchyParent String with the hierarchy parent id + * @param elasticity Integer with the resource elasticity + * @param elasticityCost Double with the elasticity cost + * @param resourceType String with the resource type + * @param resourceId String with the resource ID + */ + public void addResourceToSerialize(String resourceId, double elasticityCost, int elasticity, String resourceType, + String hierarchyParent) { + ElasticityModelEntity elasModel = new ElasticityModelEntity("elasModel" + resourceId); + elasModel.setElasticityCost(elasticityCost); + elasModel.setElasticity(elasticity); + resourcesToSerialize.put(resourceId, new ResourceEntity(resourceId, + new LinkedList<>(Collections.singletonList(hierarchyParent)), new LinkedList<>(), elasModel, + getResourceTypeFromAnnotation(resourceType), new LinkedList<>(), "someimage")); + } + + /** + * Support method that given a String returns the resourceType that it represents. + * + * @param type String with the type i.e. LOGICAL,COMPUTATIONAL or PHYSICAL + */ + private ResourceEntity.type getResourceTypeFromAnnotation(String type) { + try { + return ResourceEntity.type.valueOf(type); + } catch (IllegalArgumentException e) { + return ResourceEntity.type.LOGICAL; // Default to LOGICAL if type is not recognized + } + } + + /** + * Support method that adds a resource to the dictionary to serialize without hierarchy parent + * + * @param elasticity Integer with the resource elasticity + * @param elasticityCost Double with the elasticity cost + * @param resourceType String with the resource type + * @param resourceId String with the resource ID + */ + public void addResourceToSerialize(String resourceId, double elasticityCost, int elasticity, String resourceType) { + ElasticityModelEntity elasModel = new ElasticityModelEntity("elasModel" + resourceId); + elasModel.setElasticityCost(elasticityCost); + elasModel.setElasticity(elasticity); + resourcesToSerialize.put(resourceId, new ResourceEntity(resourceId, new LinkedList<>(), new LinkedList<>(), + elasModel, getResourceTypeFromAnnotation(resourceType), new LinkedList<>(), "someImage")); + } + + /** + * Support method used to give a System name, serialize the resources stored into the mapper struct. + * + * @param name String with the system name + */ + public void serializeResources(String name) throws IOException { + Files.createDirectories(Paths.get(FOLDER_RESOURCES)); + writeSerializationToFile(FOLDER_RESOURCES + name + "SystemResources.json", + mapper.writeValueAsString(resourcesToSerialize)); + } + + /** + * Writes the given string to a file at the specified path. + * + * @param filePath the path of the file to write to + * @param output the string to write to the file + */ + private void writeSerializationToFile(String filePath, String output) { + try { + Path path = Paths.get(filePath); + byte[] strToBytes = output.getBytes(); + Files.write(path, strToBytes); + } catch (IOException e) { + logSerializer.error("The path {} doesn't exist", filePath); + } + } + + /** + * Deserializes the JSON content from the given file into an object of the specified type. + * + * @param filePath the path of the file to deserialize + * @param typeRef the type of the object to deserialize to + * @return the deserialized object + * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is + * read + */ + public T deserialize(String filePath, TypeReference typeRef) throws IOException { + String json = new String(Files.readAllBytes(Paths.get(filePath))); + return mapper.readValue(json, typeRef); + } + + /** + * Deserializes the SystemResources.json file in the /retorchresources folder into a Map of ResourceClass objects. + * + * @param name the name of the SystemResources.json file to deserialize + * @return the deserialized Map of ResourceClass objects + * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is + * read + */ + public Map deserializeResources(String name) throws IOException { + return deserialize(FOLDER_RESOURCES + name + "SystemResources.json", new TypeReference<>() { + }); + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java new file mode 100644 index 0000000..07af049 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java @@ -0,0 +1,87 @@ +package giis.retorch.orchestration.unitary.components; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.Appender; +import giis.retorch.orchestration.model.SystemEntity; +import giis.retorch.orchestration.resourceidentification.EmptyInputException; +import giis.retorch.orchestration.resourceidentification.RetorchClassifier; +import giis.retorch.orchestration.unitary.testdata.classifier.SyntheticInvalidClassTests; +import giis.retorch.orchestration.utils.ClassifierUtils; +import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage.SyntheticClassOneTests; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.slf4j.LoggerFactory; + + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.*; + +public class ClassifierTests { + + private static final String SYSTEM_NAME = "ClassifierUnitTests"; + private final Appender appender = mock(Appender.class); //use Mockito's ArgumentCaptor to capture all logging + // events in your test case + private RetorchClassifier classifier; //mock the Appender of your Logger object + private ClassifierUtils utilsClassifier; + + @Before + public void setUp() { + //Not sure if it's the correct fix, I ve added both loggers to the appended. I am not sure if exist something + // like ROOT log in sfl-4j, but it works + ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(RetorchClassifier.class); + logger.addAppender(appender); + classifier = new RetorchClassifier(); + utilsClassifier = new ClassifierUtils(); + } + + @Test + public void testUnitArchIResValidPackage() throws EmptyInputException, IOException, ClassNotFoundException, + URISyntaxException { + String packageName = "giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage"; + SystemEntity currentSystem = classifier.getSystemFromPackage(SYSTEM_NAME, packageName); + SystemEntity expectedSystem = utilsClassifier.generateSystemPackage(); + assertEquals(expectedSystem.toString(), currentSystem.toString()); + } + + @Test + public void testUnitArchIResValidClass() throws EmptyInputException, IOException { + Class testClass = SyntheticClassOneTests.class; + SystemEntity systemEntity = classifier.getSystemFromClass(SYSTEM_NAME, testClass); + SystemEntity expectedSystem = utilsClassifier.generateSystemFromClass(); + assertEquals(expectedSystem.toString(), systemEntity.toString()); + } + + @Test(expected = EmptyInputException.class) + public void testUnitArchIResInvalidEmptyPackage() throws EmptyInputException, IOException, ClassNotFoundException + , URISyntaxException { + String packageName = "retorch.examples.architecture.aggregator.emptypackage"; + classifier.getSystemFromPackage(SYSTEM_NAME, packageName); + utilsClassifier.generateSystemFromClass(); + } + + @Test + public void testUnitArchIResInvalidClass() throws EmptyInputException, IOException { + Class invalidClass = SyntheticInvalidClassTests.class; + classifier.getSystemFromClass(SYSTEM_NAME, invalidClass); + ArgumentCaptor argument = + ArgumentCaptor.forClass(ch.qos.logback.classic.spi.LoggingEvent.class); + verify(appender, atLeast(25)).doAppend(argument.capture()); + List listEvents = argument.getAllValues(); + List listMessages = listEvents.stream().map(LoggingEvent::getMessage).toList(); + // Omission of attributes in the accessMode + assertTrue(listMessages.contains("The AccessModeType in method testThreeAttributesLoosingAccessMode is not specified")); // Check that the omitted AccessMode is detected + assertTrue(listMessages.contains("The Concurrency Attribute in method testTwoAttributesLoosingAccessMode is not present")); // Check that the concurrency omitted is detected + assertTrue(listMessages.contains("The ResourceID Attribute in method testTwoAttributesLoosingAccessMode is not present")); // Check that the resourceId omitted is detected + // Validation of the attributes + assertTrue(listMessages.contains("The AccessModeType in method validationAccessModeAttributes doesn't exist")); // AccessMode Invalid + assertTrue(listMessages.contains("The Concurrency in method validationAccessModeAttributes is not valid: non shareable resource with >1 concurrency")); // Concurrency Invalid sharing=true && <2 and sharing + assertTrue(listMessages.contains("The Concurrency in method validationAccessModeAttributes is not valid: shareable resource with >2 concurrency")); // Concurrency Invalid + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java new file mode 100644 index 0000000..2f932a3 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java @@ -0,0 +1,87 @@ +package giis.retorch.orchestration.unitary.entities; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import giis.retorch.orchestration.model.CapacityEntity; +import giis.retorch.orchestration.model.ResourceEntity; +import giis.retorch.orchestration.model.TJobEntity; +import giis.retorch.orchestration.model.ResourceInstanceEntity; + +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; + +public class TJobsEntityTests { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + TJobEntity tjob; + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + log.info("****** Running test: {} ******", testName.getMethodName()); + LinkedList listCapacities = new LinkedList<>(); + listCapacities.add(new CapacityEntity("memory", 4)); + listCapacities.add(new CapacityEntity("processor", 3)); + ResourceInstanceEntity resourceOne = new ResourceInstanceEntity("webserver", listCapacities); + LinkedList listResources = new LinkedList<>(); + listResources.add(resourceOne); + tjob = new TJobEntity("tjoba", 0, listResources); + + log.info("****** Set-up for test: {} ended ******", testName.getMethodName()); + } + + @Test + public void testTJobAvgTime() { + assertThrows(IllegalArgumentException.class, () -> + tjob.setAvgTime(25, 10, 11, 16, 17, 20)); + assertThrows(IllegalArgumentException.class, () -> + tjob.setAvgTime(20, 30, 10, 16, 5, 7)); + assertThrows(IllegalArgumentException.class, () -> + tjob.setAvgTime(30, 31, 30, 35, 40, 45)); + tjob.setAvgTime(0, 10, 11, 16, 17, 21); + + assertEquals(0, tjob.getStartSetUp(), 0); + assertEquals(10, tjob.getEndSetUp(), 0); + assertEquals(11, tjob.getStartExec(), 0); + assertEquals(16, tjob.getEndExec(), 0); + assertEquals(17, tjob.getStartTearDown(), 0); + assertEquals(21, tjob.getEndTearDown(), 0); + } + + @Test + public void testLifecycleCapacities() { + tjob.setAvgTime(2, 10, 11, 16, 17, 21); + CapacityEntity capacityOne = new CapacityEntity("memory", 4); + CapacityEntity capacityTwo = new CapacityEntity("processor", 3); + + Map.Entry> output; + output = tjob.getCapacitiesGivenTime(1, 0); + assertEquals("noexec", output.getKey()); + assertTrue(output.getValue().isEmpty()); + output = tjob.getCapacitiesGivenTime(2, 0); + assertEquals("setup", output.getKey()); + assertTrue(output.getValue().contains(capacityOne)); + assertTrue(output.getValue().contains(capacityTwo)); + output = tjob.getCapacitiesGivenTime(12, 0); + assertEquals("testexec", output.getKey()); + assertTrue(output.getValue().contains(capacityOne)); + assertTrue(output.getValue().contains(capacityTwo)); + output = tjob.getCapacitiesGivenTime(19, 0); + assertEquals("teardown", output.getKey()); + assertTrue(output.getValue().contains(capacityOne)); + assertTrue(output.getValue().contains(capacityTwo)); + output = tjob.getCapacitiesGivenTime(21, 0); + assertEquals("noexec", output.getKey()); + assertTrue(output.getValue().isEmpty()); + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java new file mode 100644 index 0000000..d2e06f5 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java @@ -0,0 +1,138 @@ +package giis.retorch.orchestration.unitary.testdata.classifier; + +import giis.retorch.annotations.AccessMode; +import org.junit.Assert; +import org.junit.Test; + +public class SyntheticInvalidClassTests { + + /** + * Attributes omitted: elasticityModel and resource Type + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testZeroLoosingAttributes() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Attributes omitted: hierarchy parent, resource id and replaceable resources + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testOneLoosingAttributes() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Invalid value of elasticity and elasticity cost. + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testValidatesElasticityValuesElasticityAndElasticityCost() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Attributes omitted: resource id, and concurrency + */ + @AccessMode(accessMode = "READWRITE") + @Test + public void testTwoAttributesLoosingAccessMode() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Attributes omitted: type of access mode and sharing + */ + @AccessMode(resID = "heavyInvalidInElasRest", concurrency = 1) + @Test + public void testThreeAttributesLoosingAccessMode() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Three errors: sharing=false with a concurrency of >1, no valid access mode and sharing true && concurrency<2 + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 4) + @AccessMode(concurrency = 1, sharing = true, resID = "mockInvalidElasticResource", accessMode = + "InventedAccessMode") + @Test + public void validationAccessModeAttributes() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Resource annotation no provided + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testDifferentNumberAnnotationsResource() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Error: Resource that doesn't exist in AccessMode^ + */ + @AccessMode(resID = "ResourceNotExist", accessMode = "READWRITE", concurrency = 1) + @Test + public void testResourceThatNotExist() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Not annotated resource (but exist) + */ + @AccessMode(resID = "lightElasticResource", accessMode = "READWRITE", concurrency = 1) + @Test + public void resourceThatExistButNotAnnotated() { + Assert.assertTrue(true);// Only for analysis purposes + } + + @Test + public void resourceWithoutAccessMode() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Provides a "good resource" for after match against it the non-consistent ones + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testResourcesDifferentReplaceableGoodResource() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Method with a different resource than the last specified + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testResourcesDifferentReplaceableBadResource() { + Assert.assertTrue(true);// Only for analysis purposes + } + + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testElasticityModelDifferentThanSpecified() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Two hierarchy parents provided + */ + @AccessMode(resID = "heavyInvalidInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testResourceWithTwoHierarchyParents() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Replaceable resource doesn't exist + */ + @AccessMode(resID = "OtherHeavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testResourceWithBadReplaceable() { + Assert.assertTrue(true);// Only for analysis purposes + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java new file mode 100644 index 0000000..f92ca42 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java @@ -0,0 +1,25 @@ +package giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage; + +import giis.retorch.annotations.AccessMode; +import org.junit.Assert; +import org.junit.Test; + +public class SyntheticClassTwoTests { + + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testFourH() { + Assert.assertTrue(true);// Only for analysis purposes + } + + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testFiveH() { + Assert.assertTrue(true);// Only for analysis purposes + } + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @Test + public void testEightH() { + Assert.assertTrue(true);// Only for analysis purposes + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java new file mode 100644 index 0000000..f890df7 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java @@ -0,0 +1,49 @@ +package giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage; + +import giis.retorch.annotations.AccessMode; +import org.junit.Assert; +import org.junit.Test; + +public class SyntheticClassOneTests { + + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @AccessMode(resID = "lightElasticResource", accessMode = "READWRITE", concurrency = 4, sharing = true) + @Test + public void testOneH() { + Assert.assertTrue(true);// Only for analysis purposes + } + + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @AccessMode(sharing = true, concurrency = 4, accessMode = "READWRITE", resID = "lightElasticResource") + @Test + public void testTwoH() { + Assert.assertTrue(true);// Only for analysis purposes + } + + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @AccessMode(concurrency = 4, sharing = true, resID = "mockElasticResource", accessMode = "READONLY") + @Test + public void testThreeH() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * This test case omits: type and parent in the first resource, elasticity cost and elasticity in the second one + */ + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @AccessMode(sharing = true, concurrency = 4, accessMode = "READWRITE", resID = "lightElasticResource") + @Test + public void testSixH() { + Assert.assertTrue(true);// Only for analysis purposes + } + + /** + * Only specifying the minimal resources required + */ + @AccessMode(resID = "heavyInElasRest", accessMode = "READWRITE", concurrency = 1) + @AccessMode(concurrency = 4, sharing = true, resID = "lightElasticResource", accessMode = "READWRITE") + @Test + public void testSevenH() { + Assert.assertTrue(true);// Only for analysis purposes + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java new file mode 100644 index 0000000..6eaccfd --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java @@ -0,0 +1,107 @@ +package giis.retorch.orchestration.utils; + +import giis.retorch.orchestration.model.*; +import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.SyntheticClassTwoTests; +import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage.SyntheticClassOneTests; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +public class ClassifierUtils extends GenericUtils { + + public List getAllTestCases() { + LinkedList listTestCases = getFirstClassTestCases(); + TestCaseEntity tCMFour = new TestCaseEntity("testFourH", SyntheticClassTwoTests.class); + tCMFour.addAccessMode(getOtherAccessModeHeavyInelasticResource()); + listTestCases.add(tCMFour); + TestCaseEntity tCMFive = new TestCaseEntity("testFiveH", SyntheticClassTwoTests.class); + tCMFive.addAccessMode(getOtherAccessModeHeavyInelasticResource()); + listTestCases.add(tCMFive); + TestCaseEntity tCMEight = new TestCaseEntity("testEightH", SyntheticClassTwoTests.class); + tCMEight.addAccessMode(this.getJSONSavedInelasticAccessMode()); + listTestCases.add(tCMEight); + return listTestCases; + } + + public SystemEntity generateSystemPackage() { + generateSystemResources(); + SystemEntity expectedSystem = new SystemEntity("ClassifierUnitTests"); + expectedSystem.addResourceClass(this.getHeavyInelasticResource()); + expectedSystem.addResourceClass(this.getLightElasticResource()); + expectedSystem.addResourceClass(this.getMockElasticResource()); + expectedSystem.addResourceClass(this.getJSONSavedInelasticResource()); + expectedSystem.addResourceClass(this.getJSONSavedElasticResource()); + expectedSystem.getResources().sort(Comparator.comparing(ResourceEntity::toString)); + expectedSystem.addListTestCases(getAllTestCases().stream().sorted(Comparator.comparing(TestCaseEntity::getName)).toList()); + return expectedSystem; + } + + public SystemEntity generateSystemFromClass() { + generateSystemResources(); + SystemEntity expectedSystem = new SystemEntity("ClassifierUnitTests"); + expectedSystem.addResourceClass(this.getHeavyInelasticResource()); + expectedSystem.addResourceClass(this.getLightElasticResource()); + expectedSystem.addResourceClass(this.getMockElasticResource()); + expectedSystem.addListTestCases(getFirstClassTestCases()); + return expectedSystem; + } + + private LinkedList getFirstClassTestCases() { + LinkedList listTestCases = new LinkedList<>(); + TestCaseEntity tCHOne = new TestCaseEntity("testOneH", SyntheticClassOneTests.class); + tCHOne.addAccessMode(this.getAccessModeHeavyInElasticResource()); + tCHOne.addAccessMode(this.getAccessModeLightElasticResource()); + listTestCases.add(tCHOne); + TestCaseEntity tCHTwo = new TestCaseEntity("testTwoH", SyntheticClassOneTests.class); + tCHTwo.addAccessMode(this.getAccessModeHeavyInElasticResource()); + tCHTwo.addAccessMode(this.getAccessModeLightElasticResource()); + listTestCases.add(tCHTwo); + TestCaseEntity tCHThree = new TestCaseEntity("testThreeH", SyntheticClassOneTests.class); + tCHThree.addAccessMode(getAccessModeHeavyInElasticResource()); + tCHThree.addAccessMode(this.getMockElasticAccessMode()); + listTestCases.add(tCHThree); + TestCaseEntity tCHSix = new TestCaseEntity("testSixH", SyntheticClassOneTests.class); + tCHSix.addAccessMode(this.getJSONSavedInelasticAccessMode()); + tCHSix.addAccessMode(this.getJSONSavedElasticAccessMode()); + listTestCases.add(tCHSix); + TestCaseEntity tCHSeven = new TestCaseEntity("testSevenH", SyntheticClassOneTests.class); + tCHSeven.addAccessMode(this.getJSONSavedInelasticAccessMode()); + tCHSeven.addAccessMode(this.getJSONSavedElasticAccessMode()); + listTestCases.add(tCHSeven); + return listTestCases; + } + + private AccessModeEntity getJSONSavedInelasticAccessMode() { + AccessModeEntity accessModeEntity = new AccessModeEntity(this.getAccessModeHeavyInElasticResource()); + accessModeEntity.setResource(this.getJSONSavedInelasticResource()); + return accessModeEntity; + } + + private AccessModeEntity getJSONSavedElasticAccessMode() { + AccessModeEntity accessModeEntity = new AccessModeEntity(this.getAccessModeLightElasticResource()); + accessModeEntity.setResource(this.getJSONSavedElasticResource()); + return accessModeEntity; + } + + private ResourceEntity getJSONSavedInelasticResource() { + ResourceEntity outputResource = new ResourceEntity(this.getHeavyInelasticResource()); + ElasticityModelEntity modelJSON = outputResource.getElasticityModel(); + modelJSON.setElasticityID("elasModelHeavyInElasRest"); + outputResource.setElasticityModel(modelJSON); + outputResource.setResourceID("heavyInElasRest"); + LinkedList parentsList = new LinkedList<>(); + parentsList.add("parentAllInelastic"); + outputResource.setHierarchyParent(parentsList); + return outputResource; + } + + private ResourceEntity getJSONSavedElasticResource() { + ResourceEntity outputResource = new ResourceEntity(this.getLightElasticResource()); + ElasticityModelEntity modelJSON = outputResource.getElasticityModel(); + modelJSON.setElasticityID("elasModelLightElasticResource"); + outputResource.setElasticityModel(modelJSON); + outputResource.setResourceID("lightElasticResource"); + return outputResource; + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java new file mode 100644 index 0000000..8f08d21 --- /dev/null +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java @@ -0,0 +1,115 @@ +package giis.retorch.orchestration.utils; + +import giis.retorch.orchestration.model.*; + +import java.util.LinkedList; +import java.util.List; + +public class GenericUtils { + + protected static final String READONLY = "READONLY"; + protected static final String READWRITE = "READWRITE"; + protected static final String MOCK_ELASTIC_ID = "mockElasticResource"; + protected static final String MEDIUM_ELASTIC_ID = "mediumElasticResource"; + protected static final String LIGHT_ELASTIC_ID = "lightElasticResource"; + protected static final String HEAVY_INELASTIC_ID = "heavyInElasRest"; + + public ElasticityModelEntity getElasticityModelMockResource() { + ElasticityModelEntity expectedElasticityModelMock = new ElasticityModelEntity("elasticityIDMockElastic"); + expectedElasticityModelMock.setElasticity(50); + expectedElasticityModelMock.setElasticityCost(0); + return expectedElasticityModelMock; + } + + public AccessModeEntity getAccessModeHeavyInElasticResource() { + AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + expectedAccessModeHeavy.setSharing(false); + expectedAccessModeHeavy.setConcurrency(1); + expectedAccessModeHeavy.setResource(this.getHeavyInelasticResource()); + expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + return expectedAccessModeHeavy; + } + + public AccessModeEntity getOtherAccessModeHeavyInelasticResource() { + AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(this.getAccessModeHeavyInElasticResource()); + expectedAccessModeHeavy.setSharing(false); + expectedAccessModeHeavy.setConcurrency(1); + expectedAccessModeHeavy.setResource(this.getHeavyInelasticResource()); + expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + return expectedAccessModeHeavy; + } + + public AccessModeEntity getAccessModeLightElasticResource() { + AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + expectedAccessModeHeavy.setSharing(true); + expectedAccessModeHeavy.setConcurrency(4); + expectedAccessModeHeavy.setResource(this.getLightElasticResource()); + expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + return expectedAccessModeHeavy; + } + + public ResourceEntity getLightElasticResource() { + ResourceEntity lightElasticResource = new ResourceEntity(LIGHT_ELASTIC_ID); + lightElasticResource.setElasticityModel(getElasticityModelLightElasticResource()); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new CapacityEntity("memory", 1)); + requiredCapacities.add(new CapacityEntity("processor", 0.5)); + lightElasticResource.setMinimalCapacities(requiredCapacities); + return lightElasticResource; + } + + public ElasticityModelEntity getElasticityModelLightElasticResource() { + ElasticityModelEntity expectedElasticityModelMySQL = new ElasticityModelEntity("elasModelLightElasticResource"); + expectedElasticityModelMySQL.setElasticity(35); + expectedElasticityModelMySQL.setElasticityCost(15.0); + return expectedElasticityModelMySQL; + } + + public AccessModeEntity getMockElasticAccessMode() { + AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + expectedAccessModeHeavy.setSharing(true); + expectedAccessModeHeavy.setConcurrency(4); + expectedAccessModeHeavy.setResource(this.getMockElasticResource()); + expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READONLY)); + return expectedAccessModeHeavy; + } + + public ResourceEntity getMockElasticResource() { + ResourceEntity mockElasticResource = new ResourceEntity(LIGHT_ELASTIC_ID); + mockElasticResource.setResourceID("mockElasticResource"); + ElasticityModelEntity modelMock = new ElasticityModelEntity("elasModelmockElasticResource", 50, 0.0); + mockElasticResource.setElasticityModel(modelMock); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new CapacityEntity("memory", 0.5)); + requiredCapacities.add(new CapacityEntity("processor", 2.0)); + mockElasticResource.setMinimalCapacities(requiredCapacities); + mockElasticResource.addReplaceableResource(LIGHT_ELASTIC_ID); + mockElasticResource.addReplaceableResource(HEAVY_INELASTIC_ID); + return mockElasticResource; + } + + public void generateSystemResources() { + getHeavyInelasticResource(); + getMockElasticResource(); + getLightElasticResource(); + } + + public ResourceEntity getHeavyInelasticResource() { + ResourceEntity heavyInelasticResource = new ResourceEntity(HEAVY_INELASTIC_ID); + heavyInelasticResource.addHierarchyParent("parentAllInelastic"); + heavyInelasticResource.setElasticityModel(getElasticityModelHeavyInelasticResource()); + heavyInelasticResource.setResourceType(ResourceEntity.type.LOGICAL); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new CapacityEntity("memory", 4.0)); + requiredCapacities.add(new CapacityEntity("processor", 0.6)); + heavyInelasticResource.setMinimalCapacities(requiredCapacities); + return heavyInelasticResource; + } + + public ElasticityModelEntity getElasticityModelHeavyInelasticResource() { + ElasticityModelEntity expectedElasticityModelHeavy = new ElasticityModelEntity("elasModelHeavyInElasRest"); + expectedElasticityModelHeavy.setElasticity(1); + expectedElasticityModelHeavy.setElasticityCost(50.0); + return expectedElasticityModelHeavy; + } +} \ No newline at end of file diff --git a/retorch-orchestration/src/test/resources/log4j2.xml b/retorch-orchestration/src/test/resources/log4j2.xml new file mode 100644 index 0000000..d8f4072 --- /dev/null +++ b/retorch-orchestration/src/test/resources/log4j2.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index 7d854dc..7f3a717 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.projectName=retorch sonar.organization=giis sonar.projectVersion=1.0 sonar.java.source=1.8 -sonar.modules=retorch-annotations +sonar.modules=retorch-annotations,retorch-orchestration sonar.sources=src/main/java sonar.sourceEncoding=UTF-8 sonar.tests=src/test/java From 6537a3d3baba80ad3bbb0b9eb83dc5306bf0fc79 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 11:06:46 +0100 Subject: [PATCH 02/28] Some changes done: - Workflows renamed, tuned to execute the tests and get the report - Fixed Java versions to 16 - Moved log imp to the parent pom - Renamed Entities - Simplified packages - Renamed several classes --- .github/workflows/build.yml | 57 --------- .github/workflows/test.yml | 119 ++++++++++++++++++ pom.xml | 10 ++ retorch-orchestration/pom.xml | 48 ++++--- .../configurations/retorchCI.properties | 8 -- ...{AccessModeEntity.java => AccessMode.java} | 42 +++---- ...eTypesEntity.java => AccessModeTypes.java} | 6 +- .../{CapacityEntity.java => Capacity.java} | 8 +- ...yModelEntity.java => ElasticityModel.java} | 12 +- .../{ResourceEntity.java => Resource.java} | 58 ++++----- ...tanceEntity.java => ResourceInstance.java} | 4 +- .../model/{SystemEntity.java => System.java} | 36 +++--- .../model/{TJobEntity.java => TJob.java} | 90 ++++++------- .../{TestCaseEntity.java => TestCase.java} | 14 +-- .../EmptyInputException.java | 2 +- .../ResourceSerializer.java} | 30 ++--- .../RetorchClassifier.java | 86 ++++++------- .../components => }/ClassifierTests.java | 28 ++--- .../entities => }/TJobsEntityTests.java | 30 ++--- .../SyntheticInvalidClassTests.java | 2 +- .../SyntheticClassTwoTests.java | 2 +- .../insidepackage/SyntheticClassOneTests.java | 2 +- .../orchestration/utils/ClassifierUtils.java | 69 +++++----- .../orchestration/utils/GenericUtils.java | 70 +++++------ .../src/test/resources/log4j2.xml | 21 ---- .../src/test/resources/logback.xml | 30 +++++ 26 files changed, 488 insertions(+), 396 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/test.yml delete mode 100644 retorch-orchestration/retorchfiles/configurations/retorchCI.properties rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{AccessModeEntity.java => AccessMode.java} (50%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{AccessModeTypesEntity.java => AccessModeTypes.java} (92%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{CapacityEntity.java => Capacity.java} (91%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{ElasticityModelEntity.java => ElasticityModel.java} (79%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{ResourceEntity.java => Resource.java} (69%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{ResourceInstanceEntity.java => ResourceInstance.java} (82%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{SystemEntity.java => System.java} (62%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{TJobEntity.java => TJob.java} (76%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/model/{TestCaseEntity.java => TestCase.java} (74%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{resourceidentification => testdata}/EmptyInputException.java (91%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{resourceidentification/RetorchClassifierUtils.java => testdata/ResourceSerializer.java} (81%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{resourceidentification => testdata}/RetorchClassifier.java (82%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{unitary/components => }/ClassifierTests.java (72%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{unitary/entities => }/TJobsEntityTests.java (73%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{unitary/testdata/classifier => testdata}/SyntheticInvalidClassTests.java (98%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{unitary/testdata/classifier => testdata}/synteticpackage/SyntheticClassTwoTests.java (90%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{unitary/testdata/classifier => testdata}/synteticpackage/insidepackage/SyntheticClassOneTests.java (95%) delete mode 100644 retorch-orchestration/src/test/resources/log4j2.xml create mode 100644 retorch-orchestration/src/test/resources/logback.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 2829dc1..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: build-annotations -on: - push: - branches-ignore: - - 'dependabot/**' #avoid duplicates: only run the PR, not the commit - - 'gh-pages' #GitHub pages do not trigger all tests - tags-ignore: - - 'v*' #avoid rerun existing commit on release - pull_request: - branches: - - 'main' -jobs: - test-java: - runs-on: ubuntu-latest - # if: ${{ false }} # disable for now - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '16' - cache: 'maven' - - - name: Build Annotation project - run: mvn compile -U --no-transfer-progress - - - sonarqube: - needs: [ test-java ] - #if: ${{ false }} # disable for now - #This job fails when comming from a dependabot PR (can't read the sonarqube token for security reasons). - #Links to discussions and workaround at: https://github.com/giis-uniovi/samples-giis-template/issues/4 - if: ${{ github.actor != 'dependabot[bot]' }} - runs-on: ubuntu-latest - steps: - - uses: javiertuya/sonarqube-action@v1.4.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - sonar-token: ${{ secrets.SONAR_TOKEN }} - - publish-java-snapshot: - #if: ${{ false }} # disable for now - #avoid publishing PRs and dependabot branches - if: ${{ github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/heads/dependabot/') && !startsWith(github.ref, 'refs/heads/dashgit/combined/') }} - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - uses: javiertuya/branch-snapshots-action@v1.2.3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - java-version: '16' - mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' - delete-old-snapshots: true - min-snapshots-to-keep: 2 - always-keep-regex: "\\d*\\.\\d*\\.\\d*-main-SNAPSHOT$" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..ce08c48 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,119 @@ +name: build-retorch +on: + push: + branches-ignore: + - 'dependabot/**' #avoid duplicates: only run the PR, not the commit + - 'gh-pages' #GitHub pages do not trigger all tests + tags-ignore: + - 'v*' #avoid rerun existing commit on release + pull_request: + branches: + - 'main' +jobs: + build-java: + runs-on: ubuntu-latest + # if: ${{ false }} # disable for now + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '16' + cache: 'maven' + + - name: Build RETORCH project + run: mvn compile -U --no-transfer-progress + + test-retorch-orchestration: + runs-on: ubuntu-latest + # if: ${{ false }} # disable for now + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '16' + cache: 'maven' + + - name: Test RETORCH orchestration module + run: mvn test -Dtest=* -pl retorch-orchestration -U --no-transfer-progress + + - name: Generate report checks + if: always() + uses: mikepenz/action-junit-report@v5 + with: + check_name: "test-result-orchestration" + report_paths: "**/surefire-reports/TEST-*.xml" + fail_on_failure: 'true' + + - if: always() + name: Publish test report files + uses: actions/upload-artifact@v4 + with: + name: "test-report-files-orchestration" + path: | + target/site + **/target/site/jacoco/jacoco.xml + **/target/surefire-reports + + sonarqube: + needs: [ build-java, test-retorch-orchestration ] + #if: ${{ false }} # disable for now + #This job fails when comming from a dependabot PR (can't read the sonarqube token for security reasons). + #Links to discussions and workaround at: https://github.com/giis-uniovi/samples-giis-template/issues/4 + if: ${{ github.actor != 'dependabot[bot]' }} + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4.1.8 + if: always() + with: + name: "test-report-files-orchestration" + - name: Aggregated junit html report + if: always() + uses: javiertuya/junit-report-action@v1.2.0 + with: + surefire-files: "**/target/surefire-reports/TEST-*.xml" + report-dir: target-ALL/site + report-title: "Test Report: ALL - Branch: ${{ github.ref_name }} - Run #${{ github.run_number }}" + - name: Index file to html reports + run: | + echo "Latest Test Reports" > target-ALL/site/index.html + echo "

Latest Test Reports - Branch: ${{ github.ref_name }} - Run #${{ github.run_number }}

" >> target-ALL/site/index.html + echo "

Single page reports

" >> target-ALL/site/index.html + echo "

Multiple page reports with frames

" >> target-ALL/site/index.html + echo "" >> target-ALL/site/index.html + - if: always() + name: Publish test report files + uses: actions/upload-artifact@v4 + with: + name: "test-report-ALL" + path: | + target-ALL/site + **/target/surefire-reports + **/target/*.html + **/target/*.log + **/reports/*.html + **/reports/*.log + - uses: javiertuya/sonarqube-action@v1.4.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + sonar-token: ${{ secrets.SONAR_TOKEN }} + restore-artifact-name1: "test-report-files-orchestration" + + publish-java-snapshot: + #if: ${{ false }} # disable for now + #avoid publishing PRs and dependabot branches + if: ${{ github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/heads/dependabot/') && !startsWith(github.ref, 'refs/heads/dashgit/combined/') }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: javiertuya/branch-snapshots-action@v1.2.3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + java-version: '16' + mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' + delete-old-snapshots: true + min-snapshots-to-keep: 2 + always-keep-regex: "\\d*\\.\\d*\\.\\d*-main-SNAPSHOT$" diff --git a/pom.xml b/pom.xml index a0ded23..4880e45 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,10 @@ 16 16 UTF-8 + + + 1.5.12 + @@ -39,6 +43,12 @@ slf4j-api 2.0.16 + + ch.qos.logback + logback-classic + ${logback-classic.version} + test + diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml index e1e08e6..ce86d51 100644 --- a/retorch-orchestration/pom.xml +++ b/retorch-orchestration/pom.xml @@ -8,26 +8,40 @@ retorch-orchestration jar retorch-orchestration - Multimodule maven project template, module without dependencies - http://github.com/giis-uniovi/samples-giis-template + This module covers the orchestration process, processes the Resource annotations and generates the necessary + scripting code to execute the RETORCH execution plan + https://github.com/giis-uniovi/retorch Software Engineering Research Group (GIIS) - Universidad de Oviedo, ES - http://giis.uniovi.es/ + https://giis.uniovi.es/ + 1.1.1-SNAPSHOT + + 3.5.2 + 2.18.1 5.14.2 - 1.5.12 + + + io.github.giis-uniovi + retorch-annotations + ${retorchannotations.version} + org.slf4j slf4j-api + + ch.qos.logback + logback-classic + junit junit @@ -43,17 +57,6 @@ ${mockito.version} test - - ch.qos.logback - logback-classic - ${logback-classic.version} - test - - - io.github.giis-uniovi - retorch-annotations - 1.1.1-SNAPSHOT - @@ -85,6 +88,21 @@ 16 + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/testdata/** + + + true + true + + false + +
\ No newline at end of file diff --git a/retorch-orchestration/retorchfiles/configurations/retorchCI.properties b/retorch-orchestration/retorchfiles/configurations/retorchCI.properties deleted file mode 100644 index dadcf41..0000000 --- a/retorch-orchestration/retorchfiles/configurations/retorchCI.properties +++ /dev/null @@ -1,8 +0,0 @@ -agentCIName=any -sut-wait-html=FullTeaching -sut-location=$WORKSPACE -docker-frontend-name=https://full-teaching- -docker-frontend-port=5000 -external-binded-port= -external-frontend-url= -testsBasePath=somepath/somedir/ \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java similarity index 50% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java index e0cf7fe..ab8dc24 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java @@ -1,30 +1,30 @@ package giis.retorch.orchestration.model; -public class AccessModeEntity { +public class AccessMode { - private AccessModeTypesEntity accessMode; + private AccessModeTypes type; private boolean sharing = false; private int concurrency = 1; - private ResourceEntity resource; + private Resource resource; - public AccessModeEntity() {} + public AccessMode() {} - public AccessModeEntity(AccessModeEntity accessMode) { - this.accessMode = accessMode.getAccessMode(); - this.concurrency = accessMode.getConcurrency(); - this.resource = accessMode.getResource(); - this.sharing = accessMode.getSharing(); + public AccessMode(AccessMode type) { + this.type = type.getType(); + this.concurrency = type.getConcurrency(); + this.resource = type.getResource(); + this.sharing = type.getSharing(); } /** * Access mode constructor - * @param accessMode {@link AccessModeTypesEntity} that could be READONLY,WRITEONLY,READWRITE,DYNAMIC or NOACCESS + * @param type {@link AccessModeTypes} that could be READONLY,WRITEONLY,READWRITE,DYNAMIC or NOACCESS * @param sharing Boolean that represents if the resource can be shared or not * @param concurrency Integer with the max number of concurrent access * @param resource Resource on which the access mode is performed */ - public AccessModeEntity(AccessModeTypesEntity accessMode, boolean sharing, int concurrency, ResourceEntity resource) { - this.accessMode = accessMode; + public AccessMode(AccessModeTypes type, boolean sharing, int concurrency, Resource resource) { + this.type = type; this.sharing = sharing; this.concurrency = concurrency; this.resource = resource; @@ -38,24 +38,24 @@ public int hashCode() { @Override public boolean equals(Object obj) { if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; - AccessModeEntity objToCompare = ((AccessModeEntity) obj); + AccessMode objToCompare = ((AccessMode) obj); return objToCompare.getSharing() == this.sharing && objToCompare.getConcurrency() == this.concurrency - && objToCompare.getAccessMode().equals(this.accessMode) && objToCompare.getResource().equals(this.resource); + && objToCompare.getType().equals(this.type) && objToCompare.getResource().equals(this.resource); } @Override public String toString() { - return "a.m.{" + accessMode + ", " + sharing + ", " + concurrency + ",'" + resource + '\'' + '}'; + return "a.m.{" + type + ", " + sharing + ", " + concurrency + ",'" + resource + '\'' + '}'; } - public AccessModeTypesEntity getAccessMode() { - return accessMode; + public AccessModeTypes getType() { + return type; } public int getConcurrency() { return concurrency; } - public ResourceEntity getResource() { + public Resource getResource() { return resource; } public boolean getSharing() { @@ -65,14 +65,14 @@ public boolean getSharing() { public void setSharing(boolean sharing) { this.sharing = sharing; } - public void setResource(ResourceEntity resource) { + public void setResource(Resource resource) { this.resource = resource; } public void setConcurrency(int concurrency) { this.concurrency = concurrency; } - public void setAccessMode(AccessModeTypesEntity accessMode) { - this.accessMode = accessMode; + public void setType(AccessModeTypes type) { + this.type = type; } } \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java similarity index 92% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java index 13c9f56..f9577ce 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypesEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java @@ -4,7 +4,7 @@ * This class is used as AccessMode parser for given a string representation of a RETORCH access mode (i.e: * READONLY,READWRITE...) convert it into the proper enumeration. Also provides */ -public class AccessModeTypesEntity { +public class AccessModeTypes { public enum type {READONLY, READWRITE, WRITEONLY, DYNAMIC, NOACCESS} @@ -12,7 +12,7 @@ public enum type {READONLY, READWRITE, WRITEONLY, DYNAMIC, NOACCESS} private type accessModeType; - public AccessModeTypesEntity(String typeOfAccess) { + public AccessModeTypes(String typeOfAccess) { this.accessStringType = typeOfAccess; switch (typeOfAccess) { case "READONLY": @@ -47,7 +47,7 @@ public String toString() { @Override public boolean equals(Object obj) { if ((obj == null)||(!obj.getClass().equals(this.getClass()))) return false; - AccessModeTypesEntity currentType = ((AccessModeTypesEntity) obj); + AccessModeTypes currentType = ((AccessModeTypes) obj); return currentType.getAccessModeType() == this.getAccessModeType(); } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Capacity.java similarity index 91% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Capacity.java index e04dd42..01172cd 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/CapacityEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Capacity.java @@ -15,9 +15,9 @@ * are supported are specified in {@code CapacityTypes}: memory, processor,slots and storage. * If the provided name is not in the list of valid capacities, it defaults to "Wrong Capacity". */ -public class CapacityEntity { +public class Capacity { - private static final Logger log = LoggerFactory.getLogger(CapacityEntity.class); + private static final Logger log = LoggerFactory.getLogger(Capacity.class); public static final String MEMORY_NAME = "memory"; public static final String PROCESSOR_NAME = "processor"; public static final String SLOTS_NAME = "slots"; @@ -29,7 +29,7 @@ public class CapacityEntity { protected static final Set LIST_CAPACITIES = new HashSet<>(); static {Collections.addAll(LIST_CAPACITIES, MEMORY_NAME, PROCESSOR_NAME, SLOTS_NAME, STORAGE_NAME);} - public CapacityEntity(@JsonProperty("name") String name, @JsonProperty("quantity") double quantity) { + public Capacity(@JsonProperty("name") String name, @JsonProperty("quantity") double quantity) { if (LIST_CAPACITIES.contains(name)) { setName(name); } else { @@ -53,7 +53,7 @@ public String toString() { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - CapacityEntity that = (CapacityEntity) o; + Capacity that = (Capacity) o; return Objects.equals(this.getName(), that.getName()) && Objects.equals(this.getQuantity(), that.getQuantity()); } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java similarity index 79% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java index 9d8e2ac..b05754a 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModelEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java @@ -2,13 +2,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public class ElasticityModelEntity { +public class ElasticityModel { private String elasticityID; private int elasticity; private double elasticityCost; - public ElasticityModelEntity(String idElasticity) {this.elasticityID = idElasticity;} + public ElasticityModel(String idElasticity) {this.elasticityID = idElasticity;} /** * Elasticity model constructor @@ -16,9 +16,9 @@ public class ElasticityModelEntity { * @param elasticityCost Double with the cost of one instance deployment * @param elasticityID String with the ElasticityID */ - public ElasticityModelEntity(@JsonProperty("elasticityID") String elasticityID, - @JsonProperty("elasticity") int elasticity, - @JsonProperty("elasticityCost") double elasticityCost) { + public ElasticityModel(@JsonProperty("elasticityID") String elasticityID, + @JsonProperty("elasticity") int elasticity, + @JsonProperty("elasticityCost") double elasticityCost) { this.elasticityID = elasticityID; this.elasticity = elasticity; this.elasticityCost = elasticityCost; @@ -37,7 +37,7 @@ public String toString() { @Override public boolean equals(Object obj) { if ((obj == null) ||(!obj.getClass().equals(this.getClass()))) return false; - ElasticityModelEntity currentType = ((ElasticityModelEntity) obj); + ElasticityModel currentType = ((ElasticityModel) obj); return currentType.getElasticity() == this.elasticity && currentType.getElasticityCost() == this.elasticityCost && currentType.getElasticityID().equals(this.getElasticityID()); } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java similarity index 69% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java index 6ff9778..45434cb 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java @@ -10,29 +10,29 @@ import java.util.LinkedList; import java.util.List; -public class ResourceEntity { +public class Resource { public enum type {PHYSICAL, LOGICAL, COMPUTATIONAL} - private final Logger logResourceClass=LoggerFactory.getLogger(ResourceEntity.class); + private final Logger logResourceClass = LoggerFactory.getLogger(Resource.class); Marker errorMarker = MarkerFactory.getMarker("Error"); private String resourceID; private List hierarchyParent; private List replaceable; - private List minimalCapacities; - private ElasticityModelEntity elasticityModel; + private List minimalCapacities; + private ElasticityModel elasticityModel; private type resourceType = type.LOGICAL; private String dockerImage; - public ResourceEntity(String resourceID) { + public Resource(String resourceID) { super(); this.resourceID = resourceID; this.replaceable = new LinkedList<>(); this.hierarchyParent = new LinkedList<>(); } - public ResourceEntity() {} + public Resource() {} /** * Resource constructor @@ -41,16 +41,16 @@ public ResourceEntity() {} * @param replaceable List with the ids of those resources that could replace the resource * @param resourceType type of the resource (LOGICAL, PHYSICAL or COMPUTATIONAL) * @param hierarchyParent String with the resource hierarchical parent - * @param minimalCapacities List with the minimal {@link CapacityEntity} required by the resource + * @param minimalCapacities List with the minimal {@link Capacity} required by the resource * @param dockerImage String with the Resource docker image name */ - public ResourceEntity(@JsonProperty("resourceId") String resourceID, - @JsonProperty("hierarchyParent") List hierarchyParent, - @JsonProperty("replaceable") List replaceable, - @JsonProperty("elasticityModel") ElasticityModelEntity elasticityModel, - @JsonProperty("resourceType") type resourceType, - @JsonProperty("minimalCapacities")List minimalCapacities, - @JsonProperty("dockerImage") String dockerImage) { + public Resource(@JsonProperty("resourceId") String resourceID, + @JsonProperty("hierarchyParent") List hierarchyParent, + @JsonProperty("replaceable") List replaceable, + @JsonProperty("elasticityModel") ElasticityModel elasticityModel, + @JsonProperty("resourceType") type resourceType, + @JsonProperty("minimalCapacities")List minimalCapacities, + @JsonProperty("dockerImage") String dockerImage) { this.resourceID = resourceID; this.hierarchyParent = hierarchyParent; this.replaceable = replaceable; @@ -60,17 +60,17 @@ public ResourceEntity(@JsonProperty("resourceId") String resourceID, this.dockerImage=dockerImage; } - public ResourceEntity(ResourceEntity resourceEntity) { - this.dockerImage = resourceEntity.dockerImage; - this.elasticityModel = resourceEntity.getElasticityModel(); - this.errorMarker = resourceEntity.errorMarker; + public Resource(Resource resource) { + this.dockerImage = resource.dockerImage; + this.elasticityModel = resource.getElasticityModel(); + this.errorMarker = resource.errorMarker; this.hierarchyParent = new LinkedList<>(); - this.hierarchyParent.addAll(resourceEntity.getHierarchyParent()); - this.minimalCapacities = resourceEntity.getMinimalCapacities(); + this.hierarchyParent.addAll(resource.getHierarchyParent()); + this.minimalCapacities = resource.getMinimalCapacities(); this.replaceable = new LinkedList<>(); - this.replaceable.addAll(resourceEntity.getReplaceable()); - this.resourceID = resourceEntity.getResourceID(); - this.resourceType = resourceEntity.getResourceType(); + this.replaceable.addAll(resource.getReplaceable()); + this.resourceID = resource.getResourceID(); + this.resourceType = resource.getResourceType(); } @Override @@ -88,7 +88,7 @@ public String toString() { public boolean equals(Object obj) { String message; if (obj == null || !obj.getClass().equals(this.getClass())) return false; - ResourceEntity resClass = (ResourceEntity) obj; + Resource resClass = (Resource) obj; if (!this.elasticityModel.equals(resClass.elasticityModel)) { if (this.elasticityModel.getElasticityID().equals(resClass.elasticityModel.getElasticityID())){ message=String.format("The elasticityModel of the resources with the same identifier " + "%s differ", resClass.getResourceID()); @@ -102,9 +102,9 @@ public boolean equals(Object obj) { } public String getDockerImage() {return dockerImage;} - public ElasticityModelEntity getElasticityModel() {return elasticityModel;} + public ElasticityModel getElasticityModel() {return elasticityModel;} public List getHierarchyParent() {return hierarchyParent;} - public List getMinimalCapacities() {return minimalCapacities;} + public List getMinimalCapacities() {return minimalCapacities;} public String getResourceID() {return resourceID;} public type getResourceType() {return resourceType;} public List getReplaceable() { @@ -113,10 +113,10 @@ public List getReplaceable() { } public void setDockerImage(String dockerImage) {this.dockerImage = dockerImage;} - public void setElasticityModel(ElasticityModelEntity elasticityModel) {this.elasticityModel = elasticityModel;} + public void setElasticityModel(ElasticityModel elasticityModel) {this.elasticityModel = elasticityModel;} public void setHierarchyParent(List hierarchyParent) {this.hierarchyParent = hierarchyParent;} - public void setMinimalCapacities(List minimalCapacities) { - minimalCapacities.sort(Comparator.comparing(CapacityEntity::getName)); + public void setMinimalCapacities(List minimalCapacities) { + minimalCapacities.sort(Comparator.comparing(Capacity::getName)); this.minimalCapacities = minimalCapacities; } public void setReplaceable(List replaceable) {this.replaceable = replaceable;} diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java similarity index 82% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java index e9d66bb..83586d9 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstanceEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java @@ -9,9 +9,9 @@ * It provides methods to get and set the name and capacities, and overrides the {@code equals}, {@code hashCode}, * and {@code toString} methods for comparison and representation purposes taking into account the list of capacities. */ -public class ResourceInstanceEntity extends ResourceEntity { +public class ResourceInstance extends Resource { - public ResourceInstanceEntity(String name, List capacities) { + public ResourceInstance(String name, List capacities) { this.setMinimalCapacities(capacities); this.setResourceID(name); } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java similarity index 62% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java index 9e834c0..4fd462c 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/SystemEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java @@ -8,15 +8,15 @@ import java.util.LinkedList; import java.util.List; -public class SystemEntity { +public class System { - private static final Logger logSystemClass = LoggerFactory.getLogger(SystemEntity.class); + private static final Logger logSystemClass = LoggerFactory.getLogger(System.class); private final String name; - private final LinkedList resources; - private final List testCases; + private final LinkedList resources; + private final List testCases; - public SystemEntity(String name) { + public System(String name) { this.name = name; this.testCases = new LinkedList<>(); this.resources = new LinkedList<>(); @@ -30,7 +30,7 @@ public int hashCode() { @Override public boolean equals(Object obj) { if ((obj == null)||(!obj.getClass().equals(this.getClass()))) return false; - SystemEntity objectToCompare = ((SystemEntity) obj); + System objectToCompare = ((System) obj); if (!objectToCompare.getName().equals(this.name)) return false; boolean containAllResources = new HashSet<>(objectToCompare.getResources()).containsAll(this.getResources()); boolean containsAllTestCases = new HashSet<>(objectToCompare.getTestCases()).containsAll(this.getTestCases()); @@ -41,40 +41,40 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("System ID: ").append(getName()).append("\n"); sb.append("Resources:\n"); - for (ResourceEntity res : getResources()){ + for (Resource res : getResources()){ sb.append("\t").append(res).append("\n"); } sb.append("TestCases:\n"); - for (TestCaseEntity tc : getTestCases()){ + for (TestCase tc : getTestCases()){ sb.append("\t").append(tc).append("\n"); } return sb.toString(); } public String getName() {return name;} - public List getResources() {return resources;} - public List getTestCases() {return testCases;} + public List getResources() {return resources;} + public List getTestCases() {return testCases;} - public void addTestCase(TestCaseEntity test) { + public void addTestCase(TestCase test) { this.testCases.add(test); - this.testCases.sort(Comparator.comparing(TestCaseEntity::getName)); + this.testCases.sort(Comparator.comparing(TestCase::getName)); } - public void addListOfResources(List listResources) { + public void addListOfResources(List listResources) { this.resources.addAll(listResources); - this.resources.sort(Comparator.comparing(ResourceEntity::getResourceID)); + this.resources.sort(Comparator.comparing(Resource::getResourceID)); } - public void addResourceClass(ResourceEntity resource) { + public void addResourceClass(Resource resource) { if (!this.resources.contains(resource)) { this.resources.add(resource); } else logSystemClass.info("The resource {} is contained in the system", resource.getResourceID()); - this.resources.sort(Comparator.comparing(ResourceEntity::getResourceID)); + this.resources.sort(Comparator.comparing(Resource::getResourceID)); } - public void addListTestCases(List listTestCases) { + public void addListTestCases(List listTestCases) { this.testCases.addAll(listTestCases); - this.testCases.sort(Comparator.comparing(TestCaseEntity::getName)); + this.testCases.sort(Comparator.comparing(TestCase::getName)); } } \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java similarity index 76% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java index a207ab7..2477dff 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJobEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java @@ -10,11 +10,11 @@ * When the TJob is created, it calculates the total amount of {@code Capacity} that is used by the list of * {@code ResourceClass} required */ -public class TJobEntity { +public class TJob { private final Logger log = LoggerFactory.getLogger(this.getClass()); - private Set totalCapacities; + private Set totalCapacities; private int stage; private double startSetUp; private double endSetUp; @@ -22,8 +22,8 @@ public class TJobEntity { private double endExec; private double startTearDown; private double endTearDown; - private List listTestCases; - private List listResourceEntities; + private List listTestCases; + private List listResourceEntities; private String idTJob = "Default"; private String intraTJobSchedule = "SequentialScheduling"; private Integer tJobConcurrency=50; @@ -47,38 +47,38 @@ public class TJobEntity { * new test * case is added. */ - public TJobEntity() { + public TJob() { this.listResourceEntities = new LinkedList<>(); this.listTestCases = new LinkedList<>(); } - public TJobEntity(String idTJob, int stage, List resourceInstances) { + public TJob(String idTJob, int stage, List resourceInstances) { //Attributes required by the tool this.listTestCases=new LinkedList<>(); //Attributes required for the cost model this.idTJob = idTJob; this.listResourceEntities = resourceInstances; this.stage = stage; - CapacityEntity memory = new CapacityEntity(CapacityEntity.MEMORY_NAME, 0); - CapacityEntity processors = new CapacityEntity(CapacityEntity.PROCESSOR_NAME, 0); - CapacityEntity slots = new CapacityEntity(CapacityEntity.SLOTS_NAME, 0); - CapacityEntity storage = new CapacityEntity(CapacityEntity.STORAGE_NAME, 0); - for (ResourceEntity resource : resourceInstances) { - for (CapacityEntity capacityEntity : resource.getMinimalCapacities()) - switch (capacityEntity.getName()) { - case CapacityEntity.PROCESSOR_NAME: - processors.addQuantity(capacityEntity.getQuantity()); + Capacity memory = new Capacity(Capacity.MEMORY_NAME, 0); + Capacity processors = new Capacity(Capacity.PROCESSOR_NAME, 0); + Capacity slots = new Capacity(Capacity.SLOTS_NAME, 0); + Capacity storage = new Capacity(Capacity.STORAGE_NAME, 0); + for (Resource resource : resourceInstances) { + for (Capacity capacity : resource.getMinimalCapacities()) + switch (capacity.getName()) { + case Capacity.PROCESSOR_NAME: + processors.addQuantity(capacity.getQuantity()); break; - case CapacityEntity.MEMORY_NAME: - memory.addQuantity(capacityEntity.getQuantity()); + case Capacity.MEMORY_NAME: + memory.addQuantity(capacity.getQuantity()); break; - case CapacityEntity.STORAGE_NAME: - storage.addQuantity(capacityEntity.getQuantity()); + case Capacity.STORAGE_NAME: + storage.addQuantity(capacity.getQuantity()); break; - case CapacityEntity.SLOTS_NAME: - slots.addQuantity(capacityEntity.getQuantity()); + case Capacity.SLOTS_NAME: + slots.addQuantity(capacity.getQuantity()); break; default: - log.warn("Capacity {} not found", capacityEntity.getName()); + log.warn("Capacity {} not found", capacity.getName()); break; } } @@ -98,8 +98,8 @@ public int hashCode() { public boolean equals(Object obj) { if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; - TJobEntity objectToCompare = ((TJobEntity) obj); - for (TestCaseEntity tc : objectToCompare.getListTestCases()) { + TJob objectToCompare = ((TJob) obj); + for (TestCase tc : objectToCompare.getListTestCases()) { if (!this.getListTestCases().contains(tc)) {return false;} } return this.getListResourceClasses().equals(objectToCompare.getListResourceClasses()) && @@ -108,9 +108,9 @@ public boolean equals(Object obj) { @Override public String toString() { - List testCasesNames = listTestCases.stream().map(TestCaseEntity::getName).toList(); + List testCasesNames = listTestCases.stream().map(TestCase::getName).toList(); List resourceNames = - listResourceEntities.stream().map(ResourceEntity::getResourceID).toList(); + listResourceEntities.stream().map(Resource::getResourceID).toList(); return "TJobClass [\n" + "listTc:{\n" + testCasesNames + "}, listRes " + resourceNames + ", intraSchedule '" + intraTJobSchedule + '\'' + ", con " + tJobConcurrency + ']'; } @@ -118,22 +118,22 @@ public String toString() { public static Set getListTJobLifecyclesNames() {return LIST_TJOB_LIFECYCLE;} public static List getListTJobLifecyclesWithDesiredOrder() { LinkedList desiredDataOrder = new LinkedList<>(); - desiredDataOrder.add(TJobEntity.LIFECYCLE_SETUP_NAME); - desiredDataOrder.add(TJobEntity.LIFECYCLE_TESTEXECUTION_NAME); - desiredDataOrder.add(TJobEntity.LIFECYCLE_TEARDOWN_NAME); + desiredDataOrder.add(TJob.LIFECYCLE_SETUP_NAME); + desiredDataOrder.add(TJob.LIFECYCLE_TESTEXECUTION_NAME); + desiredDataOrder.add(TJob.LIFECYCLE_TEARDOWN_NAME); return desiredDataOrder; } - public Set getTotalCapacities() {return totalCapacities;} - public List getCapacityNames() {return this.getTotalCapacities().stream().map(CapacityEntity::getName).toList();} + public Set getTotalCapacities() {return totalCapacities;} + public List getCapacityNames() {return this.getTotalCapacities().stream().map(Capacity::getName).toList();} public double getElasticityCostResources() {return elasticityCostResources;} public double getEndExec() {return endExec;} public double getEndSetUp() {return endSetUp;} public double getEndTearDown() {return endTearDown;} public String getIdTJob() {return idTJob.toLowerCase(Locale.ENGLISH);} public String getIntraTJobSchedule() {return intraTJobSchedule;} - public List getListResourceClasses() {return listResourceEntities;} - public List getListTestCases() { + public List getListResourceClasses() {return listResourceEntities;} + public List getListTestCases() { return listTestCases; } public int getStage() {return stage;} @@ -166,7 +166,7 @@ public void setAvgTime(double stSetUp, double endSetUp, double stExec, double en } } - public Map.Entry> getCapacitiesGivenTime(double currentTime, double startExecutionTime) { + public Map.Entry> getCapacitiesGivenTime(double currentTime, double startExecutionTime) { double adjustedStartSetUp = this.getStartSetUp() + startExecutionTime; double adjustedEndSetUp = this.getEndSetUp() + startExecutionTime; double adjustedStartExec = this.getStartExec() + startExecutionTime; @@ -187,7 +187,7 @@ public Map.Entry> getCapacitiesGivenTime(double curr return new AbstractMap.SimpleEntry<>("noexec", Collections.emptySet()); } - public boolean addTestCase(TestCaseEntity subject) { + public boolean addTestCase(TestCase subject) { if (listTestCases.contains(subject)) return false; listTestCases.add(subject); this.updateIntraTestCaseSchedule(); @@ -203,8 +203,8 @@ public boolean addTestCase(TestCaseEntity subject) { */ public void updateIntraTestCaseSchedule() { boolean thereAreAtLeastOneSequential = false; - for (TestCaseEntity subject : this.listTestCases) { - for (AccessModeEntity subjectAccessMode : subject.getAccessMode()) { + for (TestCase subject : this.listTestCases) { + for (AccessMode subjectAccessMode : subject.getAccessMode()) { if (!subjectAccessMode.getSharing()) thereAreAtLeastOneSequential = true; // Checks if the given concurrency is lower than stored (if its lower overwrite the value) if (subjectAccessMode.getConcurrency() < this.tJobConcurrency) this.tJobConcurrency = subjectAccessMode.getConcurrency(); @@ -218,19 +218,19 @@ public void updateIntraTestCaseSchedule() { * This method add a lis of test cases updating the intra- schedule after it. * @param testCases List with the test cases to be added */ - public void addListTestCases(List testCases) { + public void addListTestCases(List testCases) { this.listTestCases.addAll(testCases); this.updateIntraTestCaseSchedule(); } - public void addListResources(List listResources) { - for (ResourceEntity res : listResources) this.addResource(res); + public void addListResources(List listResources) { + for (Resource res : listResources) this.addResource(res); } /** * This method add a new resource to the current TJob. First check that the resource is not contained in the * TJob for after add it and increase the total elasticity cost of the TJob. */ - public boolean addResource(ResourceEntity subject) { + public boolean addResource(Resource subject) { if (listResourceEntities.contains(subject)) { return false; } @@ -240,7 +240,7 @@ public boolean addResource(ResourceEntity subject) { return true; } - public void removeTestCase(TestCaseEntity tc) { + public void removeTestCase(TestCase tc) { this.listTestCases.remove(tc); this.updateIntraTestCaseSchedule(); } @@ -249,7 +249,7 @@ public void removeTestCase(TestCaseEntity tc) { */ public int getMinimalElasticity() { int minimalElasticity = 50; - for (ResourceEntity res : this.getListResourceClasses()) { + for (Resource res : this.getListResourceClasses()) { int currentElasticity = res.getElasticityModel().getElasticity(); if (currentElasticity < minimalElasticity) minimalElasticity = currentElasticity; } @@ -262,8 +262,8 @@ public int getMinimalElasticity() { */ public int getMinimalConcurrency() { int minimalConcurrency = 50; - for (TestCaseEntity tc : this.getListTestCases()) { - for (AccessModeEntity acc : tc.getAccessMode()) { + for (TestCase tc : this.getListTestCases()) { + for (AccessMode acc : tc.getAccessMode()) { int concurrency = acc.getConcurrency(); if (concurrency < minimalConcurrency) minimalConcurrency = concurrency; } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java similarity index 74% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java index bcebaf9..190a8ab 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCaseEntity.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java @@ -3,18 +3,18 @@ import java.util.LinkedList; import java.util.List; -public class TestCaseEntity { +public class TestCase { private final String name; private final Class testClass; - private List accessMode; //List with the access modes (one access mode for each resource) + private List accessMode; //List with the access modes (one access mode for each resource) /** * RETORCH Test Case has the test name, its class and the access mode that performs over the resource * @param nameTestCase String with the test case name * @param classTestCase Class that contains the test case */ - public TestCaseEntity(String nameTestCase, Class classTestCase) { + public TestCase(String nameTestCase, Class classTestCase) { this.name = nameTestCase; this.testClass = classTestCase; this.accessMode = new LinkedList<>(); @@ -23,7 +23,7 @@ public TestCaseEntity(String nameTestCase, Class classTestCase) { public Class getTestClass() { return testClass; } - public void addAccessMode(AccessModeEntity accessMode) { + public void addAccessMode(AccessMode accessMode) { this.accessMode.add(accessMode); } @@ -36,7 +36,7 @@ public int hashCode() { public boolean equals(Object obj) { if ((obj == null) || (!obj.getClass().equals(this.getClass()))) return false; - TestCaseEntity objectToCompare = ((TestCaseEntity) obj); + TestCase objectToCompare = ((TestCase) obj); boolean conditionOne = objectToCompare.getAccessMode().equals(this.accessMode); boolean conditionTwo = objectToCompare.getName().equals(this.name); return conditionOne && conditionTwo; @@ -47,14 +47,14 @@ public String toString() { return "tc{" + "'" + name + '\'' + ", " + accessMode + '}'; } - public List getAccessMode() { + public List getAccessMode() { return accessMode; } public String getName() { return name; } - public void setAccessMode(List accessMode) { + public void setAccessMode(List accessMode) { this.accessMode = accessMode; } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java similarity index 91% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java index 2652eb1..911df5e 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/EmptyInputException.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.resourceidentification; +package giis.retorch.orchestration.testdata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java similarity index 81% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java index 760dbf3..cdd67c6 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifierUtils.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java @@ -1,11 +1,11 @@ -package giis.retorch.orchestration.resourceidentification; +package giis.retorch.orchestration.testdata; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import giis.retorch.orchestration.model.ElasticityModelEntity; -import giis.retorch.orchestration.model.ResourceEntity; +import giis.retorch.orchestration.model.ElasticityModel; +import giis.retorch.orchestration.model.Resource; import java.io.IOException; import java.nio.file.Files; @@ -13,19 +13,19 @@ import java.nio.file.Paths; import java.util.*; -public class RetorchClassifierUtils { +public class ResourceSerializer { - private final Logger logSerializer = LoggerFactory.getLogger(RetorchClassifierUtils.class); + private final Logger logSerializer = LoggerFactory.getLogger(ResourceSerializer.class); private static final String FOLDER_RESOURCES = "retorchfiles/configurations/";//Base path of the resource files - final HashMap resourcesToSerialize;//Map with the dictionary of resources to serialize + final HashMap resourcesToSerialize;//Map with the dictionary of resources to serialize final ObjectMapper mapper; /** * RETORCH Serializer provides utils to deserialize the configuration files, and create them from scratch with the * RETORCH entities that they want to serialize in these files. */ - public RetorchClassifierUtils() { + public ResourceSerializer() { resourcesToSerialize = new HashMap<>(); mapper = new ObjectMapper(); } @@ -43,10 +43,10 @@ public RetorchClassifierUtils() { */ public void addResourceToSerialize(String resourceId, double elasticityCost, int elasticity, String resourceType, String hierarchyParent) { - ElasticityModelEntity elasModel = new ElasticityModelEntity("elasModel" + resourceId); + ElasticityModel elasModel = new ElasticityModel("elasModel" + resourceId); elasModel.setElasticityCost(elasticityCost); elasModel.setElasticity(elasticity); - resourcesToSerialize.put(resourceId, new ResourceEntity(resourceId, + resourcesToSerialize.put(resourceId, new Resource(resourceId, new LinkedList<>(Collections.singletonList(hierarchyParent)), new LinkedList<>(), elasModel, getResourceTypeFromAnnotation(resourceType), new LinkedList<>(), "someimage")); } @@ -56,11 +56,11 @@ public void addResourceToSerialize(String resourceId, double elasticityCost, int * * @param type String with the type i.e. LOGICAL,COMPUTATIONAL or PHYSICAL */ - private ResourceEntity.type getResourceTypeFromAnnotation(String type) { + private Resource.type getResourceTypeFromAnnotation(String type) { try { - return ResourceEntity.type.valueOf(type); + return Resource.type.valueOf(type); } catch (IllegalArgumentException e) { - return ResourceEntity.type.LOGICAL; // Default to LOGICAL if type is not recognized + return Resource.type.LOGICAL; // Default to LOGICAL if type is not recognized } } @@ -73,10 +73,10 @@ private ResourceEntity.type getResourceTypeFromAnnotation(String type) { * @param resourceId String with the resource ID */ public void addResourceToSerialize(String resourceId, double elasticityCost, int elasticity, String resourceType) { - ElasticityModelEntity elasModel = new ElasticityModelEntity("elasModel" + resourceId); + ElasticityModel elasModel = new ElasticityModel("elasModel" + resourceId); elasModel.setElasticityCost(elasticityCost); elasModel.setElasticity(elasticity); - resourcesToSerialize.put(resourceId, new ResourceEntity(resourceId, new LinkedList<>(), new LinkedList<>(), + resourcesToSerialize.put(resourceId, new Resource(resourceId, new LinkedList<>(), new LinkedList<>(), elasModel, getResourceTypeFromAnnotation(resourceType), new LinkedList<>(), "someImage")); } @@ -129,7 +129,7 @@ public T deserialize(String filePath, TypeReference typeRef) throws IOExc * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is * read */ - public Map deserializeResources(String name) throws IOException { + public Map deserializeResources(String name) throws IOException { return deserialize(FOLDER_RESOURCES + name + "SystemResources.json", new TypeReference<>() { }); } diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java similarity index 82% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java index c0cff55..72bb10d 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/resourceidentification/RetorchClassifier.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java @@ -1,7 +1,8 @@ -package giis.retorch.orchestration.resourceidentification; +package giis.retorch.orchestration.testdata; import giis.retorch.annotations.AccessModes; import giis.retorch.orchestration.model.*; +import giis.retorch.orchestration.model.System; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +15,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; -import giis.retorch.annotations.AccessMode; public class RetorchClassifier { @@ -22,15 +22,15 @@ public class RetorchClassifier { private static final String CHORUS_ATTRIBUTES = " is not present"; private static final String NO_EXIST = " doesn't exist"; - private final RetorchClassifierUtils deserializer; //Serializer employed to deserialize the resources info + private final ResourceSerializer deserializer; //Serializer employed to deserialize the resources info - private Map listAllResources; + private Map listAllResources; /** * Empty constructor used to validate RETORCH in the test case */ public RetorchClassifier() { - deserializer = new RetorchClassifierUtils(); + deserializer = new ResourceSerializer(); } /** * This method gets the file specified as package, in order to do this, instantiates the classLoader @@ -95,19 +95,19 @@ private static List> findClasses(File directory, String packageName) th * @param systemName String with the system name (must be the same as specified in the resource attributes JSON * file */ - public SystemEntity getSystemFromPackage(String systemName, String packageName) throws EmptyInputException, + public System getSystemFromPackage(String systemName, String packageName) throws EmptyInputException, IOException, ClassNotFoundException, URISyntaxException { this.listAllResources= new HashMap<>(); - for (ResourceEntity res:deserializer.deserializeResources(systemName).values()){ + for (Resource res:deserializer.deserializeResources(systemName).values()){ if (resourceChecker(res)){ this.listAllResources.put(res.getResourceID(),res); } } - SystemEntity systemRetorch = new SystemEntity(systemName); + System systemRetorch = new System(systemName); File directory = getPackageSourceDirectory(packageName); List> listClassesPackage = findClasses(directory, packageName); for (Class currentClass : listClassesPackage) { - SystemEntity temporalSystem = getSystemFromClass(systemName, currentClass); + System temporalSystem = getSystemFromClass(systemName, currentClass); addUniqueResources(systemRetorch, temporalSystem); systemRetorch.addListTestCases(temporalSystem.getTestCases()); } @@ -115,15 +115,15 @@ public SystemEntity getSystemFromPackage(String systemName, String packageName) return checkSystemClass(systemRetorch); } - private void addUniqueResources(SystemEntity systemRetorch, SystemEntity temporalSystem) { + private void addUniqueResources(System systemRetorch, System temporalSystem) { temporalSystem.getResources().stream() .filter(res -> !systemRetorch.getResources().contains(res)) .forEach(systemRetorch::addResourceClass); } - private void sortSystemClass(SystemEntity systemRetorch) { - systemRetorch.getTestCases().sort(Comparator.comparing(TestCaseEntity::getName)); - systemRetorch.getResources().sort(Comparator.comparing(ResourceEntity::toString)); + private void sortSystemClass(System systemRetorch) { + systemRetorch.getTestCases().sort(Comparator.comparing(TestCase::getName)); + systemRetorch.getResources().sort(Comparator.comparing(Resource::toString)); } /** @@ -135,14 +135,14 @@ private void sortSystemClass(SystemEntity systemRetorch) { * @param systemName String with the system name * @param testCaseClass Class with the test cases annotated */ - public SystemEntity getSystemFromClass(String systemName, Class testCaseClass) throws EmptyInputException, + public System getSystemFromClass(String systemName, Class testCaseClass) throws EmptyInputException, IOException { this.listAllResources = deserializer.deserializeResources(systemName); - SystemEntity systemRetorch = new SystemEntity(systemName); + System systemRetorch = new System(systemName); List listMethods = this.getClassMethods(testCaseClass); systemRetorch.addListOfResources(new ArrayList<>(listAllResources.values())); for (Method m : listMethods) { - TestCaseEntity testCase = getTestCasesFromMethod(m, testCaseClass); + TestCase testCase = getTestCasesFromMethod(m, testCaseClass); if (validateTestCase(testCase)) { systemRetorch.addTestCase(testCase); } @@ -159,7 +159,7 @@ public SystemEntity getSystemFromClass(String systemName, Class testCaseClass * remains to the annotated resources (3) The access mode is not empty * @param testCase testCase to be validated */ - public boolean validateTestCase(TestCaseEntity testCase) { + public boolean validateTestCase(TestCase testCase) { boolean output = true; String message; if (testCase.getAccessMode().isEmpty()) { @@ -177,11 +177,11 @@ public boolean validateTestCase(TestCaseEntity testCase) { * @param currentClass Class that belongs the method * @param currentMethod Test case Method */ - public TestCaseEntity getTestCasesFromMethod(Method currentMethod, Class currentClass) { + public TestCase getTestCasesFromMethod(Method currentMethod, Class currentClass) { String methodName = currentMethod.getName(); // Directly assign the result of getAccessModesFromMethod to listAccessModesMethod - List listAccessModesMethod = this.getAccessModesFromMethod(currentMethod); - TestCaseEntity newTestCase = new TestCaseEntity(methodName, currentClass); + List listAccessModesMethod = this.getAccessModesFromMethod(currentMethod); + TestCase newTestCase = new TestCase(methodName, currentClass); newTestCase.setAccessMode(listAccessModesMethod); return newTestCase; } @@ -194,26 +194,26 @@ public TestCaseEntity getTestCasesFromMethod(Method currentMethod, Class curr * the accessModes with all the information retrieved from the annotations ( resource,elasticity,sharing...) * @param testMethod Method to retrieve the annotations. */ - public List getAccessModesFromMethod(Method testMethod) { - List listAccessModes = new ArrayList<>(); // Use ArrayList instead of LinkedList for better + public List getAccessModesFromMethod(Method testMethod) { + List listAccessModes = new ArrayList<>(); // Use ArrayList instead of LinkedList for better - List listAccessModesTag = new ArrayList<>(); // random access performance + List listAccessModesTag = new ArrayList<>(); // random access performance - if (testMethod.isAnnotationPresent(AccessMode.class)) { // Check for single annotation presence - listAccessModesTag.add(testMethod.getAnnotation(AccessMode.class)); + if (testMethod.isAnnotationPresent(giis.retorch.annotations.AccessMode.class)) { // Check for single annotation presence + listAccessModesTag.add(testMethod.getAnnotation(giis.retorch.annotations.AccessMode.class)); } if (testMethod.isAnnotationPresent(AccessModes.class) ) { // Check for multiple annotations presence listAccessModesTag.addAll(Arrays.asList(testMethod.getAnnotation(AccessModes.class).value())); // Use // addAll instead of assignment to avoid overwriting previous values } - for (AccessMode accessTag : listAccessModesTag) { + for (giis.retorch.annotations.AccessMode accessTag : listAccessModesTag) { if (this.accessModeTagChecker(accessTag, testMethod.getName())) { - AccessModeEntity currentAccessMode = new AccessModeEntity(); + AccessMode currentAccessMode = new AccessMode(); currentAccessMode.setConcurrency(accessTag.concurrency()); - ResourceEntity requiredResource = getRequiredResource(accessTag.resID()); + Resource requiredResource = getRequiredResource(accessTag.resID()); currentAccessMode.setResource(requiredResource); currentAccessMode.setSharing(accessTag.sharing()); - currentAccessMode.setAccessMode(new AccessModeTypesEntity(accessTag.accessMode())); + currentAccessMode.setType(new AccessModeTypes(accessTag.accessMode())); listAccessModes.add(currentAccessMode); } } @@ -223,14 +223,14 @@ public List getAccessModesFromMethod(Method testMethod) { /** * Support method that checks the resources annotated with the access mode */ - public ResourceEntity getRequiredResource(String idResource) { + public Resource getRequiredResource(String idResource) { String message; if (listAllResources.containsKey(idResource)) { return listAllResources.get(idResource); } else { message=String.format("The resource %s is not tagged", idResource); log.info(message); - return new ResourceEntity("Resource Not valid"); + return new Resource("Resource Not valid"); } } @@ -256,7 +256,7 @@ public List getClassMethods(Class testClass) { * for finally (3) check if there is only there are one Hierarchy Parent * @param resource ResourceClass with the resource to check */ - private boolean resourceChecker(ResourceEntity resource) { + private boolean resourceChecker(Resource resource) { List listMessages = new LinkedList<>(); if (resource.getHierarchyParent().contains("None")) { listMessages.add(String.format("The Hierarchy Parent Attribute in resource %s%s",resource.getResourceID(), CHORUS_ATTRIBUTES)); @@ -282,7 +282,7 @@ private boolean resourceChecker(ResourceEntity resource) { * of the attributes : id,elasticity or cost, (2) If the elasticity or the cost is invalid (negative) * @param resource Resource with all the attributes */ - private boolean elasticityChecker(ResourceEntity resource) { + private boolean elasticityChecker(Resource resource) { boolean isOutElasticityID = resource.getElasticityModel().getElasticityID().equals("None"); boolean isOutElasticity = resource.getElasticityModel().getElasticity() == -1; boolean isOutElasticityCost = resource.getElasticityModel().getElasticityCost() == -1; @@ -321,7 +321,7 @@ private boolean elasticityChecker(ResourceEntity resource) { * @param accessModeTag AccessMode tag * @param methodName String with the method name */ - private boolean accessModeTagChecker(AccessMode accessModeTag, String methodName) { + private boolean accessModeTagChecker(giis.retorch.annotations.AccessMode accessModeTag, String methodName) { List listMessages = new LinkedList<>(); checkConcurrency(accessModeTag, methodName, listMessages); @@ -339,7 +339,7 @@ private boolean accessModeTagChecker(AccessMode accessModeTag, String methodName return listMessages.isEmpty(); } - private void checkConcurrency(AccessMode accessModeTag, String methodName, List listMessages) { + private void checkConcurrency(giis.retorch.annotations.AccessMode accessModeTag, String methodName, List listMessages) { if (accessModeTag.concurrency() == -1) { listMessages.add(String.format("The Concurrency Attribute in method %s%s", methodName, CHORUS_ATTRIBUTES)); } @@ -351,8 +351,8 @@ private void checkConcurrency(AccessMode accessModeTag, String methodName, List< } } - private void checkAccessModeType(AccessMode accessModeTag, String methodName, List listMessages) { - if (!AccessModeTypesEntity.isValidAccessMode(accessModeTag.accessMode())) { + private void checkAccessModeType(giis.retorch.annotations.AccessMode accessModeTag, String methodName, List listMessages) { + if (!AccessModeTypes.isValidAccessMode(accessModeTag.accessMode())) { String message = accessModeTag.accessMode().equals("NOASSIGNED") ? String.format("The AccessModeType in method %s is not specified", methodName) : String.format("The AccessModeType in method %s%s", methodName, NO_EXIST); @@ -364,19 +364,19 @@ private void checkAccessModeType(AccessMode accessModeTag, String methodName, Li * Support method that validates the System provided as parameter. It checks that the replaceable resources exists * @param systemToCheck System to check tag */ - private SystemEntity checkSystemClass(SystemEntity systemToCheck) { - SystemEntity systemEntityOutput = new SystemEntity(systemToCheck.getName()); + private System checkSystemClass(System systemToCheck) { + System systemOutput = new System(systemToCheck.getName()); List idResourcesList = listAllResources.values().stream() - .map(ResourceEntity::getResourceID) + .map(Resource::getResourceID) .toList(); systemToCheck.getResources().stream() .filter(res -> idResourcesList.containsAll(res.getReplaceable())) - .forEach(systemEntityOutput::addResourceClass); + .forEach(systemOutput::addResourceClass); systemToCheck.getResources().stream() .filter(res -> !idResourcesList.containsAll(res.getReplaceable())) .forEach(res -> log.error("The Replaceable of resource {}{}", res.getResourceID(), NO_EXIST)); - systemEntityOutput.addListTestCases(systemToCheck.getTestCases()); + systemOutput.addListTestCases(systemToCheck.getTestCases()); - return systemEntityOutput; + return systemOutput; } } \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java similarity index 72% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java index 07af049..5bcca76 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/components/ClassifierTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java @@ -1,14 +1,14 @@ -package giis.retorch.orchestration.unitary.components; +package giis.retorch.orchestration; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.Appender; -import giis.retorch.orchestration.model.SystemEntity; -import giis.retorch.orchestration.resourceidentification.EmptyInputException; -import giis.retorch.orchestration.resourceidentification.RetorchClassifier; -import giis.retorch.orchestration.unitary.testdata.classifier.SyntheticInvalidClassTests; +import giis.retorch.orchestration.model.System; +import giis.retorch.orchestration.testdata.EmptyInputException; +import giis.retorch.orchestration.testdata.RetorchClassifier; +import giis.retorch.orchestration.testdata.SyntheticInvalidClassTests; import giis.retorch.orchestration.utils.ClassifierUtils; -import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage.SyntheticClassOneTests; +import giis.retorch.orchestration.testdata.synteticpackage.insidepackage.SyntheticClassOneTests; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -44,18 +44,18 @@ public void setUp() { @Test public void testUnitArchIResValidPackage() throws EmptyInputException, IOException, ClassNotFoundException, URISyntaxException { - String packageName = "giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage"; - SystemEntity currentSystem = classifier.getSystemFromPackage(SYSTEM_NAME, packageName); - SystemEntity expectedSystem = utilsClassifier.generateSystemPackage(); + String packageName = "giis.retorch.orchestration.testdata.synteticpackage"; + System currentSystem = classifier.getSystemFromPackage(SYSTEM_NAME, packageName); + System expectedSystem = utilsClassifier.generateSystemPackage(); assertEquals(expectedSystem.toString(), currentSystem.toString()); } @Test public void testUnitArchIResValidClass() throws EmptyInputException, IOException { Class testClass = SyntheticClassOneTests.class; - SystemEntity systemEntity = classifier.getSystemFromClass(SYSTEM_NAME, testClass); - SystemEntity expectedSystem = utilsClassifier.generateSystemFromClass(); - assertEquals(expectedSystem.toString(), systemEntity.toString()); + System system = classifier.getSystemFromClass(SYSTEM_NAME, testClass); + System expectedSystem = utilsClassifier.generateSystemFromClass(); + assertEquals(expectedSystem.toString(), system.toString()); } @Test(expected = EmptyInputException.class) @@ -81,7 +81,7 @@ public void testUnitArchIResInvalidClass() throws EmptyInputException, IOExcepti assertTrue(listMessages.contains("The ResourceID Attribute in method testTwoAttributesLoosingAccessMode is not present")); // Check that the resourceId omitted is detected // Validation of the attributes assertTrue(listMessages.contains("The AccessModeType in method validationAccessModeAttributes doesn't exist")); // AccessMode Invalid - assertTrue(listMessages.contains("The Concurrency in method validationAccessModeAttributes is not valid: non shareable resource with >1 concurrency")); // Concurrency Invalid sharing=true && <2 and sharing - assertTrue(listMessages.contains("The Concurrency in method validationAccessModeAttributes is not valid: shareable resource with >2 concurrency")); // Concurrency Invalid + assertTrue(listMessages.contains("Invalid Concurrency in method validationAccessModeAttributes: non-shareable resource with concurrency > 1")); // Concurrency Invalid sharing=true && <2 and sharing + assertTrue(listMessages.contains("Invalid Concurrency in method validationAccessModeAttributes: shareable resource with concurrency < 2")); // Concurrency Invalid } } \ No newline at end of file diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java similarity index 73% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java index 2f932a3..80a0179 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/entities/TJobsEntityTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.unitary.entities; +package giis.retorch.orchestration; import org.junit.Before; import org.junit.Rule; @@ -6,10 +6,10 @@ import org.junit.rules.TestName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import giis.retorch.orchestration.model.CapacityEntity; -import giis.retorch.orchestration.model.ResourceEntity; -import giis.retorch.orchestration.model.TJobEntity; -import giis.retorch.orchestration.model.ResourceInstanceEntity; +import giis.retorch.orchestration.model.Capacity; +import giis.retorch.orchestration.model.Resource; +import giis.retorch.orchestration.model.TJob; +import giis.retorch.orchestration.model.ResourceInstance; import java.util.LinkedList; import java.util.Map; @@ -21,7 +21,7 @@ public class TJobsEntityTests { private final Logger log = LoggerFactory.getLogger(this.getClass()); - TJobEntity tjob; + TJob tjob; @Rule public TestName testName = new TestName(); @@ -29,13 +29,13 @@ public class TJobsEntityTests { @Before public void setUp() { log.info("****** Running test: {} ******", testName.getMethodName()); - LinkedList listCapacities = new LinkedList<>(); - listCapacities.add(new CapacityEntity("memory", 4)); - listCapacities.add(new CapacityEntity("processor", 3)); - ResourceInstanceEntity resourceOne = new ResourceInstanceEntity("webserver", listCapacities); - LinkedList listResources = new LinkedList<>(); + LinkedList listCapacities = new LinkedList<>(); + listCapacities.add(new Capacity("memory", 4)); + listCapacities.add(new Capacity("processor", 3)); + ResourceInstance resourceOne = new ResourceInstance("webserver", listCapacities); + LinkedList listResources = new LinkedList<>(); listResources.add(resourceOne); - tjob = new TJobEntity("tjoba", 0, listResources); + tjob = new TJob("tjoba", 0, listResources); log.info("****** Set-up for test: {} ended ******", testName.getMethodName()); } @@ -61,10 +61,10 @@ public void testTJobAvgTime() { @Test public void testLifecycleCapacities() { tjob.setAvgTime(2, 10, 11, 16, 17, 21); - CapacityEntity capacityOne = new CapacityEntity("memory", 4); - CapacityEntity capacityTwo = new CapacityEntity("processor", 3); + Capacity capacityOne = new Capacity("memory", 4); + Capacity capacityTwo = new Capacity("processor", 3); - Map.Entry> output; + Map.Entry> output; output = tjob.getCapacitiesGivenTime(1, 0); assertEquals("noexec", output.getKey()); assertTrue(output.getValue().isEmpty()); diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/SyntheticInvalidClassTests.java similarity index 98% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/SyntheticInvalidClassTests.java index d2e06f5..ecf0eec 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/SyntheticInvalidClassTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/SyntheticInvalidClassTests.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.unitary.testdata.classifier; +package giis.retorch.orchestration.testdata; import giis.retorch.annotations.AccessMode; import org.junit.Assert; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/SyntheticClassTwoTests.java similarity index 90% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/SyntheticClassTwoTests.java index f92ca42..942dd60 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/SyntheticClassTwoTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/SyntheticClassTwoTests.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage; +package giis.retorch.orchestration.testdata.synteticpackage; import giis.retorch.annotations.AccessMode; import org.junit.Assert; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/insidepackage/SyntheticClassOneTests.java similarity index 95% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/insidepackage/SyntheticClassOneTests.java index f890df7..8d65940 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/unitary/testdata/classifier/synteticpackage/insidepackage/SyntheticClassOneTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/testdata/synteticpackage/insidepackage/SyntheticClassOneTests.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage; +package giis.retorch.orchestration.testdata.synteticpackage.insidepackage; import giis.retorch.annotations.AccessMode; import org.junit.Assert; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java index 6eaccfd..3f34597 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java @@ -1,8 +1,9 @@ package giis.retorch.orchestration.utils; import giis.retorch.orchestration.model.*; -import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.SyntheticClassTwoTests; -import giis.retorch.orchestration.unitary.testdata.classifier.synteticpackage.insidepackage.SyntheticClassOneTests; +import giis.retorch.orchestration.model.System; +import giis.retorch.orchestration.testdata.synteticpackage.SyntheticClassTwoTests; +import giis.retorch.orchestration.testdata.synteticpackage.insidepackage.SyntheticClassOneTests; import java.util.Comparator; import java.util.LinkedList; @@ -10,36 +11,36 @@ public class ClassifierUtils extends GenericUtils { - public List getAllTestCases() { - LinkedList listTestCases = getFirstClassTestCases(); - TestCaseEntity tCMFour = new TestCaseEntity("testFourH", SyntheticClassTwoTests.class); + public List getAllTestCases() { + LinkedList listTestCases = getFirstClassTestCases(); + TestCase tCMFour = new TestCase("testFourH", SyntheticClassTwoTests.class); tCMFour.addAccessMode(getOtherAccessModeHeavyInelasticResource()); listTestCases.add(tCMFour); - TestCaseEntity tCMFive = new TestCaseEntity("testFiveH", SyntheticClassTwoTests.class); + TestCase tCMFive = new TestCase("testFiveH", SyntheticClassTwoTests.class); tCMFive.addAccessMode(getOtherAccessModeHeavyInelasticResource()); listTestCases.add(tCMFive); - TestCaseEntity tCMEight = new TestCaseEntity("testEightH", SyntheticClassTwoTests.class); + TestCase tCMEight = new TestCase("testEightH", SyntheticClassTwoTests.class); tCMEight.addAccessMode(this.getJSONSavedInelasticAccessMode()); listTestCases.add(tCMEight); return listTestCases; } - public SystemEntity generateSystemPackage() { + public System generateSystemPackage() { generateSystemResources(); - SystemEntity expectedSystem = new SystemEntity("ClassifierUnitTests"); + System expectedSystem = new System("ClassifierUnitTests"); expectedSystem.addResourceClass(this.getHeavyInelasticResource()); expectedSystem.addResourceClass(this.getLightElasticResource()); expectedSystem.addResourceClass(this.getMockElasticResource()); expectedSystem.addResourceClass(this.getJSONSavedInelasticResource()); expectedSystem.addResourceClass(this.getJSONSavedElasticResource()); - expectedSystem.getResources().sort(Comparator.comparing(ResourceEntity::toString)); - expectedSystem.addListTestCases(getAllTestCases().stream().sorted(Comparator.comparing(TestCaseEntity::getName)).toList()); + expectedSystem.getResources().sort(Comparator.comparing(Resource::toString)); + expectedSystem.addListTestCases(getAllTestCases().stream().sorted(Comparator.comparing(TestCase::getName)).toList()); return expectedSystem; } - public SystemEntity generateSystemFromClass() { + public System generateSystemFromClass() { generateSystemResources(); - SystemEntity expectedSystem = new SystemEntity("ClassifierUnitTests"); + System expectedSystem = new System("ClassifierUnitTests"); expectedSystem.addResourceClass(this.getHeavyInelasticResource()); expectedSystem.addResourceClass(this.getLightElasticResource()); expectedSystem.addResourceClass(this.getMockElasticResource()); @@ -47,46 +48,46 @@ public SystemEntity generateSystemFromClass() { return expectedSystem; } - private LinkedList getFirstClassTestCases() { - LinkedList listTestCases = new LinkedList<>(); - TestCaseEntity tCHOne = new TestCaseEntity("testOneH", SyntheticClassOneTests.class); + private LinkedList getFirstClassTestCases() { + LinkedList listTestCases = new LinkedList<>(); + TestCase tCHOne = new TestCase("testOneH", SyntheticClassOneTests.class); tCHOne.addAccessMode(this.getAccessModeHeavyInElasticResource()); tCHOne.addAccessMode(this.getAccessModeLightElasticResource()); listTestCases.add(tCHOne); - TestCaseEntity tCHTwo = new TestCaseEntity("testTwoH", SyntheticClassOneTests.class); + TestCase tCHTwo = new TestCase("testTwoH", SyntheticClassOneTests.class); tCHTwo.addAccessMode(this.getAccessModeHeavyInElasticResource()); tCHTwo.addAccessMode(this.getAccessModeLightElasticResource()); listTestCases.add(tCHTwo); - TestCaseEntity tCHThree = new TestCaseEntity("testThreeH", SyntheticClassOneTests.class); + TestCase tCHThree = new TestCase("testThreeH", SyntheticClassOneTests.class); tCHThree.addAccessMode(getAccessModeHeavyInElasticResource()); tCHThree.addAccessMode(this.getMockElasticAccessMode()); listTestCases.add(tCHThree); - TestCaseEntity tCHSix = new TestCaseEntity("testSixH", SyntheticClassOneTests.class); + TestCase tCHSix = new TestCase("testSixH", SyntheticClassOneTests.class); tCHSix.addAccessMode(this.getJSONSavedInelasticAccessMode()); tCHSix.addAccessMode(this.getJSONSavedElasticAccessMode()); listTestCases.add(tCHSix); - TestCaseEntity tCHSeven = new TestCaseEntity("testSevenH", SyntheticClassOneTests.class); + TestCase tCHSeven = new TestCase("testSevenH", SyntheticClassOneTests.class); tCHSeven.addAccessMode(this.getJSONSavedInelasticAccessMode()); tCHSeven.addAccessMode(this.getJSONSavedElasticAccessMode()); listTestCases.add(tCHSeven); return listTestCases; } - private AccessModeEntity getJSONSavedInelasticAccessMode() { - AccessModeEntity accessModeEntity = new AccessModeEntity(this.getAccessModeHeavyInElasticResource()); - accessModeEntity.setResource(this.getJSONSavedInelasticResource()); - return accessModeEntity; + private AccessMode getJSONSavedInelasticAccessMode() { + AccessMode accessMode = new AccessMode(this.getAccessModeHeavyInElasticResource()); + accessMode.setResource(this.getJSONSavedInelasticResource()); + return accessMode; } - private AccessModeEntity getJSONSavedElasticAccessMode() { - AccessModeEntity accessModeEntity = new AccessModeEntity(this.getAccessModeLightElasticResource()); - accessModeEntity.setResource(this.getJSONSavedElasticResource()); - return accessModeEntity; + private AccessMode getJSONSavedElasticAccessMode() { + AccessMode accessMode = new AccessMode(this.getAccessModeLightElasticResource()); + accessMode.setResource(this.getJSONSavedElasticResource()); + return accessMode; } - private ResourceEntity getJSONSavedInelasticResource() { - ResourceEntity outputResource = new ResourceEntity(this.getHeavyInelasticResource()); - ElasticityModelEntity modelJSON = outputResource.getElasticityModel(); + private Resource getJSONSavedInelasticResource() { + Resource outputResource = new Resource(this.getHeavyInelasticResource()); + ElasticityModel modelJSON = outputResource.getElasticityModel(); modelJSON.setElasticityID("elasModelHeavyInElasRest"); outputResource.setElasticityModel(modelJSON); outputResource.setResourceID("heavyInElasRest"); @@ -96,9 +97,9 @@ private ResourceEntity getJSONSavedInelasticResource() { return outputResource; } - private ResourceEntity getJSONSavedElasticResource() { - ResourceEntity outputResource = new ResourceEntity(this.getLightElasticResource()); - ElasticityModelEntity modelJSON = outputResource.getElasticityModel(); + private Resource getJSONSavedElasticResource() { + Resource outputResource = new Resource(this.getLightElasticResource()); + ElasticityModel modelJSON = outputResource.getElasticityModel(); modelJSON.setElasticityID("elasModelLightElasticResource"); outputResource.setElasticityModel(modelJSON); outputResource.setResourceID("lightElasticResource"); diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java index 8f08d21..8bf8590 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java @@ -14,74 +14,74 @@ public class GenericUtils { protected static final String LIGHT_ELASTIC_ID = "lightElasticResource"; protected static final String HEAVY_INELASTIC_ID = "heavyInElasRest"; - public ElasticityModelEntity getElasticityModelMockResource() { - ElasticityModelEntity expectedElasticityModelMock = new ElasticityModelEntity("elasticityIDMockElastic"); + public ElasticityModel getElasticityModelMockResource() { + ElasticityModel expectedElasticityModelMock = new ElasticityModel("elasticityIDMockElastic"); expectedElasticityModelMock.setElasticity(50); expectedElasticityModelMock.setElasticityCost(0); return expectedElasticityModelMock; } - public AccessModeEntity getAccessModeHeavyInElasticResource() { - AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + public AccessMode getAccessModeHeavyInElasticResource() { + AccessMode expectedAccessModeHeavy = new AccessMode(); expectedAccessModeHeavy.setSharing(false); expectedAccessModeHeavy.setConcurrency(1); expectedAccessModeHeavy.setResource(this.getHeavyInelasticResource()); - expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + expectedAccessModeHeavy.setType(new AccessModeTypes(READWRITE)); return expectedAccessModeHeavy; } - public AccessModeEntity getOtherAccessModeHeavyInelasticResource() { - AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(this.getAccessModeHeavyInElasticResource()); + public AccessMode getOtherAccessModeHeavyInelasticResource() { + AccessMode expectedAccessModeHeavy = new AccessMode(this.getAccessModeHeavyInElasticResource()); expectedAccessModeHeavy.setSharing(false); expectedAccessModeHeavy.setConcurrency(1); expectedAccessModeHeavy.setResource(this.getHeavyInelasticResource()); - expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + expectedAccessModeHeavy.setType(new AccessModeTypes(READWRITE)); return expectedAccessModeHeavy; } - public AccessModeEntity getAccessModeLightElasticResource() { - AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + public AccessMode getAccessModeLightElasticResource() { + AccessMode expectedAccessModeHeavy = new AccessMode(); expectedAccessModeHeavy.setSharing(true); expectedAccessModeHeavy.setConcurrency(4); expectedAccessModeHeavy.setResource(this.getLightElasticResource()); - expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READWRITE)); + expectedAccessModeHeavy.setType(new AccessModeTypes(READWRITE)); return expectedAccessModeHeavy; } - public ResourceEntity getLightElasticResource() { - ResourceEntity lightElasticResource = new ResourceEntity(LIGHT_ELASTIC_ID); + public Resource getLightElasticResource() { + Resource lightElasticResource = new Resource(LIGHT_ELASTIC_ID); lightElasticResource.setElasticityModel(getElasticityModelLightElasticResource()); - List requiredCapacities = new LinkedList<>(); - requiredCapacities.add(new CapacityEntity("memory", 1)); - requiredCapacities.add(new CapacityEntity("processor", 0.5)); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new Capacity("memory", 1)); + requiredCapacities.add(new Capacity("processor", 0.5)); lightElasticResource.setMinimalCapacities(requiredCapacities); return lightElasticResource; } - public ElasticityModelEntity getElasticityModelLightElasticResource() { - ElasticityModelEntity expectedElasticityModelMySQL = new ElasticityModelEntity("elasModelLightElasticResource"); + public ElasticityModel getElasticityModelLightElasticResource() { + ElasticityModel expectedElasticityModelMySQL = new ElasticityModel("elasModelLightElasticResource"); expectedElasticityModelMySQL.setElasticity(35); expectedElasticityModelMySQL.setElasticityCost(15.0); return expectedElasticityModelMySQL; } - public AccessModeEntity getMockElasticAccessMode() { - AccessModeEntity expectedAccessModeHeavy = new AccessModeEntity(); + public AccessMode getMockElasticAccessMode() { + AccessMode expectedAccessModeHeavy = new AccessMode(); expectedAccessModeHeavy.setSharing(true); expectedAccessModeHeavy.setConcurrency(4); expectedAccessModeHeavy.setResource(this.getMockElasticResource()); - expectedAccessModeHeavy.setAccessMode(new AccessModeTypesEntity(READONLY)); + expectedAccessModeHeavy.setType(new AccessModeTypes(READONLY)); return expectedAccessModeHeavy; } - public ResourceEntity getMockElasticResource() { - ResourceEntity mockElasticResource = new ResourceEntity(LIGHT_ELASTIC_ID); + public Resource getMockElasticResource() { + Resource mockElasticResource = new Resource(LIGHT_ELASTIC_ID); mockElasticResource.setResourceID("mockElasticResource"); - ElasticityModelEntity modelMock = new ElasticityModelEntity("elasModelmockElasticResource", 50, 0.0); + ElasticityModel modelMock = new ElasticityModel("elasModelmockElasticResource", 50, 0.0); mockElasticResource.setElasticityModel(modelMock); - List requiredCapacities = new LinkedList<>(); - requiredCapacities.add(new CapacityEntity("memory", 0.5)); - requiredCapacities.add(new CapacityEntity("processor", 2.0)); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new Capacity("memory", 0.5)); + requiredCapacities.add(new Capacity("processor", 2.0)); mockElasticResource.setMinimalCapacities(requiredCapacities); mockElasticResource.addReplaceableResource(LIGHT_ELASTIC_ID); mockElasticResource.addReplaceableResource(HEAVY_INELASTIC_ID); @@ -94,20 +94,20 @@ public void generateSystemResources() { getLightElasticResource(); } - public ResourceEntity getHeavyInelasticResource() { - ResourceEntity heavyInelasticResource = new ResourceEntity(HEAVY_INELASTIC_ID); + public Resource getHeavyInelasticResource() { + Resource heavyInelasticResource = new Resource(HEAVY_INELASTIC_ID); heavyInelasticResource.addHierarchyParent("parentAllInelastic"); heavyInelasticResource.setElasticityModel(getElasticityModelHeavyInelasticResource()); - heavyInelasticResource.setResourceType(ResourceEntity.type.LOGICAL); - List requiredCapacities = new LinkedList<>(); - requiredCapacities.add(new CapacityEntity("memory", 4.0)); - requiredCapacities.add(new CapacityEntity("processor", 0.6)); + heavyInelasticResource.setResourceType(Resource.type.LOGICAL); + List requiredCapacities = new LinkedList<>(); + requiredCapacities.add(new Capacity("memory", 4.0)); + requiredCapacities.add(new Capacity("processor", 0.6)); heavyInelasticResource.setMinimalCapacities(requiredCapacities); return heavyInelasticResource; } - public ElasticityModelEntity getElasticityModelHeavyInelasticResource() { - ElasticityModelEntity expectedElasticityModelHeavy = new ElasticityModelEntity("elasModelHeavyInElasRest"); + public ElasticityModel getElasticityModelHeavyInelasticResource() { + ElasticityModel expectedElasticityModelHeavy = new ElasticityModel("elasModelHeavyInElasRest"); expectedElasticityModelHeavy.setElasticity(1); expectedElasticityModelHeavy.setElasticityCost(50.0); return expectedElasticityModelHeavy; diff --git a/retorch-orchestration/src/test/resources/log4j2.xml b/retorch-orchestration/src/test/resources/log4j2.xml deleted file mode 100644 index d8f4072..0000000 --- a/retorch-orchestration/src/test/resources/log4j2.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/retorch-orchestration/src/test/resources/logback.xml b/retorch-orchestration/src/test/resources/logback.xml new file mode 100644 index 0000000..544b7d6 --- /dev/null +++ b/retorch-orchestration/src/test/resources/logback.xml @@ -0,0 +1,30 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%throwable + + + + + + target/log-test.log + true + + %d [%thread] %-5level %logger{36} - %msg%n%throwable + + + + + + + + + + + + + + + From 578bbb666eef112fff597e095ac11a2a2fbd9154 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 11:19:45 +0100 Subject: [PATCH 03/28] Solved some problems in the workflow file --- .github/workflows/test.yml | 2 +- retorch-annotations/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce08c48..a3840f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,7 @@ jobs: cache: 'maven' - name: Test RETORCH orchestration module - run: mvn test -Dtest=* -pl retorch-orchestration -U --no-transfer-progress + run: mvn test -pl retorch-orchestration -am -U --no-transfer-progress - name: Generate report checks if: always() diff --git a/retorch-annotations/pom.xml b/retorch-annotations/pom.xml index cb301c6..95f649f 100644 --- a/retorch-annotations/pom.xml +++ b/retorch-annotations/pom.xml @@ -15,7 +15,7 @@ https://github.com/giis-uniovi/retorch Software Engineering Research Group (GIIS) - University of Oviedo, ES - http://giis.uniovi.es/ + https://giis.uniovi.es/ From f75856d1c27605afcffb68d1a3efc3c8a50baab9 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 11:22:28 +0100 Subject: [PATCH 04/28] Adding dependencies between build-test --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a3840f4..e818a32 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,6 +25,7 @@ jobs: run: mvn compile -U --no-transfer-progress test-retorch-orchestration: + needs: [build-java] runs-on: ubuntu-latest # if: ${{ false }} # disable for now steps: From 2682c0de9e7033b97b91da361c3136126c13a996 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 11:38:08 +0100 Subject: [PATCH 05/28] Use the Maven reactor to build and resolve dependencies across modules --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e818a32..a42bc92 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,7 +114,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} java-version: '16' - mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' + mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -am -U --no-transfer-progress' delete-old-snapshots: true - min-snapshots-to-keep: 2 + min-snapshots-to-keep: 4 always-keep-regex: "\\d*\\.\\d*\\.\\d*-main-SNAPSHOT$" From 0e9be529e6603544ca4089f1e7eb6934024daf87 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 11:51:42 +0100 Subject: [PATCH 06/28] Use the Maven reactor to build and resolve dependencies across modules --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a42bc92..e818a32 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,7 +114,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} java-version: '16' - mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -am -U --no-transfer-progress' + mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' delete-old-snapshots: true - min-snapshots-to-keep: 4 + min-snapshots-to-keep: 2 always-keep-regex: "\\d*\\.\\d*\\.\\d*-main-SNAPSHOT$" From 7d998197723aa39896c7c49a49ecad921d106e20 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 12:02:04 +0100 Subject: [PATCH 07/28] Adding Jacoco to generate the coverage reports --- retorch-orchestration/pom.xml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml index ce86d51..b6fa6a8 100644 --- a/retorch-orchestration/pom.xml +++ b/retorch-orchestration/pom.xml @@ -21,6 +21,8 @@ 3.5.2 + 0.8.12 + 2.18.1 5.14.2 @@ -97,12 +99,45 @@ **/testdata/** + + ${surefireArgLine} true true false + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-test + + prepare-agent + + + ${project.build.directory}/coverage-reports/jacoco.exec + surefireArgLine + + + + + post-unit-test + test + + report + + + ${project.build.directory}/coverage-reports/jacoco.exec + ${project.reporting.outputDirectory}/jacoco + + + + + \ No newline at end of file From 92474df658b6ac7871ccc3244226f24fafc69a87 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 12:40:10 +0100 Subject: [PATCH 08/28] Moving dependencies to the parent pom and finishing to declare versions in prop. --- pom.xml | 81 +++++++++++++++++++++++++++++------ retorch-orchestration/pom.xml | 40 ----------------- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/pom.xml b/pom.xml index 4880e45..e6fc38e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,12 +7,11 @@ pom retorch - RETORCH: Resource-aware Orchestration of End-to-End Test Cases - + RETORCH: Resource-aware Orchestration of End-to-End Test Cases https://github.com/giis-uniovi/retorch Software Engineering Research Group (GIIS) - University of Oviedo, ES - http://giis.uniovi.es/ + https://giis.uniovi.es/ @@ -20,9 +19,26 @@ 16 UTF-8 + 4.13.2 + + 2.0.16 1.5.12 + 2.18.1 + + 3.3.1 + + 3.5.2 + + 3.10.1 + + 3.2.7 + + 1.7.0 + + 0.8.12 + @@ -35,13 +51,13 @@ junit junit - 4.13.2 + ${junit.version} test org.slf4j slf4j-api - 2.0.16 + ${slf4japi.version} ch.qos.logback @@ -49,6 +65,11 @@ ${logback-classic.version} test + + com.fasterxml.jackson.core + jackson-databind + ${jacksonjson.version} + @@ -58,7 +79,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.1 + ${maven-source-plugin.version} attach-sources @@ -71,7 +92,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.10.1 + ${maven-javadoc-plugin.version} true none @@ -86,6 +107,40 @@ + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-test + + prepare-agent + + + ${project.build.directory}/coverage-reports/jacoco.exec + surefireArgLine + + + + post-unit-test + test + + report + + + ${project.build.directory}/coverage-reports/jacoco.exec + ${project.reporting.outputDirectory}/jacoco + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + @@ -93,19 +148,19 @@ Cristian Augusto - http://www.augustocristian.es + https://www.augustocristian.es Claudio de la Riva - http://giis.uniovi.es + https://giis.uniovi.es Javier Tuya - http://giis.uniovi.es + https://giis.uniovi.es Jesús Morán - http://giis.uniovi.es + https://giis.uniovi.es @@ -137,7 +192,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.7.0 + ${nexus-staging-maven-plugin.version} true ossrh @@ -148,7 +203,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.2.7 + ${maven-gpg-plugin.version} sign-artifacts diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml index b6fa6a8..25efeb8 100644 --- a/retorch-orchestration/pom.xml +++ b/retorch-orchestration/pom.xml @@ -19,16 +19,8 @@ 1.1.1-SNAPSHOT - 3.5.2 - - 0.8.12 - - 2.18.1 - 5.14.2 - - @@ -51,7 +43,6 @@ com.fasterxml.jackson.core jackson-databind - ${jacksonjson.version} org.mockito @@ -93,7 +84,6 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} **/testdata/** @@ -107,36 +97,6 @@ false - - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - - pre-unit-test - - prepare-agent - - - ${project.build.directory}/coverage-reports/jacoco.exec - surefireArgLine - - - - - post-unit-test - test - - report - - - ${project.build.directory}/coverage-reports/jacoco.exec - ${project.reporting.outputDirectory}/jacoco - - - - From 18f34a2a4b183e6d16bb5113c31788cbf17700a3 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 16:59:55 +0100 Subject: [PATCH 09/28] Changes requested 2 - Moving dependencies to the parent. - Removing hardcoded dependency to annotations - Aligning actions with giis-samples --- .github/workflows/test.yml | 56 ++++------------------------------- pom.xml | 8 +++++ retorch-orchestration/pom.xml | 15 ++++------ 3 files changed, 19 insertions(+), 60 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e818a32..b180d14 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,8 @@ on: branches: - 'main' jobs: - build-java: + test-retorch: + needs: runs-on: ubuntu-latest # if: ${{ false }} # disable for now steps: @@ -21,23 +22,8 @@ jobs: java-version: '16' cache: 'maven' - - name: Build RETORCH project - run: mvn compile -U --no-transfer-progress - - test-retorch-orchestration: - needs: [build-java] - runs-on: ubuntu-latest - # if: ${{ false }} # disable for now - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '16' - cache: 'maven' - - - name: Test RETORCH orchestration module - run: mvn test -pl retorch-orchestration -am -U --no-transfer-progress + - name: Test RETORCH and aggregate surefire report + run: mvn test surefire-report:report -Daggregate=true -Dmaven.test.failure.ignore=true -U --no-transfer-progress - name: Generate report checks if: always() @@ -58,48 +44,18 @@ jobs: **/target/surefire-reports sonarqube: - needs: [ build-java, test-retorch-orchestration ] + needs: [ test-retorch ] #if: ${{ false }} # disable for now #This job fails when comming from a dependabot PR (can't read the sonarqube token for security reasons). #Links to discussions and workaround at: https://github.com/giis-uniovi/samples-giis-template/issues/4 if: ${{ github.actor != 'dependabot[bot]' }} runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v4.1.8 - if: always() - with: - name: "test-report-files-orchestration" - - name: Aggregated junit html report - if: always() - uses: javiertuya/junit-report-action@v1.2.0 - with: - surefire-files: "**/target/surefire-reports/TEST-*.xml" - report-dir: target-ALL/site - report-title: "Test Report: ALL - Branch: ${{ github.ref_name }} - Run #${{ github.run_number }}" - - name: Index file to html reports - run: | - echo "Latest Test Reports" > target-ALL/site/index.html - echo "

Latest Test Reports - Branch: ${{ github.ref_name }} - Run #${{ github.run_number }}

" >> target-ALL/site/index.html - echo "

Single page reports

" >> target-ALL/site/index.html - echo "

Multiple page reports with frames

" >> target-ALL/site/index.html - echo "" >> target-ALL/site/index.html - - if: always() - name: Publish test report files - uses: actions/upload-artifact@v4 - with: - name: "test-report-ALL" - path: | - target-ALL/site - **/target/surefire-reports - **/target/*.html - **/target/*.log - **/reports/*.html - **/reports/*.log - uses: javiertuya/sonarqube-action@v1.4.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} sonar-token: ${{ secrets.SONAR_TOKEN }} - restore-artifact-name1: "test-report-files-orchestration" + restore-artifact-name1: "test-report-files" publish-java-snapshot: #if: ${{ false }} # disable for now diff --git a/pom.xml b/pom.xml index e6fc38e..b350188 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,8 @@ 0.8.12 + 5.14.2 + @@ -70,6 +72,12 @@ jackson-databind ${jacksonjson.version}
+ + org.mockito + mockito-core + ${mockito.version} + test +
diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml index 25efeb8..54cda0b 100644 --- a/retorch-orchestration/pom.xml +++ b/retorch-orchestration/pom.xml @@ -15,18 +15,15 @@ Software Engineering Research Group (GIIS) - Universidad de Oviedo, ES https://giis.uniovi.es/ - - - 1.1.1-SNAPSHOT - - 5.14.2 + + io.github.giis-uniovi retorch-annotations - ${retorchannotations.version} + ${project.version} org.slf4j @@ -40,15 +37,13 @@ junit junit - + com.fasterxml.jackson.core jackson-databind - + org.mockito mockito-core - ${mockito.version} - test From f7fffdbadc71c782cc54e70f034359a4022de6bd Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 17:03:23 +0100 Subject: [PATCH 10/28] Some mistake in the pipeline code --- .github/workflows/test.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b180d14..e04a195 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,14 +22,20 @@ jobs: java-version: '16' cache: 'maven' - - name: Test RETORCH and aggregate surefire report + - name: Test and aggregate surefire report run: mvn test surefire-report:report -Daggregate=true -Dmaven.test.failure.ignore=true -U --no-transfer-progress + - name: Additional aggregated junit report + uses: javiertuya/junit-report-action@v1 + with: + surefire-files: "**/target/surefire-reports/TEST-*.xml" + report-dir: target/site + - name: Generate report checks if: always() uses: mikepenz/action-junit-report@v5 with: - check_name: "test-result-orchestration" + check_name: "test-result" report_paths: "**/surefire-reports/TEST-*.xml" fail_on_failure: 'true' @@ -37,7 +43,7 @@ jobs: name: Publish test report files uses: actions/upload-artifact@v4 with: - name: "test-report-files-orchestration" + name: "test-report-files" path: | target/site **/target/site/jacoco/jacoco.xml From 9a08652c5d4daa4e8bbd520ee9c85ea3c2db8f34 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 17:06:43 +0100 Subject: [PATCH 11/28] Some mistake in the pipeline code --- .github/workflows/test.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e04a195..db6a5ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,7 +3,7 @@ on: push: branches-ignore: - 'dependabot/**' #avoid duplicates: only run the PR, not the commit - - 'gh-pages' #GitHub pages do not trigger all tests + - 'gh-pages' #github pages do not trigger all tests tags-ignore: - 'v*' #avoid rerun existing commit on release pull_request: @@ -11,9 +11,10 @@ on: - 'main' jobs: test-retorch: - needs: runs-on: ubuntu-latest - # if: ${{ false }} # disable for now + #if: ${{ false }} # disable for now + #avoids duplicate execution of pr from local repo, but allows pr from forked repos and dependabot + if: (github.event_name != 'pull_request' && ! github.event.pull_request.head.repo.fork) || (github.event_name == 'pull_request' && (github.event.pull_request.head.repo.fork || startsWith(github.head_ref, 'dependabot/'))) steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 @@ -33,7 +34,7 @@ jobs: - name: Generate report checks if: always() - uses: mikepenz/action-junit-report@v5 + uses: mikepenz/action-junit-report@v4.3.1 with: check_name: "test-result" report_paths: "**/surefire-reports/TEST-*.xml" From 10929cd562fe6f78e264617839b0ae91b4490baf Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 17:30:19 +0100 Subject: [PATCH 12/28] Changes to be commited: - Undo the accidental package renaming - Moving utils to src.test.orchestration - Change version of java in the last site to 16 (sonar) --- .../{testdata => classifier}/EmptyInputException.java | 2 +- .../{testdata => classifier}/ResourceSerializer.java | 2 +- .../{testdata => classifier}/RetorchClassifier.java | 2 +- .../java/giis/retorch/orchestration/ClassifierTests.java | 5 ++--- .../retorch/orchestration/{utils => }/ClassifierUtils.java | 2 +- .../giis/retorch/orchestration/{utils => }/GenericUtils.java | 2 +- sonar-project.properties | 2 +- 7 files changed, 8 insertions(+), 9 deletions(-) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{testdata => classifier}/EmptyInputException.java (92%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{testdata => classifier}/ResourceSerializer.java (99%) rename retorch-orchestration/src/main/java/giis/retorch/orchestration/{testdata => classifier}/RetorchClassifier.java (99%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{utils => }/ClassifierUtils.java (99%) rename retorch-orchestration/src/test/java/giis/retorch/orchestration/{utils => }/GenericUtils.java (99%) diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java similarity index 92% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java index 911df5e..67778bf 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/EmptyInputException.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.testdata; +package giis.retorch.orchestration.classifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java similarity index 99% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java index cdd67c6..17ad322 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/ResourceSerializer.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.testdata; +package giis.retorch.orchestration.classifier; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java similarity index 99% rename from retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java rename to retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java index 72bb10d..7c776be 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/testdata/RetorchClassifier.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.testdata; +package giis.retorch.orchestration.classifier; import giis.retorch.annotations.AccessModes; import giis.retorch.orchestration.model.*; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java index 5bcca76..7205ebd 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java @@ -4,10 +4,9 @@ import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.Appender; import giis.retorch.orchestration.model.System; -import giis.retorch.orchestration.testdata.EmptyInputException; -import giis.retorch.orchestration.testdata.RetorchClassifier; +import giis.retorch.orchestration.classifier.EmptyInputException; +import giis.retorch.orchestration.classifier.RetorchClassifier; import giis.retorch.orchestration.testdata.SyntheticInvalidClassTests; -import giis.retorch.orchestration.utils.ClassifierUtils; import giis.retorch.orchestration.testdata.synteticpackage.insidepackage.SyntheticClassOneTests; import org.junit.Before; import org.junit.Test; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java similarity index 99% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java index 3f34597..261bcc2 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/ClassifierUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.utils; +package giis.retorch.orchestration; import giis.retorch.orchestration.model.*; import giis.retorch.orchestration.model.System; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java similarity index 99% rename from retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java rename to retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java index 8bf8590..bb597ce 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/utils/GenericUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java @@ -1,4 +1,4 @@ -package giis.retorch.orchestration.utils; +package giis.retorch.orchestration; import giis.retorch.orchestration.model.*; diff --git a/sonar-project.properties b/sonar-project.properties index 7f3a717..d838fa9 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectKey=my:retorch sonar.projectName=retorch sonar.organization=giis sonar.projectVersion=1.0 -sonar.java.source=1.8 +sonar.java.source=16 sonar.modules=retorch-annotations,retorch-orchestration sonar.sources=src/main/java sonar.sourceEncoding=UTF-8 From d2789f152970e36cc24e75c1cea07364d36352b3 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 17:34:00 +0100 Subject: [PATCH 13/28] Last change: - mikepenz/action-junit-report undo to the previous version (v5) that was accidentally changed --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db6a5ee..36ab62e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: - name: Generate report checks if: always() - uses: mikepenz/action-junit-report@v4.3.1 + uses: mikepenz/action-junit-report@v5 with: check_name: "test-result" report_paths: "**/surefire-reports/TEST-*.xml" From 0363ad90e3e2a233bdec9bd4f7e8afa10350948e Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 18:33:14 +0100 Subject: [PATCH 14/28] Last change: - Java downgrade to Java 8 version --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 4 ++-- pom.xml | 4 ++-- retorch-orchestration/pom.xml | 4 ++-- .../orchestration/classifier/EmptyInputException.java | 3 --- .../orchestration/classifier/ResourceSerializer.java | 2 +- .../orchestration/classifier/RetorchClassifier.java | 6 +++--- .../main/java/giis/retorch/orchestration/model/TJob.java | 7 ++++--- .../java/giis/retorch/orchestration/ClassifierTests.java | 3 ++- .../java/giis/retorch/orchestration/ClassifierUtils.java | 3 ++- sonar-project.properties | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2570c32..2d511cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: uses: actions/setup-java@v4 with: # running setup-java again overwrites the settings.xml distribution: 'temurin' - java-version: '16' + java-version: '8' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36ab62e..f8899d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '16' + java-version: '8' cache: 'maven' - name: Test and aggregate surefire report @@ -76,7 +76,7 @@ jobs: - uses: javiertuya/branch-snapshots-action@v1.2.3 with: token: ${{ secrets.GITHUB_TOKEN }} - java-version: '16' + java-version: '8' mvn-deploy-args: '-P publish-github -DskipTests=true -Dmaven.test.failure.ignore=false -U --no-transfer-progress' delete-old-snapshots: true min-snapshots-to-keep: 2 diff --git a/pom.xml b/pom.xml index b350188..5c1bf14 100644 --- a/pom.xml +++ b/pom.xml @@ -15,8 +15,8 @@ - 16 - 16 + 8 + 8 UTF-8 4.13.2 diff --git a/retorch-orchestration/pom.xml b/retorch-orchestration/pom.xml index 54cda0b..b42c37a 100644 --- a/retorch-orchestration/pom.xml +++ b/retorch-orchestration/pom.xml @@ -72,8 +72,8 @@ org.apache.maven.plugins maven-compiler-plugin - 16 - 16 + 8 + 8
diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java index 67778bf..0088f0c 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java @@ -3,15 +3,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.Serial; - /** * This exception is thrown when the classifier receives an input that is empty or its invalid i.e: null, no exist * directories... */ public class EmptyInputException extends Exception { - @Serial private static final long serialVersionUID = -6473170362328956807L; private static final Logger logEmptyInputException = LoggerFactory.getLogger(EmptyInputException.class); diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java index 17ad322..3449260 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java @@ -130,7 +130,7 @@ public T deserialize(String filePath, TypeReference typeRef) throws IOExc * read */ public Map deserializeResources(String name) throws IOException { - return deserialize(FOLDER_RESOURCES + name + "SystemResources.json", new TypeReference<>() { + return deserialize(FOLDER_RESOURCES + name + "SystemResources.json", new TypeReference>() { }); } } \ No newline at end of file diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java index 7c776be..0e20bbe 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; +import java.util.stream.Collectors; public class RetorchClassifier { @@ -243,7 +244,7 @@ public List getClassMethods(Class testClass) { List methods = Arrays.stream(testClass.getDeclaredMethods()) .sorted(Comparator.comparing(Method::toString)) // Sort methods .filter(meth -> !meth.getName().equals("$jacocoInit")) // Filter out methods with name "$jacocoInit" - .toList(); // Collect results to a list + .collect(Collectors.toList());// Collect results to a list methods.forEach(meth -> log.info("The method name its : {}", meth.getName())); return methods; } @@ -367,8 +368,7 @@ private void checkAccessModeType(giis.retorch.annotations.AccessMode accessModeT private System checkSystemClass(System systemToCheck) { System systemOutput = new System(systemToCheck.getName()); List idResourcesList = listAllResources.values().stream() - .map(Resource::getResourceID) - .toList(); + .map(Resource::getResourceID).collect(Collectors.toList()); systemToCheck.getResources().stream() .filter(res -> idResourcesList.containsAll(res.getReplaceable())) .forEach(systemOutput::addResourceClass); diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java index 2477dff..4c8306c 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java @@ -4,6 +4,7 @@ import org.slf4j.LoggerFactory; import java.util.*; +import java.util.stream.Collectors; /** * The {@code TJobClass} class represents a TJob with a name, stage, and a set of {@code ResourceClass}. @@ -108,9 +109,9 @@ public boolean equals(Object obj) { @Override public String toString() { - List testCasesNames = listTestCases.stream().map(TestCase::getName).toList(); + List testCasesNames = listTestCases.stream().map(TestCase::getName).collect(Collectors.toList()); List resourceNames = - listResourceEntities.stream().map(Resource::getResourceID).toList(); + listResourceEntities.stream().map(Resource::getResourceID).collect(Collectors.toList()); return "TJobClass [\n" + "listTc:{\n" + testCasesNames + "}, listRes " + resourceNames + ", intraSchedule '" + intraTJobSchedule + '\'' + ", con " + tJobConcurrency + ']'; } @@ -125,7 +126,7 @@ public static List getListTJobLifecyclesWithDesiredOrder() { } public Set getTotalCapacities() {return totalCapacities;} - public List getCapacityNames() {return this.getTotalCapacities().stream().map(Capacity::getName).toList();} + public List getCapacityNames() {return this.getTotalCapacities().stream().map(Capacity::getName).collect(Collectors.toList());} public double getElasticityCostResources() {return elasticityCostResources;} public double getEndExec() {return endExec;} public double getEndSetUp() {return endSetUp;} diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java index 7205ebd..f3bcb8e 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.List; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -73,7 +74,7 @@ public void testUnitArchIResInvalidClass() throws EmptyInputException, IOExcepti ArgumentCaptor.forClass(ch.qos.logback.classic.spi.LoggingEvent.class); verify(appender, atLeast(25)).doAppend(argument.capture()); List listEvents = argument.getAllValues(); - List listMessages = listEvents.stream().map(LoggingEvent::getMessage).toList(); + List listMessages = listEvents.stream().map(LoggingEvent::getMessage).collect(Collectors.toList()); // Omission of attributes in the accessMode assertTrue(listMessages.contains("The AccessModeType in method testThreeAttributesLoosingAccessMode is not specified")); // Check that the omitted AccessMode is detected assertTrue(listMessages.contains("The Concurrency Attribute in method testTwoAttributesLoosingAccessMode is not present")); // Check that the concurrency omitted is detected diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java index 261bcc2..b31af2a 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java @@ -8,6 +8,7 @@ import java.util.Comparator; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; public class ClassifierUtils extends GenericUtils { @@ -34,7 +35,7 @@ public System generateSystemPackage() { expectedSystem.addResourceClass(this.getJSONSavedInelasticResource()); expectedSystem.addResourceClass(this.getJSONSavedElasticResource()); expectedSystem.getResources().sort(Comparator.comparing(Resource::toString)); - expectedSystem.addListTestCases(getAllTestCases().stream().sorted(Comparator.comparing(TestCase::getName)).toList()); + expectedSystem.addListTestCases(getAllTestCases().stream().sorted(Comparator.comparing(TestCase::getName)).collect(Collectors.toList())); return expectedSystem; } diff --git a/sonar-project.properties b/sonar-project.properties index d838fa9..7f3a717 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectKey=my:retorch sonar.projectName=retorch sonar.organization=giis sonar.projectVersion=1.0 -sonar.java.source=16 +sonar.java.source=1.8 sonar.modules=retorch-annotations,retorch-orchestration sonar.sources=src/main/java sonar.sourceEncoding=UTF-8 From 3b6352174553e71983cb74e04a23009d2ec68f5a Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 18:40:06 +0100 Subject: [PATCH 15/28] Last change: - Downgrade logback-classic to suport Java 8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5c1bf14..26603af 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 2.0.16 - 1.5.12 + 1.3.14 2.18.1 From 50e0a75a588c4eca7b61a1ce49ad432e977af27f Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 18:44:02 +0100 Subject: [PATCH 16/28] Last change: - Downgrade Mockito to support Java 8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 26603af..f908735 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 0.8.12 - 5.14.2 + 5.11.0 From 83221cd8b9ac50518a985305c40bad53c6b8019c Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 15 Nov 2024 18:46:18 +0100 Subject: [PATCH 17/28] Last change: - Downgrade Mockito to 4.11.0 support Java 8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f908735..2e72120 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 0.8.12 - 5.11.0 + 4.11.0 From 4d8aa72d8dcc8c34f214d4f4f28d92a15f7c53b6 Mon Sep 17 00:00:00 2001 From: Augusto Date: Tue, 3 Dec 2024 23:09:25 +0100 Subject: [PATCH 18/28] Changes required by Javier: - Goal of all test classes specified clearly and as short as possible - Some typos detected in the comments (resource with lowercase) solved - Included in the README.md a short description of the new module. --- README.md | 6 +++++- .../orchestration/classifier/EmptyInputException.java | 4 ++-- .../orchestration/classifier/ResourceSerializer.java | 6 ++++++ .../retorch/orchestration/classifier/RetorchClassifier.java | 5 +++++ .../java/giis/retorch/orchestration/model/AccessMode.java | 5 +++++ .../giis/retorch/orchestration/model/AccessModeTypes.java | 4 ++-- .../giis/retorch/orchestration/model/ElasticityModel.java | 4 ++++ .../java/giis/retorch/orchestration/model/Resource.java | 5 +++++ .../giis/retorch/orchestration/model/ResourceInstance.java | 2 +- .../main/java/giis/retorch/orchestration/model/System.java | 3 +++ .../main/java/giis/retorch/orchestration/model/TJob.java | 4 ++-- .../java/giis/retorch/orchestration/model/TestCase.java | 4 ++++ .../java/giis/retorch/orchestration/ClassifierTests.java | 3 +++ .../java/giis/retorch/orchestration/ClassifierUtils.java | 5 +++++ .../test/java/giis/retorch/orchestration/GenericUtils.java | 5 ++++- .../java/giis/retorch/orchestration/TJobsEntityTests.java | 3 +++ 16 files changed, 59 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 221c2ad..5d5a6e4 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Additional components will be added in future releases. - [RETORCH: Resource-aware End-to-End Test Orchestration:]() - [Quick Start](#quick-start) - [RETORCH Annotations](#retorch-annotations) + - [RETORCH Orchestration](#retorch-orchestration) - [Contributing](#contributing) - [Contact](#contact) - [Citing this work](#citing-this-work) @@ -71,6 +72,10 @@ void forumLoadEntriesTest(String usermail,String password,String role){ this.slowLogin(user,usermail,password); } ``` +## RETORCH Orchestration +The RETORCH framework provides a tool that generates an Execution Plan, along with the required pipelining and script +files for execution in a CI environment. The generation of scripts and pipelining code is based on the Access Modes +annotated within the test cases and the Resource information specified in `/retorchfiles/[SUT_NAME]SystemResources.json`. ## Contributing @@ -91,7 +96,6 @@ RETORCH E2E Test Orchestration framework: *Software Quality Journal*, vol. 28, no. 3, 2020. https://doi.org/10.1007/s11219-020-09505-2 - [Full Article available](https://link.springer.com/article/10.1007/s11219-020-09505-2) - [Authors version](https://digibuo.uniovi.es/dspace/bitstream/handle/10651/55405/RETORCHSQJExtension_BUO.pdf;jsessionid=0E661594C8732B8D2CA53636A31E4FD5?sequence=1) - [Download citation](https://citation-needed.springer.com/v2/references/10.1007/s11219-020-09505-2?format=refman&flavour=citation) - ## Acknowledgments This work has been developed under the TestBUS (PID2019-105455GB-C32) project supported diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java index 0088f0c..1bd7354 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/EmptyInputException.java @@ -4,8 +4,8 @@ import org.slf4j.LoggerFactory; /** - * This exception is thrown when the classifier receives an input that is empty or its invalid i.e: null, no exist - * directories... + * The {@code EmptyInputException} is thrown when the {@code RetorchClassifier} receives an input that is empty + * or its invalid i.e: null, no exist directories... */ public class EmptyInputException extends Exception { diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java index 3449260..4ef7657 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/ResourceSerializer.java @@ -13,6 +13,12 @@ import java.nio.file.Paths; import java.util.*; +/** + * The {@code ResourceSerializer} class provides utilities for managing Resource configurations + * in the RETORCH orchestration Tool. Supports the serialization of Resources into JSON files and + * its deserialization back into Java objects, enabling the retrieval of Resources attributes from Resources + * JSON configuration files. + */ public class ResourceSerializer { private final Logger logSerializer = LoggerFactory.getLogger(ResourceSerializer.class); diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java index 0e20bbe..d6955e2 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/classifier/RetorchClassifier.java @@ -17,6 +17,11 @@ import java.util.*; import java.util.stream.Collectors; +/** + * The {@code RetorchClassifier} class provides utilities for performing the Resource Identification phase. Provides + * methods to retrieve the test cases from a package, reads the {@code AccessMode}, deserializes the Resource file, and + * starts creating the different {@code Resources} and {@code TestCases} that compose the {@code System} + */ public class RetorchClassifier { private static final Logger log = LoggerFactory.getLogger(RetorchClassifier.class); diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java index ab8dc24..9f80c75 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessMode.java @@ -1,5 +1,10 @@ package giis.retorch.orchestration.model; +/** + * The {@code AccessMode} class represents the Access Mode performed by a {@code TestCase} on a {@code Resource}. + * It defines the type of access, the max number of concurrent test cases that can access the {@code Resource}, + * and whether the {@code Resource} can be shared. + */ public class AccessMode { private AccessModeTypes type; diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java index f9577ce..7cfc45d 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/AccessModeTypes.java @@ -1,8 +1,8 @@ package giis.retorch.orchestration.model; /** - * This class is used as AccessMode parser for given a string representation of a RETORCH access mode (i.e: - * READONLY,READWRITE...) convert it into the proper enumeration. Also provides + * The {@code AccessModeTypes} class is used as AccessMode parser for given a string representation of a RETORCH access mode (i.e: + * READONLY,READWRITE...) convert it into the proper enumeration. */ public class AccessModeTypes { diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java index b05754a..3d22db2 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ElasticityModel.java @@ -2,6 +2,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; +/** + * The {@code ElasticityModel} class represents the Elasticity Model of one {@code Resource}. It defines the Elasticity + * Model attributes: the id, the upper bound of {@code Resource} that we can instantiate and its individual cost. + */ public class ElasticityModel { private String elasticityID; diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java index 45434cb..89a319c 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/Resource.java @@ -10,6 +10,11 @@ import java.util.LinkedList; import java.util.List; +/** + * The {@code Resource} class represents a Resource required by one or more {@code TestCases}. Provides the different + * Resource attributes: identifier, hierarchy Parent, {@code Resource} that can replace it, the minimal {@code Capacity} + * required,the {@code ElasticityModel}, the type and its docker image. + */ public class Resource { public enum type {PHYSICAL, LOGICAL, COMPUTATIONAL} diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java index 83586d9..9f4b376 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/ResourceInstance.java @@ -3,7 +3,7 @@ import java.util.List; /** - * The {@code ResourceInstance} class represents a resource with a name and a list of {@code Capacity} that requires + * The {@code ResourceInstance} class represents a Resource with a name and a list of {@code Capacity} that requires * for its instantiation.This class is used during the profile generation to calculate the overall {@code Capacity} that * are used-required. * It provides methods to get and set the name and capacities, and overrides the {@code equals}, {@code hashCode}, diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java index 4fd462c..ea1f020 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/System.java @@ -8,6 +8,9 @@ import java.util.LinkedList; import java.util.List; +/** + * The {@code System} class represents the whole RETORCH System composed by the Lists of {@code Resources} and {@code TestCase} + */ public class System { private static final Logger logSystemClass = LoggerFactory.getLogger(System.class); diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java index 4c8306c..926712b 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TJob.java @@ -7,9 +7,9 @@ import java.util.stream.Collectors; /** - * The {@code TJobClass} class represents a TJob with a name, stage, and a set of {@code ResourceClass}. + * The {@code TJob} class represents a TJob with a name, stage, and a set of {@code Resource}. * When the TJob is created, it calculates the total amount of {@code Capacity} that is used by the list of - * {@code ResourceClass} required + * {@code Resource} required */ public class TJob { diff --git a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java index 190a8ab..5cc8d62 100644 --- a/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java +++ b/retorch-orchestration/src/main/java/giis/retorch/orchestration/model/TestCase.java @@ -3,6 +3,10 @@ import java.util.LinkedList; import java.util.List; +/** + * The {@code TestCase} class represents a test case that compose the End-to-End test suite. It has a name, its class + * and the list of {@code AccessMode} performed over the different {@code Resource} + */ public class TestCase { private final String name; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java index f3bcb8e..afaa9ba 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierTests.java @@ -23,6 +23,9 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; +/** + * {@code ClassifierTests} class provides the unitary tests of the different {@code RetorchClassifier} methods + * */ public class ClassifierTests { private static final String SYSTEM_NAME = "ClassifierUnitTests"; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java index b31af2a..3a26d59 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/ClassifierUtils.java @@ -10,6 +10,11 @@ import java.util.List; import java.util.stream.Collectors; +/** + * {@code ClassifierUtils} class extends {@code GenericUtils} providing a series of utils that generates + * a {@code System} with its Lists of {@code TestCase} and {@code Resource} for being used + * in the {@code ClassifierTests} class + */ public class ClassifierUtils extends GenericUtils { public List getAllTestCases() { diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java index bb597ce..5c6177e 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/GenericUtils.java @@ -4,7 +4,10 @@ import java.util.LinkedList; import java.util.List; - +/** + * {@code GenericUtils} class provides a series of methods that creates different types of Resources for + * being used during the integration and unitary testing. + */ public class GenericUtils { protected static final String READONLY = "READONLY"; diff --git a/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java b/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java index 80a0179..6184634 100644 --- a/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java +++ b/retorch-orchestration/src/test/java/giis/retorch/orchestration/TJobsEntityTests.java @@ -17,6 +17,9 @@ import static org.junit.Assert.*; +/** + * {@code TJobsEntityTests} class provides the unitary tests of the different {@code TJob} methods + */ public class TJobsEntityTests { private final Logger log = LoggerFactory.getLogger(this.getClass()); From 9ce55edd36ee7f8f3f8c9a0adcac7b74d62b6bc7 Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:18:01 +0100 Subject: [PATCH 19/28] First version of the README with inputs-ouputs detailed --- README.md | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/README.md b/README.md index 5d5a6e4..3ab813e 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,193 @@ The RETORCH framework provides a tool that generates an Execution Plan, along wi files for execution in a CI environment. The generation of scripts and pipelining code is based on the Access Modes annotated within the test cases and the Resource information specified in `/retorchfiles/[SUT_NAME]SystemResources.json`. +The RETORCH orchestration tool requires 4 inputs: +- The annotated E2E test cases with the [RETORCH access modes](#retorch-annotations). +- A file with the Resources in JSON format. +- A properties file with the Environment configuration. +- A custom `docker-compose.yml` file. + +Give this inputs, the tool generates as output the necessary scripting code and the `Jenkinsfile` to execute the E2E test +suite into a Continuous Integration system. + +### Prepare the E2E Test suite +To execute the RETORCH Orchestration tool and generate the script and pipelining code, requires to perform series of configurations +into the test suite. The first step is create several folders to store the configurations and place the docker-compose.yml +in the root of the repository. +The resulting directory tree should look like as: +``` +. +├── src +├── docker-compose.yml +├── retorchfiles/ +│ ├── configurations/ +│ └── customscriptscode/ + +``` +- The `retorchfiles/` directory would contain all the configuration files and scripting snippets that would be used to generate the +pipelining code as well as the scripts to set-up, deploy and tear-down the different Resources and TJob. Contains two subdirectories: + - `configurations/`: contains the Resource and CI configuration files + - `customscriptscode/`: stores the different script snippets for the tear-down, set-up and environment. +- The `docker-compose.yml` in the root of the directory. +- The different project directories-files. + +The following subsections explain how to create each configuration file and how to prepare the docker-compose.yml file. + +#### Create the Resource.json file +The Resource file must be placed in the `retorchfiles/configurations/` and named with the system or test suite name, followed +by `SystemResources.json`. This file contains a Map with a series of Resources, using as key their unique ResourceID. For each +Resource the tester needs specify the following attributes: +- `resourceID`: A unique identifier for the Resource. +- `replaceable`: A list of Resources that can replace the current one. +- `hierarchyParent`: A resourceID of the hierarchical parent of the Resource. +- `elasticityModel`: The elasticity model of the Resource, is composed by the following attributes: + - `elasticityID`: A unique identifier for the elasticity model. + - `elasticity`: Integer with the available Resources + - `elasticityCost`: Instantiation cost of each Resource +- `resourceType`: String with the type of the Resource(e.g. LOGICAL, PHYSICAL or COMPUTATIONAL) +- `minimalCapacities`: List with the Minimal Capacities required by the Resource, each Capacity is composed by: + - `name`: String between "memory","processor" and "storage" + - `quantity`: float with the amount fo Capacity Required: +- `dockerImage`: String with the concatenation of the placeholder name in the docker-compose, "[IMG:]" and the image name + +The following snippet shows an example of two Resources declared in the JSON file: + +```json +{ + "userservice": { + "hierarchyParent": ["mysql"], + "replaceable": [], + "elasticityModel": {"elasticityID": "elasmodeluserservice", "elasticity": 5, "elasticityCost": 30.0}, + "resourceType": "LOGICAL", "resourceID": "userservice", + "minimalCapacities": [ + {"name": "memory", "quantity": 0.2929}, + {"name": "processor", "quantity": 0.2}, + {"name": "storage", "quantity": 0.5}], + "dockerImage": "userservice[IMG:]wigo4it/identityserver4:latest" +}, + "frontend": { + "hierarchyParent": [], "replaceable": [], + "elasticityModel": {"elasticityID": "elasmodelfrontend", "elasticity": 1, "elasticityCost": 300.0}, + "resourceType": "LOGICAL", "resourceID": "frontend", + "minimalCapacities": [ + {"name": "memory", "quantity": 2}, + {"name": "processor", "quantity": 1}, + {"name": "storage", "quantity": 0.88}], + "dockerImage": "frontend[IMG:]nginx:latest" + } + +} +``` + +#### Create the retorchCI.properties file +The CI file must be placed in `retorchfiles/configurations/`, namely `retorchCI.properties` contain several parameters +related to the SUT and the Continuous Integration Infrastructure, has the following parameters: +- `agentCIName`: Specific Jenkins agent used to execute the test suite. +- `sut-wait-html`: State in the frontend (html displayed) when the SUT is ready for execute the test SUITE. +- `sut-location`: Location of the docker-compose file used to deploy the SUT. +- `docker-frontend-name`: ID of the container used as frontend . +- `docker-frontend-port`: PORT on which the frontend is available. +- `external-binded-port`: EXTERNAL PORT where the frontend is made available (if its available). +- `external-frontend-url`: EXTERNAL URI where the frontend is made available. +- `testsBasePath`: Path to the java project. + +The following snippet provides an example of how this file looks like: + +```properties + agentCIName=any + sut-wait-html=Hello World + sut-location=$WORKSPACE + docker-frontend-name=https://sutexample- + docker-frontend-port=5000 + external-binded-port= + external-frontend-url= + testsBasePath=./ +``` + +#### Preparing the docker-compose.yml file +The RETORCH tool also requires to parametrize the docker-compose used to deploy the application, by means include the +necessary environment variables in the containers names and URIs, as well as the placeholders of the images above specified. +The next code present how was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): + +```diff +services: + full-teaching-mysql: +- container_name: full-teaching-mysql ++ container_name: full-teaching-mysql-${tjobname} + ... ++ networks: ++ - jenkins_network + + full-teaching-openvidu-server-kms: +- container_name: full-teaching-openvidu-server-kms +- image: openvidu/openvidu-server-kms:1.7.0 ++ container_name: full-teaching-${tjobname}-openvidu-server-kms ++ image: ${mediaserver} + ... + environment: +- - openvidu.publicurl=https://full-teaching-openvidu-server-kms:8443 ++ - openvidu.publicurl=https://full-teaching-${tjobname}-openvidu-server-kms:8443 ++ networks: ++ - jenkins_network + + full-teaching: +- container_name: full-teaching ++ container_name: full-teaching-${tjobname} + ... + environment: +- - WAIT_HOSTS=full-teaching-mysql:3306 ++ - WAIT_HOSTS=full-teaching-mysql-${tjobname}:3306 +- - MYSQL_PORT_3306_TCP_ADDR=full-teaching-mysql ++ - MYSQL_PORT_3306_TCP_ADDR=full-teaching-mysql-${tjobname} +- - openvidu.url=https://full-teaching-openvidu-server-kms:8443 ++ - openvidu.url=https://full-teaching-${tjobname}-openvidu-server-kms:8443 + - ... ++ networks: ++ - jenkins_network + ++ networks: ++ jenkins_network: ++ external: true +``` + +#### (Optional) Specify script snippets to include in the set-up tear-down and environment +The RETORCH orchestration tool allows to specify scripting code/commands to be included in the generated set-up, tear-down and +the environment declaration of each TJob. To include it, the tester must create the following files in `retorch\customscriptscode` +- `custom-tjob-setup`: Contains the custom set-up code (e.g. deploy the SUT) or custom logging systems. +- `custom-tjob-teardown`: Contains the custom tear-down code (e.g. tear-down the SUT) +- `custom.env`: Contains environment variables common to all TJobs + +Examples of the three snippets files can be consulted in [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching) +and [eShopOnContainers](https://github.com/giis-uniovi/retorch-st-eShopContainers) + +Once created the different properties and configuration files, the tree directory might look like: + +``` +. +├── src +├── docker-compose.yml +├── retorchfiles/ +│ ├── configurations/ +│ │ ├── [SUTNAME]SystemResource.json +│ │ └── retorchCI.properties +│ └── customscriptscode/ + ├── custom-tjob-setup + ├── custom-tjob-teardown + └── custom.env +``` + +### Executing the Orchestration tool +[TO-DO] Pending to decide-implement the final version + +### RETORCH Orchestration Tool outputs +The tool provides four different outputs, the pipelining code, the necessary scripts to set-up, tear-down and execute the TJobs(`/retorchfiles/tjoblifecycles`), +the infrastructure(`/retorchfiles/tjoblifecycles`) and the different environment files of each TJob (`/retorchfiles/envfiles`) : +- `Jenkinsfile`: located in the root of the project, contains the pipelining code with the different stages in sequential-parallel +that perform the set-up, execute and tear-down the TJobs. +- `/retorchfiles/tjoblifecycles` and `/retorchfiles/coilifecycles` contains the set-up, execution and tear-down scripts for the TJobs and infrastructure +- `/retorchfiles/envfiles`: contains the generated custom environment of each TJob. + + ## Contributing See the general contribution policies and guidelines for *giis-uniovi* at From 072c2abf87faa5f3bec9531696d10f61719583c8 Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:30:40 +0100 Subject: [PATCH 20/28] Fixing english typos --- README.md | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 3ab813e..06fa132 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,13 @@ The RETORCH orchestration tool requires 4 inputs: - A properties file with the Environment configuration. - A custom `docker-compose.yml` file. -Give this inputs, the tool generates as output the necessary scripting code and the `Jenkinsfile` to execute the E2E test +Given these inputs, the tool generates as output the necessary scripting code and the `Jenkinsfile` to execute the E2E test suite into a Continuous Integration system. ### Prepare the E2E Test suite -To execute the RETORCH Orchestration tool and generate the script and pipelining code, requires to perform series of configurations -into the test suite. The first step is create several folders to store the configurations and place the docker-compose.yml -in the root of the repository. +Execute the RETORCH Orchestration tool and generate the script and pipelining code requires to perform a series of configurations +into the test suite. The first step is to create several folders to store the configurations and place the `docker-compose.yml` +in the project repository. The resulting directory tree should look like as: ``` . @@ -101,30 +101,30 @@ The resulting directory tree should look like as: ``` - The `retorchfiles/` directory would contain all the configuration files and scripting snippets that would be used to generate the -pipelining code as well as the scripts to set-up, deploy and tear-down the different Resources and TJob. Contains two subdirectories: - - `configurations/`: contains the Resource and CI configuration files +pipelining code and the scripts to set up, deploy, and tear down the different Resources and TJob. Contains two subdirectories: + - `configurations/`: stores the Resource and CI configuration files. - `customscriptscode/`: stores the different script snippets for the tear-down, set-up and environment. - The `docker-compose.yml` in the root of the directory. -- The different project directories-files. +- The different project directories and files. The following subsections explain how to create each configuration file and how to prepare the docker-compose.yml file. #### Create the Resource.json file The Resource file must be placed in the `retorchfiles/configurations/` and named with the system or test suite name, followed -by `SystemResources.json`. This file contains a Map with a series of Resources, using as key their unique ResourceID. For each -Resource the tester needs specify the following attributes: +by `SystemResources.json`. This file contains a map with a series of resources, using their unique ResourceID as a key. For each +Resource the tester needs to specify the following attributes: - `resourceID`: A unique identifier for the Resource. - `replaceable`: A list of Resources that can replace the current one. - `hierarchyParent`: A resourceID of the hierarchical parent of the Resource. - `elasticityModel`: The elasticity model of the Resource, is composed by the following attributes: - `elasticityID`: A unique identifier for the elasticity model. - - `elasticity`: Integer with the available Resources - - `elasticityCost`: Instantiation cost of each Resource -- `resourceType`: String with the type of the Resource(e.g. LOGICAL, PHYSICAL or COMPUTATIONAL) -- `minimalCapacities`: List with the Minimal Capacities required by the Resource, each Capacity is composed by: - - `name`: String between "memory","processor" and "storage" - - `quantity`: float with the amount fo Capacity Required: -- `dockerImage`: String with the concatenation of the placeholder name in the docker-compose, "[IMG:]" and the image name + - `elasticity`: Integer with the available Resources. + - `elasticityCost`: Instantiation cost of each Resource. +- `resourceType`: String with the type of the Resource(e.g. LOGICAL, PHYSICAL or COMPUTATIONAL). +- `minimalCapacities`: List with the Minimal Capacities required by the Resource; each Capacity is composed by: + - `name`: String between "memory", "processor" and "storage". + - `quantity`: float with the amount of Capacity Required. +- `dockerImage`: String with the concatenation of the placeholder name in the docker-compose, "[IMG:]" and the image name. The following snippet shows an example of two Resources declared in the JSON file: @@ -156,10 +156,10 @@ The following snippet shows an example of two Resources declared in the JSON fil ``` #### Create the retorchCI.properties file -The CI file must be placed in `retorchfiles/configurations/`, namely `retorchCI.properties` contain several parameters -related to the SUT and the Continuous Integration Infrastructure, has the following parameters: -- `agentCIName`: Specific Jenkins agent used to execute the test suite. -- `sut-wait-html`: State in the frontend (html displayed) when the SUT is ready for execute the test SUITE. +The CI file must be placed in `retorchfiles/configurations/`, namely `retorchCI.properties` containing several parameters +related to the SUT and the Continuous Integration Infrastructure has the following parameters: +- `agentCIName`: the specific Jenkins agent used to execute the test suite. +- `sut-wait-html`: State in the frontend (html displayed) when the SUT is ready to execute the test SUITE. - `sut-location`: Location of the docker-compose file used to deploy the SUT. - `docker-frontend-name`: ID of the container used as frontend . - `docker-frontend-port`: PORT on which the frontend is available. @@ -181,9 +181,9 @@ The following snippet provides an example of how this file looks like: ``` #### Preparing the docker-compose.yml file -The RETORCH tool also requires to parametrize the docker-compose used to deploy the application, by means include the -necessary environment variables in the containers names and URIs, as well as the placeholders of the images above specified. -The next code present how was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): +The RETORCH tool also requires to parametrize the docker-compose used to deploy the application by means including the +necessary environment variables in the containers names and URIs, as well as the placeholders of the images specified above. +The following snippet present how it was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): ```diff services: @@ -227,7 +227,7 @@ services: ``` #### (Optional) Specify script snippets to include in the set-up tear-down and environment -The RETORCH orchestration tool allows to specify scripting code/commands to be included in the generated set-up, tear-down and +The RETORCH orchestration tool allows to specify scripting code/commands to be included in the generated set-up, tear-down, and the environment declaration of each TJob. To include it, the tester must create the following files in `retorch\customscriptscode` - `custom-tjob-setup`: Contains the custom set-up code (e.g. deploy the SUT) or custom logging systems. - `custom-tjob-teardown`: Contains the custom tear-down code (e.g. tear-down the SUT) @@ -256,11 +256,11 @@ Once created the different properties and configuration files, the tree director [TO-DO] Pending to decide-implement the final version ### RETORCH Orchestration Tool outputs -The tool provides four different outputs, the pipelining code, the necessary scripts to set-up, tear-down and execute the TJobs(`/retorchfiles/tjoblifecycles`), +The tool provides four different outputs: the pipelining code, the necessary scripts to set up, tear down and execute the TJobs(`/retorchfiles/tjoblifecycles`), the infrastructure(`/retorchfiles/tjoblifecycles`) and the different environment files of each TJob (`/retorchfiles/envfiles`) : - `Jenkinsfile`: located in the root of the project, contains the pipelining code with the different stages in sequential-parallel -that perform the set-up, execute and tear-down the TJobs. -- `/retorchfiles/tjoblifecycles` and `/retorchfiles/coilifecycles` contains the set-up, execution and tear-down scripts for the TJobs and infrastructure +that perform the different TJob lifecycle stages. +- `/retorchfiles/tjoblifecycles` and `/retorchfiles/coilifecycles` contains the set up, execution, and tear down scripts for the TJobs and infrastructure - `/retorchfiles/envfiles`: contains the generated custom environment of each TJob. From 03950cded38f5ed61ed00a461f7d393d474b114b Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:34:40 +0100 Subject: [PATCH 21/28] Adding the Quick start steps and the new article to the citations --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 06fa132..13ade66 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Additional components will be added in future releases. - Add the dependency [`io.github.giis-uniovi:retorch-annotations`](https://central.sonatype.com/artifact/io.github.giis-uniovi/retorch-annotations) to the pom.xml of your SUT. - Add the annotations to the test classes as indicated below +- Configure the E2E test suite as indicated below +- Execute the orchestration tool and generate the pipelining-scripting code - [TO-DO] ## RETORCH Annotations @@ -283,6 +285,15 @@ RETORCH E2E Test Orchestration framework: *Software Quality Journal*, vol. 28, no. 3, 2020. https://doi.org/10.1007/s11219-020-09505-2 - [Full Article available](https://link.springer.com/article/10.1007/s11219-020-09505-2) - [Authors version](https://digibuo.uniovi.es/dspace/bitstream/handle/10651/55405/RETORCHSQJExtension_BUO.pdf;jsessionid=0E661594C8732B8D2CA53636A31E4FD5?sequence=1) - [Download citation](https://citation-needed.springer.com/v2/references/10.1007/s11219-020-09505-2?format=refman&flavour=citation) + +RETORCH*: A Cost and Resource aware Model for E2E Testing in the Cloud: + +- Cristian Augusto, Jesús Morán, Antonia Bertolino, Claudio de la Riva, and Javier Tuya, + “RETORCH*: A Cost and Resource aware Model for E2E Testing in the Cloud”, + *Journal of Systems and Software*, vol. 221 , pages. 112237, 2025. + https://doi.org/10.1016/j.jss.2024.112237 - [Full Paper available](https://www.sciencedirect.com/science/article/pii/S0164121224002814?via%3Dihub) - [Authors version](https://hdl.handle.net/10651/75794) - + [Download citation](https://www.sciencedirect.com/science/article/pii/S0164121224002814?via%3Dihub#:~:text=Export%20citation%20to%20text) + ## Acknowledgments This work has been developed under the TestBUS (PID2019-105455GB-C32) project supported From 1b66acec080db1fd0331af851f0387accf24c03b Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:40:33 +0100 Subject: [PATCH 22/28] Some minor typos --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 13ade66..ddbcfb0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ This repository contains a series of components of the RETORCH End-to-End (E2E) goal is to optimize E2E test execution by reducing both the execution time and the number of unnecessary resource redeployment's. -NOTE: In this initial version, only the annotations to identify the resources and access modes have been included. +NOTE: The repository is a work in progress, the initial version only made available the annotations, and currently we're +migrating the orchestration module. Additional components will be added in future releases. ## Contents @@ -33,8 +34,8 @@ Additional components will be added in future releases. ## RETORCH Annotations -The RETORCH framework provides a set of custom annotations to define and manage resources used in end-to-end testing. These -annotations allow testers to group, schedule, and characterize resources. To execute test cases using RETORCH, +The RETORCH framework provides a set of custom annotations to define and manage Resources used in end-to-end testing. These +annotations allow testers to group, schedule, and characterize Resources. To execute test cases using RETORCH, each test case must be annotated with at least one access mode and resource. The tester needs to specify the access mode using the following attributes: @@ -51,13 +52,13 @@ The tester needs to specify the access mode using the following attributes: Each access mode annotation corresponds to a specific resource, which must be annotated with the following attributes: - `resID`: A unique identifier for the resource. -- `replaceable`: A list of resources that can replace the current one. +- `replaceable`: A list of Resources that can replace the current one. ```java @Resource(resID = "LoginService", replaceable = {}) ``` -The following code snippets illustrate a test case annotated with multiple resources and access modes: +The following code snippets illustrate a test case annotated with multiple Resources and access modes: ```java @Resource(resID = "LoginService", replaceable = {}) @@ -92,7 +93,7 @@ suite into a Continuous Integration system. Execute the RETORCH Orchestration tool and generate the script and pipelining code requires to perform a series of configurations into the test suite. The first step is to create several folders to store the configurations and place the `docker-compose.yml` in the project repository. -The resulting directory tree should look like as: +The resulting tree directory might look like as: ``` . ├── src @@ -113,7 +114,7 @@ The following subsections explain how to create each configuration file and how #### Create the Resource.json file The Resource file must be placed in the `retorchfiles/configurations/` and named with the system or test suite name, followed -by `SystemResources.json`. This file contains a map with a series of resources, using their unique ResourceID as a key. For each +by `SystemResources.json`. This file contains a map with a series of Resources, using their unique ResourceID as a key. For each Resource the tester needs to specify the following attributes: - `resourceID`: A unique identifier for the Resource. - `replaceable`: A list of Resources that can replace the current one. From 6f08a7449ab28bd4cdd8cbcfadca3faeee4e3daf Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:44:19 +0100 Subject: [PATCH 23/28] Adding foot note --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ddbcfb0..33bbbf5 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,15 @@ # RETORCH: Resource-aware End-to-End Test Orchestration This repository contains a series of components of the RETORCH End-to-End (E2E) test orchestration framework. It's primary -goal is to optimize E2E test execution by reducing both the execution time and the number of unnecessary resource +goal is to optimize E2E test execution by reducing both the execution time and the number of unnecessary Resource[^1] redeployment's. NOTE: The repository is a work in progress, the initial version only made available the annotations, and currently we're migrating the orchestration module. Additional components will be added in future releases. +[^1]: Henceforth, we will use the term "Resources" (capitalized) when referring to the ones required by the E2E test suite. + ## Contents - [RETORCH: Resource-aware End-to-End Test Orchestration:]() From 35c17cba7cd885e71574567268e6c9b54c32ac54 Mon Sep 17 00:00:00 2001 From: Augusto Date: Wed, 4 Dec 2024 13:51:57 +0100 Subject: [PATCH 24/28] Ready for review --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 33bbbf5..e4b5a99 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ void forumLoadEntriesTest(String usermail,String password,String role){ ## RETORCH Orchestration The RETORCH framework provides a tool that generates an Execution Plan, along with the required pipelining and script files for execution in a CI environment. The generation of scripts and pipelining code is based on the Access Modes -annotated within the test cases and the Resource information specified in `/retorchfiles/[SUT_NAME]SystemResources.json`. +annotated within the test cases and the Resource information specified in `[SUT_NAME]SystemResources.json`. The RETORCH orchestration tool requires 4 inputs: - The annotated E2E test cases with the [RETORCH access modes](#retorch-annotations). @@ -94,8 +94,8 @@ suite into a Continuous Integration system. ### Prepare the E2E Test suite Execute the RETORCH Orchestration tool and generate the script and pipelining code requires to perform a series of configurations into the test suite. The first step is to create several folders to store the configurations and place the `docker-compose.yml` -in the project repository. -The resulting tree directory might look like as: +in the project root. +The resulting directory tree might look like as: ``` . ├── src @@ -162,15 +162,15 @@ The following snippet shows an example of two Resources declared in the JSON fil #### Create the retorchCI.properties file The CI file must be placed in `retorchfiles/configurations/`, namely `retorchCI.properties` containing several parameters -related to the SUT and the Continuous Integration Infrastructure has the following parameters: +related to the SUT and the Continuous Integration Infrastructure, these parameters are the following: - `agentCIName`: the specific Jenkins agent used to execute the test suite. -- `sut-wait-html`: State in the frontend (html displayed) when the SUT is ready to execute the test SUITE. -- `sut-location`: Location of the docker-compose file used to deploy the SUT. +- `sut-wait-html`: state in the frontend (html displayed) when the SUT is ready to execute the test SUITE. +- `sut-location`: location of the `docker-compose.yml` file used to deploy the SUT. - `docker-frontend-name`: ID of the container used as frontend . -- `docker-frontend-port`: PORT on which the frontend is available. +- `docker-frontend-port`: PORT on which the frontend container is available. - `external-binded-port`: EXTERNAL PORT where the frontend is made available (if its available). - `external-frontend-url`: EXTERNAL URI where the frontend is made available. -- `testsBasePath`: Path to the java project. +- `testsBasePath`: Path to the Java project root. The following snippet provides an example of how this file looks like: @@ -186,7 +186,7 @@ The following snippet provides an example of how this file looks like: ``` #### Preparing the docker-compose.yml file -The RETORCH tool also requires to parametrize the docker-compose used to deploy the application by means including the +The RETORCH tool also requires to parametrize the `docker-compose.yml` used to deploy the application by means including the necessary environment variables in the containers names and URIs, as well as the placeholders of the images specified above. The following snippet present how it was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): @@ -241,7 +241,7 @@ the environment declaration of each TJob. To include it, the tester must create Examples of the three snippets files can be consulted in [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching) and [eShopOnContainers](https://github.com/giis-uniovi/retorch-st-eShopContainers) -Once created the different properties and configuration files, the tree directory might look like: +Once created the different properties and configuration files, the directory tree might look like: ``` . @@ -262,7 +262,7 @@ Once created the different properties and configuration files, the tree director ### RETORCH Orchestration Tool outputs The tool provides four different outputs: the pipelining code, the necessary scripts to set up, tear down and execute the TJobs(`/retorchfiles/tjoblifecycles`), -the infrastructure(`/retorchfiles/tjoblifecycles`) and the different environment files of each TJob (`/retorchfiles/envfiles`) : +the infrastructure(`/retorchfiles/coilifecycles`) and the different environment files of each TJob (`/retorchfiles/envfiles`) : - `Jenkinsfile`: located in the root of the project, contains the pipelining code with the different stages in sequential-parallel that perform the different TJob lifecycle stages. - `/retorchfiles/tjoblifecycles` and `/retorchfiles/coilifecycles` contains the set up, execution, and tear down scripts for the TJobs and infrastructure From c994ac190ca57f56109cf41fea2c25e8a8d1cae0 Mon Sep 17 00:00:00 2001 From: Augusto Date: Thu, 5 Dec 2024 10:11:41 +0100 Subject: [PATCH 25/28] Changes: - Reviewed english and expression - Changed how we refer to the module (tool<>generator) - Added how currently the scripting code is generated --- README.md | 60 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e4b5a99..a3115c6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ goal is to optimize E2E test execution by reducing both the execution time and t redeployment's. NOTE: The repository is a work in progress, the initial version only made available the annotations, and currently we're -migrating the orchestration module. +migrating the orchestration generator module. Additional components will be added in future releases. [^1]: Henceforth, we will use the term "Resources" (capitalized) when referring to the ones required by the E2E test suite. @@ -31,7 +31,7 @@ Additional components will be added in future releases. [`io.github.giis-uniovi:retorch-annotations`](https://central.sonatype.com/artifact/io.github.giis-uniovi/retorch-annotations) to the pom.xml of your SUT. - Add the annotations to the test classes as indicated below - Configure the E2E test suite as indicated below -- Execute the orchestration tool and generate the pipelining-scripting code +- Execute the orchestration generator and generate the pipelining-scripting code - [TO-DO] ## RETORCH Annotations @@ -78,22 +78,21 @@ void forumLoadEntriesTest(String usermail,String password,String role){ } ``` ## RETORCH Orchestration -The RETORCH framework provides a tool that generates an Execution Plan, along with the required pipelining and script +The RETORCH framework provides a generator that creates the Execution Plan, along with the required pipelining and script files for execution in a CI environment. The generation of scripts and pipelining code is based on the Access Modes annotated within the test cases and the Resource information specified in `[SUT_NAME]SystemResources.json`. -The RETORCH orchestration tool requires 4 inputs: +The RETORCH orchestration generator requires 4 inputs: - The annotated E2E test cases with the [RETORCH access modes](#retorch-annotations). - A file with the Resources in JSON format. - A properties file with the Environment configuration. - A custom `docker-compose.yml` file. -Given these inputs, the tool generates as output the necessary scripting code and the `Jenkinsfile` to execute the E2E test +Given these inputs, the generator gives as output the necessary scripting code and the `Jenkinsfile` to execute the E2E test suite into a Continuous Integration system. ### Prepare the E2E Test suite -Execute the RETORCH Orchestration tool and generate the script and pipelining code requires to perform a series of configurations -into the test suite. The first step is to create several folders to store the configurations and place the `docker-compose.yml` +The first step is to create several folders to store the configurations and place the `docker-compose.yml` in the project root. The resulting directory tree might look like as: ``` @@ -108,11 +107,11 @@ The resulting directory tree might look like as: - The `retorchfiles/` directory would contain all the configuration files and scripting snippets that would be used to generate the pipelining code and the scripts to set up, deploy, and tear down the different Resources and TJob. Contains two subdirectories: - `configurations/`: stores the Resource and CI configuration files. - - `customscriptscode/`: stores the different script snippets for the tear-down, set-up and environment. -- The `docker-compose.yml` in the root of the directory. + - `customscriptscode/`: stores the different script snippets for the tear down, set up and environment. +- The `docker-compose.yml` in the root of the project. - The different project directories and files. -The following subsections explain how to create each configuration file and how to prepare the docker-compose.yml file. +The following subsections explain how to create each configuration file and how to prepare the `docker-compose.yml` file. #### Create the Resource.json file The Resource file must be placed in the `retorchfiles/configurations/` and named with the system or test suite name, followed @@ -164,7 +163,7 @@ The following snippet shows an example of two Resources declared in the JSON fil The CI file must be placed in `retorchfiles/configurations/`, namely `retorchCI.properties` containing several parameters related to the SUT and the Continuous Integration Infrastructure, these parameters are the following: - `agentCIName`: the specific Jenkins agent used to execute the test suite. -- `sut-wait-html`: state in the frontend (html displayed) when the SUT is ready to execute the test SUITE. +- `sut-wait-html`: state in the frontend (HTML displayed) when the SUT is ready to execute the test SUITE. - `sut-location`: location of the `docker-compose.yml` file used to deploy the SUT. - `docker-frontend-name`: ID of the container used as frontend . - `docker-frontend-port`: PORT on which the frontend container is available. @@ -186,7 +185,7 @@ The following snippet provides an example of how this file looks like: ``` #### Preparing the docker-compose.yml file -The RETORCH tool also requires to parametrize the `docker-compose.yml` used to deploy the application by means including the +The orchestration generator also requires to parametrize the `docker-compose.yml` used to deploy the application by means including the necessary environment variables in the containers names and URIs, as well as the placeholders of the images specified above. The following snippet present how it was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): @@ -232,14 +231,14 @@ services: ``` #### (Optional) Specify script snippets to include in the set-up tear-down and environment -The RETORCH orchestration tool allows to specify scripting code/commands to be included in the generated set-up, tear-down, and -the environment declaration of each TJob. To include it, the tester must create the following files in `retorch\customscriptscode` -- `custom-tjob-setup`: Contains the custom set-up code (e.g. deploy the SUT) or custom logging systems. -- `custom-tjob-teardown`: Contains the custom tear-down code (e.g. tear-down the SUT) -- `custom.env`: Contains environment variables common to all TJobs +The RETORCH orchestration generator allows to specify scripting code/commands to be included in the generated set up, tear down, and +the environment declaration of each TJob. To include it, the tester must create the following files in `retorch\customscriptscode`: +- `custom-tjob-setup`: Contains the custom set up code (e.g. declare some environment variable specific for each TJob) or custom logging systems. +- `custom-tjob-teardown`: Contains the custom tear down code (e.g. save some generated outputs). +- `custom.env`: Contains configurations and environment variables common to all TJobs. Examples of the three snippets files can be consulted in [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching) -and [eShopOnContainers](https://github.com/giis-uniovi/retorch-st-eShopContainers) +and [eShopOnContainers](https://github.com/giis-uniovi/retorch-st-eShopContainers). Once created the different properties and configuration files, the directory tree might look like: @@ -257,18 +256,31 @@ Once created the different properties and configuration files, the directory tre └── custom.env ``` -### Executing the Orchestration tool -[TO-DO] Pending to decide-implement the final version +### Executing the Orchestration generator +Once all the files created and the `docker-compose.yml` is prepared, to execute the generator we only need to create a +main class and instantiate an `OrchestratinGenericToolbox` object. Calling the `generateJenkinsFile()` method with +the package route, the system name and the destination for the `Jenkinsfile`. +The following code snippet shows an example of the method invocation: + ```java +import retorch.orchestration.main.OrchestrationGenericToolBox; -### RETORCH Orchestration Tool outputs -The tool provides four different outputs: the pipelining code, the necessary scripts to set up, tear down and execute the TJobs(`/retorchfiles/tjoblifecycles`), +public class SutExampleRetorchMain { + + public static void main(String[] args) { + OrchestrationGenericToolBox toolBox = new OrchestrationGenericToolBox(); + toolBox.generateJenkinsfile("giis.sutexample.e2e.functional.tests", "sutexample", "./"); + } +} +``` + +### RETORCH Orchestration generator outputs +The generator provides four different outputs: the pipelining code, the necessary scripts to set up, tear down and execute the TJobs(`/retorchfiles/tjoblifecycles`), the infrastructure(`/retorchfiles/coilifecycles`) and the different environment files of each TJob (`/retorchfiles/envfiles`) : - `Jenkinsfile`: located in the root of the project, contains the pipelining code with the different stages in sequential-parallel that perform the different TJob lifecycle stages. - `/retorchfiles/tjoblifecycles` and `/retorchfiles/coilifecycles` contains the set up, execution, and tear down scripts for the TJobs and infrastructure - `/retorchfiles/envfiles`: contains the generated custom environment of each TJob. - ## Contributing See the general contribution policies and guidelines for *giis-uniovi* at @@ -299,6 +311,6 @@ RETORCH*: A Cost and Resource aware Model for E2E Testing in the Cloud: ## Acknowledgments -This work has been developed under the TestBUS (PID2019-105455GB-C32) project supported +This work has been developed under the TestBUS (PID2019-105455GB-C32) and project supported by the [Ministry of Science and Innovation (SPAIN)](https://www.ciencia.gob.es/) From 7435dc12f854ecd7f675358e9d93969ea755cf99 Mon Sep 17 00:00:00 2001 From: Augusto Date: Thu, 5 Dec 2024 11:41:41 +0100 Subject: [PATCH 26/28] Detailed the parameters of the generateJenkinsfile() method. --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3115c6..109ce39 100644 --- a/README.md +++ b/README.md @@ -258,8 +258,12 @@ Once created the different properties and configuration files, the directory tre ### Executing the Orchestration generator Once all the files created and the `docker-compose.yml` is prepared, to execute the generator we only need to create a -main class and instantiate an `OrchestratinGenericToolbox` object. Calling the `generateJenkinsFile()` method with -the package route, the system name and the destination for the `Jenkinsfile`. +main class and instantiate an `OrchestratinGenericToolbox` object. Calling the `generateJenkinsFile()` method with the following +parameters: +- `packageRoute`: String that specifies the complete package name to the E2E annotated tests folder. +- `systemName`: String that specifies the system name, must correspond with the name used in the [Resources JSON file](#create-the-resourcejson-file). +- `jenkinsFilePath`: String with the destination of the `Jenkinsfile`. + The following code snippet shows an example of the method invocation: ```java import retorch.orchestration.main.OrchestrationGenericToolBox; From d2edc8abe0cf49e747325710b74c39c07243f8e1 Mon Sep 17 00:00:00 2001 From: Augusto Date: Thu, 5 Dec 2024 14:12:19 +0100 Subject: [PATCH 27/28] Adding the single module requirement in the inputs and the Prepare section --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 109ce39..bedcda8 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ files for execution in a CI environment. The generation of scripts and pipelinin annotated within the test cases and the Resource information specified in `[SUT_NAME]SystemResources.json`. The RETORCH orchestration generator requires 4 inputs: -- The annotated E2E test cases with the [RETORCH access modes](#retorch-annotations). +- The annotated E2E test cases with the [RETORCH access modes](#retorch-annotations) into a **single module** Maven project. - A file with the Resources in JSON format. - A properties file with the Environment configuration. - A custom `docker-compose.yml` file. @@ -93,7 +93,7 @@ suite into a Continuous Integration system. ### Prepare the E2E Test suite The first step is to create several folders to store the configurations and place the `docker-compose.yml` -in the project root. +in the single module project root. The resulting directory tree might look like as: ``` . @@ -240,7 +240,7 @@ the environment declaration of each TJob. To include it, the tester must create Examples of the three snippets files can be consulted in [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching) and [eShopOnContainers](https://github.com/giis-uniovi/retorch-st-eShopContainers). -Once created the different properties and configuration files, the directory tree might look like: +Once created the different properties and configuration files, the single module directory tree might look like: ``` . From d49bffcd56d4f52a01f949d659ae84372b78a883 Mon Sep 17 00:00:00 2001 From: Augusto Date: Thu, 12 Dec 2024 10:39:36 +0100 Subject: [PATCH 28/28] Removing the diff of the compose Clarifying the utility of jenkinsFilePath parameter Adapting the package name --- README.md | 54 ++++++++++-------------------------------------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index bedcda8..eb1ef45 100644 --- a/README.md +++ b/README.md @@ -187,48 +187,14 @@ The following snippet provides an example of how this file looks like: #### Preparing the docker-compose.yml file The orchestration generator also requires to parametrize the `docker-compose.yml` used to deploy the application by means including the necessary environment variables in the containers names and URIs, as well as the placeholders of the images specified above. -The following snippet present how it was done in one of the services of the [FullTeaching Test Suite](https://github.com/giis-uniovi/retorch-st-fullteaching): - -```diff -services: - full-teaching-mysql: -- container_name: full-teaching-mysql -+ container_name: full-teaching-mysql-${tjobname} - ... -+ networks: -+ - jenkins_network - - full-teaching-openvidu-server-kms: -- container_name: full-teaching-openvidu-server-kms -- image: openvidu/openvidu-server-kms:1.7.0 -+ container_name: full-teaching-${tjobname}-openvidu-server-kms -+ image: ${mediaserver} - ... - environment: -- - openvidu.publicurl=https://full-teaching-openvidu-server-kms:8443 -+ - openvidu.publicurl=https://full-teaching-${tjobname}-openvidu-server-kms:8443 -+ networks: -+ - jenkins_network - - full-teaching: -- container_name: full-teaching -+ container_name: full-teaching-${tjobname} - ... - environment: -- - WAIT_HOSTS=full-teaching-mysql:3306 -+ - WAIT_HOSTS=full-teaching-mysql-${tjobname}:3306 -- - MYSQL_PORT_3306_TCP_ADDR=full-teaching-mysql -+ - MYSQL_PORT_3306_TCP_ADDR=full-teaching-mysql-${tjobname} -- - openvidu.url=https://full-teaching-openvidu-server-kms:8443 -+ - openvidu.url=https://full-teaching-${tjobname}-openvidu-server-kms:8443 - - ... -+ networks: -+ - jenkins_network - -+ networks: -+ jenkins_network: -+ external: true -``` +Examples of the necessary changes in the `docker-compose.yml` can consulted in the FullTeaching and eShopOnContainers repositories: + +- FullTeaching: + - [Original `docker-compose.yml`](https://github.com/elastest/full-teaching/blob/master/application/docker-compose/docker-compose.yml) + - [RETORCH `docker-compose.yml`](https://github.com/giis-uniovi/retorch-st-fullteaching/blob/main/docker-compose.yml) +- EshopContainers: + - [Original `docker-compose.yml`](https://github.com/erjain/eShopOnContainers/blob/dev/src/docker-compose.yml) and [ `docker-compose.prod.yml`](https://github.com/erjain/eShopOnContainers/blob/dev/src/docker-compose.prod.yml) + - [RETORCH `docker-compose.yml`](https://github.com/giis-uniovi/retorch-st-eShopContainers/blob/main/sut/src/docker-compose.yml) #### (Optional) Specify script snippets to include in the set-up tear-down and environment The RETORCH orchestration generator allows to specify scripting code/commands to be included in the generated set up, tear down, and @@ -262,11 +228,11 @@ main class and instantiate an `OrchestratinGenericToolbox` object. Calling the ` parameters: - `packageRoute`: String that specifies the complete package name to the E2E annotated tests folder. - `systemName`: String that specifies the system name, must correspond with the name used in the [Resources JSON file](#create-the-resourcejson-file). -- `jenkinsFilePath`: String with the destination of the `Jenkinsfile`. +- `jenkinsFilePath`: String with the location where the `Jenkinsfile` will be created (usually the root of the project: `./`). The following code snippet shows an example of the method invocation: ```java -import retorch.orchestration.main.OrchestrationGenericToolBox; +import giis.retorch.orchestration.main.OrchestrationGenericToolBox; public class SutExampleRetorchMain {