package org.alien4cloud.tosca.editor; import static org.alien4cloud.test.util.SPELUtils.evaluateAndAssertExpression; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import javax.annotation.Resource; import javax.inject.Inject; import org.alien4cloud.tosca.catalog.ArchiveUploadService; import org.alien4cloud.tosca.catalog.index.CsarService; import org.alien4cloud.tosca.catalog.index.ITopologyCatalogService; import org.alien4cloud.tosca.editor.operations.AbstractEditorOperation; import org.alien4cloud.tosca.editor.operations.UpdateFileOperation; import org.alien4cloud.tosca.model.Csar; import org.alien4cloud.tosca.model.templates.Topology; import org.alien4cloud.tosca.model.types.AbstractInstantiableToscaType; import org.alien4cloud.tosca.model.types.AbstractToscaType; import org.alien4cloud.tosca.model.types.ArtifactType; import org.alien4cloud.tosca.model.types.CapabilityType; import org.alien4cloud.tosca.model.types.DataType; import org.alien4cloud.tosca.model.types.NodeType; import org.alien4cloud.tosca.model.types.PrimitiveDataType; import org.alien4cloud.tosca.model.types.RelationshipType; import org.elasticsearch.index.query.QueryBuilders; import org.junit.Assert; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.test.context.ContextConfiguration; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import alien4cloud.application.ApplicationService; import alien4cloud.common.AlienConstants; import alien4cloud.dao.IGenericSearchDAO; import alien4cloud.dao.model.FacetedSearchResult; import alien4cloud.dao.model.GetMultipleDataResult; import alien4cloud.exception.NotFoundException; import alien4cloud.model.application.Application; import alien4cloud.model.application.ApplicationEnvironment; import alien4cloud.model.application.ApplicationVersion; import alien4cloud.model.components.CSARSource; import alien4cloud.security.model.User; import alien4cloud.topology.TopologyDTO; import alien4cloud.tosca.parser.ParsingErrorLevel; import alien4cloud.tosca.parser.ParsingResult; import alien4cloud.utils.FileUtil; import cucumber.api.DataTable; import cucumber.api.java.Before; import cucumber.api.java.en.And; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; import gherkin.formatter.model.DataTableRow; import lombok.extern.slf4j.Slf4j; @ContextConfiguration("classpath:org/alien4cloud/tosca/editor/application-context-test.xml") @Slf4j public class EditorStepDefs { @Resource(name = "alien-es-dao") private IGenericSearchDAO alienDAO; @Inject private ArchiveUploadService csarUploadService; @Inject private EditorService editorService; @Inject private EditionContextManager editionContextManager; @Inject private CsarService csarService; @Inject private ITopologyCatalogService catalogService; @Inject private ApplicationService applicationService; private LinkedList<String> topologyIds = new LinkedList(); private EvaluationContext topologyEvaluationContext; private EvaluationContext dtoEvaluationContext; private EvaluationContext exceptionEvaluationContext; private EvaluationContext csarEvaluationContext; private Exception thrownException; private Map<String, String> topologyIdToLastOperationId = new HashMap<>(); private List<Class> typesToClean = Lists.newArrayList(); public static final Path CSAR_TARGET_PATH = Paths.get("target/csars"); public EditorStepDefs() { super(); typesToClean.add(AbstractInstantiableToscaType.class); typesToClean.add(AbstractToscaType.class); typesToClean.add(CapabilityType.class); typesToClean.add(ArtifactType.class); typesToClean.add(RelationshipType.class); typesToClean.add(NodeType.class); typesToClean.add(DataType.class); typesToClean.add(PrimitiveDataType.class); typesToClean.add(Csar.class); typesToClean.add(Topology.class); typesToClean.add(Application.class); typesToClean.add(ApplicationEnvironment.class); typesToClean.add(ApplicationVersion.class); } @Before public void init() throws IOException { thrownException = null; GetMultipleDataResult<Application> apps = alienDAO.search(Application.class, "", null, 100); for (Application application : apps.getData()) { try { applicationService.delete(application.getId()); } catch (Throwable e) { } } FacetedSearchResult<Topology> searchResult = catalogService.search(Topology.class, "", 100, null); Topology[] topologies = searchResult.getData(); for (Topology topology : topologies) { csarService.forceDeleteCsar(topology.getId()); } topologyIds.clear(); editionContextManager.clearCache(); } @Given("^I am authenticated with \"(.*?)\" role$") public void i_am_authenticated_with_role(String role) throws Throwable { User user = new User(); user.setUsername("Username"); user.setFirstName("firstName"); user.setLastName("lastname"); user.setEmail("user@fastco"); Authentication auth = new TestAuth(user, role); SecurityContextHolder.getContext().setAuthentication(auth); } @When("^I get the archive with name \"([^\"]*)\" and version \"([^\"]*)\"$") public void i_Get_The_Archive_With_Name_And_Version(String name, String version) throws Throwable { Csar csar = csarService.get(name, version); csarEvaluationContext = new StandardEvaluationContext(csar); } @Then("^The csar SPEL expression \"([^\"]*)\" should return \"([^\"]*)\"$") public void the_Csar_SPEL_Expression_Should_Return(String spelExpression, String expected) throws Throwable { evaluateAndAssertExpression(csarEvaluationContext, spelExpression, expected); } @And("^I delete the archive \"([^\"]*)\" \"([^\"]*)\" if any$") public void iDeleteTheArchiveIfAny(String name, String version) throws Throwable { try { csarService.deleteCsar(new Csar(name, version).getId()); } catch (NotFoundException e) { } } @And("^I get the topology related to the CSAR with name \"([^\"]*)\" and version \"([^\"]*)\"$") public void iGetTheTopologyRelatedToTheCSARWithName(String archiveName, String archiveVersion) throws Throwable { Topology topology = catalogService.get(archiveName + ":" + archiveVersion); if (topology != null) { topologyIds.addLast(topology.getId()); } } @And("^I should be able to find a component with id \"([^\"]*)\"$") public void iShouldBeAbleToFindAComponentWithId(String id) throws Throwable { AbstractToscaType compoennt = alienDAO.findById(AbstractToscaType.class, id); Assert.assertNotNull(compoennt); } @And("^I should not be able to find a component with id \"([^\"]*)\"$") public void iShouldNotBeAbleToFindAComponentWithId(String id) throws Throwable { Assert.assertNull(alienDAO.findById(AbstractToscaType.class, id)); } private static class TestAuth extends UsernamePasswordAuthenticationToken { Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); public TestAuth(User user, String role) { super(user, null); authorities.add(new SimpleGrantedAuthority(role)); } @Override public Collection<GrantedAuthority> getAuthorities() { return authorities; } } @Given("^I upload CSAR from path \"(.*?)\"$") public void i_upload_CSAR_from_path(String path) throws Throwable { uploadCsar(Paths.get(path)); } @When("^I upload unzipped CSAR from path \"(.*?)\"$") public void i_upload_unzipped_CSAR_From_path(String path) throws Throwable { Path source = Paths.get(path); Path csarTargetPath = CSAR_TARGET_PATH.resolve(source.getFileName() + ".csar"); FileUtil.zip(source, csarTargetPath); uploadCsar(csarTargetPath); } private void uploadCsar(Path path) throws Throwable { ParsingResult<Csar> result = csarUploadService.upload(path, CSARSource.UPLOAD, AlienConstants.GLOBAL_WORKSPACE_ID); Assert.assertFalse(result.hasError(ParsingErrorLevel.ERROR)); if (result.getContext().getParsingErrors().size() > 0) { System.out.println(result); } } @Given("^I cleanup archives$") public void i_cleanup_archives() throws Throwable { for (Class<?> type : typesToClean) { alienDAO.delete(type, QueryBuilders.matchAllQuery()); } } // // @When("^I get the topology related to the template with name \"(.*?)\"$") // public void iGetTheTopologyRelatedToTheTemplateWithName(String templateName) throws Throwable { //// TopologyTemplate topologyTeplate = topologyTemplateService.getTopologyTemplateByName(templateName); //// Topology topology = alienDAO.customFind(Topology.class, QueryBuilders.matchQuery("delegateId", topologyTeplate.getId())); //// topologyIds.addLast(topology.getId()); // } // // // @When("^I delete the template with name \"(.*?)\" and archive \"(.*?)\" \"(.*?)\" if any$") // public void iRemoveTheTemplateWithName(String templateName, String archiveName, String archiveVersion) throws Throwable { //// TopologyTemplate topologyTemplate = topologyTemplateService.getTopologyTemplateByName(templateName); //// if (topologyTemplate != null) { //// topologyTemplateService.delete(topologyTemplate.getId()); //// csarService.deleteCsar(archiveName, archiveVersion); //// } // } @When("^I get the edited topology$") public void I_get_the_edited_topology() { thrownException = null; try { editionContextManager.init(topologyIds.getLast()); Topology topology = editionContextManager.getTopology(); topologyEvaluationContext = new StandardEvaluationContext(topology); } catch (Exception e) { log.error("Exception ocrured while getting the topology", e); thrownException = e; exceptionEvaluationContext = new StandardEvaluationContext(e); } finally { editionContextManager.destroy(); } } @Given("^I create an empty topology$") public void i_create_an_empty_topology() throws Throwable { i_create_an_empty_topology_template(UUID.randomUUID().toString().replaceAll("-", "_")); } @Given("^I create an empty topology template \"([^\"]*)\"$") public void i_create_an_empty_topology_template(String topologyTemplateName) throws Throwable { i_create_an_empty_topology_template_version(topologyTemplateName, null); } @Given("^I create an empty topology template \"([^\"]*)\" version \"([^\"]*)\"$") public void i_create_an_empty_topology_template_version(String topologyTemplateName, String version) throws Throwable { try { Topology topology = catalogService.createTopologyAsTemplate(topologyTemplateName, null, version, AlienConstants.GLOBAL_WORKSPACE_ID, null); topologyIds.addLast(topology.getId()); topologyEvaluationContext = new StandardEvaluationContext(topology); } catch (Exception e) { log.error("Exception occurred while creating a topology template", e); thrownException = e; exceptionEvaluationContext = new StandardEvaluationContext(e); } } @Given("^I execute the operation on the topology number (\\d+)$") public void i_execute_the_operation_on_topology_number(int indexOfTopologyId, DataTable operationDT) throws Throwable { Map<String, String> operationMap = Maps.newHashMap(); for (DataTableRow row : operationDT.getGherkinRows()) { operationMap.put(row.getCells().get(0), row.getCells().get(1)); } Class operationClass = Class.forName(operationMap.get("type")); AbstractEditorOperation operation = (AbstractEditorOperation) operationClass.newInstance(); EvaluationContext operationContext = new StandardEvaluationContext(operation); SpelParserConfiguration config = new SpelParserConfiguration(true, true); SpelExpressionParser parser = new SpelExpressionParser(config); for (Map.Entry<String, String> operationEntry : operationMap.entrySet()) { if (!"type".equals(operationEntry.getKey())) { parser.parseRaw(operationEntry.getKey()).setValue(operationContext, operationEntry.getValue()); } } doExecuteOperation(operation, topologyIds.get(indexOfTopologyId)); } @Given("^I execute the operation$") public void i_execute_the_operation(DataTable operationDT) throws Throwable { i_execute_the_operation_on_topology_number(topologyIds.size() - 1, operationDT); } @Given("^I save the topology$") public void i_save_the_topology() throws Throwable { editorService.save(topologyIds.getLast(), topologyIdToLastOperationId.get(topologyIds.getLast())); topologyIdToLastOperationId.put(topologyIds.getLast(), null); } @Given("^I upload a file located at \"(.*?)\" to the archive path \"(.*?)\"$") public void i_upload_a_file_located_at_to_the_archive_path(String filePath, String archiveTargetPath) throws Throwable { UpdateFileOperation updateFileOperation = new UpdateFileOperation(archiveTargetPath, Files.newInputStream(Paths.get(filePath))); doExecuteOperation(updateFileOperation); } private void doExecuteOperation(AbstractEditorOperation operation, String topologyId) { thrownException = null; operation.setPreviousOperationId(topologyIdToLastOperationId.get(topologyId)); try { TopologyDTO topologyDTO = editorService.execute(topologyId, operation); String lastOperationId = topologyDTO.getOperations().get(topologyDTO.getLastOperationIndex()).getId(); topologyIdToLastOperationId.put(topologyId, lastOperationId); topologyEvaluationContext = new StandardEvaluationContext(topologyDTO.getTopology()); dtoEvaluationContext = new StandardEvaluationContext(topologyDTO); } catch (Exception e) { log.error("Exception occurred while executing operation", e); thrownException = e; exceptionEvaluationContext = new StandardEvaluationContext(e); } } private void doExecuteOperation(AbstractEditorOperation operation) { doExecuteOperation(operation, topologyIds.getLast()); } @Then("^The SPEL expression \"([^\"]*)\" should return \"([^\"]*)\"$") public void evaluateSpelExpressionUsingCurrentTopologyContext(String spelExpression, String expected) { evaluateAndAssertExpression(topologyEvaluationContext, spelExpression, expected); } @Then("^The SPEL expression \"([^\"]*)\" should return (true|false)$") public void evaluateSpelExpressionUsingCurrentTopologyContext(String spelExpression, Boolean expected) { evaluateAndAssertExpression(topologyEvaluationContext, spelExpression, expected); } @Then("^The SPEL expression \"([^\"]*)\" should return (\\d+)$") public void evaluateSpelExpressionUsingCurrentTopologyContext(String spelExpression, Integer expected) { evaluateAndAssertExpression(topologyEvaluationContext, spelExpression, expected); } @Then("^The dto SPEL expression \"([^\"]*)\" should return \"([^\"]*)\"$") public void evaluateSpelExpressionUsingCurrentDTOContext(String spelExpression, String expected) { evaluateAndAssertExpression(dtoEvaluationContext, spelExpression, expected); } @Then("^The dto SPEL expression \"([^\"]*)\" should return (true|false)$") public void evaluateSpelExpressionUsingCurrentDTOContext(String spelExpression, Boolean expected) { evaluateAndAssertExpression(dtoEvaluationContext, spelExpression, expected); } @Then("^The dto SPEL expression \"([^\"]*)\" should return (\\d+)$") public void evaluateSpelExpressionUsingCurrentDTOContext(String spelExpression, Integer expected) { evaluateAndAssertExpression(dtoEvaluationContext, spelExpression, expected); } @Then("^The exception SPEL expression \"([^\"]*)\" should return \"([^\"]*)\"$") public void evaluateSpelExpressionUsingCurrentExceptionContext(String spelExpression, String expected) { evaluateAndAssertExpression(exceptionEvaluationContext, spelExpression, expected); } @Then("^The exception SPEL expression \"([^\"]*)\" should return (true|false)$") public void evaluateSpelExpressionUsingCurrentExceptionContext(String spelExpression, Boolean expected) { evaluateAndAssertExpression(exceptionEvaluationContext, spelExpression, expected); } @Then("^The exception SPEL expression \"([^\"]*)\" should return (\\d+)$") public void evaluateSpelExpressionUsingCurrentExceptionContext(String spelExpression, Integer expected) { evaluateAndAssertExpression(exceptionEvaluationContext, spelExpression, expected); } @Then("^No exception should be thrown$") public void no_exception_should_be_thrown() throws Throwable { Assert.assertNull(thrownException); } @Then("^an exception of type \"(.*?)\" should be thrown$") public void an_exception_of_type_should_be_thrown(String exceptionTypesStr) throws Throwable { String[] exceptionTypes = exceptionTypesStr.split("/"); Throwable checkException = thrownException; for (String exceptionType : exceptionTypes) { Class<?> exceptionClass = Class.forName(exceptionType); Assert.assertNotNull(checkException); Assert.assertEquals(exceptionClass, checkException.getClass()); checkException = checkException.getCause(); } } @When("^I recover the topology$") public void i_Recover_The_Topology() throws Throwable { thrownException = null; try { TopologyDTO dto = editorService.recover(topologyIds.getLast(), topologyIdToLastOperationId.get(topologyIds.getLast())); topologyIdToLastOperationId.put(topologyIds.getLast(), null); dtoEvaluationContext = new StandardEvaluationContext(dto); topologyEvaluationContext = new StandardEvaluationContext(dto.getTopology()); } catch (Exception e) { log.error("Error occurred when recovering the topology", e); thrownException = e; exceptionEvaluationContext = new StandardEvaluationContext(e); } } @When("^I reset the topology$") public void iResetTheTopology() throws Throwable { thrownException = null; try { TopologyDTO dto = editorService.reset(topologyIds.getLast(), topologyIdToLastOperationId.get(topologyIds.getLast())); topologyIdToLastOperationId.put(topologyIds.getLast(), null); dtoEvaluationContext = new StandardEvaluationContext(dto); topologyEvaluationContext = new StandardEvaluationContext(dto.getTopology()); } catch (Exception e) { log.error("Error occurred when resetting the topology", e); thrownException = e; exceptionEvaluationContext = new StandardEvaluationContext(e); } } }