/**
* 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.paas.projection;
import com.francetelecom.clara.cloud.commons.P6SpyAppender;
import com.francetelecom.clara.cloud.coremodel.*;
import com.francetelecom.clara.cloud.logicalmodel.InvalidConfigServiceException;
import com.francetelecom.clara.cloud.logicalmodel.LogicalDeployment;
import com.francetelecom.clara.cloud.logicalmodel.ProcessingNode;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.SampleAppFactory;
import com.francetelecom.clara.cloud.logicalmodel.samplecatalog.SimpleConfigProbeLogicalModelCatalog;
import com.francetelecom.clara.cloud.model.DeploymentProfileEnum;
import com.francetelecom.clara.cloud.model.TechnicalDeployment;
import com.francetelecom.clara.cloud.model.TechnicalDeploymentInstance;
import com.francetelecom.clara.cloud.model.TechnicalDeploymentTemplate;
import com.francetelecom.clara.cloud.model.validators.ModelItemGenericValidationUtils;
import com.francetelecom.clara.cloud.mvn.consumer.MvnRepoDao;
import com.francetelecom.clara.cloud.mvn.consumer.MvnRepoDaoTestUtils;
import com.francetelecom.clara.cloud.paas.projection.cf.ProjectionPlanStrategy;
import com.francetelecom.clara.cloud.techmodel.cf.App;
import com.francetelecom.clara.cloud.techmodel.cf.EnvVariableKey;
import com.francetelecom.clara.cloud.techmodel.cf.EnvVariableValue;
import org.junit.After;
import org.junit.Before;
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.xml.bind.JAXBException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import static java.util.Arrays.asList;
import static org.junit.Assert.*;
/**
* Integrated tests for projection: asserts the created technical model respects expectations.
* <p>
* To keep it fast, this does not include persistence tests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class ProjectionServiceIT {
protected static Logger logger = LoggerFactory.getLogger(ProjectionServiceIT.class.getName());
private static Logger loggerDump = LoggerFactory.getLogger("com.francetelecom.clara.cloud.dump");
/**
* Maven Dao is mocked for unit testing
*/
@Autowired
protected MvnRepoDao mvnRepoDaoMock;
@Autowired
@Qualifier("projectionService")
MultiProfileProjectionServiceDispatcherImpl projectionService;
/**
* white box autowire, to place mock JonasScale
*/
@Autowired
@Qualifier("cfProjectionPlanProdStrategy")
ProjectionPlanStrategy planProdStrategy;
@Autowired
@Qualifier("simpleConfigProbeLogicalModelCatalog")
SampleAppFactory configLogicalModelCatalog;
P6SpyAppender p6spyAppender = null;
@Test
public void testConfigDevProjection() throws JAXBException, IOException, UnsupportedProjectionException {
generateAndAssertTechnicalModel(configLogicalModelCatalog, MiddlewareProfile.getDefault(), 1, 1, false, false);
}
@Test
public void testConfigProdProjection() throws JAXBException, IOException, UnsupportedProjectionException {
generateAndAssertTechnicalModel(configLogicalModelCatalog, MiddlewareProfile.getDefault(), 1, 2, /* Two Apps per JeeProcessing */ true, false);
}
@Before
public void setUp() {
// Mock MvnRepoDao.resolveUrl()
MvnRepoDaoTestUtils.mockResolveUrl(mvnRepoDaoMock);
p6spyAppender = P6SpyAppender.getCurrentInstance();
if (p6spyAppender != null) {
p6spyAppender.reset();
}
}
@After
public void tearDown() {
p6spyAppender = P6SpyAppender.getCurrentInstance();
if (p6spyAppender != null) {
p6spyAppender.checkStats(false);
}
}
/**
* Entry point for assertions on the generated TDT, using
* {@link ProjectionServiceIT.ApplicationModelEnum}
*
* @throws com.francetelecom.clara.cloud.paas.projection.UnsupportedProjectionException
*/
public TechnicalDeploymentTemplate generateAndAssertTechnicalModel(SampleAppFactory configLogicalModelCatalog1, MiddlewareProfile middlewareProfileVersion, int requestedMaxNumberSessions, int expectedNbAppInstances, boolean isProd, boolean sizeWithConstraintSolver)
throws JAXBException, IOException, UnsupportedProjectionException {
final ApplicationRelease applicationRelease = generateApplicationRelease(middlewareProfileVersion, configLogicalModelCatalog1
);
if (sizeWithConstraintSolver) {
assert isProd : "sizeWithConstraintSolver makes only sense in production projections";
}
DeploymentProfileEnum projectionProfile;
if (isProd) {
projectionProfile = DeploymentProfileEnum.PRODUCTION;
} else {
projectionProfile = DeploymentProfileEnum.DEVELOPMENT;
}
LogicalDeployment logicalDeployment = applicationRelease.getLogicalDeployment();
TechnicalDeploymentTemplate tdt = projectionService.generateNewDeploymentTemplate(applicationRelease, projectionProfile);
TechnicalDeployment td = tdt.getTechnicalDeployment();
assertDefaultConfig(logicalDeployment, td);
// Update is done at env creation time but is needed here to assert configuration in assertConfig
TechnicalDeploymentInstance tdi = new TechnicalDeploymentInstance(tdt, td);
ConfigRole configRole = new ConfigRole(applicationRelease.getApplication().getUID());
configRole.setValues(asList(new ConfigValue(SimpleConfigProbeLogicalModelCatalog.WHOLE_APP_CONFIG, "enable.palier.for.open.launch", "true", "Launch is active!")));
List<ConfigRole> configRoles = asList(configRole);
projectionService.updateDeploymentTemplateInstance(tdi, applicationRelease, configRoles);
assertOverridenConfigInAllApps(td, "enable.palier.for.open.launch", "true");
if (loggerDump.isDebugEnabled()) { // enable when needed
loggerDump.debug(td.dumpXml());
}
try {
ModelItemGenericValidationUtils.validateModel(tdt, logger);
} catch (Exception e) {
fail("unexpected invalid model:" + e);
}
assertNotNull("expecting a name in the TD", td.getName());
return tdt;
}
private void assertOverridenConfigInAllApps(TechnicalDeployment td, String key, String expectedValue) {
Set<App> apps = td.listXaasSubscriptionTemplates(App.class);
for (App app : apps) {
String envVarValue = app.getEnvVarValue(key);
assertEquals("invalid env vars " + app.listEnvVariables() + " in app:" + app.getAppName(), expectedValue, envVarValue);
}
}
/**
* Asserts that each ConfigService was properly filled in as Env vars
*/
private void assertDefaultConfig(LogicalDeployment ld, TechnicalDeployment td) {
List<ProcessingNode> executionNodes = ld.listProcessingNodes();
for (ProcessingNode executionNode : executionNodes) {
Set<App> apps = td.listXaasSubscriptionTemplates(App.class, executionNode.getName());
for (App app : apps) {
Set<Map.Entry<EnvVariableKey, EnvVariableValue>> envs = app.listEnvVariables().entrySet();
Properties mergedConfigServicesProperties = null;
try {
mergedConfigServicesProperties = executionNode.getMergedConfigServicesProperties();
} catch (InvalidConfigServiceException e) {
fail("caught expected " + e);
}
Set<Map.Entry<Object, Object>> entries = mergedConfigServicesProperties.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
String configKey = (String) entry.getKey();
String configValue = (String) entry.getValue();
String context = "configKey=" + configKey + " configValue=" + configValue;
boolean matchFound = false;
for (Map.Entry<EnvVariableKey, EnvVariableValue> env : envs) {
boolean keysMatch = new EnvVariableKey(configKey).equals(env.getKey());
boolean valuesMatch = new EnvVariableValue(configValue).equals(env.getValue());
if (keysMatch && valuesMatch) {
assertFalse("duplicate env entry found: " + context, matchFound);
matchFound = true;
}
}
assertTrue("missing env entry for " + context, matchFound);
}
}
}
}
/**
* Utility method to generate an application release (along with the logical
* deployment) corresponding
*/
protected ApplicationRelease generateApplicationRelease(MiddlewareProfile middlewareProfileVersion, SampleAppFactory logicalModelCatalog) {
ApplicationRelease applicationRelease = new ApplicationRelease(new Application("mon Appli", "code"), "G1R0C0");
LogicalDeployment logicalDeploymentToUpdate = applicationRelease.getLogicalDeployment();
logicalModelCatalog.populateLogicalDeployment(logicalDeploymentToUpdate);
if (middlewareProfileVersion != null) {
logger.info("set middleware profile version:{}", middlewareProfileVersion);
applicationRelease.setMiddlewareProfileVersion(middlewareProfileVersion.getVersion());
}
return applicationRelease;
}
/**
* Initial attempt to variabilize tests with different types of application
* models.
*/
public static enum ApplicationModelEnum {
//
CONFIG()
}
}