diff options
21 files changed, 492 insertions, 245 deletions
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java index 0cf1f99ec..eb5b6dc9b 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,10 @@ public class AutomationComposition extends ToscaEntity implements Comparable<Aut @NonNull private LockState lockState = LockState.NONE; + private String lastMsg; + + private Integer phase; + private Map<UUID, AutomationCompositionElement> elements; private StateChangeResult stateChangeResult; @@ -69,6 +73,8 @@ public class AutomationComposition extends ToscaEntity implements Comparable<Aut this.restarting = otherAutomationComposition.restarting; this.deployState = otherAutomationComposition.deployState; this.lockState = otherAutomationComposition.lockState; + this.lastMsg = otherAutomationComposition.lastMsg; + this.phase = otherAutomationComposition.phase; this.elements = PfUtils.mapMap(otherAutomationComposition.elements, AutomationCompositionElement::new); this.stateChangeResult = otherAutomationComposition.stateChangeResult; } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/Participant.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/Participant.java index 5bdf4d312..6ddec6179 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/Participant.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/Participant.java @@ -49,6 +49,9 @@ public class Participant { @NonNull private Map<UUID, ParticipantSupportedElementType> participantSupportedElementTypes = new HashMap<>(); + @NonNull + private Map<UUID, ParticipantReplica> replicas = new HashMap<>(); + /** * Copy constructor. * @@ -60,5 +63,6 @@ public class Participant { this.lastMsg = otherParticipant.lastMsg; this.participantSupportedElementTypes = PfUtils.mapMap(otherParticipant.getParticipantSupportedElementTypes(), ParticipantSupportedElementType::new); + this.replicas = PfUtils.mapMap(otherParticipant.replicas, ParticipantReplica::new); } } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplica.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplica.java new file mode 100644 index 000000000..23f72191a --- /dev/null +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplica.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.models.acm.concepts; + +import java.util.UUID; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +@NoArgsConstructor +@Data +@EqualsAndHashCode +public class ParticipantReplica { + + @NonNull + private UUID replicaId; + + @NonNull + private ParticipantState participantState = ParticipantState.ON_LINE; + + @NonNull + private String lastMsg; + + /** + * Copy constructor. + * + * @param other the ParticipantReplica to copy from + */ + public ParticipantReplica(ParticipantReplica other) { + this.replicaId = other.replicaId; + this.participantState = other.participantState; + this.lastMsg = other.lastMsg; + } +} diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationComposition.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationComposition.java index 5e27fde53..0bf6a9e1a 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationComposition.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationComposition.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import jakarta.persistence.InheritanceType; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -44,6 +45,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.utils.TimestampHelper; import org.onap.policy.common.parameters.annotations.NotNull; import org.onap.policy.common.parameters.annotations.Valid; import org.onap.policy.models.base.PfAuthorative; @@ -98,6 +100,13 @@ public class JpaAutomationComposition extends Validated private StateChangeResult stateChangeResult; @Column + @NotNull + private Timestamp lastMsg; + + @Column + private Integer phase; + + @Column private String description; @NotNull @@ -149,6 +158,8 @@ public class JpaAutomationComposition extends Validated this.restarting = copyConcept.restarting; this.deployState = copyConcept.deployState; this.lockState = copyConcept.lockState; + this.lastMsg = copyConcept.lastMsg; + this.phase = copyConcept.phase; this.description = copyConcept.description; this.stateChangeResult = copyConcept.stateChangeResult; this.elements = PfUtils.mapList(copyConcept.elements, JpaAutomationCompositionElement::new); @@ -177,6 +188,8 @@ public class JpaAutomationComposition extends Validated automationComposition.setRestarting(restarting); automationComposition.setDeployState(deployState); automationComposition.setLockState(lockState); + automationComposition.setLastMsg(lastMsg.toString()); + automationComposition.setPhase(phase); automationComposition.setDescription(description); automationComposition.setStateChangeResult(stateChangeResult); automationComposition.setElements(new LinkedHashMap<>(this.elements.size())); @@ -199,6 +212,8 @@ public class JpaAutomationComposition extends Validated this.restarting = automationComposition.getRestarting(); this.deployState = automationComposition.getDeployState(); this.lockState = automationComposition.getLockState(); + this.lastMsg = TimestampHelper.toTimestamp(automationComposition.getLastMsg()); + this.phase = automationComposition.getPhase(); this.description = automationComposition.getDescription(); this.stateChangeResult = automationComposition.getStateChangeResult(); this.elements = new ArrayList<>(automationComposition.getElements().size()); @@ -229,6 +244,16 @@ public class JpaAutomationComposition extends Validated return result; } + result = lastMsg.compareTo(other.lastMsg); + if (result != 0) { + return result; + } + + result = ObjectUtils.compare(phase, other.phase); + if (result != 0) { + return result; + } + result = ObjectUtils.compare(version, other.version); if (result != 0) { return result; diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipant.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipant.java index cfde55767..f35fff9e7 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipant.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipant.java @@ -41,6 +41,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NonNull; import org.apache.commons.lang3.ObjectUtils; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; import org.onap.policy.clamp.models.acm.concepts.Participant; import org.onap.policy.clamp.models.acm.concepts.ParticipantState; import org.onap.policy.clamp.models.acm.utils.TimestampHelper; @@ -84,11 +86,18 @@ public class JpaParticipant extends Validated foreignKey = @ForeignKey(name = "supported_element_fk")) private List<@NotNull @Valid JpaParticipantSupportedElementType> supportedElements; + @NotNull + @OneToMany + @LazyCollection(LazyCollectionOption.FALSE) + @JoinColumn(name = "participantId", referencedColumnName = "participantId", + foreignKey = @ForeignKey(name = "participant_replica_fk")) + private List<@NotNull @Valid JpaParticipantReplica> replicas; + /** * The Default Constructor creates a {@link JpaParticipant} object with a null key. */ public JpaParticipant() { - this(UUID.randomUUID().toString(), ParticipantState.ON_LINE, new ArrayList<>()); + this(UUID.randomUUID().toString(), ParticipantState.ON_LINE, new ArrayList<>(), new ArrayList<>()); } /** @@ -96,13 +105,17 @@ public class JpaParticipant extends Validated * * @param participantId the participant id * @param participantState the state of the participant + * @param supportedElements the list of supported Element Type + * @param replicas the list of replica */ public JpaParticipant(@NonNull String participantId, @NonNull final ParticipantState participantState, - @NonNull final List<JpaParticipantSupportedElementType> supportedElements) { + @NonNull final List<JpaParticipantSupportedElementType> supportedElements, + @NonNull final List<JpaParticipantReplica> replicas) { this.participantId = participantId; this.participantState = participantState; this.supportedElements = supportedElements; this.lastMsg = TimestampHelper.nowTimestamp(); + this.replicas = replicas; } /** @@ -115,6 +128,7 @@ public class JpaParticipant extends Validated this.description = copyConcept.description; this.participantId = copyConcept.participantId; this.supportedElements = copyConcept.supportedElements; + this.replicas = copyConcept.replicas; this.lastMsg = copyConcept.lastMsg; } @@ -139,7 +153,9 @@ public class JpaParticipant extends Validated participant.getParticipantSupportedElementTypes() .put(UUID.fromString(element.getId()), element.toAuthorative()); } - + for (var replica : this.replicas) { + participant.getReplicas().put(UUID.fromString(replica.getReplicaId()), replica.toAuthorative()); + } return participant; } @@ -148,14 +164,22 @@ public class JpaParticipant extends Validated this.setParticipantState(participant.getParticipantState()); this.participantId = participant.getParticipantId().toString(); this.lastMsg = TimestampHelper.toTimestamp(participant.getLastMsg()); - this.supportedElements = new ArrayList<>(participant.getParticipantSupportedElementTypes().size()); + this.supportedElements = new ArrayList<>(participant.getParticipantSupportedElementTypes().size()); for (var elementEntry : participant.getParticipantSupportedElementTypes().entrySet()) { var jpaParticipantSupportedElementType = new JpaParticipantSupportedElementType(); jpaParticipantSupportedElementType.setParticipantId(this.participantId); jpaParticipantSupportedElementType.fromAuthorative(elementEntry.getValue()); this.supportedElements.add(jpaParticipantSupportedElementType); } + + this.replicas = new ArrayList<>(participant.getReplicas().size()); + for (var replicaEntry : participant.getReplicas().entrySet()) { + var jpaReplica = new JpaParticipantReplica(); + jpaReplica.setParticipantId(this.participantId); + jpaReplica.fromAuthorative(replicaEntry.getValue()); + this.replicas.add(jpaReplica); + } } @Override diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplica.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplica.java new file mode 100644 index 000000000..beaab601f --- /dev/null +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplica.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.models.acm.persistence.concepts; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.Table; +import java.sql.Timestamp; +import java.util.UUID; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import org.onap.policy.clamp.models.acm.concepts.ParticipantReplica; +import org.onap.policy.clamp.models.acm.concepts.ParticipantState; +import org.onap.policy.clamp.models.acm.utils.TimestampHelper; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.models.base.PfAuthorative; +import org.onap.policy.models.base.Validated; + +@Entity +@Table(name = "ParticipantReplica") +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@Data +@EqualsAndHashCode(callSuper = false) +public class JpaParticipantReplica extends Validated implements PfAuthorative<ParticipantReplica> { + + @Id + @NotNull + private String replicaId; + + @NotNull + @Column + private String participantId; + + @Column + @NotNull + private ParticipantState participantState; + + @Column + @NotNull + private Timestamp lastMsg; + + public JpaParticipantReplica() { + this(UUID.randomUUID().toString(), UUID.randomUUID().toString()); + } + + public JpaParticipantReplica(@NonNull String replicaId, @NonNull String participantId) { + this.replicaId = replicaId; + this.participantId = participantId; + } + + @Override + public ParticipantReplica toAuthorative() { + var participantReplica = new ParticipantReplica(); + participantReplica.setReplicaId(UUID.fromString(replicaId)); + participantReplica.setParticipantState(participantState); + participantReplica.setLastMsg(lastMsg.toString()); + return participantReplica; + } + + @Override + public void fromAuthorative(@NonNull ParticipantReplica participantReplica) { + this.replicaId = participantReplica.getReplicaId().toString(); + this.participantState = participantReplica.getParticipantState(); + this.lastMsg = TimestampHelper.toTimestamp(participantReplica.getLastMsg()); + } +} diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java index 0293bd3c5..5f523ad27 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java @@ -29,7 +29,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Queue; import java.util.UUID; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -71,7 +70,7 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class AcmUtils { public static final String ENTRY = "entry "; - private static StringToMapConverter MAP_CONVERTER = new StringToMapConverter(); + private static final StringToMapConverter MAP_CONVERTER = new StringToMapConverter(); /** * Get the Policy information in the service template for the deploy message to participants. @@ -379,6 +378,7 @@ public final class AcmUtils { final DeployState deployState, final LockState lockState) { automationComposition.setDeployState(deployState); automationComposition.setLockState(lockState); + automationComposition.setLastMsg(TimestampHelper.now()); if (MapUtils.isEmpty(automationComposition.getElements())) { return; diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplicaTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplicaTest.java new file mode 100644 index 000000000..8df6db65e --- /dev/null +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantReplicaTest.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.models.acm.concepts; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.models.acm.utils.CommonTestData; + +class ParticipantReplicaTest { + + @Test + void testParticipantLombok() { + assertDoesNotThrow(() -> new ParticipantReplica()); + var p0 = new ParticipantReplica(); + + assertThat(p0.toString()).contains("ParticipantReplica("); + assertThat(p0.hashCode()).isNotZero(); + assertNotEquals(null, p0); + + var p1 = new ParticipantReplica(); + + p1.setReplicaId(CommonTestData.getReplicaId()); + p1.setParticipantState(ParticipantState.ON_LINE); + + assertThat(p1.toString()).contains("ParticipantReplica("); + assertNotEquals(0, p1.hashCode()); + assertNotEquals(p1, p0); + assertNotEquals(null, p1); + + var p2 = new ParticipantReplica(); + assertThatThrownBy(() -> p2.setParticipantState(null)).isInstanceOf(NullPointerException.class); + assertEquals(p2, p0); + } + + @Test + void testCopyConstructor() { + var p0 = new ParticipantReplica(); + p0.setReplicaId(UUID.randomUUID()); + p0.setParticipantState(ParticipantState.ON_LINE); + + var p2 = new ParticipantReplica(p0); + assertEquals(p2, p0); + } +} diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionTest.java index 66554e7ec..b56e77801 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.sql.Timestamp; +import java.time.Instant; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.UUID; @@ -35,6 +37,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.utils.TimestampHelper; import org.onap.policy.models.base.PfConceptKey; /** @@ -93,9 +96,9 @@ class JpaAutomationCompositionTest { @Test void testJpaAutomationComposition() { - var jpaAutomationComposition = createJpaAutomationCompositionInstance(); - var automationComposition = createAutomationCompositionInstance(); + var jpaAutomationComposition = new JpaAutomationComposition(automationComposition); + assertEquals(automationComposition, jpaAutomationComposition.toAuthorative()); var target = UUID.randomUUID(); @@ -125,7 +128,7 @@ class JpaAutomationCompositionTest { @Test void testJpaAutomationCompositionValidation() { - var testJpaAutomationComposition = createJpaAutomationCompositionInstance(); + var testJpaAutomationComposition = new JpaAutomationComposition(createAutomationCompositionInstance()); assertThatThrownBy(() -> testJpaAutomationComposition.validate(null)) .hasMessageMatching("fieldName is marked .*ull but is null"); @@ -135,7 +138,7 @@ class JpaAutomationCompositionTest { @Test void testJpaAutomationCompositionCompareTo() { - var jpaAutomationComposition = createJpaAutomationCompositionInstance(); + var jpaAutomationComposition = new JpaAutomationComposition(createAutomationCompositionInstance()); var otherJpaAutomationComposition = new JpaAutomationComposition(jpaAutomationComposition); assertEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); @@ -168,6 +171,16 @@ class JpaAutomationCompositionTest { jpaAutomationComposition.setVersion("0.0.1"); assertEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); + jpaAutomationComposition.setLastMsg(Timestamp.from(Instant.EPOCH)); + assertNotEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); + jpaAutomationComposition.setLastMsg(otherJpaAutomationComposition.getLastMsg()); + assertEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); + + jpaAutomationComposition.setPhase(0); + assertNotEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); + jpaAutomationComposition.setPhase(null); + assertEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); + jpaAutomationComposition.setDeployState(DeployState.DEPLOYED); assertNotEquals(0, jpaAutomationComposition.compareTo(otherJpaAutomationComposition)); jpaAutomationComposition.setDeployState(DeployState.UNDEPLOYED); @@ -225,19 +238,12 @@ class JpaAutomationCompositionTest { assertEquals(ac2, ac0); } - private JpaAutomationComposition createJpaAutomationCompositionInstance() { - var testAutomationComposition = createAutomationCompositionInstance(); - var testJpaAutomationComposition = new JpaAutomationComposition(); - testJpaAutomationComposition.fromAuthorative(testAutomationComposition); - - return testJpaAutomationComposition; - } - private AutomationComposition createAutomationCompositionInstance() { var testAutomationComposition = new AutomationComposition(); testAutomationComposition.setName("automation-composition"); testAutomationComposition.setInstanceId(UUID.fromString(INSTANCE_ID)); testAutomationComposition.setVersion("0.0.1"); + testAutomationComposition.setLastMsg(TimestampHelper.now()); testAutomationComposition.setCompositionId(UUID.fromString(COMPOSITION_ID)); testAutomationComposition.setElements(new LinkedHashMap<>()); diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplicaTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplicaTest.java new file mode 100644 index 000000000..d77760860 --- /dev/null +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplicaTest.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.models.acm.persistence.concepts; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.models.acm.concepts.ParticipantReplica; +import org.onap.policy.clamp.models.acm.concepts.ParticipantState; +import org.onap.policy.clamp.models.acm.utils.TimestampHelper; + +class JpaParticipantReplicaTest { + + @Test + void testJpaParticipantReplicaConstructor() { + assertThatThrownBy(() -> new JpaParticipantReplica(UUID.randomUUID().toString(), null)) + .hasMessageMatching("participantId is marked .*ull but is null"); + + assertThatThrownBy(() -> new JpaParticipantReplica(null, UUID.randomUUID().toString())) + .hasMessageMatching("replicaId is marked .*ull but is null"); + + assertDoesNotThrow(() -> new JpaParticipantReplica()); + assertDoesNotThrow(() -> new JpaParticipantReplica(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + } + + @Test + void testJpaParticipantReplica() { + var p0 = new JpaParticipantReplica(); + + assertThat(p0.toString()).contains("JpaParticipantReplica("); + assertThat(p0.hashCode()).isNotZero(); + assertNotEquals(null, p0); + + var p1 = new JpaParticipantReplica(); + p1.setParticipantState(ParticipantState.ON_LINE); + + assertThat(p1.toString()).contains("ParticipantReplica("); + assertNotEquals(0, p1.hashCode()); + assertNotEquals(p1, p0); + assertNotEquals(null, p1); + + var p2 = new JpaParticipantReplica(); + p2.setReplicaId(p0.getReplicaId()); + p2.setParticipantId(p0.getParticipantId()); + p2.setLastMsg(p0.getLastMsg()); + p2.setParticipantState(p0.getParticipantState()); + assertEquals(p2, p0); + } +} diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantTest.java index e64a6893f..e0f2f55c1 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantTest.java @@ -52,20 +52,25 @@ class JpaParticipantTest { assertThatThrownBy(() -> new JpaParticipant((JpaParticipant) null)) .hasMessageMatching("copyConcept is marked .*ull but is null"); - assertThatThrownBy(() -> new JpaParticipant(null, null, null)).hasMessageMatching(NULL_KEY_ERROR); - - assertThatThrownBy(() -> new JpaParticipant(null, ParticipantState.ON_LINE, new ArrayList<>())) + assertThatThrownBy(() -> new JpaParticipant(null, ParticipantState.ON_LINE, + new ArrayList<>(), new ArrayList<>())) .hasMessageMatching(NULL_KEY_ERROR); - assertThatThrownBy(() -> new JpaParticipant(UUID.randomUUID().toString(), null, new ArrayList<>())) + assertThatThrownBy(() -> new JpaParticipant(UUID.randomUUID().toString(), null, + new ArrayList<>(), new ArrayList<>())) .hasMessageMatching("participantState is marked .*ull but is null"); - assertThatThrownBy(() -> new JpaParticipant(UUID.randomUUID().toString(), ParticipantState.ON_LINE, null)) + assertThatThrownBy(() -> new JpaParticipant(UUID.randomUUID().toString(), ParticipantState.ON_LINE, + null, new ArrayList<>())) .hasMessageMatching("supportedElements is marked .*ull but is null"); + assertThatThrownBy(() -> new JpaParticipant(UUID.randomUUID().toString(), ParticipantState.ON_LINE, + new ArrayList<>(), null)) + .hasMessageMatching("replicas is marked .*ull but is null"); + assertDoesNotThrow(() -> new JpaParticipant()); assertDoesNotThrow(() -> new JpaParticipant(UUID.randomUUID().toString(), - ParticipantState.ON_LINE, new ArrayList<>())); + ParticipantState.ON_LINE, new ArrayList<>(), new ArrayList<>())); } @Test @@ -158,6 +163,7 @@ class JpaParticipantTest { testParticipant.setParticipantId(UUID.randomUUID()); testParticipant.setLastMsg(TimestampHelper.now()); testParticipant.setParticipantSupportedElementTypes(new LinkedHashMap<>()); + testParticipant.setReplicas(new LinkedHashMap<>()); return testParticipant; } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java index 463e958f3..8e7e50de7 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java @@ -85,6 +85,7 @@ class AutomationCompositionProviderTest { var createdAutomationComposition = automationCompositionProvider.createAutomationComposition(inputAc); inputAc.setInstanceId(createdAutomationComposition.getInstanceId()); + inputAc.setLastMsg(createdAutomationComposition.getLastMsg()); assertEquals(inputAc, createdAutomationComposition); } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java index b8075c3ef..3bd1549ad 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java @@ -51,9 +51,9 @@ public class CommonTestData { } /** - * Returns participantId for test cases. + * Returns participant replica Id for test cases. * - * @return participant Id + * @return replica Id */ public static UUID getReplicaId() { return REPLICA_ID; diff --git a/models/src/test/resources/providers/TestAutomationCompositions.json b/models/src/test/resources/providers/TestAutomationCompositions.json index 24f5a4870..c75337bc1 100644 --- a/models/src/test/resources/providers/TestAutomationCompositions.json +++ b/models/src/test/resources/providers/TestAutomationCompositions.json @@ -5,6 +5,7 @@ "instanceId": "809c62b3-8918-41b9-a748-e21eb79c6c89", "deployState": "UNDEPLOYED", "lockState": "NONE", + "lastMsg": "2024-05-22 10:04:37.6020187", "elements": { "709c62b3-8918-41b9-a747-e21eb79c6c20": { "id": "709c62b3-8918-41b9-a747-e21eb79c6c20", @@ -56,6 +57,7 @@ "instanceId": "809c62b3-8918-41b9-a748-e21eb79c6c90", "deployState": "UNDEPLOYED", "lockState": "NONE", + "lastMsg": "2024-05-22 10:04:37.6020187", "elements": { "709c62b3-8918-41b9-a747-e21eb79c6c24": { "id": "709c62b3-8918-41b9-a747-e21eb79c6c24", diff --git a/models/src/test/resources/providers/TestParticipant.json b/models/src/test/resources/providers/TestParticipant.json index 3f19baab4..3335865e1 100644 --- a/models/src/test/resources/providers/TestParticipant.json +++ b/models/src/test/resources/providers/TestParticipant.json @@ -22,5 +22,12 @@ "typeName": "org.onap.policy.clamp.acm.AutomationCompositionElement", "typeVersion": "1.0.0" } + }, + "replicas": { + "82fd8ef9-1d1e-4343-9b28-7f9564ee3de6":{ + "replicaId": "82fd8ef9-1d1e-4343-9b28-7f9564ee3de6", + "lastMsg": "2024-05-22 10:04:37.6020187", + "participantState": "ON_LINE" + } } } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java index d6fa5d8d7..802c6603b 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java @@ -86,8 +86,9 @@ public class SupervisionAcHandler { AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYING, LockState.NONE); } automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); - automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); executor.execute( () -> automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(), startPhase, true)); @@ -112,8 +113,9 @@ public class SupervisionAcHandler { } automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationComposition.setCompositionTargetId(null); - automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); executor.execute( () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true)); } @@ -136,8 +138,9 @@ public class SupervisionAcHandler { AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.UNLOCKING); } automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); - automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); executor.execute( () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true)); } @@ -160,8 +163,9 @@ public class SupervisionAcHandler { AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKING); } automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); - automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); executor.execute( () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true)); } @@ -187,8 +191,9 @@ public class SupervisionAcHandler { public void delete(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { AcmUtils.setCascadedState(automationComposition, DeployState.DELETING, LockState.NONE); automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); - automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); executor.execute( () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true)); } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java index 96e75df62..06d464671 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java @@ -23,9 +23,7 @@ package org.onap.policy.clamp.acm.runtime.supervision; import java.util.HashMap; -import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher; @@ -51,9 +49,6 @@ import org.springframework.stereotype.Component; public class SupervisionScanner { private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class); - private final TimeoutHandler<UUID> acTimeout = new TimeoutHandler<>(); - private final Map<UUID, Integer> phaseMap = new HashMap<>(); - private final long maxStatusWaitMs; private final AutomationCompositionProvider automationCompositionProvider; @@ -79,8 +74,6 @@ public class SupervisionScanner { this.acDefinitionProvider = acDefinitionProvider; this.automationCompositionStateChangePublisher = automationCompositionStateChangePublisher; this.automationCompositionDeployPublisher = automationCompositionDeployPublisher; - - acTimeout.setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs()); this.maxStatusWaitMs = acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs(); } @@ -105,9 +98,6 @@ public class SupervisionScanner { } scanAutomationComposition(automationComposition, acDefinition.getServiceTemplate()); } - var set = acList.stream().map(AutomationComposition::getInstanceId).collect(Collectors.toSet()); - acTimeout.removeIfNotPresent(set); - LOGGER.debug("Automation composition scan complete . . ."); } @@ -143,17 +133,9 @@ public class SupervisionScanner { LOGGER.debug("automation composition {} scanned, OK", automationComposition.getInstanceId()); // Clear Timeout on automation composition - removeTimeout(automationComposition); return; } - if (acTimeout.isTimeout(automationComposition.getInstanceId()) - && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) { - // retry by the user - LOGGER.debug("clearing Timeout for the ac instance"); - clearTimeout(automationComposition, true); - } - var completed = true; var minSpNotCompleted = 1000; // min startPhase not completed var maxSpNotCompleted = 0; // max startPhase not completed @@ -173,18 +155,18 @@ public class SupervisionScanner { } if (completed) { - LOGGER.debug("automation composition scan: transition state {} {} ", automationComposition.getDeployState(), - automationComposition.getLockState()); + LOGGER.debug("automation composition scan: transition state {} {} completed", + automationComposition.getDeployState(), automationComposition.getLockState()); complete(automationComposition); } else { - LOGGER.debug("automation composition scan: transition from state {} to {} not completed", + LOGGER.debug("automation composition scan: transition state {} {} not completed", automationComposition.getDeployState(), automationComposition.getLockState()); if (DeployState.UPDATING.equals(automationComposition.getDeployState()) || DeployState.MIGRATING.equals(automationComposition.getDeployState())) { // UPDATING do not need phases - handleTimeout(automationComposition); + handleTimeoutUpdate(automationComposition); return; } @@ -192,14 +174,11 @@ public class SupervisionScanner { AcmUtils.isForward(automationComposition.getDeployState(), automationComposition.getLockState()); var nextSpNotCompleted = isForward ? minSpNotCompleted : maxSpNotCompleted; - var firstStartPhase = isForward ? defaultMin : defaultMax; - if (nextSpNotCompleted != phaseMap.getOrDefault(automationComposition.getInstanceId(), firstStartPhase)) { - phaseMap.put(automationComposition.getInstanceId(), nextSpNotCompleted); - sendAutomationCompositionMsg(automationComposition, serviceTemplate, nextSpNotCompleted, - firstStartPhase == nextSpNotCompleted); + if (nextSpNotCompleted != automationComposition.getPhase()) { + sendAutomationCompositionMsg(automationComposition, serviceTemplate, nextSpNotCompleted, false); } else { - handleTimeout(automationComposition); + handleTimeoutWithPhase(automationComposition, serviceTemplate); } } } @@ -213,6 +192,7 @@ public class SupervisionScanner { } automationComposition.setDeployState(AcmUtils.deployCompleted(deployState)); automationComposition.setLockState(AcmUtils.lockCompleted(deployState, automationComposition.getLockState())); + automationComposition.setPhase(null); if (StateChangeResult.TIMEOUT.equals(automationComposition.getStateChangeResult())) { automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); } @@ -221,21 +201,6 @@ public class SupervisionScanner { } else { automationCompositionProvider.updateAutomationComposition(automationComposition); } - - // Clear timeout on automation composition - removeTimeout(automationComposition); - } - - private void clearTimeout(AutomationComposition automationComposition, boolean cleanPhase) { - acTimeout.clear(automationComposition.getInstanceId()); - if (cleanPhase) { - phaseMap.remove(automationComposition.getInstanceId()); - } - } - - private void removeTimeout(AutomationComposition automationComposition) { - acTimeout.remove(automationComposition.getInstanceId()); - phaseMap.remove(automationComposition.getInstanceId()); } private void handleTimeout(AutomationCompositionDefinition acDefinition) { @@ -253,23 +218,60 @@ public class SupervisionScanner { } } - private void handleTimeout(AutomationComposition automationComposition) { - var instanceId = automationComposition.getInstanceId(); - if (acTimeout.isTimeout(instanceId)) { + private void handleTimeoutUpdate(AutomationComposition automationComposition) { + if (StateChangeResult.TIMEOUT.equals(automationComposition.getStateChangeResult())) { LOGGER.debug("The ac instance is in timeout {}", automationComposition.getInstanceId()); return; } + var now = TimestampHelper.nowEpochMilli(); + var lastMsg = TimestampHelper.toEpochMilli(automationComposition.getLastMsg()); + for (var element : automationComposition.getElements().values()) { + if (!AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState())) { + continue; + } + if ((now - lastMsg) > maxStatusWaitMs) { + LOGGER.debug("Report timeout for the ac instance {}", automationComposition.getInstanceId()); + automationComposition.setStateChangeResult(StateChangeResult.TIMEOUT); + automationCompositionProvider.updateAutomationComposition(automationComposition); + break; + } + } + } - if (acTimeout.getDuration(instanceId) > acTimeout.getMaxWaitMs()) { - LOGGER.debug("Report timeout for the ac instance {}", automationComposition.getInstanceId()); - acTimeout.setTimeout(instanceId); - automationComposition.setStateChangeResult(StateChangeResult.TIMEOUT); - automationCompositionProvider.updateAutomationComposition(automationComposition); + private void handleTimeoutWithPhase(AutomationComposition automationComposition, + ToscaServiceTemplate serviceTemplate) { + if (StateChangeResult.TIMEOUT.equals(automationComposition.getStateChangeResult())) { + LOGGER.debug("The ac instance is in timeout {}", automationComposition.getInstanceId()); + return; + } + int currentPhase = automationComposition.getPhase(); + var now = TimestampHelper.nowEpochMilli(); + var lastMsg = TimestampHelper.toEpochMilli(automationComposition.getLastMsg()); + for (var element : automationComposition.getElements().values()) { + if (!AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState())) { + continue; + } + var toscaNodeTemplate = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates() + .get(element.getDefinition().getName()); + int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties()); + if (currentPhase != startPhase) { + continue; + } + if ((now - lastMsg) > maxStatusWaitMs) { + LOGGER.debug("Report timeout for the ac instance {}", automationComposition.getInstanceId()); + automationComposition.setStateChangeResult(StateChangeResult.TIMEOUT); + automationCompositionProvider.updateAutomationComposition(automationComposition); + break; + } } } private void sendAutomationCompositionMsg(AutomationComposition automationComposition, ToscaServiceTemplate serviceTemplate, int startPhase, boolean firstStartPhase) { + automationComposition.setLastMsg(TimestampHelper.now()); + automationComposition.setPhase(startPhase); + automationCompositionProvider.updateAutomationComposition(automationComposition); + if (DeployState.DEPLOYING.equals(automationComposition.getDeployState())) { LOGGER.debug("retry message AutomationCompositionUpdate"); automationCompositionDeployPublisher.send(automationComposition, serviceTemplate, startPhase, @@ -278,7 +280,5 @@ public class SupervisionScanner { LOGGER.debug("retry message AutomationCompositionStateChange"); automationCompositionStateChangePublisher.send(automationComposition, startPhase, firstStartPhase); } - // Clear timeout on automation composition - clearTimeout(automationComposition, false); } } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java deleted file mode 100644 index 3b34252bf..000000000 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.acm.runtime.supervision; - -import java.time.Instant; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import lombok.Getter; -import lombok.Setter; - -public class TimeoutHandler<K> { - @Getter - @Setter - private long maxWaitMs; - - private final Set<K> mapTimeout = new HashSet<>(); - private final Map<K, Long> mapTimer = new HashMap<>(); - - public long getDuration(K id) { - mapTimer.putIfAbsent(id, getEpochMilli()); - return getEpochMilli() - mapTimer.get(id); - } - - /** - * Reset timer and timeout by id. - * - * @param id the id - */ - public void clear(K id) { - mapTimeout.remove(id); - mapTimer.put(id, getEpochMilli()); - } - - /** - * Remove timer and timeout by id. - * - * @param id the id - */ - public void remove(K id) { - mapTimeout.remove(id); - mapTimer.remove(id); - } - - /** - * Remove elements that are not present in set. - * - * @param set the elements that should be present - */ - public void removeIfNotPresent(final Set<K> set) { - var res = mapTimeout.stream().filter(el -> !set.contains(el)).toList(); - if (!res.isEmpty()) { - res.forEach(this::remove); - } - } - - public void setTimeout(K id) { - mapTimeout.add(id); - } - - public boolean isTimeout(K id) { - return mapTimeout.contains(id); - } - - protected long getEpochMilli() { - return Instant.now().toEpochMilli(); - } -} diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/rest/InstantiationControllerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/rest/InstantiationControllerTest.java index cd1a3856a..bcfdea1dd 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/rest/InstantiationControllerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/rest/InstantiationControllerTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -155,6 +155,7 @@ class InstantiationControllerTest extends CommonRestController { var automationCompositionFromDb = instantiationProvider.getAutomationComposition(compositionId, instResponse.getInstanceId()); + automationCompositionFromRsc.setLastMsg(automationCompositionFromDb.getLastMsg()); assertNotNull(automationCompositionFromDb); assertEquals(automationCompositionFromRsc, automationCompositionFromDb); @@ -223,7 +224,9 @@ class InstantiationControllerTest extends CommonRestController { var automationCompositionsQuery = rawresp.readEntity(AutomationCompositions.class); assertNotNull(automationCompositionsQuery); assertThat(automationCompositionsQuery.getAutomationCompositionList()).hasSize(1); - assertEquals(automationComposition, automationCompositionsQuery.getAutomationCompositionList().get(0)); + var automationCompositionRc = automationCompositionsQuery.getAutomationCompositionList().get(0); + automationComposition.setLastMsg(automationCompositionRc.getLastMsg()); + assertEquals(automationComposition, automationCompositionRc); } @Test @@ -241,6 +244,7 @@ class InstantiationControllerTest extends CommonRestController { assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); var automationCompositionGet = rawresp.readEntity(AutomationComposition.class); assertNotNull(automationCompositionGet); + automationComposition.setLastMsg(automationCompositionGet.getLastMsg()); assertEquals(automationComposition, automationCompositionGet); } @@ -272,7 +276,9 @@ class InstantiationControllerTest extends CommonRestController { assertNotNull(automationCompositionsFromDb); assertThat(automationCompositionsFromDb.getAutomationCompositionList()).hasSize(1); - assertEquals(automationComposition, automationCompositionsFromDb.getAutomationCompositionList().get(0)); + var acFromDb = automationCompositionsFromDb.getAutomationCompositionList().get(0); + automationComposition.setLastMsg(acFromDb.getLastMsg()); + assertEquals(automationComposition, acFromDb); } @Test diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java index 8ed250fba..d5163be14 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java @@ -243,10 +243,15 @@ class SupervisionScannerTest { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DEPLOYING); automationComposition.setLockState(LockState.NONE); + automationComposition.setPhase(0); automationComposition.setCompositionId(compositionId); - for (Map.Entry<UUID, AutomationCompositionElement> entry : automationComposition.getElements().entrySet()) { + for (var entry : automationComposition.getElements().entrySet()) { entry.getValue().setDeployState(DeployState.DEPLOYING); } + // the first element is already completed + automationComposition.getElements().entrySet().iterator().next().getValue() + .setDeployState(DeployState.DEPLOYED); + var automationCompositionProvider = mock(AutomationCompositionProvider.class); when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); @@ -261,14 +266,22 @@ class SupervisionScannerTest { acRuntimeParameterGroup); automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); + automationComposition.setLastMsg(TimestampHelper.now()); scannerObj2.run(); verify(automationCompositionProvider, times(1)).updateAutomationComposition(any(AutomationComposition.class)); assertEquals(StateChangeResult.TIMEOUT, automationComposition.getStateChangeResult()); + //already in TIMEOUT + clearInvocations(automationCompositionProvider); + scannerObj2.run(); + verify(automationCompositionProvider, times(0)).updateAutomationComposition(any(AutomationComposition.class)); + + clearInvocations(automationCompositionProvider); for (Map.Entry<UUID, AutomationCompositionElement> entry : automationComposition.getElements().entrySet()) { entry.getValue().setDeployState(DeployState.DEPLOYED); } scannerObj2.run(); + verify(automationCompositionProvider, times(1)).updateAutomationComposition(any(AutomationComposition.class)); assertEquals(StateChangeResult.NO_ERROR, automationComposition.getStateChangeResult()); } @@ -277,6 +290,7 @@ class SupervisionScannerTest { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DEPLOYING); automationComposition.setLockState(LockState.NONE); + automationComposition.setPhase(0); automationComposition.setCompositionId(compositionId); for (var element : automationComposition.getElements().values()) { if ("org.onap.domain.database.Http_PMSHMicroserviceAutomationCompositionElement" @@ -314,10 +328,15 @@ class SupervisionScannerTest { var compositionTargetId = UUID.randomUUID(); automationComposition.setCompositionTargetId(compositionTargetId); automationComposition.setLockState(LockState.LOCKED); + automationComposition.setLastMsg(TimestampHelper.now()); + automationComposition.setPhase(0); for (var element : automationComposition.getElements().values()) { element.setDeployState(DeployState.DEPLOYED); element.setLockState(LockState.LOCKED); } + // first element is not migrated yet + automationComposition.getElements().entrySet().iterator().next().getValue() + .setDeployState(DeployState.MIGRATING); var automationCompositionProvider = mock(AutomationCompositionProvider.class); when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); @@ -331,7 +350,15 @@ class SupervisionScannerTest { acRuntimeParameterGroup); supervisionScanner.run(); + verify(automationCompositionProvider, times(0)).updateAutomationComposition(any(AutomationComposition.class)); + assertEquals(DeployState.MIGRATING, automationComposition.getDeployState()); + + // first element is migrated + automationComposition.getElements().entrySet().iterator().next().getValue() + .setDeployState(DeployState.DEPLOYED); + supervisionScanner.run(); verify(automationCompositionProvider, times(1)).updateAutomationComposition(any(AutomationComposition.class)); + assertEquals(DeployState.DEPLOYED, automationComposition.getDeployState()); assertEquals(compositionTargetId, automationComposition.getCompositionId()); } @@ -342,6 +369,7 @@ class SupervisionScannerTest { automationComposition.setDeployState(DeployState.DEPLOYED); automationComposition.setLockState(LockState.UNLOCKING); automationComposition.setCompositionId(compositionId); + automationComposition.setPhase(0); for (var element : automationComposition.getElements().values()) { if ("org.onap.domain.database.Http_PMSHMicroserviceAutomationCompositionElement" .equals(element.getDefinition().getName())) { diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandlerTest.java deleted file mode 100644 index 21c5b3d2c..000000000 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandlerTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.acm.runtime.supervision; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class TimeoutHandlerTest { - - private static final int ID = 1; - - @Test - void testFault() { - var timeoutHandler = new TimeoutHandler<Integer>(); - timeoutHandler.setTimeout(ID); - assertThat(timeoutHandler.isTimeout(ID)).isTrue(); - timeoutHandler.clear(ID); - assertThat(timeoutHandler.isTimeout(ID)).isFalse(); - } - - @Test - void testDuration() { - var timeoutHandler = new TimeoutHandler<Integer>() { - long epochMilli = 0; - - @Override - protected long getEpochMilli() { - return epochMilli; - } - }; - timeoutHandler.epochMilli = 100; - var result = timeoutHandler.getDuration(ID); - assertThat(result).isZero(); - - timeoutHandler.epochMilli += 100; - result = timeoutHandler.getDuration(ID); - assertThat(result).isEqualTo(100); - - timeoutHandler.epochMilli += 100; - result = timeoutHandler.getDuration(ID); - assertThat(result).isEqualTo(200); - - timeoutHandler.epochMilli += 100; - timeoutHandler.clear(ID); - result = timeoutHandler.getDuration(ID); - assertThat(result).isZero(); - } -} |