/**
* Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis
*
* The present code is developed in the scope of the joint LINAGORA -
* Université Joseph Fourier - Floralis research program and is designated
* as a "Result" pursuant to the terms and conditions of the LINAGORA
* - Université Joseph Fourier - Floralis research program. Each copyright
* holder of Results enumerated here above fully & independently holds complete
* ownership of the complete Intellectual Property rights applicable to the whole
* of said Results, and may freely exploit it in any manner which does not infringe
* the moral rights of the other copyright holders.
*
* 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 net.roboconf.core.model;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import net.roboconf.core.Constants;
import net.roboconf.core.ErrorCode;
import net.roboconf.core.dsl.ParsingModelIo;
import net.roboconf.core.dsl.ParsingModelValidator;
import net.roboconf.core.dsl.converters.FromGraphDefinition;
import net.roboconf.core.dsl.converters.FromInstanceDefinition;
import net.roboconf.core.dsl.parsing.FileDefinition;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.ApplicationTemplate;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.ExportedVariable;
import net.roboconf.core.model.beans.Facet;
import net.roboconf.core.model.beans.Graphs;
import net.roboconf.core.model.beans.ImportedVariable;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.helpers.ComponentHelpers;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.model.helpers.RoboconfErrorHelpers;
import net.roboconf.core.utils.Utils;
/**
* @author Vincent Zurczak - Linagora
*/
public class RuntimeModelValidatorTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testComponent() {
Component comp = new Component();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_COMPONENT_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_EMPTY_COMPONENT_INSTALLER, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setName( "my # component" );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_COMPONENT_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_EMPTY_COMPONENT_INSTALLER, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setName( "my.component" );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_DOT_IS_NOT_ALLOWED, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_EMPTY_COMPONENT_INSTALLER, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setName( "comp" );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_COMPONENT_INSTALLER, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setInstallerName( "my installer !!" );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_COMPONENT_INSTALLER, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setInstallerName( "my installer" );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_ROOT_INSTALLER_MUST_BE_TARGET, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.setInstallerName( Constants.TARGET_INSTALLER );
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
comp.associateFacet( new Facet( "" ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
iterator = RuntimeModelValidator.validate( comp.getFacets().iterator().next()).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_FACET_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.disassociateFacet( comp.getFacets().iterator().next());
comp.associateFacet( new Facet( "!nvalid-facet-n@me" ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
iterator = RuntimeModelValidator.validate( comp.getFacets().iterator().next()).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_FACET_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.disassociateFacet( comp.getFacets().iterator().next());
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
comp.addExportedVariable( new ExportedVariable( "comp.ip", null ));
comp.addExportedVariable( new ExportedVariable( "comp.port", "9000" ));
comp.addImportedVariable( new ImportedVariable( "comp.ip", false, false ));
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_COMPONENT_IMPORTS_EXPORTS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.addImportedVariable( new ImportedVariable( "comp.ip", true, false ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
comp.addImportedVariable( new ImportedVariable( "", false, false ));
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.importedVariables.clear();
comp.addImportedVariable( new ImportedVariable( "comp.inva!id", false, false ));
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp.importedVariables.clear();
comp.addExportedVariable( new ExportedVariable( "toto", "" ));
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertFalse( iterator.hasNext());
comp.exportedVariables.clear();
comp.addExportedVariable( new ExportedVariable( "toto.ip", "" ));
iterator = RuntimeModelValidator.validate( comp ).iterator();
Assert.assertFalse( iterator.hasNext());
comp.exportedVariables.clear();
}
@Test
public void testFacet() {
Facet facet = new Facet();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_FACET_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
facet.setName( "my # facet" );
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_FACET_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
facet.setName( "my.facet" );
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertEquals( ErrorCode.RM_DOT_IS_NOT_ALLOWED, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
facet.setName( "facet" );
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertFalse( iterator.hasNext());
facet.addExportedVariable( new ExportedVariable( "", "value" ));
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
facet.exportedVariables.clear();
facet.addExportedVariable( new ExportedVariable( "facet.inva!id", "value" ));
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
facet.exportedVariables.clear();
facet.addExportedVariable( new ExportedVariable( "toto", "" ));
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertFalse( iterator.hasNext());
facet.exportedVariables.clear();
facet.addExportedVariable( new ExportedVariable( "toto.ip", "" ));
iterator = RuntimeModelValidator.validate( facet ).iterator();
Assert.assertFalse( iterator.hasNext());
facet.exportedVariables.clear();
}
@Test
public void testCycleInComponentInheritance() {
Component c1 = new Component( "c1" ).installerName( Constants.TARGET_INSTALLER );
Component c2 = new Component( "c2" ).installerName( Constants.TARGET_INSTALLER );
Component c3 = new Component( "c3" ).installerName( Constants.TARGET_INSTALLER );
Component c4 = new Component( "c4" ).installerName( Constants.TARGET_INSTALLER );
c1.extendComponent( c2 );
c2.extendComponent( c3 );
c3.extendComponent( c4 );
Assert.assertEquals( 0, RuntimeModelValidator.validate( c1 ).size());
Assert.assertEquals( 0, RuntimeModelValidator.validate( c2 ).size());
Assert.assertEquals( 0, RuntimeModelValidator.validate( c3 ).size());
Assert.assertEquals( 0, RuntimeModelValidator.validate( c4 ).size());
c4.extendComponent( c1 );
Iterator<ModelError> iterator = RuntimeModelValidator.validate( c1 ).iterator();
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS_INHERITANCE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
iterator = RuntimeModelValidator.validate( c1 ).iterator();
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS_INHERITANCE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
iterator = RuntimeModelValidator.validate( c2 ).iterator();
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS_INHERITANCE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
iterator = RuntimeModelValidator.validate( c4 ).iterator();
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS_INHERITANCE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
c1.extendComponent( c1 );
iterator = RuntimeModelValidator.validate( c1 ).iterator();
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS_INHERITANCE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testGraphs_withCaseErrorInImports() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/graph-with-invalid-case-imports.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs g = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( g );
Assert.assertEquals( 1, errors.size());
Assert.assertEquals( ErrorCode.RM_UNRESOLVABLE_VARIABLE, errors.iterator().next().getErrorCode());
}
@Test
public void testGraphs() {
Graphs graphs = new Graphs();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( graphs ).iterator();
Assert.assertEquals( ErrorCode.RM_NO_ROOT_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
Component comp1 = new Component( "comp1" ).installerName( Constants.TARGET_INSTALLER );
graphs.getRootComponents().add( comp1 );
Component duplicateComp1 = new Component( "comp1" ).installerName( Constants.TARGET_INSTALLER );
graphs.getRootComponents().add( duplicateComp1 );
// The validator checks something that cannot happen for the moment.
// But we must keep it to prevent regressions.
iterator = RuntimeModelValidator.validate( graphs ).iterator();
if( iterator.hasNext()) {
//Assert.assertEquals( ErrorCode.RM_DUPLICATE_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
// Unresolvable variable
graphs.getRootComponents().clear();
graphs.getRootComponents().add( comp1 );
comp1.addImportedVariable( new ImportedVariable( "tomcat.port", false, false ));
iterator = RuntimeModelValidator.validate( graphs ).iterator();
Assert.assertEquals( ErrorCode.RM_UNRESOLVABLE_VARIABLE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp1.addImportedVariable( new ImportedVariable( "tomcat.port", true, false ));
iterator = RuntimeModelValidator.validate( graphs ).iterator();
Assert.assertEquals( ErrorCode.RM_UNRESOLVABLE_VARIABLE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
comp1.importedVariables.clear();
// Test for loops: comp2 -> comp3 -> comp2
Component comp2 = new Component( "comp2" ).installerName( "installer-2" );
Component comp3 = new Component( "comp3" ).installerName( "installer-3" );
comp1.addChild( comp2 );
comp2.addChild( comp3 );
comp3.addChild( comp2 );
Collection<ModelError> errors = RuntimeModelValidator.validate( graphs );
Assert.assertEquals( 2, errors.size());
for( ModelError error: errors )
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_COMPONENTS, error.getErrorCode());
}
@Test
public void testGraphs_notRoot() {
Component comp1 = new Component( "comp1" ).installerName( Constants.TARGET_INSTALLER );
Component comp2 = new Component( "comp2" ).installerName( Constants.TARGET_INSTALLER );
comp1.addChild( comp2 );
Graphs graphs = new Graphs();
graphs.getRootComponents().add( comp2 );
Iterator<ModelError> iterator = RuntimeModelValidator.validate( graphs ).iterator();
Assert.assertEquals( ErrorCode.RM_NOT_A_ROOT_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testInstance() {
Instance inst = new Instance();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_INSTANCE_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_EMPTY_INSTANCE_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
inst.setName( "?my instance?" );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_INSTANCE_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_EMPTY_INSTANCE_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
inst.setName( "my-instance" );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_INSTANCE_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
inst.setComponent( new Component( "comp" ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( inst ).size());
inst.setName( "my instance" );
Assert.assertEquals( 0, RuntimeModelValidator.validate( inst ).size());
inst.overriddenExports.put( "inst.value", "whatever" );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testInstance_noVariableValue() {
// Create a valid instance and a valid component
Instance inst = new Instance( "my instance" );
Iterator<ModelError> iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_INSTANCE_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
Component comp = new Component( "comp" ).installerName( "target" );
comp.addExportedVariable( new ExportedVariable( "ip", "" ));
comp.addExportedVariable( new ExportedVariable( "p1", "value1" ));
comp.addExportedVariable( new ExportedVariable( "p2", "" ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( comp ).size());
// Associate them together => variable without value
inst.setComponent( comp );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_VARIABLE_VALUE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
// Fix it and make sure validation succeeds
inst.overriddenExports.put( "inst.value1", "whatever" );
inst.overriddenExports.put( "comp.p2", "a default value" );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
// Define a new instance variable without value => error
inst.overriddenExports.put( "something else", "" );
iterator = RuntimeModelValidator.validate( inst ).iterator();
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_VARIABLE_VALUE, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testInstances() {
List<Instance> instances = new ArrayList<> ();
for( int i=0; i<10; i++ ) {
Instance inst = new Instance( "inst-" + i ).component( new Component( "comp" ));
instances.add( inst );
}
Assert.assertEquals( 0, RuntimeModelValidator.validate( instances ).size());
}
@Test
public void testApplication() {
ApplicationTemplate app = new ApplicationTemplate();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GRAPHS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setName( "My Application #!" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_APPLICATION_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GRAPHS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setName( "My Application (test)" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GRAPHS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setName( "My Application" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GRAPHS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setQualifier( "Snapshot Build #2401" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GRAPHS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setGraphs( new Graphs());
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_NO_ROOT_COMPONENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
Component comp = new Component( "root" ).installerName( Constants.TARGET_INSTALLER );
app.getGraphs().getRootComponents().add( comp );
Assert.assertEquals( 0, RuntimeModelValidator.validate( app ).size());
app.externalExports.put( "comp.!nvalid", "ko" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_INVALID_EXTERNAL_EXPORT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.externalExports.remove( "comp.!nvalid" );
app.externalExports.put( "comp.valid", "!invalid" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_INVALID_EXTERNAL_EXPORT, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.externalExports.put( "comp.valid", "ok" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_INVALID_EXTERNAL_EXPORT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.externalExports.remove( "comp.valid" );
comp.addExportedVariable( new ExportedVariable( "test", "default" ));
app.externalExports.put( "root.test", "alias" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setExternalExportsPrefix( "inval!d prefix" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_APPLICATION_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
app.setExternalExportsPrefix( "prefix" );
Assert.assertEquals( 0, RuntimeModelValidator.validate( app ).size());
comp.addExportedVariable( new ExportedVariable( "test-bis", "default" ));
app.externalExports.put( "root.test-bis", "alias" );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_ALREADY_DEFINED_EXTERNAL_EXPORT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testApplicationDescriptor() {
ApplicationTemplateDescriptor desc = new ApplicationTemplateDescriptor();
Iterator<ModelError> iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_NAME, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_DSL_ID, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GEP, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.setName( "My Application #!" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_QUALIFIER, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_DSL_ID, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GEP, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.setQualifier( "Snapshot Build #2401" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_DSL_ID, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GEP, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.setDslId( "roboconf-1.0" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_APPLICATION_GEP, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.setGraphEntryPoint( "graph.graph" );
Assert.assertEquals( 0, RuntimeModelValidator.validate( desc ).size());
desc.invalidExternalExports.add( "oops" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.PROJ_INVALID_EXTERNAL_EXPORTS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.invalidExternalExports.clear();
desc.externalExports.put( "comp.valid", "ok" );
desc.externalExports.put( "comp.!nvalid", "ko" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
desc.externalExports.remove( "comp.!nvalid" );
Assert.assertEquals( 0, RuntimeModelValidator.validate( desc ).size());
desc.externalExports.put( "comp.valid", "!nvalid" );
iterator = RuntimeModelValidator.validate( desc ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testSelfImports() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/component-self-imports.graph" );
FileDefinition def = ParsingModelIo.readConfigurationFile( f, true );
Assert.assertEquals( 0, def.getParsingErrors().size());
Collection<ParsingError> validationErrors = ParsingModelValidator.validate( def );
Assert.assertEquals( 0, validationErrors.size());
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs graphs = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Iterator<ModelError> iterator = RuntimeModelValidator.validate( graphs ).iterator();
Assert.assertEquals( ErrorCode.RM_COMPONENT_IMPORTS_EXPORTS, iterator.next().getErrorCode());
Assert.assertEquals( ErrorCode.RM_COMPONENT_IMPORTS_EXPORTS, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testExportedVariableNames() throws Exception {
Component component = new Component( "my-component" ).installerName( Constants.TARGET_INSTALLER );
Assert.assertEquals( 0, RuntimeModelValidator.validate( component ).size());
component.addExportedVariable( new ExportedVariable( "ip", null ));
Iterator<ModelError> iterator = RuntimeModelValidator.validate( component ).iterator();
//Assert.assertEquals( ErrorCode.RM_INVALID_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
component.exportedVariables.clear();
component.addExportedVariable( new ExportedVariable( "my-component.ip", null ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( component ).size());
component.addExportedVariable( new ExportedVariable( "ip", null ));
iterator = RuntimeModelValidator.validate( component ).iterator();
//Assert.assertEquals( ErrorCode.RM_INVALID_EXPORT_PREFIX, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
component.exportedVariables.clear();
component.addExportedVariable( new ExportedVariable( "my-component.ip", null ));
component.addExportedVariable( new ExportedVariable( "another-prefix.ip", null ));
iterator = RuntimeModelValidator.validate( component ).iterator();
Assert.assertFalse( iterator.hasNext());
component.associateFacet( new Facet( "my-facet" ));
Assert.assertEquals( 0, RuntimeModelValidator.validate( component ).size());
component.exportedVariables.clear();
component.addExportedVariable( new ExportedVariable( "my-component.@", "yo" ));
iterator = RuntimeModelValidator.validate( component ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
component.exportedVariables.clear();
component.addExportedVariable( new ExportedVariable( "my-component.inva!id", null ));
iterator = RuntimeModelValidator.validate( component ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
component.exportedVariables.clear();
component.addExportedVariable( new ExportedVariable( "", null ));
iterator = RuntimeModelValidator.validate( component ).iterator();
Assert.assertEquals( ErrorCode.RM_EMPTY_VARIABLE_NAME, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testInvalidChildInstance_1() throws Exception {
Component vmComponent1 = new Component( "VM_type1" ).installerName( Constants.TARGET_INSTALLER );
Component vmComponent2 = new Component( "VM_type2" ).installerName( Constants.TARGET_INSTALLER );
Component tomcatComponent = new Component( "Tomcat" ).installerName( "puppet" );
vmComponent1.addChild( tomcatComponent );
vmComponent2.addChild( tomcatComponent );
Graphs graphs = new Graphs();
graphs.getRootComponents().add( vmComponent1 );
graphs.getRootComponents().add( vmComponent2 );
// We cannot instantiate a VM under a VM
Instance vmInstance1 = new Instance("vm1" ).component( vmComponent1 );
Instance vmInstance2 = new Instance("vm2" ).component( vmComponent1 );
InstanceHelpers.insertChild( vmInstance1, vmInstance2 );
ApplicationTemplate app = new ApplicationTemplate( "app" ).qualifier( "snapshot" ).graphs( graphs );
app.getRootInstances().add( vmInstance1 );
Iterator<ModelError> iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_INSTANCE_PARENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
// We cannot have a Tomcat as a root instance
Instance tomcatInstance = new Instance("tomcat" ).component( tomcatComponent );
app.getRootInstances().clear();
app.getRootInstances().add( tomcatInstance );
iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_MISSING_INSTANCE_PARENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
// We can insert a Tomcat under a VM
vmInstance1.getChildren().clear();
InstanceHelpers.insertChild( vmInstance1, tomcatInstance );
app.getRootInstances().clear();
app.getRootInstances().add( vmInstance1 );
Assert.assertEquals( 0, RuntimeModelValidator.validate( app ).size());
}
@Test
public void testInvalidChildInstance_2() throws Exception {
Component vmComponent = new Component( "VM" ).installerName( "target" );
Component tomcatComponent = new Component( "Tomcat" ).installerName( "puppet" );
Graphs graphs = new Graphs();
graphs.getRootComponents().add( vmComponent );
// We cannot instantiate a VM under a VM
Instance vmInstance = new Instance("vm" ).component( vmComponent );
Instance tomcatInstance = new Instance("tomcat" ).component( tomcatComponent );
InstanceHelpers.insertChild( vmInstance, tomcatInstance );
ApplicationTemplate app = new ApplicationTemplate( "app" ).qualifier( "snapshot" ).graphs( graphs );
app.getRootInstances().add( vmInstance );
Iterator<ModelError> iterator = RuntimeModelValidator.validate( app ).iterator();
Assert.assertEquals( ErrorCode.RM_INVALID_INSTANCE_PARENT, iterator.next().getErrorCode());
Assert.assertFalse( iterator.hasNext());
}
@Test
public void testTargetInstaller() throws Exception {
Graphs graphs = new Graphs();
graphs.getRootComponents().add( new Component( "VM" ).installerName( "target" ));
File appDir = this.folder.newFolder();
Collection<ModelError> errors = RuntimeModelValidator.validate( graphs, appDir );
Assert.assertEquals( 1, errors.size());
Assert.assertEquals( ErrorCode.PROJ_NO_RESOURCE_DIRECTORY, errors.iterator().next().getErrorCode());
File componentDir = new File( appDir, Constants.PROJECT_DIR_GRAPH + "/VM" );
Assert.assertTrue( componentDir.mkdirs());
// No target.properties => no error
errors = RuntimeModelValidator.validate( graphs, appDir );
Assert.assertEquals( 0, errors.size());
// A target.properties is present => no error
File targetPropertiesFile = new File( componentDir, Constants.TARGET_PROPERTIES_FILE_NAME );
Assert.assertTrue( targetPropertiesFile.createNewFile());
errors = RuntimeModelValidator.validate( graphs, appDir );
Assert.assertEquals( 3, errors.size());
Iterator<ModelError> it = errors.iterator();
Assert.assertEquals( ErrorCode.REC_TARGET_NO_ID, it.next().getErrorCode());
Assert.assertEquals( ErrorCode.REC_TARGET_NO_HANDLER, it.next().getErrorCode());
Assert.assertEquals( ErrorCode.REC_TARGET_NO_NAME, it.next().getErrorCode());
// Add the required properties
Utils.writeStringInto( "id: tid\nhandler: test\nname: n", targetPropertiesFile );
errors = RuntimeModelValidator.validate( graphs, appDir );
Assert.assertEquals( 0, errors.size());
}
@Test
public void testAnalyzeOverriddenExport() {
Component tomcatComponent = new Component( "Tomcat" ).installerName( "puppet" );
tomcatComponent.addExportedVariable( new ExportedVariable( "Tomcat.ip", null ));
tomcatComponent.addExportedVariable( new ExportedVariable( "Tomcat.port", "8080" ));
Instance tomcatInstance = new Instance( "tomcat" ).component( tomcatComponent );
Collection<ModelError> errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
tomcatInstance.overriddenExports.put( "Tomcat.port", "whatever" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
tomcatInstance.overriddenExports.put( "oops", "whatever" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 1, errors.size());
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, errors.iterator().next().getErrorCode());
tomcatInstance.overriddenExports.remove( "oops" );
tomcatInstance.overriddenExports.put( "port", "whatever" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
tomcatInstance.overriddenExports.remove( "Tomcat.port" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
Facet facet = new Facet( "facet" );
facet.addExportedVariable( new ExportedVariable( "ip", null ));
tomcatComponent.associateFacet( facet );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
tomcatInstance.overriddenExports.put( "ip", "localhost" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 1, errors.size());
Assert.assertEquals( ErrorCode.RM_AMBIGUOUS_OVERRIDING, errors.iterator().next().getErrorCode());
tomcatInstance.overriddenExports.remove( "ip" );
tomcatInstance.overriddenExports.put( "facet.ip", "localhost" );
errors = RuntimeModelValidator.validate( tomcatInstance );
Assert.assertEquals( 0, errors.size());
}
@Test
public void testOverriddenExports() throws Exception {
Component vmComponent = new Component( "VM" ).installerName( "target" );
Component tomcatComponent = new Component( "Tomcat" ).installerName( "puppet" );
tomcatComponent.addExportedVariable( new ExportedVariable( "Tomcat.ip", null ));
tomcatComponent.addExportedVariable( new ExportedVariable( "Tomcat.port", "8080" ));
vmComponent.addChild( tomcatComponent );
Graphs graphs = new Graphs();
graphs.getRootComponents().add( vmComponent );
File f = TestUtils.findTestFile( "/configurations/valid/instance-overridden-exports.instances" );
FromInstanceDefinition fromDef = new FromInstanceDefinition( f.getParentFile());
Collection<Instance> rootInstances = fromDef.buildInstances( graphs, f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Assert.assertEquals( 1, rootInstances.size());
Instance rootInstance = rootInstances.iterator().next();
Collection<Instance> instances = InstanceHelpers.buildHierarchicalList( rootInstance );
Assert.assertEquals( 2, instances.size());
Collection<ModelError> errors = RuntimeModelValidator.validate( instances );
Assert.assertEquals( 1, errors.size());
Assert.assertEquals( ErrorCode.RM_MAGIC_INSTANCE_VARIABLE, errors.iterator().next().getErrorCode());
}
@Test
public void testCycleInFacet() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/cycle-in-facet.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs graphs = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( graphs );
Assert.assertEquals( 5, errors.size());
RoboconfErrorHelpers.filterErrorsForRecipes( errors );
Assert.assertEquals( 3, errors.size());
Set<String> messages = new HashSet<> ();
for( ModelError error : errors ) {
Assert.assertEquals( ErrorCode.RM_CYCLE_IN_FACETS_INHERITANCE, error.getErrorCode());
messages.add( error.getDetails());
}
Assert.assertEquals( 3, messages.size());
}
@Test
public void testWildcardImports() throws Exception {
File f = TestUtils.findTestFile( "/configurations/valid/graph-with-wildcards.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs graphs = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( graphs );
Assert.assertEquals( 0, errors.size());
Component component = ComponentHelpers.findComponent( graphs, "app" );
Assert.assertNotNull( component );
Map<String,String> exports = ComponentHelpers.findAllExportedVariables( component );
Assert.assertEquals( 2, exports.size());
Assert.assertNull( exports.get( "app.ip" ));
Assert.assertEquals( "toto", exports.get( "app.port" ));
Map<String,ImportedVariable> imports = ComponentHelpers.findAllImportedVariables( component );
Assert.assertEquals( 2, imports.size());
Assert.assertNotNull( imports.get( "database.*" ));
Assert.assertFalse( imports.get( "database.*" ).isOptional());
Assert.assertNotNull( imports.get( "f-messaging-2.*" ));
Assert.assertFalse( imports.get( "f-messaging-2.*" ).isOptional());
}
@Test
public void testWildcardImports_withErrors() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/graph-with-wildcards-and-errors.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs graphs = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( graphs );
Assert.assertEquals( 1, errors.size());
ModelError error = errors.iterator().next();
Assert.assertEquals( ErrorCode.RM_UNRESOLVABLE_VARIABLE, error.getErrorCode());
Assert.assertEquals( new Component( "app" ), error.getModelObject());
Assert.assertTrue( error.getDetails().contains( "messaging.*" ));
}
@Test
public void testInvalidRandomPort() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/component-with-invalid-random-port.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs g = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( g );
Assert.assertEquals( 1, errors.size());
ModelError error = errors.iterator().next();
Assert.assertEquals( ErrorCode.RM_INVALID_RANDOM_KIND, error.getErrorCode());
Assert.assertEquals( new Component( "comp2" ), error.getModelObject());
Assert.assertTrue( error.getDetails().contains( "string" ));
}
@Test
public void testInvalidRandomPortWithValue() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/component-with-invalid-random-port-value.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs g = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( g );
Assert.assertEquals( 1, errors.size());
ModelError error = errors.iterator().next();
Assert.assertEquals( ErrorCode.RM_NO_VALUE_FOR_RANDOM, error.getErrorCode());
Assert.assertEquals( new Component( "comp2" ), error.getModelObject());
Assert.assertTrue( error.getDetails().contains( "httpPort" ));
}
@Test
public void testValidRandomPort() throws Exception {
File f = TestUtils.findTestFile( "/configurations/valid/component-with-random-ports.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs g = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
Collection<ModelError> errors = RuntimeModelValidator.validate( g );
Assert.assertEquals( 0, errors.size());
}
@Test
public void testUnreachableComponent() throws Exception {
File f = TestUtils.findTestFile( "/configurations/invalid/facet-without-component.graph" );
FromGraphDefinition fromDef = new FromGraphDefinition( f.getParentFile());
Graphs g = fromDef.buildGraphs( f );
Assert.assertEquals( 0, fromDef.getErrors().size());
List<ModelError> errors = new ArrayList<>( RuntimeModelValidator.validate( g ));
Assert.assertEquals( 3, errors.size());
Assert.assertEquals( ErrorCode.RM_ROOT_INSTALLER_MUST_BE_TARGET, errors.get( 0 ).getErrorCode());
Assert.assertEquals( new Component( "t" ), errors.get( 0 ).getModelObject());
Assert.assertEquals( ErrorCode.RM_ORPHAN_FACET_WITH_CHILDREN, errors.get( 1 ).getErrorCode());
Assert.assertEquals( new Facet( "f" ), errors.get( 1 ).getModelObject());
Assert.assertEquals( ErrorCode.RM_UNREACHABLE_COMPONENT, errors.get( 2 ).getErrorCode());
Assert.assertEquals( new Component( "t" ), errors.get( 2 ).getModelObject());
}
}