/** * Copyright 2015-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.io.IOException; import java.util.List; import java.util.logging.Logger; import org.junit.Assert; import net.roboconf.core.ErrorCode; import net.roboconf.core.internal.tests.TestUtils; import net.roboconf.core.model.beans.Component; import net.roboconf.core.model.beans.ImportedVariable; import net.roboconf.core.utils.ProgramUtils; import net.roboconf.core.utils.ResourceUtils; import net.roboconf.core.utils.Utils; import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * @author Vincent Zurczak - Linagora */ public class RecipesValidatorTest { @Rule public TemporaryFolder folder = new TemporaryFolder(); private final Logger logger = Logger.getLogger(this.getClass().getName()); /** * @return {@code true} if and only if puppet is installed. * @throws IOException when something bad happened. */ private boolean puppetIsInstalled() throws IOException { int exitCode; try { exitCode = ProgramUtils.executeCommand( this.logger, new String[]{"puppet", "-v"}, null, null, null, null); } catch (InterruptedException | IOException e) { exitCode = 1; } return exitCode == 0; } @Test public void testScriptValidation_noScriptAtAll() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "script" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, RecipesValidator.SCRIPTS_DIR_NAME ).mkdirs()); Assert.assertEquals( 0, RecipesValidator.validateComponentRecipes( appDir, comp ).size()); } @Test public void testScriptValidation_success() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "script" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, RecipesValidator.SCRIPTS_DIR_NAME ).mkdirs()); Utils.writeStringInto( "\ntest", new File( directory, RecipesValidator.SCRIPTS_DIR_NAME + "/test.sh" )); Assert.assertEquals( 0, RecipesValidator.validateComponentRecipes( appDir, comp ).size()); } @Test public void testScriptValidation_noScriptsDirectory() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "script" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( directory.mkdirs()); Utils.writeStringInto( "", new File( directory, "test.sh" )); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_SCRIPT_NO_SCRIPTS_DIR, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_noModule() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( directory.mkdirs()); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_HAS_NO_RBCF_MODULE, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_twoModules() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto" ).mkdirs()); Assert.assertTrue( new File( directory, "roBoconf_titi" ).mkdirs()); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_HAS_TOO_MANY_RBCF_MODULES, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_oneModuleButWildCardImports() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); comp.addImportedVariable( new ImportedVariable( "Other.*", true, false )); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto" ).mkdirs()); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_DISLIKES_WILDCARD_IMPORTS, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_invalidUpdatePp() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/update.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/invalid-update.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_IMPORT_DIFF, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_validUpdatePp() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/update.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/update.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 0, errors.size()); } @Test public void testPuppetValidation_invalidInitPp() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/init.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/invalid-update.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_IMPORT_DIFF, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_invalidUpdatePp_validInitPp() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/init.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/invalid-update.pp" ); Utils.copyStream( inputFile, targetFile ); targetFile = new File( directory, "roboconf_toto/manifests/update.pp" ); Utils.copyStream( inputFile, targetFile ); // The init.pp is not considered as being called during updates. // So, no error about imports. List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_IMPORT_DIFF, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_onlyStartPp() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/invalid-update.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 0, errors.size()); } @Test public void testPuppetValidation_missingRunningState() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/missing-running-state.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_RUNNING_STATE, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_missingParameterFromImports() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); comp.addImportedVariable( new ImportedVariable( "Test.ip", true, false )); comp.addImportedVariable( new ImportedVariable( "Test.port", true, false )); comp.addImportedVariable( new ImportedVariable( "Oops.ip", true, false )); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/update.pp" ); Utils.copyStream( inputFile, targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 2, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_FROM_IMPORT, errors.get( 0 ).getErrorCode()); Assert.assertTrue( errors.get( 0 ).getDetails().contains( "Parameter: test" )); Assert.assertEquals( ErrorCode.REC_PUPPET_MISSING_PARAM_FROM_IMPORT, errors.get( 1 ).getErrorCode()); Assert.assertTrue( errors.get( 1 ).getDetails().contains( "Parameter: oops" )); } @Test public void testPuppetValidation_invalidPuppetClass() throws Exception { Assume.assumeTrue(puppetIsInstalled()); File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); comp.addImportedVariable( new ImportedVariable( "Test.ip", true, false )); comp.addImportedVariable( new ImportedVariable( "Test.port", true, false )); comp.addImportedVariable( new ImportedVariable( "Oops.ip", true, false )); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); Utils.writeStringInto( "Not a valid puppet class...", targetFile ); List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_SYNTAX_ERROR, errors.get( 0 ).getErrorCode()); } @Test public void testPuppetValidation_withMatchingImport() throws Exception { File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); comp.addImportedVariable( new ImportedVariable( "WithInit.value", true, false )); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/update.pp" ); Utils.copyStream( inputFile, targetFile ); // We only parse what we know... List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 0, errors.size()); } @Test public void testPuppetValidation_invalidSyntax() throws Exception { Assume.assumeTrue(puppetIsInstalled()); File appDir = this.folder.newFolder(); Component comp = new Component( "toto" ).installerName( "puppet" ); File directory = ResourceUtils.findInstanceResourcesDirectory( appDir, comp ); Assert.assertTrue( new File( directory, "roboconf_toto/manifests" ).mkdirs()); File targetFile = new File( directory, "roboconf_toto/manifests/start.pp" ); File inputFile = TestUtils.findTestFile( "/recipes/invalid-syntax.pp" ); Utils.copyStream( inputFile, targetFile ); // We only parse what we know... List<ModelError> errors = RecipesValidator.validateComponentRecipes( appDir, comp ); Assert.assertEquals( 1, errors.size()); Assert.assertEquals( ErrorCode.REC_PUPPET_SYNTAX_ERROR, errors.get( 0 ).getErrorCode()); } }