/**
* 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.commons.MavenReference;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.ElPaaSoTomcatLogicalModelCatalog;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.SampleAppFactory;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import static org.junit.Assert.*;
/**
* A set of LogicalModel tests which do not require persistence context and are grouped into
* a distinct class to make their execution faster.
*
* @author skwg9735
*/
@ContextConfiguration(locations = "application-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class LogicalModelEqualsHashCodeTest {
/**
* Creates the default app used for some specific test with empty constructor
*/
@Autowired
@Qualifier(value = "springooLogicalModelCatalog")
SampleAppFactory defaultSampleAppFactory;
/**
* The factories to test all of our sample apps.
*/
@Autowired
Map<String, SampleAppFactory> sampleAppFactories;
@Autowired
LogicalDeploymentRepository logicalDeploymentRepository;
@Autowired
private EntityManagerFactory emf;
private static Logger logger = LoggerFactory.getLogger(LogicalModelEqualsHashCodeTest.class.getName());
@Test
public void testUiidSize() {
UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString();
int length = uuidString.length();
assertEquals("unexpected UUID generated toString size", 36, length);
}
/**
* Tests that a {@link LogicalWebGUIService} obtained from the sample app catalog, and one filled manually using
* its fields may be considered equals ignoring the associations (i.e. using {@link LogicalService#equalsShallow(LogicalService)}
*/
@Test
public void testStandaloneLogicalWebGuiEquals() {
assertStandaloneServiceEquals(LogicalWebGUIService.class, new LogicalEntityPropertyCopier<LogicalWebGUIService>() {
@Override
public void copyFields(LogicalWebGUIService logicalService, LogicalWebGUIService webGUIServiceBeingPopulated) {
webGUIServiceBeingPopulated.setStateful(logicalService.isStateful());
webGUIServiceBeingPopulated.setSecure(logicalService.isSecure());
webGUIServiceBeingPopulated.setLabel(logicalService.getLabel());
webGUIServiceBeingPopulated.setContextRoot(logicalService.getContextRoot());
webGUIServiceBeingPopulated.setMaxNumberSessions(logicalService.getMaxNumberSessions());
webGUIServiceBeingPopulated.setMaxReqPerSeconds(logicalService.getMaxReqPerSeconds());
}
});
}
/**
* Tests that a {@link LogicalWebGUIService} obtained from the sample app catalog, and one filled manually using
* its fields may be considered equals ignoring the associations (i.e. using {@link LogicalService#equalsShallow(LogicalService)}
*/
@Test
public void testStandaloneSoapConsumersEquals() {
assertStandaloneServiceEquals(LogicalSoapConsumer.class, new LogicalEntityPropertyCopier<LogicalSoapConsumer>() {
@Override
public void copyFields(LogicalSoapConsumer soapConsumer, LogicalSoapConsumer soapConsummerBeingPopulated) {
soapConsummerBeingPopulated.setLabel(soapConsumer.getLabel());
soapConsummerBeingPopulated.setWsDomain(soapConsumer.getWsDomain());
soapConsummerBeingPopulated.setServiceProviderName(soapConsumer.getServiceProviderName());
soapConsummerBeingPopulated.setServiceName(soapConsumer.getServiceName());
soapConsummerBeingPopulated.setServiceName(soapConsumer.getServiceName());
soapConsummerBeingPopulated.setServiceMajorVersion(soapConsumer.getServiceMajorVersion());
soapConsummerBeingPopulated.setServiceMinorVersion(soapConsumer.getServiceMinorVersion());
soapConsummerBeingPopulated.setJndiPrefix(soapConsumer.getJndiPrefix());
}
});
}
/**
* Factors out the logic to test services equality among classes
*/
private <E extends LogicalService> void assertStandaloneServiceEquals(Class<E> serviceClass, LogicalEntityPropertyCopier logicalEntityPropertyCopier) {
int totalSampleService= 0;
for (Map.Entry<String, SampleAppFactory> sampleAppFactoryEntry : sampleAppFactories.entrySet()) {
String sampleFactoryName = sampleAppFactoryEntry.getKey();
SampleAppFactory sampleAppFactory = sampleAppFactoryEntry.getValue();
LogicalDeployment sampleLogicalModel1 = null;
try {
sampleLogicalModel1 = sampleAppFactory.populateLogicalDeployment(null);
} catch (Throwable e) {
logger.info("Skipping sample app [" + sampleFactoryName + "] as it seems not working in our context: Caught: " +e);
continue;
}
Set<E> logicalWebGUIServices = sampleLogicalModel1.listLogicalServices(serviceClass);
for (E logicalService : logicalWebGUIServices) {
totalSampleService++;
E webGUIServiceBeingPopulated = null;
try {
webGUIServiceBeingPopulated = serviceClass.newInstance();
} catch (Exception e) {
fail("could not instanciate service of class [" + serviceClass + "] caught:" + e);
}
logicalEntityPropertyCopier.copyFields(logicalService, webGUIServiceBeingPopulated);
assertServicesEqualsShallow(sampleFactoryName, logicalService, webGUIServiceBeingPopulated);
}
}
assertTrue("expected at least one " + serviceClass.getSimpleName() + "in all samples", totalSampleService >= 1);
}
private void assertServicesEqualsShallow(String sampleFactoryName, LogicalService logicalWebGUIService, LogicalService webGUIServiceBeingPopulated) {
assertTrue("expected identical objects as returned by equalsShallow() for sample app [" + sampleFactoryName + "]. expected 1 got 2: (please ignore associations in manual inspection)\n1=" + logicalWebGUIService.toString() + "\n2=" + webGUIServiceBeingPopulated , webGUIServiceBeingPopulated.equalsShallow(logicalWebGUIService));
}
/**
* Tests that a {@link LogicalWebGUIService} obtained from the sample app catalog, and one filled manually using
* its fields may be considered equals ignoring the associations (i.e. using {@link LogicalService#equalsShallow(LogicalService)}
*/
public void testStandaloneLogicalExecutionNodeEquals() {
for (Map.Entry<String, SampleAppFactory> sampleAppFactoryEntry : sampleAppFactories.entrySet()) {
String sampleFactoryName = sampleAppFactoryEntry.getKey();
SampleAppFactory sampleAppFactory = sampleAppFactoryEntry.getValue();
LogicalDeployment sampleLogicalModel1 = sampleAppFactory.populateLogicalDeployment(null);
List<ProcessingNode> jeeProcessings = sampleLogicalModel1.listProcessingNodes();
assertTrue(jeeProcessings.size() >=1);
for (ProcessingNode jeeProcessing : jeeProcessings) {
ProcessingNode jeeProcessingBeingConstructed = new JeeProcessing();
MavenReference mavenReference = new MavenReference(jeeProcessing.getSoftwareReference());
jeeProcessingBeingConstructed.setSoftwareReference(mavenReference);
assertEquals("expected ExecNode to match the one from sample catalog [" + sampleFactoryName + "]", jeeProcessing, jeeProcessingBeingConstructed);
}
}
}
/**
* Checks that two distinct logical model trees created the same way are equals
*/
@Test
public void testTransientSpringooLogicalModelEquals() {
testSampleLogicalModelEquals(false, defaultSampleAppFactory, null);
}
/**
* Checks that two distinct logical model trees created the same way and persistent are equals
*/
@Test
// @Ignore("Waiting a fix for bug #80111")
@Transactional
public void testPersistentSpringooLogicalModelEquals() {
testSampleLogicalModelEquals(true, defaultSampleAppFactory, null);
}
/**
* Check modifications that do not bring semantic changes are ignored
*/
@Test
public void testSpringooLogicalModelEqualsIgnoringSemanticlessChanges() {
//JPA id is ignored in LogicalDeployment from exclusion in base class LogicalModelItem
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ld.id = 23;
}
});
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ld.name = "toto";
}
});
//JPA id needs to be excluded explicitly in each subclass
//JeeProcessing
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ProcessingNode executionNode = ld.listProcessingNodes().iterator().next();
executionNode.name = "toto";
}
});
//LogicalService
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
logicalService.name = "toto";
//if (logicalService instanceof LogicalRelationalService) {
//}
}
}
});
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
logicalService.id = 23;
}
}
});
testSampleLogicalModelEquals(false, defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
logicalService.logicalDeployment = null;
}
}
});
}
private void testSampleLogicalModelEquals(boolean persistModels, SampleAppFactory sampleAppFactory, LogicalModelModifier modifier) {
LogicalDeployment sampleLogicalModel1 = sampleAppFactory.populateLogicalDeployment(null);
LogicalDeployment sampleLogicalModel2 = sampleAppFactory.populateLogicalDeployment(null);
if (persistModels) {
logicalDeploymentRepository.save(sampleLogicalModel1);
logicalDeploymentRepository.save(sampleLogicalModel2);
sampleLogicalModel1 = logicalDeploymentRepository.findOne(sampleLogicalModel1.getId());
sampleLogicalModel2 = logicalDeploymentRepository.findOne(sampleLogicalModel2.getId());
}
if(modifier != null) {
modifier.applyModifications(sampleLogicalModel2);
}
if (! sampleLogicalModel1.equals(sampleLogicalModel2)) {
logger.error("Unexpected different objects:\nobject 1=" + sampleLogicalModel1.toString() + "\nobject 2=" + sampleLogicalModel2.toString());
}
Assert.assertEquals("expected unmodified objects to be identical", sampleLogicalModel1, sampleLogicalModel2);
Assert.assertNotSame(sampleLogicalModel1, sampleLogicalModel2);
}
/**
* Checks that two distinct @{link JeeProcessing} with different labels are seen as distinct
*/
@Test
public void testConfigLogicalModelEqualsDetectsDifferentObjects() {
//JeeProcessing properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ProcessingNode executionNode = ld.listProcessingNodes().iterator().next();
executionNode.setLabel(executionNode.getLabel() + "suffix");
}
});
}
/**
* Checks that two distinct logical model trees with semantic modifications are not equals.
*/
@Test
public void testSpringooLogicalModelEqualsDetectsDifferentObjects() {
//LogicalDeployment properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ld.setTemplate(false);
}
});
//JeeProcessing properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ProcessingNode executionNode = ld.listProcessingNodes().iterator().next();
executionNode.setSoftwareReference(null);
}
});
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
ProcessingNode executionNode = ld.listProcessingNodes().iterator().next();
executionNode.setAvailable(true);
}
});
//MavenReference properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
MavenReference softwareReference = ld.listProcessingNodes().iterator().next().getSoftwareReference();
softwareReference.setArtifactId("brokenValue");
}
});
//LogicalRelationalService properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
if (logicalService instanceof LogicalRelationalService) {
LogicalRelationalService rdbs = (LogicalRelationalService) logicalService;
rdbs.setCapacityMo(1);
}
}
}
});
//LogicalRelationalService properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
if (logicalService instanceof LogicalRelationalService) {
LogicalRelationalService rdbs = (LogicalRelationalService) logicalService;
rdbs.setSqlVersion(LogicalRelationalServiceSqlDialectEnum.MYSQL_DEFAULT);
}
}
}
});
//LogicalWebGUIService properly compared
testSpringooLogicalModelEqualsHashCodeContracts(defaultSampleAppFactory, new LogicalModelModifier() {
public void applyModifications(LogicalDeployment ld) {
for (LogicalService logicalService : ld.listLogicalServices()) {
if (logicalService instanceof LogicalWebGUIService) {
LogicalWebGUIService gui = (LogicalWebGUIService) logicalService;
gui.setContextRoot(new ContextRoot("/"));
}
}
}
});
}
/**
* Utility method to assert that the {@link Object#equals(Object)} and {@link Object#hashCode()} are indeed
* respected
* @param utilSpringooIntegration
* @param modifier
*/
public void testSpringooLogicalModelEqualsHashCodeContracts(SampleAppFactory utilSpringooIntegration, LogicalModelModifier modifier) {
final LogicalDeployment springooLogicalModel1 = utilSpringooIntegration.populateLogicalDeployment(null);
final LogicalDeployment springooLogicalModel2 = utilSpringooIntegration.populateLogicalDeployment(null);
//Test that two semantically equivalent instances are equals, and have identical hashcodes
Assert.assertEquals("expected unmodified objects to be equals", springooLogicalModel1, springooLogicalModel2);
Assert.assertEquals("expected unmodified objects to have identical hashcodes", springooLogicalModel1.hashCode(), springooLogicalModel2.hashCode());
Assert.assertEquals("expected unmodified objects to have the same toString()", springooLogicalModel1.toString(), springooLogicalModel2.toString());
//Then apply some modifications
modifier.applyModifications(springooLogicalModel2);
//And asserts that equals indeed report non equals objects
Assert.assertTrue("expected modified objects to not be equals", ! springooLogicalModel1.equals(springooLogicalModel2));
Assert.assertFalse("expected modified objects to not have same toString(): \n" + springooLogicalModel1.toString()
, springooLogicalModel1.toString().equals(springooLogicalModel2.toString()));
}
/**
* Utility interface to allow for factoring out {@link LogicalModelEqualsHashCodeTest#assertServicesEqualsShallow}
* @param <E> the concrete class to apply the modifs on. This avoids manual casts
*/
private abstract static class LogicalEntityPropertyCopier<E extends LogicalEntity> {
public abstract void copyFields(E from, E to);
}
@Test
public void testEmptyLd() {
testPersistence(new LogicalDeployment());
}
@Test
public void testCatalogsPersistence() {
for (SampleAppFactory factory : sampleAppFactories.values()) {
// Can't test for elpaaso catalog, need datacenter:prismo property
if (!(factory instanceof ElPaaSoTomcatLogicalModelCatalog)) {
testTypedAndEmptyConstructorLd(factory);
}
}
}
private void testTypedAndEmptyConstructorLd(SampleAppFactory sampleAppFactory) {
testPersistence(sampleAppFactory.populateLogicalDeployment(new LogicalDeployment()));
}
public void testPersistence(LogicalDeployment toBePersisted) {
// Need an entity Manager
EntityManager em=emf.createEntityManager();
// Need a transaction Manager
EntityTransaction tx;
tx = em.getTransaction();
try {
tx.begin();
em.persist(toBePersisted);
tx.commit();
} finally{
em.close();
}
em=emf.createEntityManager();
tx = em.getTransaction();
LogicalDeployment readFromDb = null;
try {
tx.begin();
readFromDb = em.find(LogicalDeployment.class,toBePersisted.getId());
tx.commit();
assertNotNull("entity does not exist",readFromDb);
assertNotSame(readFromDb, toBePersisted);
//Note: this equals is would trigger lazy loading, we need to assert while the entity manager is still opened
assertEquals(toBePersisted, readFromDb);
} finally{
if (readFromDb != null) {
tx.begin();
em.remove(readFromDb);
tx.commit();
}
em.close();
}
}
}