Fix TIMEOUT support in MIGRATING.
Avoid conflicts updating AC instance Element instead
of a full AC instance.
Using ExecutorService to send messages to the participant,
the transaction will completed before the message is sent.
Issue-ID: POLICY-4811
Change-Id: I2730ae694c8a5c9edfe500b1fa93cfb3787f32c5
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
// timeout
this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, DEPLOY);
- this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
- this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UPDATING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
-
this.graph.put(new String[] {DEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, DEPLOY);
+
+ this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
+ this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UPDATING, LOCKED, TIMEOUT}, UNDEPLOY);
+ this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, MIGRATING, LOCKED, TIMEOUT}, UNDEPLOY);
this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
this.graph.put(new String[] {DELETE, LOCK_NONE, DELETING, LOCK_NONE, TIMEOUT}, DELETE);
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.models.tosca.authorative.concepts.ToscaConceptIdentifier;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
/**
* @param instanceId the ID of the automation composition to get
* @return the automation composition found
*/
- @Transactional(readOnly = true)
+ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
public Optional<AutomationComposition> findAutomationComposition(final UUID instanceId) {
var result = automationCompositionRepository.findById(instanceId.toString());
return result.stream().map(JpaAutomationComposition::toAuthorative).findFirst();
}
acElementRepository.saveAll(jpaList);
}
+
+ /**
+ * Update AutomationCompositionElement.
+ *
+ * @param element the AutomationCompositionElement
+ * @param instanceId the instance Id
+ */
+ public void updateAutomationCompositionElement(@NonNull final AutomationCompositionElement element,
+ @NonNull final UUID instanceId) {
+ var jpaAcElement = new JpaAutomationCompositionElement(element.getId().toString(), instanceId.toString());
+ jpaAcElement.fromAuthorative(element);
+ ProviderUtils.validate(element, jpaAcElement, "AutomationCompositionElement");
+ acElementRepository.save(jpaAcElement);
+ }
}
*/
public static <A, J extends Validated & PfAuthorative<A>> J getJpaAndValidate(A authorativeConcept,
Supplier<J> jpaSupplier, String conceptDescription) {
- var validationResult = new BeanValidationResult(conceptDescription, authorativeConcept);
-
var jpaConcept = jpaSupplier.get();
jpaConcept.fromAuthorative(authorativeConcept);
+ validate(authorativeConcept, jpaConcept, conceptDescription);
+ return jpaConcept;
+ }
+
+ /**
+ * Validate a Jpa object.
+ *
+ * @param authorativeConcept the concept
+ * @param jpaConcept the Jpa of the concept
+ * @param conceptDescription the description used for validation result
+ */
+ public static <A, J extends Validated & PfAuthorative<A>> void validate(A authorativeConcept,
+ J jpaConcept, String conceptDescription) {
+ var validationResult = new BeanValidationResult(conceptDescription, authorativeConcept);
validationResult.addResult(jpaConcept.validate(conceptDescription));
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
}
- return jpaConcept;
}
/**
for (var element : automationComposition.getElements().values()) {
element.setDeployState(deployState);
element.setLockState(lockState);
+ element.setMessage(null);
}
}
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.verify;
import static org.mockito.Mockito.when;
import java.util.List;
class AutomationCompositionProviderTest {
- private static final String OBJECT_IS_NULL = "automationComposition is marked non-null but is null";
+ 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 Coder CODER = new StandardCoder();
private static final String AUTOMATION_COMPOSITION_JSON =
mock(AutomationCompositionElementRepository.class));
assertThatThrownBy(() -> automationCompositionProvider.updateAutomationComposition(null))
- .hasMessageMatching(OBJECT_IS_NULL);
+ .hasMessageMatching(AC_IS_NULL);
when(automationCompositionRepository.save(inputAutomationCompositionsJpa.get(0)))
.thenReturn(inputAutomationCompositionsJpa.get(0));
automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
assertEquals(automationComposition, deletedAc);
}
+
+ @Test
+ void testAutomationCompositionElementUpdate() {
+ var acElementRepository = mock(AutomationCompositionElementRepository.class);
+ var automationCompositionProvider = new AutomationCompositionProvider(
+ mock(AutomationCompositionRepository.class), acElementRepository);
+
+ assertThatThrownBy(() -> automationCompositionProvider.updateAutomationCompositionElement(null, null))
+ .hasMessageMatching(ACELEMENT_IS_NULL);
+
+ var acElement = inputAutomationCompositions.getAutomationCompositionList().get(0).getElements().values()
+ .iterator().next();
+ automationCompositionProvider.updateAutomationCompositionElement(acElement, UUID.randomUUID());
+ verify(acElementRepository).save(any());
+ }
}
*/
private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
Integer startPhaseMsg) {
+ automationComposition.setCompositionTargetId(null);
for (var acElement : automationComposition.getElements().values()) {
int startPhase = ParticipantUtils.findStartPhase(
cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
var checkOpt = automationComposition.getElements().values().stream()
.filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
if (checkOpt.isEmpty()) {
- if (DeployState.MIGRATING.equals(automationComposition.getDeployState())) {
+ if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
+ && automationComposition.getCompositionTargetId() != null) {
// migration scenario
automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
automationComposition.setCompositionTargetId(null);
var compositionTarget = UUID.randomUUID();
automationComposition.setCompositionTargetId(compositionTarget);
- automationComposition.setDeployState(DeployState.MIGRATING);
+ automationComposition.setDeployState(DeployState.DEPLOYED);
when(cacheProvider.getAcElementsDefinitions()).thenReturn(Map.of(compositionTarget, Map.of()));
for (var element : automationComposition.getElements().values()) {
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import lombok.AllArgsConstructor;
import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher;
import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
private final AcElementPropertiesPublisher acElementPropertiesPublisher;
private final AutomationCompositionMigrationPublisher acCompositionMigrationPublisher;
+ private final ExecutorService executor = Executors.newFixedThreadPool(1);
+
/**
* Handle Deploy an AutomationComposition instance.
*
for (var element : automationComposition.getElements().values()) {
if (!DeployState.DEPLOYED.equals(element.getDeployState())) {
element.setDeployState(DeployState.DEPLOYING);
+ element.setMessage(null);
}
}
} else {
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
automationCompositionProvider.updateAutomationComposition(automationComposition);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
- automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(), startPhase,
- true);
+ executor.execute(
+ () -> automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(),
+ startPhase, true));
}
/**
AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYING, LockState.NONE);
}
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
+ automationComposition.setCompositionTargetId(null);
automationCompositionProvider.updateAutomationComposition(automationComposition);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
- automationCompositionStateChangePublisher.send(automationComposition, startPhase, true);
+ executor.execute(
+ () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true));
}
/**
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
automationCompositionProvider.updateAutomationComposition(automationComposition);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
- automationCompositionStateChangePublisher.send(automationComposition, startPhase, true);
+ executor.execute(
+ () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true));
}
/**
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
automationCompositionProvider.updateAutomationComposition(automationComposition);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
- automationCompositionStateChangePublisher.send(automationComposition, startPhase, true);
+ executor.execute(
+ () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true));
}
/**
public void update(AutomationComposition automationComposition) {
AcmUtils.setCascadedState(automationComposition, DeployState.UPDATING, automationComposition.getLockState());
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
- acElementPropertiesPublisher.send(automationComposition);
+ executor.execute(
+ () -> acElementPropertiesPublisher.send(automationComposition));
}
/**
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
automationCompositionProvider.updateAutomationComposition(automationComposition);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
- automationCompositionStateChangePublisher.send(automationComposition, startPhase, true);
+ executor.execute(
+ () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true));
}
/**
for (var element : automationComposition.getElements().values()) {
if (element.getParticipantId().equals(automationCompositionAckMessage.getParticipantId())) {
element.setDeployState(DeployState.DELETED);
+ automationCompositionProvider.updateAutomationCompositionElement(element,
+ automationComposition.getInstanceId());
}
}
- automationCompositionProvider.updateAutomationComposition(automationComposition);
} else {
LOGGER.warn("Empty AutomationCompositionResultMap {} {}",
automationCompositionAckMessage.getAutomationCompositionId(),
StateChangeResult stateChangeResult) {
var updated = false;
boolean inProgress = !StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult());
- if (inProgress) {
+ if (inProgress && !stateChangeResult.equals(automationComposition.getStateChangeResult())) {
automationComposition.setStateChangeResult(stateChangeResult);
+ updated = true;
}
for (var acElementAck : automationCompositionResultSet) {
element.setDeployState(acElementAck.getValue().getDeployState());
element.setLockState(acElementAck.getValue().getLockState());
element.setRestarting(null);
- updated = true;
+ automationCompositionProvider.updateAutomationCompositionElement(element,
+ automationComposition.getInstanceId());
}
}
.map(AutomationCompositionElement::getRestarting).filter(Objects::nonNull).findAny();
if (restarting.isEmpty()) {
automationComposition.setRestarting(null);
+ updated = true;
}
}
public void migrate(AutomationComposition automationComposition, UUID compositionTargetId) {
AcmUtils.setCascadedState(automationComposition, DeployState.MIGRATING, LockState.LOCKED);
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
- acCompositionMigrationPublisher.send(automationComposition, compositionTargetId);
+ executor.execute(
+ () -> acCompositionMigrationPublisher.send(automationComposition, compositionTargetId));
}
}
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.onap.policy.clamp.acm.runtime.util.CommonTestData.TOSCA_SERVICE_TEMPLATE_YAML;
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.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
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;
automationComposition, DeployState.DEPLOYED, LockState.UNLOCKED);
handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage);
- verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
+ verify(automationCompositionProvider, times(3))
+ .updateAutomationCompositionElement(any(AutomationCompositionElement.class), any());
}
private AutomationCompositionDeployAck getAutomationCompositionDeployAck(ParticipantMessageType messageType,
}
automationCompositionAckMessage.setAutomationCompositionId(automationComposition.getInstanceId());
automationCompositionAckMessage.setParticipantId(CommonTestData.getParticipantId());
+ automationCompositionAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR);
return automationCompositionAckMessage;
}
var automationCompositionAckMessage =
new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK);
+ automationCompositionAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR);
for (var element : automationComposition.getElements().values()) {
element.setDeployState(DeployState.DEPLOYED);
}
handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
- verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
+ verify(automationCompositionProvider)
+ .updateAutomationCompositionElement(any(AutomationCompositionElement.class), any());
}
@Test
automationComposition.setStateChangeResult(StateChangeResult.FAILED);
handler.deploy(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(automationComposition);
- verify(automationCompositionDeployPublisher).send(automationComposition, acDefinition.getServiceTemplate(), 0,
- true);
+ verify(automationCompositionDeployPublisher, timeout(1000))
+ .send(automationComposition, acDefinition.getServiceTemplate(), 0, true);
}
@Test
handler.undeploy(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
.forEach(element -> element.setDeployState(DeployState.UNDEPLOYING));
handler.undeploy(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(automationComposition);
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
handler.unlock(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
handler.unlock(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
handler.lock(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
handler.lock(automationComposition, acDefinition);
verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
- verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean());
+ verify(acStateChangePublisher, timeout(1000)).send(any(AutomationComposition.class), anyInt(), anyBoolean());
}
@Test
handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
- verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
+ verify(automationCompositionProvider)
+ .updateAutomationCompositionElement(any(AutomationCompositionElement.class), any());
}
@Test
var automationComposition =
InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Lock");
handler.update(automationComposition);
- verify(acElementPropertiesPublisher).send(any(AutomationComposition.class));
+ verify(acElementPropertiesPublisher, timeout(1000)).send(any(AutomationComposition.class));
}
@Test
var automationComposition =
InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
handler.migrate(automationComposition, UUID.randomUUID());
- verify(acCompositionMigrationPublisher).send(any(AutomationComposition.class), any());
+ verify(acCompositionMigrationPublisher, timeout(1000)).send(any(AutomationComposition.class), any());
}
}