/**
* Copyright (C) 2015 Orange
* 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.
*/
package com.francetelecom.clara.cloud.logicalmodel;
import com.francetelecom.clara.cloud.PersistenceTestUtil;
import com.francetelecom.clara.cloud.commons.BusinessException;
import com.francetelecom.clara.cloud.commons.TechnicalException;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.ConfigLogicalModelCatalog;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: wwnl9733
* Date: 15/02/12
* Time: 10:18
* To change this template use File | Settings | File Templates.
*/
@ContextConfiguration(locations = "application-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class LogicalModelOrphanObjectsTest {
/**
* Creates the default config app with empty constructor used for some specific test
*/
@Autowired
ConfigLogicalModelCatalog configLogicalModelCatalog;
@Autowired
LogicalDeploymentRepository logicalDeploymentRepository;
@PersistenceContext
EntityManager em;
@Autowired
PersistenceTestUtil persistenceTestUtil;
@Test
public void testAddAssociationToServiceNotInLogicalDeployment() {
// Given: a sample config LogicalDeployment persisted in database
LogicalDeployment logicalDeployment = configLogicalModelCatalog.populateLogicalDeployment(new LogicalDeployment());
// When: I create a new LogicalConfigService without adding to the LogicalDeployment
LogicalConfigService config = new LogicalConfigService();
boolean hasFailed = false;
try {
// I try to add an association to this service
logicalDeployment.listProcessingNodes().get(0).addLogicalServiceUsage(config, LogicalServiceAccessTypeEnum.NOT_APPLICABLE);
} catch (TechnicalException e) {
hasFailed = true;
}
// Then: The request to add the service is rejected
Assert.assertTrue("add of the service should have raised an exception", hasFailed);
}
@Test
@Transactional
public void testUUIDRandomCollision() {
// Given: a sample config LogicalDeployment persisted in db, with a LogicalConfigService with name=id1
LogicalDeployment logicalDeployment = configLogicalModelCatalog.populateLogicalDeployment(new LogicalDeployment());
LogicalDeployment logicalDeployment2 = configLogicalModelCatalog.populateLogicalDeployment(new LogicalDeployment());
boolean persistenceHasFailed = false;
String persistenceError = "";
try {
Field field = LogicalEntity.class.getDeclaredField("name");
field.setAccessible(true);
field.set(logicalDeployment, "id1");
logicalDeploymentRepository.save(logicalDeployment);
Field field2 = LogicalEntity.class.getDeclaredField("name");
field2.setAccessible(true);
field2.set(logicalDeployment2, "id1");
logicalDeploymentRepository.save(logicalDeployment2);
} catch (DataIntegrityViolationException e) {
persistenceHasFailed = true;
Throwable sqlException = getSQLException(e);
persistenceError = sqlException == null ? "" : sqlException.getMessage();
} catch (Exception e){
}
// Then: the persistence fails with an error message that gives hint about UUID collision
// the JPA persistence fails with the unique constraint on the name field
Assert.assertTrue("merge should have failed", persistenceHasFailed);
Assert.assertFalse("exception message should not be empty", "".equals(persistenceError));
}
/**
* Recursive function which allows to find the SQLException in the stack
* @param e the exception which should contain a SQLException in its stack
* @return the first SQLException in the stack
*/
private Throwable getSQLException(Throwable e) {
if (e.equals(e.getCause())) {
return null;
}
return (e instanceof SQLException) ? e : getSQLException(e.getCause());
}
@Test
public void testDeletedServicesCantBeRetrieved() {
// Given: a sample config LogicalDeployment in database
LogicalDeployment logicalDeployment = configLogicalModelCatalog.populateLogicalDeployment(new LogicalDeployment());
logicalDeploymentRepository.save(logicalDeployment);
// When: I remove all services and exec nodes from the LogicalDeployment
logicalDeployment.removeAllProcessingNodes();
try {
logicalDeployment.removeAllLogicalService();
} catch (BusinessException e) {
}
// I try to persist the LogicalDeployment
logicalDeploymentRepository.save(logicalDeployment);
final LogicalDeployment finalLd = logicalDeployment;
// Then: the original JeeProcessing and LogicalService can not be retrieved from the database
persistenceTestUtil.executeWithinTransaction(new Runnable() {
@Override
public void run() {
TypedQuery qNodes = em.createQuery("SELECT DISTINCT n FROM LogicalDeployment l JOIN l.processingNodes n WHERE l.id = :id", ProcessingNode.class);
qNodes.setParameter("id", finalLd.getId());
List<ProcessingNode> nodesFromBase = qNodes.getResultList();
Assert.assertTrue("deleted execution nodes should not be found in the database", nodesFromBase.isEmpty());
TypedQuery qServices = em.createQuery("SELECT DISTINCT s FROM LogicalDeployment l JOIN l.logicalServices s WHERE l.id = :id", LogicalService.class);
qServices.setParameter("id", finalLd.getId());
List<LogicalService> servicesFromBase = qServices.getResultList();
Assert.assertTrue("logical deployment from base should not have services", servicesFromBase.isEmpty());
}
});
}
@Test
public void testNodeNotAddedToLogicalDeploymentCantBeRetrieved() {
// Given: an empty LogicalDeployment
LogicalDeployment logicalDeployment = new LogicalDeployment();
// When: I instantiate a JeeProcessing without adding it to the LogicalDeployment, and I persist the LogicalDeployment
ProcessingNode node = new JeeProcessing();
logicalDeploymentRepository.save(logicalDeployment);
// Then: the JeeProcessing can't be retrieved from the database by its name
// Then: the original JeeProcessing and LogicalService can not be retrieved from the database
final ProcessingNode finalNode = node;
persistenceTestUtil.executeWithinTransaction(new Runnable() {
@Override
public void run() {
TypedQuery q = em.createQuery("SELECT n FROM JeeProcessing n WHERE n.name = :name", ProcessingNode.class);
q.setParameter("name", finalNode.getName());
List<ProcessingNode> nodesFromBase = q.getResultList();
Assert.assertTrue("there should be no node retrieved from the base", nodesFromBase.isEmpty());
// the id of the JeeProcessing has not been updated
Assert.assertEquals("the node should have its id equal to 0", 0, finalNode.getId());
}
});
}
@Test
public void testNodeAddedThenRemovedToLogicalDeploymentCantBeRetrieved() {
// Given: an empty LogicalDeployment
LogicalDeployment logicalDeployment = new LogicalDeployment();
// When: I instantiate a JeeProcessing and add it to the LogicalDeployment
ProcessingNode node1 = new JeeProcessing();
node1.setLabel("node1");
logicalDeployment.addExecutionNode(node1);
ProcessingNode node2 = new JeeProcessing();
node2.setLabel("node2");
logicalDeployment.addExecutionNode(node2);
// I remove the JeeProcessing from the LogicalDeployment
logicalDeploymentRepository.save(logicalDeployment);
logicalDeployment.removeProcessingNode(node1);
// I persist the LogicalDeployment
logicalDeploymentRepository.save(logicalDeployment);
final ProcessingNode finalNode1 = node1;
final ProcessingNode finalNode2 = node2;
persistenceTestUtil.executeWithinTransaction(new Runnable() {
@Override
public void run() {
TypedQuery q = em.createQuery("SELECT n FROM JeeProcessing n WHERE n.name = :name", ProcessingNode.class);
// Then: the removed JeeProcessing can not be retrieved from the database by its name node1
q.setParameter("name", finalNode1.getName());
List<ProcessingNode> nodesFromBase = q.getResultList();
Assert.assertTrue("there should be no node1 retrieved from the base", nodesFromBase.isEmpty());
// Then: the non-removed JeeProcessing can still be retrieved from the database by its name node2
q.setParameter("name", finalNode2.getName());
nodesFromBase = q.getResultList();
Assert.assertTrue("there should be only node2 retrieved from the base", nodesFromBase.get(0).equals(finalNode2));
}
});
}
}