/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.project.server; import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.project.NewProjectConfig; import org.eclipse.che.api.core.model.project.ProjectConfig; import org.eclipse.che.api.core.model.project.SourceStorage; import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.core.util.LineConsumerFactory; import org.eclipse.che.api.core.util.ValueHolder; import org.eclipse.che.api.project.server.RegisteredProject.Problem; import org.eclipse.che.api.project.server.handlers.CreateProjectHandler; import org.eclipse.che.api.project.server.importer.ProjectImportOutputWSLineConsumer; import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.type.AttributeValue; import org.eclipse.che.api.project.server.type.BaseProjectType; import org.eclipse.che.api.project.server.type.Variable; import org.eclipse.che.api.vfs.Path; import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; import org.eclipse.che.dto.server.DtoFactory; import org.junit.Before; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * @author gazarenkov */ public class ProjectManagerWriteTest extends WsAgentTestBase { private static final String FILE_CONTENT = "to be or not to be"; @Before public void setUp() throws Exception { super.setUp(); projectTypeRegistry.registerProjectType(new PT2()); projectTypeRegistry.registerProjectType(new PT3()); projectTypeRegistry.registerProjectType(new PT4NoGen()); projectTypeRegistry.registerProjectType(new M2()); projectTypeRegistry.registerProjectType(new PTsettableVP()); projectHandlerRegistry.register(new SrcGenerator()); } @Test public void testCreateBatchProjectsByConfigs() throws Exception { final String projectPath1 = "/testProject1"; final String projectPath2 = "/testProject2"; final NewProjectConfig config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, null); final NewProjectConfig config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, null); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config1); configs.add(config2); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(projectPath1); checkProjectExist(projectPath2); assertEquals(2, projectRegistry.getProjects().size()); } @Test public void testCreateBatchProjectsByImportingSourceCode() throws Exception { final String projectPath1 = "/testProject1"; final String projectPath2 = "/testProject2"; final String importType1 = "importType1"; final String importType2 = "importType2"; final String [] paths1 = {"folder1/", "folder1/file1.txt"}; final List<String> children1 = new ArrayList<>(Arrays.asList(paths1)); registerImporter(importType1, prepareZipArchiveBasedOn(children1)); final String [] paths2 = {"folder2/", "folder2/file2.txt"}; final List<String> children2 = new ArrayList<>(Arrays.asList(paths2)); registerImporter(importType2, prepareZipArchiveBasedOn(children2)); final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1); final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config1); configs.add(config2); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project1 = projectRegistry.getProject(projectPath1); final FolderEntry projectFolder1 = project1.getBaseFolder(); checkProjectExist(projectPath1); checkChildrenFor(projectFolder1, children1); final RegisteredProject project2 = projectRegistry.getProject(projectPath2); final FolderEntry projectFolder2 = project2.getBaseFolder(); checkProjectExist(projectPath2); checkChildrenFor(projectFolder2, children2); } @Test public void testCreateProjectWhenSourceCodeIsNotReachable() throws Exception { final String projectPath = "/testProject"; final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); final NewProjectConfigDto config = createProjectConfigObject("testProject1", projectPath, BaseProjectType.ID, source); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config); try { pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("Exception should be thrown when source code is not reachable"); } catch (Exception e) { assertEquals(0, projectRegistry.getProjects().size()); assertNull(projectRegistry.getProject(projectPath)); assertNull(pm.getProjectsRoot().getChild(projectPath)); } } @Test public void shouldRollbackCreatingBatchProjects() throws Exception { // we should rollback operation of creating batch projects when we have not source code for at least one project // For example: two projects were success created, but we could not get source code for third configuration // At this use case we should rollback the operation and clean up all created projects final String projectPath1 = "/testProject1"; final String projectPath2 = "/testProject2"; final String projectPath3 = "/testProject3"; final String importType1 = "importType1"; final String importType2 = "importType2"; final String [] paths1 = {"folder1/", "folder1/file1.txt"}; final List<String> children1 = new ArrayList<>(Arrays.asList(paths1)); registerImporter(importType1, prepareZipArchiveBasedOn(children1)); final String [] paths2 = {"folder2/", "folder2/file2.txt"}; final List<String> children2 = new ArrayList<>(Arrays.asList(paths2)); registerImporter(importType2, prepareZipArchiveBasedOn(children2)); final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1); final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2); final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); final NewProjectConfigDto config3 = createProjectConfigObject("testProject3", projectPath3, BaseProjectType.ID, source); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config1); //will be success created configs.add(config2); //will be success created configs.add(config3); //we be failed - we have not registered importer - source code will not be imported try { pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("We should rollback operation of creating batch projects when we could not get source code for at least one project"); } catch (Exception e) { assertEquals(0, projectRegistry.getProjects().size()); assertNull(projectRegistry.getProject(projectPath1)); assertNull(pm.getProjectsRoot().getChild(projectPath1)); assertNull(projectRegistry.getProject(projectPath2)); assertNull(pm.getProjectsRoot().getChild(projectPath2)); assertNull(projectRegistry.getProject(projectPath3)); assertNull(pm.getProjectsRoot().getChild(projectPath3)); } } @Test public void testCreateBatchProjectsWithInnerProject() throws Exception { final String rootProjectPath = "/testProject1"; final String innerProjectPath = "/testProject1/innerProject"; final String importType = "importType1"; final String innerProjectType = "pt2"; Map<String, List<String>> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); final String [] paths1 = {"folder1/", "folder1/file1.txt"}; final String [] paths2 = {"innerProject/", "innerProject/folder2/", "innerProject/folder2/file2.txt"}; final List<String> children1 = Arrays.asList(paths1); final List<String> children2 = Arrays.asList(paths2); final List<String> children = new ArrayList<>(children1); children.addAll(children2); registerImporter(importType, prepareZipArchiveBasedOn(children)); SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType); NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source); NewProjectConfigDto config2 = createProjectConfigObject("innerProject", innerProjectPath, innerProjectType, null); config2.setAttributes(attributes); List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config1); configs.add(config2); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); FolderEntry rootProjectFolder = rootProject.getBaseFolder(); RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath); FolderEntry innerProjectFolder = innerProject.getBaseFolder(); assertNotNull(rootProject); assertTrue(rootProjectFolder.getVirtualFile().exists()); assertEquals(rootProjectPath, rootProject.getPath()); checkChildrenFor(rootProjectFolder, children1); assertNotNull(innerProject); assertTrue(innerProjectFolder.getVirtualFile().exists()); assertEquals(innerProjectPath, innerProject.getPath()); assertEquals(innerProjectType, innerProject.getType()); checkChildrenFor(rootProjectFolder, children2); } @Test public void testCreateBatchProjectsWithInnerProjectWhenInnerProjectContainsSource() throws Exception { final String rootProjectPath = "/rootProject"; final String innerProjectPath = "/rootProject/innerProject"; final String rootImportType = "rootImportType"; final String innerImportType = "innerImportType"; final String innerProjectType = "pt2"; Map<String, List<String>> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); final String [] paths1 = {"folder1/", "folder1/file1.txt"}; final List<String> children1 = new ArrayList<>(Arrays.asList(paths1)); registerImporter(rootImportType, prepareZipArchiveBasedOn(children1)); final String [] paths2 = {"folder2/", "folder2/file2.txt"}; final List<String> children2 = new ArrayList<>(Arrays.asList(paths2)); registerImporter(innerImportType, prepareZipArchiveBasedOn(children2)); final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(rootImportType); final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source1); final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(innerImportType); final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", innerProjectPath, innerProjectType, source2); config2.setAttributes(attributes); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config2); configs.add(config1); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath); FolderEntry rootProjectFolder = rootProject.getBaseFolder(); checkProjectExist(rootProjectPath); checkChildrenFor(rootProjectFolder, children1); RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath); FolderEntry innerProjectFolder = innerProject.getBaseFolder(); assertNotNull(innerProject); assertTrue(innerProjectFolder.getVirtualFile().exists()); assertEquals(innerProjectPath, innerProject.getPath()); assertEquals(innerProjectType, innerProject.getType()); checkChildrenFor(innerProjectFolder, children2); } @Test public void testCreateBatchProjectsWithMixInnerProjects() throws Exception { // Projects should be sorted by path before creating final String [] paths = {"/1/z", "/2/z", "/1/d", "/2", "/1", "/1/a"}; final List<String> projectsPaths = new ArrayList<>(Arrays.asList(paths)); final List<NewProjectConfig> configs = new ArrayList<>(projectsPaths.size()); for (String path : projectsPaths) { configs.add(createProjectConfigObject(path.substring(path.length() - 1, path.length()), path, BaseProjectType.ID, null)); } pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); for (String path : projectsPaths) { checkProjectExist(path); } } @Test public void testCreateBatchProjectsWhenConfigContainsOnlyPath() throws Exception { // NewProjectConfig object contains only one mandatory Project Path field final String projectPath1 = "/testProject1"; final String projectPath2 = "/testProject2"; final NewProjectConfig config1 = createProjectConfigObject(null, projectPath1, null, null); final NewProjectConfig config2 = createProjectConfigObject(null, projectPath2, null, null); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config1); configs.add(config2); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(projectPath1); checkProjectExist(projectPath2); assertEquals(2, projectRegistry.getProjects().size()); } @Test public void shouldThrowBadRequestExceptionAtCreatingBatchProjectsWhenConfigNotContainsPath() throws Exception { //Path is mandatory field for NewProjectConfig final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType"); final NewProjectConfig config = createProjectConfigObject("project", null, BaseProjectType.ID, source); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config); try { pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("BadRequestException should be thrown : path field is mandatory"); } catch (BadRequestException e) { assertEquals(0, projectRegistry.getProjects().size()); } } @Test public void shouldThrowConflictExceptionAtCreatingBatchProjectsWhenProjectWithPathAlreadyExist() throws Exception { final String path = "/somePath"; final NewProjectConfig config = createProjectConfigObject("project", path, BaseProjectType.ID, null); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(path); assertEquals(1, projectRegistry.getProjects().size()); try { pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); fail("ConflictException should be thrown : Project config with the same path is already exists"); } catch (ConflictException e) { assertEquals(1, projectRegistry.getProjects().size()); } } @Test public void shouldCreateParentFolderAtCreatingProjectWhenParentDoesNotExist() throws Exception { final String nonExistentParentPath = "/rootProject"; final String innerProjectPath = "/rootProject/innerProject"; final NewProjectConfig config = createProjectConfigObject(null, innerProjectPath, null, null); final List<NewProjectConfig> configs = new ArrayList<>(2); configs.add(config); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); checkProjectExist(nonExistentParentPath); checkProjectExist(innerProjectPath); assertEquals(2, projectRegistry.getProjects().size()); } @Test public void shouldRewriteProjectAtCreatingBatchProjectsWhenProjectAlreadyExist() throws Exception { final String projectPath = "/testProject"; final String importType1 = "importType1"; final String importType2 = "importType2"; final String [] paths1 = {"folder1/", "folder1/file1.txt"}; final List<String> children1 = new ArrayList<>(Arrays.asList(paths1)); registerImporter(importType1, prepareZipArchiveBasedOn(children1)); final String [] paths2 = {"folder2/", "folder2/file2.txt"}; final List<String> children2 = new ArrayList<>(Arrays.asList(paths2)); registerImporter(importType2, prepareZipArchiveBasedOn(children2)); final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1); final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath, "blank", source1); final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2); final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath, "blank", source2); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config1); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final FolderEntry projectFolder1 = projectRegistry.getProject(projectPath).getBaseFolder(); checkProjectExist(projectPath); checkChildrenFor(projectFolder1, children1); assertEquals(1, projectRegistry.getProjects().size()); configs.clear(); configs.add(config2); pm.createBatchProjects(configs, true, new ProjectOutputLineConsumerFactory("ws", 300)); final FolderEntry projectFolder2 = projectRegistry.getProject(projectPath).getBaseFolder(); checkProjectExist(projectPath); checkChildrenFor(projectFolder2, children2); assertEquals(1, projectRegistry.getProjects().size()); assertNull(projectFolder2.getChild("folder1/")); assertNull(projectFolder2.getChild("folder1/file1.txt")); } @Test public void shouldSetBlankTypeAtCreatingBatchProjectsWhenConfigContainsUnregisteredProjectType() throws Exception {// If declared primary PT is not registered, project is created as Blank, with Problem 12 final String projectPath = "/testProject"; final String projectType = "unregisteredProjectType"; final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, projectType, null); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project = projectRegistry.getProject(projectPath); final List<Problem> problems = project.getProblems(); checkProjectExist(projectPath); assertNotEquals(projectType, project.getType()); assertEquals(1, problems.size()); assertEquals(12, problems.get(0).code); assertEquals(1, projectRegistry.getProjects().size()); } @Test public void shouldCreateBatchProjectsWithoutMixinPTWhenThisOneIsUnregistered() throws Exception {// If declared mixin PT is not registered, project is created w/o it, with Problem 12 final String projectPath = "/testProject"; final String mixinPType = "unregistered"; final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, BaseProjectType.ID, null); config.getMixins().add(mixinPType); final List<NewProjectConfig> configs = new ArrayList<>(1); configs.add(config); pm.createBatchProjects(configs, false, new ProjectOutputLineConsumerFactory("ws", 300)); final RegisteredProject project = projectRegistry.getProject(projectPath); final List<Problem> problems = project.getProblems(); checkProjectExist(projectPath); assertEquals(1, problems.size()); assertEquals(12, problems.get(0).code); assertTrue(project.getMixins().isEmpty()); assertEquals(1, projectRegistry.getProjects().size()); } @Test public void testCreateProject() throws Exception { Map<String, List<String>> attrs = new HashMap<>(); List<String> v = new ArrayList<>(); v.add("meV"); attrs.put("var1", v); ProjectConfig config = DtoFactory.newDto(ProjectConfigDto.class) .withPath("createProject") .withName("create") .withType("primary1") .withDescription("description") .withAttributes(attrs); pm.createProject(config, new HashMap<>()); RegisteredProject project = pm.getProject("/createProject"); assertTrue(project.getBaseFolder().getVirtualFile().exists()); assertEquals("/createProject", project.getPath()); assertEquals(2, project.getAttributeEntries().size()); assertEquals("meV", project.getAttributeEntries().get("var1").getString()); } @Test public void testCreateProjectWithInvalidAttribute() throws Exception { // SPECS: // Project will be created with problem code = 13(Value for required attribute is not initialized) // when required attribute is not initialized final String path = "/testCreateProjectInvalidAttributes"; final String projectType = "pt2"; final NewProjectConfig config = new NewProjectConfigImpl(path, projectType, null, "name", "descr", null, null, null); pm.createProject(config, null); RegisteredProject project = projectRegistry.getProject(path); assertNotNull(project); assertNotNull(pm.getProjectsRoot().getChild(path)); assertEquals(projectType, project.getType()); List<Problem> problems = project.getProblems(); assertNotNull(problems); assertFalse(problems.isEmpty()); assertEquals(1, problems.size()); assertEquals(13, problems.get(0).code); } @Test public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasGenerator() throws Exception { final String path = "/testCreateProjectWithRequiredProvidedAttribute"; final String projectTypeId = "pt3"; final Map<String, List<String>> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", attributes, null, null); pm.createProject(pc, null); final RegisteredProject project = projectRegistry.getProject(path); assertEquals(projectTypeId, project.getType()); assertNotNull(project.getBaseFolder().getChild("file1")); assertEquals("pt2-provided1", project.getAttributes().get("pt2-provided1").get(0)); } @Test public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasNotGenerator() throws Exception { // SPECS: // Project will be created with problem code = 13 (Value for required attribute is not initialized) // when project type has provided required attributes // but have not respective generator(CreateProjectHandler) final String path = "/testCreateProjectWithRequiredProvidedAttribute"; final String projectTypeId = "pt4"; final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", null, null, null); pm.createProject(pc, null); final RegisteredProject project = projectRegistry.getProject(path); final List<VirtualFileEntry> children = project.getBaseFolder().getChildren(); final List<Problem> problems = project.getProblems(); assertNotNull(project); assertNotNull(pm.getProjectsRoot().getChild(path)); assertEquals(projectTypeId, project.getType()); assertTrue(children.isEmpty()); assertTrue(project.getAttributes().isEmpty()); assertFalse(problems.isEmpty()); assertEquals(1, problems.size()); assertEquals(13, problems.get(0).code); } @Test public void testSamePathProjectCreateFailed() throws Exception { // SPECS: // If there is a project with the same path ConflictException will be thrown on create project ProjectConfig pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null); pm.createProject(pc, null); pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null); try { pm.createProject(pc, null); fail("ConflictException: Project config already exists /testSamePathProjectCreateFailed"); } catch (ConflictException e) { } assertNotNull(projectRegistry.getProject("/testSamePathProjectCreateFailed")); } @Test public void testInvalidPTProjectCreateFailed() throws Exception { // SPECS: // project will be created as project of "blank" type // with problem code 12(Primary type "someType" is not registered. Base Project Type assigned.) // when primary project type is not registered in PT registry final String path = "/testInvalidPTProjectCreateFailed"; ProjectConfig pc = new NewProjectConfigImpl(path, "invalid", null, "name", "descr", null, null, null); pm.createProject(pc, null); RegisteredProject project = projectRegistry.getProject(path); assertNotNull(project); assertNotNull(pm.getProjectsRoot().getChild(path)); assertEquals(BaseProjectType.ID, project.getType()); List<Problem> problems = project.getProblems(); assertNotNull(problems); assertFalse(problems.isEmpty()); assertEquals(1, problems.size()); assertEquals(12, problems.get(0).code); //clean up project.getBaseFolder().getVirtualFile().delete(); projectRegistry.removeProjects(path); assertNull(projectRegistry.getProject(path)); // SPECS: // project will be created without mixin project type and // with problem code 12(Project type "someType" is not registered. Skipped.) // when mixin project type is not registered in PT registry List<String> ms = new ArrayList<>(); ms.add("invalid"); pc = new NewProjectConfigImpl(path, "blank", ms, "name", "descr", null, null, null); pm.createProject(pc, null); project = projectRegistry.getProject(path); assertNotNull(project); assertNotNull(pm.getProjectsRoot().getChild(path)); assertTrue(project.getMixins().isEmpty()); problems = project.getProblems(); assertNotNull(problems); assertFalse(problems.isEmpty()); assertEquals(1, problems.size()); assertEquals(12, problems.get(0).code); } @Test public void testConflictAttributesProjectCreateFailed() throws Exception { // SPECS: // project will be created with problem code 13(Attribute name conflict) // when there are attributes with the same name in primary and mixin PT or between mixins final String path = "/testConflictAttributesProjectCreateFailed"; final String projectTypeId = "pt2"; final String mixin = "m2"; final List<String> ms = new ArrayList<>(1); ms.add(mixin); ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, ms, "name", "descr", null, null, null); pm.createProject(pc, null); final RegisteredProject project = projectRegistry.getProject(path); assertNotNull(project); assertNotNull(pm.getProjectsRoot().getChild(path)); final List<String> mixins = project.getMixins(); assertFalse(mixins.isEmpty()); assertEquals(mixin, mixins.get(0)); final List<Problem> problems = project.getProblems(); assertNotNull(problems); assertFalse(problems.isEmpty()); assertEquals(13, problems.get(0).code); } @Test public void testInvalidConfigProjectCreateFailed() throws Exception { // SPECS: // If project path is not defined // Project creation failed with ConflictException ProjectConfig pc = new NewProjectConfigImpl(null, "pt2", null, "name", "descr", null, null, null); try { pm.createProject(pc, null); fail("ConflictException: Path for new project should be defined "); } catch (ConflictException e) { } } @Test public void testCreateInnerProject() throws Exception { ProjectConfig pc = new NewProjectConfigImpl("/testCreateInnerProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); pc = new NewProjectConfigImpl("/testCreateInnerProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/testCreateInnerProject/inner")); assertEquals(2, projectRegistry.getProjects().size()); assertEquals(1, projectRegistry.getProjects("/testCreateInnerProject").size()); // If there are no parent folder it will be created pc = new NewProjectConfigImpl("/nothing/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/nothing/inner")); assertNotNull(projectRegistry.getProject("/nothing")); assertNotNull(pm.getProjectsRoot().getChildFolder("/nothing")); } @Test public void testUpdateProjectWithPersistedAttributes() throws Exception { Map<String, List<String>> attributes = new HashMap<>(); ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", BaseProjectType.ID, null, "name", "descr", null, null, null); RegisteredProject p = pm.createProject(pc, null); assertEquals(BaseProjectType.ID, p.getType()); assertEquals("name", p.getName()); attributes.put("pt2-var2", new AttributeValue("updated").getList()); ProjectConfig pc1 = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "updatedName", "descr", attributes, null, null); p = pm.updateProject(pc1); assertEquals("pt2", p.getType()); assertEquals("updated", p.getAttributes().get("pt2-var2").get(0)); assertEquals("updatedName", p.getName()); } @Test public void testUpdateProjectWithProvidedAttributes() throws Exception { // SPECS: Project should be updated with problem code = 13 when value for required attribute is not initialized Map<String, List<String>> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test").getList()); ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "name", "descr", attributes, null, null); pm.createProject(pc, null); pc = new NewProjectConfigImpl("/testUpdateProject", "pt3", null, "updatedName", "descr", attributes, null, null); RegisteredProject project = pm.updateProject(pc); final List<Problem> problems = project.getProblems(); assertNotNull(problems); assertFalse(problems.isEmpty()); assertEquals(1, problems.size()); assertEquals(13, problems.get(0).code); } @Test public void testUpdateProjectOnRawFolder() throws Exception { ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProjectOnRawFolder", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); String folderPath = "/testUpdateProjectOnRawFolder/folder"; pm.getProjectsRoot().createFolder(folderPath); // SPECS: // If update is called on raw folder new project should be created pc = new NewProjectConfigImpl(folderPath, BaseProjectType.ID, null, "raw", "descr", null, null, null); pm.updateProject(pc); assertEquals(BaseProjectType.ID, pm.getProject(folderPath).getType()); } @Test public void testInvalidUpdateConfig() throws Exception { ProjectConfig pc = new NewProjectConfigImpl(null, BaseProjectType.ID, null, "name", "descr", null, null, null); try { pm.updateProject(pc); fail("ConflictException: Project path is not defined"); } catch (ConflictException e) { } pc = new NewProjectConfigImpl("/nothing", BaseProjectType.ID, null, "name", "descr", null, null, null); try { pm.updateProject(pc); fail("NotFoundException: Project '/nothing' doesn't exist."); } catch (NotFoundException e) { } } @Test public void testDeleteProject() throws Exception { ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); pc = new NewProjectConfigImpl("/testDeleteProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); assertNotNull(projectRegistry.getProject("/testDeleteProject/inner")); pm.delete("/testDeleteProject"); assertNull(projectRegistry.getProject("/testDeleteProject/inner")); assertNull(projectRegistry.getProject("/testDeleteProject")); assertNull(pm.getProjectsRoot().getChild("/testDeleteProject/inner")); //assertNull(projectRegistry.folder("/testDeleteProject/inner")); } @Test public void testDeleteProjectEvent() throws Exception { ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null); pm.createProject(pc, null); String[] deletedPath = new String[1]; eventService.subscribe(new EventSubscriber<ProjectDeletedEvent>() { @Override public void onEvent(ProjectDeletedEvent event) {deletedPath[0] = event.getProjectPath();} }); pm.delete("/testDeleteProject"); assertEquals("/testDeleteProject", deletedPath[0]); } @Test public void testImportProject() throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); String fileContent = "to be or not to be"; ZipOutputStream zipOut = new ZipOutputStream(bout); zipOut.putNextEntry(new ZipEntry("folder1/")); zipOut.putNextEntry(new ZipEntry("folder1/file1.txt")); zipOut.putNextEntry(new ZipEntry("file1")); zipOut.write(fileContent.getBytes()); zipOut.close(); final InputStream zip = new ByteArrayInputStream(bout.toByteArray()); final String importType = "_123_"; registerImporter(importType, zip); SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType(importType); pm.importProject("/testImportProject", sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("BATCH", "ws", 300)); RegisteredProject project = projectRegistry.getProject("/testImportProject"); assertNotNull(project); // BASE //System.out.println(">>> "+project.getProjectType()); assertNotNull(project.getBaseFolder().getChild("file1")); assertEquals(fileContent, project.getBaseFolder().getChild("file1").getVirtualFile().getContentAsString()); } @Test public void testRemoveFolderForSourcesWhenImportingProjectIsFailed() throws Exception { final String projectPath = "/testImportProject"; final String importType = "_123_"; registerImporter(importType, null); SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType(importType); try { pm.importProject(projectPath, sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("testImportProject", "ws", 300)); } catch (Exception e) { } boolean projectFolderExist = vfsProvider.getVirtualFileSystem().getRoot().hasChild(Path.of(projectPath)); assertFalse(projectFolderExist); } @Test public void testImportProjectWithoutImporterFailed() throws Exception { SourceStorage sourceConfig = DtoFactory.newDto(SourceStorageDto.class).withType("nothing"); try { pm.importProject("/testImportProject", sourceConfig, false, () -> new ProjectImportOutputWSLineConsumer("testImportProject", "ws", 300)); fail("NotFoundException: Unable import sources project from 'null'. Sources type 'nothing' is not supported."); } catch (NotFoundException e) { } } @Test public void testProvidedAttributesNotSerialized() throws Exception { Map<String, List<String>> attributes = new HashMap<>(); attributes.put("pt2-var2", new AttributeValue("test2").getList()); attributes.put("pt2-var1", new AttributeValue("test1").getList()); ProjectConfig pc = new NewProjectConfigImpl("/testProvidedAttributesNotSerialized", "pt3", null, "name", "descr", attributes, null, null); pm.createProject(pc, null); // SPECS: // Only persisted variables should be persisted (no constants, no provided variables) for (ProjectConfig project : workspaceHolder.getProjects()) { if (project.getPath().equals("/testProvidedAttributesNotSerialized")) { assertNotNull(project.getAttributes().get("pt2-var1")); assertNotNull(project.getAttributes().get("pt2-var2")); assertNull(project.getAttributes().get("pt2-const1")); assertNull(project.getAttributes().get("pt2-provided1")); } } } @Test public void testSettableValueProvider() throws Exception { assertTrue(((Variable)projectTypeRegistry.getProjectType("settableVPPT").getAttribute("my")).isValueProvided()); ProjectConfig pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", new HashMap<>(), null, null); pm.createProject(pc, null); RegisteredProject project = pm.getProject("/testSettableValueProvider"); assertEquals(1, project.getAttributes().size()); assertEquals("notset", project.getAttributes().get("my").get(0)); Map<String, List<String>> attributes = new HashMap<>(); attributes.put("my", new AttributeValue("set").getList()); pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", attributes, null, null); pm.updateProject(pc); project = pm.getProject("/testSettableValueProvider"); assertEquals("set", project.getAttributes().get("my").get(0)); } /* ---------------------------------- */ /* private */ /* ---------------------------------- */ private void checkProjectExist(String projectPath) { RegisteredProject project = projectRegistry.getProject(projectPath); FolderEntry projectFolder = project.getBaseFolder(); assertNotNull(project); assertTrue(projectFolder.getVirtualFile().exists()); assertEquals(projectPath, project.getPath()); assertEquals(BaseProjectType.ID, project.getType()); } private void checkChildrenFor(FolderEntry projectFolder, List<String> children) throws ServerException, ForbiddenException { for (String path : children) { assertNotNull(projectFolder.getChild(path)); if (path.contains("file")) { String fileContent = projectFolder.getChild(path).getVirtualFile().getContentAsString(); assertEquals(FILE_CONTENT, fileContent); } } } private InputStream prepareZipArchiveBasedOn(List<String> paths) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ZipOutputStream zipOut = new ZipOutputStream(bout); for (String path : paths) { zipOut.putNextEntry(new ZipEntry(path)); if (path.contains("file")) { zipOut.write(FILE_CONTENT.getBytes()); } } zipOut.close(); return new ByteArrayInputStream(bout.toByteArray()); } private NewProjectConfigDto createProjectConfigObject(String projectName, String projectPath, String projectType, SourceStorageDto sourceStorage) { return DtoFactory.newDto(NewProjectConfigDto.class) .withPath(projectPath) .withName(projectName) .withType(projectType) .withDescription("description") .withSource(sourceStorage) .withAttributes(new HashMap<>()); } private void registerImporter(String importType, InputStream zip) throws Exception { final ValueHolder<FolderEntry> folderHolder = new ValueHolder<>(); importerRegistry.register(new ProjectImporter() { @Override public String getId() { return importType; } @Override public boolean isInternal() { return false; } @Override public String getDescription() { return "importer"; } @Override public void importSources(FolderEntry baseFolder, SourceStorage storage) throws ConflictException, ServerException, ForbiddenException { importSources(baseFolder, storage, LineConsumerFactory.NULL); } @Override public void importSources(FolderEntry baseFolder, SourceStorage storage, LineConsumerFactory importOutputConsumerFactory) throws ConflictException, ServerException, ForbiddenException { // Don't really use location in this test. baseFolder.getVirtualFile().unzip(zip, true, 0); folderHolder.set(baseFolder); } @Override public ImporterCategory getCategory() { return ProjectImporter.ImporterCategory.ARCHIVE; } }); } class SrcGenerator implements CreateProjectHandler { @Override public void onCreateProject(Path projectPath, Map<String, AttributeValue> attributes, Map<String, String> options) throws ForbiddenException, ConflictException, ServerException { FolderEntry baseFolder = new FolderEntry(vfsProvider.getVirtualFileSystem().getRoot().createFolder(projectPath.toString())); baseFolder.createFolder("file1"); } @Override public String getProjectType() { return "pt3"; } } }