diff options
author | 2025-02-18 14:11:52 +0000 | |
---|---|---|
committer | 2025-02-18 17:18:52 +0000 | |
commit | 5b42ebe43ce4201ebea05a157e8ca71d0c5ece51 (patch) | |
tree | efeeb270c095a474093fd510d276cd7c02334282 /models | |
parent | 18cee276924e749754fc0a4fe5e021f4f10e9c07 (diff) |
Update ACM-r message handling architecture in ACM
Issue-ID: POLICY-5286
Change-Id: I8e74bc1dcdfcbed258778e88542bdef5fe1e9149
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
Diffstat (limited to 'models')
6 files changed, 497 insertions, 203 deletions
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java index 6de27f76f..bd99a756b 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java @@ -24,18 +24,16 @@ import jakarta.ws.rs.core.Response; import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition; -import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState; -import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.document.base.ToscaServiceTemplateValidation; import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionDefinition; -import org.onap.policy.clamp.models.acm.persistence.concepts.JpaNodeTemplateState; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionDefinitionRepository; -import org.onap.policy.clamp.models.acm.persistence.repository.NodeTemplateStateRepository; import org.onap.policy.clamp.models.acm.utils.AcmUtils; import org.onap.policy.clamp.models.acm.utils.TimestampHelper; import org.onap.policy.common.parameters.BeanValidationResult; @@ -43,7 +41,6 @@ import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; import org.springframework.data.domain.Example; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @Service @@ -54,7 +51,6 @@ public class AcDefinitionProvider { private static final String NAME = "AutomationCompositionDefinition"; private final AutomationCompositionDefinitionRepository acmDefinitionRepository; - private final NodeTemplateStateRepository nodeTemplateStateRepository; /** * Create Automation Composition Definition. @@ -147,40 +143,6 @@ public class AcDefinitionProvider { } /** - * Update Ac Definition AcTypeState, StateChangeResult and restarting. - * - * @param compositionId The UUID of the automation composition definition to update - * @param state the AcTypeState - * @param stateChangeResult the StateChangeResult - */ - public void updateAcDefinitionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult) { - var jpaUpdate = acmDefinitionRepository.findById(compositionId.toString()); - if (jpaUpdate.isEmpty()) { - String errorMessage = "update of Automation Composition Definition \"" + compositionId - + "\" failed, Automation Composition Definition does not exist"; - throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage); - } - var acDefinition = jpaUpdate.get(); - acDefinition.setState(state); - acDefinition.setStateChangeResult(stateChangeResult); - acmDefinitionRepository.save(acDefinition); - acmDefinitionRepository.flush(); - } - - /** - * Update Ac DefinitionElement. - * - * @param nodeTemplateState the NodeTemplateState - * @param compositionId The UUID of the automation composition definition - */ - public void updateAcDefinitionElement(NodeTemplateState nodeTemplateState, UUID compositionId) { - var jpaNodeTemplateState = new JpaNodeTemplateState( - nodeTemplateState.getNodeTemplateStateId().toString(), compositionId.toString()); - jpaNodeTemplateState.fromAuthorative(nodeTemplateState); - nodeTemplateStateRepository.save(jpaNodeTemplateState); - } - - /** * Delete Automation Composition Definition. * * @param compositionId The UUID of the automation composition definition to delete @@ -222,7 +184,7 @@ public class AcDefinitionProvider { * @param compositionId The UUID of the automation composition definition to delete * @return the automation composition definition */ - @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) + @Transactional(readOnly = true) public Optional<AutomationCompositionDefinition> findAcDefinition(UUID compositionId) { var jpaGet = acmDefinitionRepository.findById(compositionId.toString()); return jpaGet.stream().map(JpaAutomationCompositionDefinition::toAuthorative).findFirst(); @@ -234,9 +196,10 @@ public class AcDefinitionProvider { * @return the Automation Composition Definitions found */ @Transactional(readOnly = true) - public List<AutomationCompositionDefinition> getAllAcDefinitionsInTransition() { + public Set<UUID> getAllAcDefinitionsInTransition() { var jpaList = acmDefinitionRepository.findByStateIn(List.of(AcTypeState.PRIMING, AcTypeState.DEPRIMING)); - return ProviderUtils.asEntityList(jpaList); + return jpaList.stream().map(JpaAutomationCompositionDefinition::getCompositionId) + .map(UUID::fromString).collect(Collectors.toSet()); } /** diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java index ab80bc277..3bfcf72ed 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation. + * Copyright (C) 2021-2025 Nordix Foundation. * ================================================================================ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -24,20 +24,19 @@ package org.onap.policy.clamp.models.acm.persistence.provider; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; -import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import lombok.AllArgsConstructor; import lombok.NonNull; import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; -import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo; 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.SubState; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition; -import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionElement; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository; import org.onap.policy.clamp.models.acm.utils.AcmUtils; @@ -118,23 +117,6 @@ public class AutomationCompositionProvider { return result.toAuthorative(); } - - /** - * Update automation composition state. - * - * @param acSource the automation composition to update - * @return the updated automation composition - */ - public AutomationComposition updateAcState(final AutomationComposition acSource) { - var automationComposition = automationCompositionRepository - .getReferenceById(acSource.getInstanceId().toString()); - automationComposition.fromAuthorativeBase(acSource); - var result = automationCompositionRepository.save(automationComposition); - automationCompositionRepository.flush(); - // Return the saved automation composition - return result.toAuthorative(); - } - /** * Update automation composition. * @@ -168,14 +150,15 @@ public class AutomationCompositionProvider { * @return all automation compositions found */ @Transactional(readOnly = true) - public List<AutomationComposition> getAcInstancesInTransition() { + public Set<UUID> getAcInstancesInTransition() { var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING, DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING)); jpaList.addAll(automationCompositionRepository.findByLockStateIn( List.of(LockState.LOCKING, LockState.UNLOCKING))); jpaList.addAll(automationCompositionRepository.findBySubStateIn( List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING))); - return ProviderUtils.asEntityList(jpaList); + return jpaList.stream().map(JpaAutomationComposition::getInstanceId) + .map(UUID::fromString).collect(Collectors.toSet()); } /** @@ -227,49 +210,6 @@ public class AutomationCompositionProvider { } /** - * Upgrade States. - * - * @param automationCompositionInfoList list of AutomationCompositionInfo - */ - public void upgradeStates(@NonNull final List<AutomationCompositionInfo> automationCompositionInfoList) { - if (automationCompositionInfoList.isEmpty()) { - return; - } - List<JpaAutomationCompositionElement> jpaList = new ArrayList<>(); - for (var acInstance : automationCompositionInfoList) { - for (var element : acInstance.getElements()) { - var jpa = acElementRepository.getReferenceById(element.getAutomationCompositionElementId().toString()); - jpa.setUseState(element.getUseState()); - jpa.setOperationalState(element.getOperationalState()); - jpa.setOutProperties(element.getOutProperties()); - jpaList.add(jpa); - } - } - acElementRepository.saveAll(jpaList); - } - - /** - * Update AutomationCompositionElement. - * - * @param element the AutomationCompositionElement - */ - public void updateAutomationCompositionElement(@NonNull final AutomationCompositionElement element) { - var jpaAcElement = acElementRepository.getReferenceById(element.getId().toString()); - jpaAcElement.setMessage(element.getMessage()); - jpaAcElement.setOutProperties(element.getOutProperties()); - jpaAcElement.setOperationalState(element.getOperationalState()); - jpaAcElement.setUseState(element.getUseState()); - jpaAcElement.setDeployState(element.getDeployState()); - jpaAcElement.setLockState(element.getLockState()); - jpaAcElement.setSubState(element.getSubState()); - jpaAcElement.setStage(element.getStage()); - jpaAcElement.setRestarting(element.getRestarting()); - - ProviderUtils.validate(element, jpaAcElement, "AutomationCompositionElement"); - acElementRepository.save(jpaAcElement); - } - - /** * Delete AutomationCompositionElement. * * @param elementId the AutomationCompositionElement Id diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProvider.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProvider.java new file mode 100644 index 000000000..c3e5543d9 --- /dev/null +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProvider.java @@ -0,0 +1,238 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2025 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.provider; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import org.onap.policy.clamp.models.acm.document.concepts.DocMessage; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantAckMessage; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaMessage; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaMessageJob; +import org.onap.policy.clamp.models.acm.persistence.repository.MessageJobRepository; +import org.onap.policy.clamp.models.acm.persistence.repository.MessageRepository; +import org.onap.policy.clamp.models.acm.utils.AcmUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@AllArgsConstructor +public class MessageProvider { + + private final MessageRepository messageRepository; + private final MessageJobRepository messageJobRepository; + + /** + * Save ParticipantPrimeAck message. + * + * @param message the ParticipantPrimeAck message + */ + public void save(ParticipantPrimeAck message) { + var doc = from(message); + doc.setCompositionState(message.getCompositionState()); + doc.setMessage(AcmUtils.validatedMessage(message.getMessage())); + var jpa = new JpaMessage(message.getCompositionId().toString(), doc); + ProviderUtils.validate(doc, jpa, "ParticipantPrimeAck message"); + messageRepository.save(jpa); + } + + /** + * Save AutomationCompositionDeployAck message. + * + * @param message the AutomationCompositionDeployAck message + */ + public void save(AutomationCompositionDeployAck message) { + for (var entry : message.getAutomationCompositionResultMap().entrySet()) { + var doc = from(message); + doc.setStage(message.getStage()); + doc.setInstanceElementId(entry.getKey()); + doc.setInstanceId(message.getAutomationCompositionId()); + doc.setMessage(AcmUtils.validatedMessage(entry.getValue().getMessage())); + doc.setDeployState(entry.getValue().getDeployState()); + doc.setLockState(entry.getValue().getLockState()); + var jpa = new JpaMessage(message.getAutomationCompositionId().toString(), doc); + ProviderUtils.validate(doc, jpa, "AutomationCompositionDeployAck message"); + messageRepository.save(jpa); + } + } + + /** + * Save ParticipantStatus message. + * + * @param message the ParticipantStatus message + */ + public void save(ParticipantStatus message) { + if (!message.getAutomationCompositionInfoList().isEmpty()) { + saveInstanceOutProperties(message); + } + if (!message.getParticipantDefinitionUpdates().isEmpty()) { + saveCompositionOutProperties(message); + } + } + + private void saveInstanceOutProperties(ParticipantStatus message) { + for (var instance : message.getAutomationCompositionInfoList()) { + for (var element : instance.getElements()) { + var jpa = new JpaMessage(); + jpa.setIdentificationId(instance.getAutomationCompositionId().toString()); + var doc = from(message); + doc.setInstanceId(instance.getAutomationCompositionId()); + doc.setUseState(element.getUseState()); + doc.setOperationalState(element.getOperationalState()); + doc.setOutProperties(element.getOutProperties()); + doc.setInstanceElementId(element.getAutomationCompositionElementId()); + jpa.fromAuthorative(doc); + ProviderUtils.validate(doc, jpa, "ParticipantStatus instance message"); + messageRepository.save(jpa); + } + } + } + + private void saveCompositionOutProperties(ParticipantStatus message) { + for (var acDefinition : message.getParticipantDefinitionUpdates()) { + for (var element : acDefinition.getAutomationCompositionElementDefinitionList()) { + var jpa = new JpaMessage(); + jpa.setIdentificationId(message.getCompositionId().toString()); + var doc = from(message); + doc.setOutProperties(element.getOutProperties()); + doc.setAcElementDefinitionId(element.getAcElementDefinitionId()); + jpa.fromAuthorative(doc); + ProviderUtils.validate(doc, jpa, "ParticipantStatus composition message"); + messageRepository.save(jpa); + } + } + } + + private DocMessage from(ParticipantStatus message) { + var doc = new DocMessage(); + doc.setMessageType(message.getMessageType()); + doc.setCompositionId(message.getCompositionId()); + doc.setParticipantId(message.getParticipantId()); + doc.setReplicaId(message.getReplicaId()); + doc.setMessageType(message.getMessageType()); + return doc; + } + + private DocMessage from(ParticipantAckMessage message) { + var doc = new DocMessage(); + doc.setMessageType(message.getMessageType()); + doc.setCompositionId(message.getCompositionId()); + doc.setStateChangeResult(message.getStateChangeResult()); + doc.setParticipantId(message.getParticipantId()); + doc.setReplicaId(message.getReplicaId()); + return doc; + } + + @Transactional(readOnly = true) + public List<DocMessage> getAllMessages(UUID identificationId) { + var result = messageRepository.findByIdentificationIdOrderByLastMsgDesc(identificationId.toString()); + return result.stream().map(JpaMessage::toAuthorative).toList(); + } + + /** + * Find all Composition ids from Messages. + * + * @return set of Composition ids + */ + @Transactional(readOnly = true) + public Set<UUID> findCompositionMessages() { + var result = messageRepository.findAll(); + return result.stream() + .map(JpaMessage::toAuthorative) + .filter(doc -> doc.getInstanceId() == null) + .map(DocMessage::getCompositionId) + .collect(Collectors.toSet()); + } + + /** + * Find all Instance ids from Messages. + * + * @return set of Instance ids + */ + @Transactional(readOnly = true) + public Set<UUID> findInstanceMessages() { + var result = messageRepository.findAll(); + return result.stream() + .map(JpaMessage::toAuthorative) + .map(DocMessage::getInstanceId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + /** + * Remove the message. + * + * @param messageId the messageId + */ + public void removeMessage(String messageId) { + messageRepository.deleteById(messageId); + } + + /** + * Remove old jobs. + */ + public void removeOldJobs() { + var list = messageJobRepository.findAll(); + var old = Timestamp.from(Instant.now().minusSeconds(200)); + for (var job : list) { + if (job.getJobStarted().before(old)) { + messageJobRepository.deleteById(job.getJobId()); + } + } + } + + /** + * Create new Job related to the identificationId. + * + * @param identificationId the instanceId or compositionId + * + * @return the jobId if the job has been created + */ + public Optional<String> createJob(UUID identificationId) { + var opt = messageJobRepository.findByIdentificationId(identificationId.toString()); + if (opt.isPresent()) { + // already exist a job with this identificationId + return Optional.empty(); + } + var job = new JpaMessageJob(identificationId.toString()); + var result = messageJobRepository.save(job); + return Optional.of(result.getJobId()); + } + + /** + * Remove the job by jobId. + * + * @param jobId the jobId + */ + public void removeJob(String jobId) { + messageJobRepository.deleteById(jobId); + } +} diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java index b6fbe093b..bc0a0939e 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java @@ -23,7 +23,6 @@ package org.onap.policy.clamp.models.acm.persistence.provider; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -39,12 +38,9 @@ import org.mockito.Mockito; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition; import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState; -import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionDefinition; -import org.onap.policy.clamp.models.acm.persistence.concepts.JpaNodeTemplateState; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionDefinitionRepository; -import org.onap.policy.clamp.models.acm.persistence.repository.NodeTemplateStateRepository; import org.onap.policy.clamp.models.acm.utils.CommonTestData; import org.onap.policy.clamp.models.acm.utils.TimestampHelper; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -68,7 +64,7 @@ class AcDefinitionProviderTest { @Test void testBadRequest() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var compositionId = UUID.randomUUID(); var serviceTemplate = new ToscaServiceTemplate(); @@ -82,10 +78,6 @@ class AcDefinitionProviderTest { var acmDefinition = getAcDefinition(docServiceTemplate); assertThatThrownBy(() -> acDefinitionProvider.updateAcDefinition(acmDefinition, "CompositionName")) .hasMessageStartingWith("\"AutomationCompositionDefinition\" INVALID, item has status INVALID"); - - assertThatThrownBy(() -> acDefinitionProvider.updateAcDefinitionState(compositionId, AcTypeState.PRIMED, - StateChangeResult.NO_ERROR)) - .hasMessageStartingWith("update of Automation Composition Definition"); } @BeforeAll @@ -120,7 +112,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.save(any(JpaAutomationCompositionDefinition.class))) .thenReturn(new JpaAutomationCompositionDefinition(acmDefinition)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); @@ -132,7 +124,7 @@ class AcDefinitionProviderTest { void testToscaWithInvalidElement() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); assertThatThrownBy(() -> acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, INVALID_ELEMENT_NAME, NODE_TYPE)) @@ -143,7 +135,7 @@ class AcDefinitionProviderTest { void testToscaWithInvalidNodeType() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); assertThatThrownBy(() -> acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, INVALID_NODE_TYPE)) @@ -160,7 +152,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.save(any(JpaAutomationCompositionDefinition.class))) .thenReturn(new JpaAutomationCompositionDefinition(acmDefinition)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); inputServiceTemplate.setMetadata(new HashMap<>()); var result = acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); @@ -172,7 +164,7 @@ class AcDefinitionProviderTest { @Test void testUpdateServiceTemplate() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); acDefinitionProvider.updateServiceTemplate(UUID.randomUUID(), inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); verify(acmDefinitionRepository).save(any(JpaAutomationCompositionDefinition.class)); } @@ -180,7 +172,7 @@ class AcDefinitionProviderTest { @Test void testUpdateAcDefinition() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var acmDefinition = getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate)); acDefinitionProvider.updateAcDefinition(acmDefinition, NODE_TYPE); verify(acmDefinitionRepository).save(any(JpaAutomationCompositionDefinition.class)); @@ -189,40 +181,20 @@ class AcDefinitionProviderTest { @Test void testUpdateAcDefinitionState() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var acmDefinition = getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate)); acmDefinition.setState(AcTypeState.PRIMING); - var jpa = new JpaAutomationCompositionDefinition(acmDefinition); - when(acmDefinitionRepository.findById(acmDefinition.getCompositionId().toString())) - .thenReturn(Optional.of(jpa)); - acDefinitionProvider.updateAcDefinitionState(acmDefinition.getCompositionId(), AcTypeState.PRIMED, - StateChangeResult.NO_ERROR); - verify(acmDefinitionRepository).save(jpa); - - clearInvocations(acmDefinitionRepository); acDefinitionProvider.updateAcDefinitionState(acmDefinition); verify(acmDefinitionRepository).save(any()); } @Test - void testUpdateAcDefinitionElement() { - var nodeTemplateState = new NodeTemplateState(); - nodeTemplateState.setNodeTemplateId(new ToscaConceptIdentifier("name", "1.0.0")); - nodeTemplateState.setNodeTemplateStateId(UUID.randomUUID()); - nodeTemplateState.setState(AcTypeState.PRIMED); - var nodeTemplateStateRepository = mock(NodeTemplateStateRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(null, nodeTemplateStateRepository); - acDefinitionProvider.updateAcDefinitionElement(nodeTemplateState, UUID.randomUUID()); - verify(nodeTemplateStateRepository).save(any(JpaNodeTemplateState.class)); - } - - @Test void testGetAcDefinition() { var jpa = new JpaAutomationCompositionDefinition(); jpa.fromAuthorative(getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate))); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); when(acmDefinitionRepository.findById(jpa.getCompositionId())).thenReturn(Optional.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider.getAcDefinition(UUID.fromString(jpa.getCompositionId())); assertThat(result).isNotNull(); } @@ -230,7 +202,7 @@ class AcDefinitionProviderTest { @Test void testGetAcDefinitionNotFound() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var compositionId = UUID.randomUUID(); assertThatThrownBy(() -> acDefinitionProvider.getAcDefinition(compositionId)) .hasMessage("Get serviceTemplate \"" + compositionId + "\" failed, serviceTemplate does not exist"); @@ -242,7 +214,7 @@ class AcDefinitionProviderTest { jpa.fromAuthorative(getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate))); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); when(acmDefinitionRepository.findById(jpa.getCompositionId())).thenReturn(Optional.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var compositionId = UUID.fromString(jpa.getCompositionId()); var result = acDefinitionProvider.findAcDefinition(compositionId); assertThat(result).isNotEmpty(); @@ -257,7 +229,7 @@ class AcDefinitionProviderTest { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); when(acmDefinitionRepository.findByStateIn(List.of(AcTypeState.PRIMING, AcTypeState.DEPRIMING))) .thenReturn(List.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider.getAllAcDefinitionsInTransition(); assertThat(result).isNotEmpty(); } @@ -271,7 +243,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findById(acmDefinition.getCompositionId().toString())) .thenReturn(Optional.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider.deleteAcDefintion(acmDefinition.getCompositionId()); assertThat(result).isEqualTo(docServiceTemplate.toAuthorative()); @@ -281,7 +253,7 @@ class AcDefinitionProviderTest { void testDeleteServiceTemplateEmpty() { var compositionId = UUID.randomUUID(); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); assertThatThrownBy(() -> acDefinitionProvider.deleteAcDefintion(compositionId)) .hasMessage("delete of Automation Composition Definition \"" + compositionId + "\" failed, Automation Composition Definition does not exist"); @@ -295,7 +267,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findAll(Mockito.<Example<JpaAutomationCompositionDefinition>>any())) .thenReturn(List.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider.getServiceTemplateList(inputServiceTemplate.getName(), inputServiceTemplate.getVersion()); @@ -311,7 +283,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findAll(Mockito.<Example<JpaAutomationCompositionDefinition>>any())) .thenReturn(List.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); var result = acDefinitionProvider.getServiceTemplateList(null, inputServiceTemplate.getVersion()); 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 c2368fe10..67a05be16 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 @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation. + * Copyright (C) 2021-2025 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,11 +22,9 @@ package org.onap.policy.clamp.models.acm.persistence.provider; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyIterable; -import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -38,8 +36,6 @@ import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo; -import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; @@ -55,7 +51,6 @@ import org.springframework.data.domain.Example; class AutomationCompositionProviderTest { private static final String AC_IS_NULL = "automationComposition is marked non-null but is null"; - private static final String ACELEMENT_IS_NULL = "element is marked non-null but is null"; private static final String ACELEMENT_ID_IS_NULL = "elementId is marked non-null but is null"; private static final Coder CODER = new StandardCoder(); @@ -199,7 +194,9 @@ class AutomationCompositionProviderTest { when(automationCompositionRepository.findByLockStateIn(List.of(LockState.LOCKING, LockState.UNLOCKING))) .thenReturn(List.of(inputAutomationCompositionsJpa.get(1))); var acList = automationCompositionProvider.getAcInstancesInTransition(); - assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList); + assertThat(acList).hasSize(2) + .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId()) + .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId()); } @Test @@ -221,27 +218,6 @@ class AutomationCompositionProviderTest { } @Test - void testAutomationCompositionElementUpdate() { - var acElementRepository = mock(AutomationCompositionElementRepository.class); - var automationCompositionProvider = new AutomationCompositionProvider( - mock(AutomationCompositionRepository.class), acElementRepository); - - assertThatThrownBy(() -> automationCompositionProvider.updateAutomationCompositionElement(null)) - .hasMessageMatching(ACELEMENT_IS_NULL); - - var acElement = inputAutomationCompositions.getAutomationCompositionList().get(0).getElements().values() - .iterator().next(); - var jpa = new JpaAutomationCompositionElement(); - jpa.setElementId(acElement.getId().toString()); - jpa.setInstanceId(UUID.randomUUID().toString()); - jpa.fromAuthorative(acElement); - when(acElementRepository.getReferenceById(acElement.getId().toString())).thenReturn(jpa); - - automationCompositionProvider.updateAutomationCompositionElement(acElement); - verify(acElementRepository).save(any()); - } - - @Test void testDeleteElementById() { var acElementRepository = mock(AutomationCompositionElementRepository.class); var automationCompositionProvider = new AutomationCompositionProvider( @@ -282,26 +258,4 @@ class AutomationCompositionProviderTest { result = automationCompositionProvider.validateElementIds(ac); assertThat(result.isValid()).isTrue(); } - - @Test - void testUpgradeStates() { - var acElementRepository = mock(AutomationCompositionElementRepository.class); - var automationCompositionProvider = new AutomationCompositionProvider( - mock(AutomationCompositionRepository.class), acElementRepository); - - assertDoesNotThrow(() -> automationCompositionProvider.upgradeStates(List.of())); - var acElement = inputAutomationCompositions.getAutomationCompositionList().get(0).getElements().values() - .iterator().next(); - - var acInfo = new AutomationCompositionInfo(); - var acElementInfo = new AutomationCompositionElementInfo(); - acInfo.setElements(List.of(acElementInfo)); - acElementInfo.setAutomationCompositionElementId(acElement.getId()); - - when(acElementRepository.getReferenceById(acElement.getId().toString())) - .thenReturn(new JpaAutomationCompositionElement(acElement)); - - automationCompositionProvider.upgradeStates(List.of(acInfo)); - verify(acElementRepository).saveAll(anyList()); - } } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProviderTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProviderTest.java new file mode 100644 index 000000000..8276d5627 --- /dev/null +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/MessageProviderTest.java @@ -0,0 +1,227 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2025 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.provider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck; +import org.onap.policy.clamp.models.acm.concepts.AcTypeState; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo; +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.ParticipantDefinition; +import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.document.concepts.DocMessage; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaMessage; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaMessageJob; +import org.onap.policy.clamp.models.acm.persistence.repository.MessageJobRepository; +import org.onap.policy.clamp.models.acm.persistence.repository.MessageRepository; +import org.onap.policy.clamp.models.acm.utils.CommonTestData; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +class MessageProviderTest { + + @Test + void testSaveParticipantPrimeAck() { + var message = new ParticipantPrimeAck(); + message.setCompositionState(AcTypeState.PRIMED); + message.setCompositionId(UUID.randomUUID()); + message.setParticipantId(UUID.randomUUID()); + message.setReplicaId(UUID.randomUUID()); + var messageRepository = mock(MessageRepository.class); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + messageProvider.save(message); + verify(messageRepository).save(any()); + } + + @Test + void testSaveAutomationCompositionDeployAck() { + var message = new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK); + message.setAutomationCompositionId(UUID.randomUUID()); + message.setCompositionId(UUID.randomUUID()); + message.setStateChangeResult(StateChangeResult.NO_ERROR); + message.setParticipantId(UUID.randomUUID()); + message.setReplicaId(UUID.randomUUID()); + var element = new AcElementDeployAck(DeployState.DEPLOYED, + LockState.LOCKED, null, null, Map.of(), true, ""); + message.setAutomationCompositionResultMap(Map.of(UUID.randomUUID(), element)); + var messageRepository = mock(MessageRepository.class); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + messageProvider.save(message); + verify(messageRepository).save(any()); + } + + @Test + void testSaveParticipantStatusComposition() { + var message = new ParticipantStatus(); + message.setCompositionId(UUID.randomUUID()); + message.setParticipantId(UUID.randomUUID()); + message.setReplicaId(UUID.randomUUID()); + var participantDefinition = new ParticipantDefinition(); + participantDefinition.setParticipantId(message.getParticipantId()); + var element = CommonTestData.getAcElementDefinition(new ToscaConceptIdentifier("name", "1.0.0")); + element.setOutProperties(Map.of("compositionProperty", "value")); + participantDefinition.setAutomationCompositionElementDefinitionList(List.of(element)); + message.setParticipantDefinitionUpdates(List.of(participantDefinition)); + var messageRepository = mock(MessageRepository.class); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + messageProvider.save(message); + verify(messageRepository).save(any()); + } + + @Test + void testSaveParticipantStatusInstance() { + var message = new ParticipantStatus(); + message.setCompositionId(UUID.randomUUID()); + message.setParticipantId(UUID.randomUUID()); + message.setReplicaId(UUID.randomUUID()); + var automationCompositionInfo = new AutomationCompositionInfo(); + automationCompositionInfo.setAutomationCompositionId(UUID.randomUUID()); + var element = new AutomationCompositionElementInfo(); + element.setAutomationCompositionElementId(UUID.randomUUID()); + element.setOutProperties(Map.of("instanceProperty", "value")); + automationCompositionInfo.setElements(List.of(element)); + message.setAutomationCompositionInfoList(List.of(automationCompositionInfo)); + var messageRepository = mock(MessageRepository.class); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + messageProvider.save(message); + verify(messageRepository).save(any()); + } + + @Test + void testGetAllMessages() { + var messageRepository = mock(MessageRepository.class); + var instanceId = UUID.randomUUID(); + var jpaMessage = new JpaMessage(); + when(messageRepository.findByIdentificationIdOrderByLastMsgDesc(instanceId.toString())) + .thenReturn(List.of(jpaMessage)); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + var result = messageProvider.getAllMessages(instanceId); + assertThat(result).hasSize(1); + var doc = result.iterator().next(); + assertEquals(jpaMessage.getMessageId(), doc.getMessageId()); + } + + @Test + void testFindCompositionMessages() { + var jpa1 = createJpaCompositionMessage(); + var jpa2 = createJpaInstanceMessage(); + var messageRepository = mock(MessageRepository.class); + when(messageRepository.findAll()).thenReturn(List.of(jpa1, jpa2)); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + var result = messageProvider.findCompositionMessages(); + assertThat(result).hasSize(1); + var compositionId = result.iterator().next(); + assertEquals(jpa1.getDocMessage().getCompositionId(), compositionId); + } + + private JpaMessage createJpaCompositionMessage() { + var message = new DocMessage(); + message.setCompositionId(UUID.randomUUID()); + return new JpaMessage(message.getCompositionId().toString(), message); + } + + private JpaMessage createJpaInstanceMessage() { + var message = new DocMessage(); + message.setCompositionId(UUID.randomUUID()); + message.setInstanceId(UUID.randomUUID()); + return new JpaMessage(message.getInstanceId().toString(), message); + } + + @Test + void testFindInstanceMessages() { + var jpa1 = createJpaCompositionMessage(); + var jpa2 = createJpaInstanceMessage(); + var messageRepository = mock(MessageRepository.class); + when(messageRepository.findAll()).thenReturn(List.of(jpa1, jpa2)); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + var result = messageProvider.findInstanceMessages(); + assertThat(result).hasSize(1); + var instanceId = result.iterator().next(); + assertEquals(jpa2.getDocMessage().getInstanceId(), instanceId); + } + + @Test + void testRemoveMessage() { + var messageRepository = mock(MessageRepository.class); + var messageProvider = new MessageProvider(messageRepository, mock(MessageJobRepository.class)); + var messageId = UUID.randomUUID(); + messageProvider.removeMessage(messageId.toString()); + verify(messageRepository).deleteById(messageId.toString()); + } + + @Test + void testRemoveOldJobs() { + var messageJobRepository = mock(MessageJobRepository.class); + var jpaJob1 = new JpaMessageJob(UUID.randomUUID().toString()); + var jpaJob2 = new JpaMessageJob(UUID.randomUUID().toString()); + var old = Timestamp.from(Instant.now().minusSeconds(200)); + jpaJob2.setJobStarted(old); + when(messageJobRepository.findAll()).thenReturn(List.of(jpaJob1, jpaJob2)); + var messageProvider = new MessageProvider(mock(MessageRepository.class), messageJobRepository); + messageProvider.removeOldJobs(); + verify(messageJobRepository, times(0)).deleteById(jpaJob1.getJobId()); + verify(messageJobRepository).deleteById(jpaJob2.getJobId()); + } + + @Test + void testCreateJob() { + var messageJobRepository = mock(MessageJobRepository.class); + var identificationId = UUID.randomUUID(); + var jpaJob = new JpaMessageJob(identificationId.toString()); + when(messageJobRepository.save(any())).thenReturn(jpaJob); + var messageProvider = new MessageProvider(mock(MessageRepository.class), messageJobRepository); + var opt = messageProvider.createJob(identificationId); + assertThat(opt).isNotEmpty(); + assertEquals(jpaJob.getJobId(), opt.get()); + + when(messageJobRepository.findByIdentificationId(identificationId.toString())).thenReturn(Optional.of(jpaJob)); + opt = messageProvider.createJob(identificationId); + assertThat(opt).isEmpty(); + } + + @Test + void testRemoveJob() { + var messageJobRepository = mock(MessageJobRepository.class); + var messageProvider = new MessageProvider(mock(MessageRepository.class), messageJobRepository); + var jobId = UUID.randomUUID().toString(); + messageProvider.removeJob(jobId); + verify(messageJobRepository).deleteById(jobId); + } +} |