From ea165e5982744f2d258e0bf4af740201620ed79f Mon Sep 17 00:00:00 2001 From: Sergii Kabashniuk Date: Tue, 5 Dec 2017 10:45:31 +0200 Subject: [PATCH 1/7] Change default workspace path --- .../LocalProjectsFolderPathProvider.java | 23 ++++++++++--------- ...eLocalProjectsFolderOnWorkspaceRemove.java | 3 ++- .../LocalProjectsFolderPathProviderTest.java | 19 +++++++++------ ...alProjectsFolderOnWorkspaceRemoveTest.java | 12 ++++++---- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java index 0a734fe7693..85ca9a11008 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java @@ -106,25 +106,26 @@ public String getPath(String workspaceId) throws IOException { if (!isWindows && hostProjectsFolder != null) { return hostProjectsFolder; } - try { - Workspace workspace = workspaceDao.get(workspaceId); - String wsName = workspace.getConfig().getName(); - return doGetPathByName(wsName); - } catch (NotFoundException | ServerException e) { - throw new IOException(e.getLocalizedMessage()); - } + return doGetPathById(workspaceId); } - public String getPathByName(String workspaceName) throws IOException { + public String getPathByName(String workspaceName, String workspaceNamespace) throws IOException { if (!isWindows && hostProjectsFolder != null) { return hostProjectsFolder; } - return doGetPathByName(workspaceName); + + try { + Workspace workspace = workspaceDao.get(workspaceName, workspaceNamespace); + return getPath(workspace.getId()); + } catch (NotFoundException | ServerException e) { + throw new IOException(e.getLocalizedMessage()); + } } - private String doGetPathByName(String workspaceName) throws IOException { + private String doGetPathById(String workspaceId) throws IOException { + final String workspaceFolderPath = - Paths.get(workspacesMountPoint).resolve(workspaceName).toString(); + Paths.get(workspacesMountPoint).resolve(workspaceId).toString(); ensureExist(workspaceFolderPath, null); return workspaceFolderPath; } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java index c11c46e38f7..180d5e31336 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java @@ -85,7 +85,8 @@ public void onEvent(WorkspaceRemovedEvent event) { String projectSourcesPath; try { - projectSourcesPath = workspaceFolderPathProvider.getPathByName(workspaceName); + projectSourcesPath = + workspaceFolderPathProvider.getPathByName(workspaceName, workspace.getNamespace()); } catch (IOException e) { LOG.error( "Failed to evaluate projects files path for workspace with id: '{}'. Cause: '{}'", diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java index 82ad4c2f484..366ea779d89 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java @@ -37,6 +37,7 @@ public class LocalProjectsFolderPathProviderTest { private static final String WS_ID = "testWsId"; private static final String WS_NAME = "testWsName"; + private static final String WS_NAMESPACE = "che"; @Mock private WorkspaceDao workspaceDao; @@ -50,8 +51,11 @@ public void setUp() throws Exception { WorkspaceImpl workspace = mock(WorkspaceImpl.class); WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class); when(workspaceDao.get(WS_ID)).thenReturn(workspace); + when(workspaceDao.get(WS_NAME, WS_NAMESPACE)).thenReturn(workspace); when(workspace.getConfig()).thenReturn(workspaceConfig); when(workspaceConfig.getName()).thenReturn(WS_NAME); + when(workspace.getNamespace()).thenReturn(WS_NAMESPACE); + when(workspace.getId()).thenReturn(WS_ID); Path tempDirectory = Files.createTempDirectory(getClass().getSimpleName()); workspacesRoot = tempDirectory.toString(); @@ -104,7 +108,7 @@ public void createsFoldersIfConfigured() throws Exception { @Test public void worksIfWorkspaceFolderExists() throws Exception { - assertTrue(Paths.get(workspacesRoot, WS_NAME).toFile().mkdir()); + assertTrue(Paths.get(workspacesRoot, WS_ID).toFile().mkdir()); LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider( workspacesRoot, @@ -119,7 +123,7 @@ public void worksIfWorkspaceFolderExists() throws Exception { assertTrue(workspacesRootFile.exists()); assertTrue(workspacesRootFile.isDirectory()); - String providerPath = provider.getPath(WS_ID); + String providerPath = provider.getPathByName(WS_NAME, WS_NAMESPACE); assertTrue(new File(providerPath).exists()); assertTrue(new File(providerPath).isDirectory()); @@ -159,7 +163,7 @@ public void returnSpecificFolderOnOnWindows() throws Exception { String providerPath = provider.getPath(WS_ID); assertEquals( - providerPath, WindowsHostUtils.getCheHome().resolve("vfs").resolve(WS_NAME).toString()); + providerPath, WindowsHostUtils.getCheHome().resolve("vfs").resolve(WS_ID).toString()); } @Test @@ -188,7 +192,7 @@ public void useOlderFolderIfConfigured() throws Exception { provider.init(); String providerPath = provider.getPath(WS_ID); - assertEquals(providerPath, Paths.get(oldWorkspacesRoot, WS_NAME).toString()); + assertEquals(providerPath, Paths.get(oldWorkspacesRoot, WS_ID).toString()); } @Test( @@ -196,7 +200,7 @@ public void useOlderFolderIfConfigured() throws Exception { expectedExceptionsMessageRegExp = "Workspace folder '.*' is not directory" ) public void throwsExceptionIfFileIsFoundByWorkspacesPath() throws Exception { - assertTrue(Paths.get(workspacesRoot, WS_NAME).toFile().createNewFile()); + assertTrue(Paths.get(workspacesRoot, WS_ID).toFile().createNewFile()); LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider(workspacesRoot, null, null, true, workspaceDao, false); @@ -238,11 +242,12 @@ public void throwsExceptionIfFileIsFoundBySingleWorkspacePath() throws Exception expectedExceptionsMessageRegExp = "expected test exception" ) public void throwsIOExceptionIfWorkspaceRetrievalFails() throws Exception { - when(workspaceDao.get(WS_ID)).thenThrow(new ServerException("expected test exception")); + when(workspaceDao.get(WS_NAME, WS_NAMESPACE)) + .thenThrow(new ServerException("expected test exception")); LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, true); provider.init(); - provider.getPath(WS_ID); + provider.getPathByName(WS_NAME, WS_NAMESPACE); } } diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java index 44a573bf948..bb00ae05d16 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java @@ -37,6 +37,7 @@ public class RemoveLocalProjectsFolderOnWorkspaceRemoveTest { private static final String WORKSPACE_NAME = "test-workspace"; + private static final String WORKSPACE_NAMESPACE = "che"; private static final String WORKSPACE_ID = "workspace123"; private static final String HOST_INSTANCE_DATA_FOLDER = "/home"; @@ -58,6 +59,7 @@ public void setUp() { when(workspaceConfig.getName()).thenReturn(WORKSPACE_NAME); when(workspace.getId()).thenReturn(WORKSPACE_ID); + when(workspace.getNamespace()).thenReturn(WORKSPACE_NAMESPACE); when(workspace.getConfig()).thenReturn(workspaceConfig); } @@ -72,13 +74,14 @@ public void shouldSubscribeListenerToEventService() { @Test public void hostInstanceDataFolderShouldBeCutAndProjectsFolderShouldBeCleaned() throws Exception { - when(projectsFolderPathProvider.getPathByName(anyString())).thenReturn(HOST_PROJECTS_FOLDER); + when(projectsFolderPathProvider.getPathByName(anyString(), anyString())) + .thenReturn(HOST_PROJECTS_FOLDER); when(removeLocalProjectsFolderOnWorkspaceRemove.getInstanceDataPath()) .thenReturn(HOST_INSTANCE_DATA_FOLDER); removeLocalProjectsFolderOnWorkspaceRemove.onEvent(new WorkspaceRemovedEvent(workspace)); - verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME); + verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME, WORKSPACE_NAMESPACE); verify(removeLocalProjectsFolderOnWorkspaceRemove) .deleteRecursiveAsync(WORKSPACE_ID, CONTAINER_MOUNTED_PROJECTS_FOLDER); } @@ -90,13 +93,14 @@ public void workspaceShouldNotBeCleanedIfHostProjectsRootFolderIsConfigured() th new RemoveLocalProjectsFolderOnWorkspaceRemove( HOST_PROJECTS_FOLDER, projectsFolderPathProvider)); - when(projectsFolderPathProvider.getPathByName(anyString())).thenReturn(HOST_PROJECTS_FOLDER); + when(projectsFolderPathProvider.getPathByName(anyString(), anyString())) + .thenReturn(HOST_PROJECTS_FOLDER); when(removeLocalProjectsFolderOnWorkspaceRemove.getInstanceDataPath()) .thenReturn(HOST_INSTANCE_DATA_FOLDER); removeLocalProjectsFolderOnWorkspaceRemove.onEvent(new WorkspaceRemovedEvent(workspace)); - verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME); + verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME, WORKSPACE_NAMESPACE); verify(removeLocalProjectsFolderOnWorkspaceRemove, never()) .deleteRecursiveAsync(anyString(), anyString()); } From 4d4290aeda1c37868cadbf028e229269742dede9 Mon Sep 17 00:00:00 2001 From: Mykhailo Kuznietsov Date: Tue, 12 Dec 2017 17:11:09 +0200 Subject: [PATCH 2/7] Add migration of workspaces storage on Docker infrastructure --- infrastructures/docker/infrastructure/pom.xml | 4 + .../LocalProjectsFolderPathProvider.java | 65 +++++++++++++ ...eLocalProjectsFolderOnWorkspaceRemove.java | 5 +- .../LocalProjectsFolderPathProviderTest.java | 42 ++++++++ ...alProjectsFolderOnWorkspaceRemoveTest.java | 10 +- .../tracker/RamResourceUsageTracker.java | 12 ++- .../tracker/RuntimeResourceUsageTracker.java | 12 ++- .../WorkspaceResourceUsageTracker.java | 11 ++- .../RuntimeResourceUsageTrackerTest.java | 21 ++-- .../WorkspaceResourceUsageTrackerTest.java | 18 +++- .../JpaEntitiesCascadeRemovalTest.java | 4 +- .../spi/jpa/MultiuserJpaWorkspaceDao.java | 96 +++++++++++++------ .../jpa/MultiuserJpaWorkspaceDaoTest.java | 2 +- .../server/TemporaryWorkspaceRemover.java | 28 +++--- .../workspace/server/WorkspaceManager.java | 18 ++-- .../workspace/server/WorkspaceService.java | 16 +++- .../workspace/server/jpa/JpaWorkspaceDao.java | 91 ++++++++++++------ .../server/model/impl/WorkspaceImpl.java | 11 ++- .../workspace/server/spi/WorkspaceDao.java | 10 +- .../server/TemporaryWorkspaceRemoverTest.java | 27 ++---- .../server/WorkspaceManagerTest.java | 52 +++++----- .../server/WorkspaceServiceTest.java | 12 ++- .../server/spi/tck/WorkspaceDaoTest.java | 22 +++-- .../che/core/db/jpa/CascadeRemovalTest.java | 4 +- 24 files changed, 417 insertions(+), 176 deletions(-) diff --git a/infrastructures/docker/infrastructure/pom.xml b/infrastructures/docker/infrastructure/pom.xml index 6f98f20f43a..f00ea1fa5d6 100644 --- a/infrastructures/docker/infrastructure/pom.xml +++ b/infrastructures/docker/infrastructure/pom.xml @@ -42,6 +42,10 @@ com.google.inject.extensions guice-multibindings + + commons-io + commons-io + javax.annotation javax.annotation-api diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java index 85ca9a11008..1ecf1cd8100 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java @@ -11,6 +11,7 @@ package org.eclipse.che.workspace.infrastructure.docker.local.projects; import static java.lang.String.format; +import static org.eclipse.che.api.core.Pages.iterate; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; @@ -19,6 +20,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; import javax.annotation.PostConstruct; import javax.inject.Named; import javax.inject.Singleton; @@ -26,8 +31,11 @@ import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.util.SystemInfo; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides path to workspace projects folder on host. @@ -40,6 +48,10 @@ public class LocalProjectsFolderPathProvider { public static final String ALLOW_FOLDERS_CREATION_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE_CREATE_FOLDERS"; public static final String WORKSPACE_STORAGE_PATH_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE"; + public static final String WORKSPACE_STORAGE_MIGRATION_FLAG_ENV_VARIABLE = + "che.workspace.migrate_workspaces_stored_by_name"; + + private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsFolderPathProvider.class); private final WorkspaceDao workspaceDao; private final boolean isWindows; @@ -173,6 +185,8 @@ void init() throws IOException { } else { ensureExist(hostProjectsFolder, "host.projects.root"); } + + performWorkspaceLocationMigration(); } private void ensureExist(String path, String prop) throws IOException { @@ -210,4 +224,55 @@ private void ensureExist(String path, String prop) throws IOException { } } } + + /** + * Get all workspaces, and check if they are stored in workspacesMountPoint by their name, and + * migrate them, so they will be stored by id + */ + private void performWorkspaceLocationMigration() { + if (!isWindows || hostProjectsFolder != null) { + Map workspaceName2id = getId2NameWorkspaceMapping(); + for (Entry entry : workspaceName2id.entrySet()) { + Path workspaceStoredByNameLocation = + Paths.get(workspacesMountPoint).resolve(entry.getValue()); + if (!Files.exists(workspaceStoredByNameLocation)) { + // migration is not needed for this workspace + continue; + } + LOG.info( + "Starting migration of workspace with id '{}' and name '{}'", + entry.getKey(), + entry.getValue()); + Path workspaceStoredByIdLocation = Paths.get(workspacesMountPoint).resolve(entry.getKey()); + try { + Files.move( + workspaceStoredByNameLocation, + workspaceStoredByIdLocation, + StandardCopyOption.ATOMIC_MOVE); + LOG.info( + "Successfully workspace with id '{}' and name '{}'", + entry.getKey(), + entry.getValue()); + } catch (IOException e) { + LOG.error( + "Failed to workspace with id '{}' and name '{}'", entry.getKey(), entry.getValue()); + } + } + } + } + + private Map getId2NameWorkspaceMapping() { + try { + Map result = new HashMap<>(); + + for (WorkspaceImpl workspace : + iterate( + (maxItems, skipCount) -> workspaceDao.getWorkspaces(false, maxItems, skipCount))) { + result.put(workspace.getId(), workspace.getConfig().getName()); + } + return result; + } catch (ServerException e) { + throw new RuntimeException(e); + } + } } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java index 180d5e31336..c720bebba89 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemove.java @@ -81,12 +81,11 @@ public void subscribe(EventService eventService) { @Override public void onEvent(WorkspaceRemovedEvent event) { Workspace workspace = event.getWorkspace(); - String workspaceName = workspace.getConfig().getName(); + String workspaceId = workspace.getId(); String projectSourcesPath; try { - projectSourcesPath = - workspaceFolderPathProvider.getPathByName(workspaceName, workspace.getNamespace()); + projectSourcesPath = workspaceFolderPathProvider.getPath(workspaceId); } catch (IOException e) { LOG.error( "Failed to evaluate projects files path for workspace with id: '{}'. Cause: '{}'", diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java index 366ea779d89..942679a04b1 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java @@ -10,6 +10,9 @@ */ package org.eclipse.che.workspace.infrastructure.docker.local.projects; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -21,6 +24,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; +import org.apache.commons.io.FileUtils; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -28,6 +34,7 @@ import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -52,6 +59,8 @@ public void setUp() throws Exception { WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class); when(workspaceDao.get(WS_ID)).thenReturn(workspace); when(workspaceDao.get(WS_NAME, WS_NAMESPACE)).thenReturn(workspace); + when(workspaceDao.getWorkspaces(eq(false), anyInt(), anyLong())) + .thenReturn(new Page<>(Collections.singletonList(workspace), 0, 1, 1)); when(workspace.getConfig()).thenReturn(workspaceConfig); when(workspaceConfig.getName()).thenReturn(WS_NAME); when(workspace.getNamespace()).thenReturn(WS_NAMESPACE); @@ -65,6 +74,11 @@ public void setUp() throws Exception { oldWorkspacesRoot = Paths.get(workspacesRoot, "oldWorkspacesRoot").toString(); } + @AfterMethod + public void tearDown() throws Exception { + FileUtils.deleteDirectory(workspacesRootFile); + } + @Test public void createsFoldersByDefault() throws Exception { assertTrue(workspacesRootFile.delete()); @@ -250,4 +264,32 @@ public void throwsIOExceptionIfWorkspaceRetrievalFails() throws Exception { provider.init(); provider.getPathByName(WS_NAME, WS_NAMESPACE); } + + @Test + public void shouldPerformWorkspaceMigration() throws Exception { + Files.createDirectories(Paths.get(workspacesRoot).resolve(WS_NAME)); + Files.createFile(Paths.get(workspacesRoot).resolve(WS_NAME).resolve("pom.xml")); + + LocalProjectsFolderPathProvider provider = + new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, false); + + provider.init(); + + Path expectedNewWorkspacePath = Paths.get(workspacesRoot).resolve(WS_ID); + assertTrue(Files.exists(expectedNewWorkspacePath)); + } + + @Test + public void shouldPerformWorkspaceMigration2() throws Exception { + Files.createDirectories(Paths.get(workspacesRoot).resolve(WS_NAME)); + Files.createFile(Paths.get(workspacesRoot).resolve(WS_NAME).resolve("pom.xml")); + + LocalProjectsFolderPathProvider provider = + new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, false); + + provider.init(); + + Path expectedNewWorkspacePath = Paths.get(workspacesRoot).resolve(WS_ID); + assertTrue(Files.exists(expectedNewWorkspacePath)); + } } diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java index bb00ae05d16..6b388396385 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/RemoveLocalProjectsFolderOnWorkspaceRemoveTest.java @@ -74,14 +74,13 @@ public void shouldSubscribeListenerToEventService() { @Test public void hostInstanceDataFolderShouldBeCutAndProjectsFolderShouldBeCleaned() throws Exception { - when(projectsFolderPathProvider.getPathByName(anyString(), anyString())) - .thenReturn(HOST_PROJECTS_FOLDER); + when(projectsFolderPathProvider.getPath(anyString())).thenReturn(HOST_PROJECTS_FOLDER); when(removeLocalProjectsFolderOnWorkspaceRemove.getInstanceDataPath()) .thenReturn(HOST_INSTANCE_DATA_FOLDER); removeLocalProjectsFolderOnWorkspaceRemove.onEvent(new WorkspaceRemovedEvent(workspace)); - verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME, WORKSPACE_NAMESPACE); + verify(projectsFolderPathProvider).getPath(WORKSPACE_ID); verify(removeLocalProjectsFolderOnWorkspaceRemove) .deleteRecursiveAsync(WORKSPACE_ID, CONTAINER_MOUNTED_PROJECTS_FOLDER); } @@ -93,14 +92,13 @@ public void workspaceShouldNotBeCleanedIfHostProjectsRootFolderIsConfigured() th new RemoveLocalProjectsFolderOnWorkspaceRemove( HOST_PROJECTS_FOLDER, projectsFolderPathProvider)); - when(projectsFolderPathProvider.getPathByName(anyString(), anyString())) - .thenReturn(HOST_PROJECTS_FOLDER); + when(projectsFolderPathProvider.getPath(anyString())).thenReturn(HOST_PROJECTS_FOLDER); when(removeLocalProjectsFolderOnWorkspaceRemove.getInstanceDataPath()) .thenReturn(HOST_INSTANCE_DATA_FOLDER); removeLocalProjectsFolderOnWorkspaceRemove.onEvent(new WorkspaceRemovedEvent(workspace)); - verify(projectsFolderPathProvider).getPathByName(WORKSPACE_NAME, WORKSPACE_NAMESPACE); + verify(projectsFolderPathProvider).getPath(WORKSPACE_ID); verify(removeLocalProjectsFolderOnWorkspaceRemove, never()) .deleteRecursiveAsync(anyString(), anyString()); } diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java index ed17471d100..8848a6405d9 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java @@ -10,8 +10,10 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; +import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; +import com.google.common.collect.Lists; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -57,9 +59,13 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); List activeWorkspaces = - workspaceManagerProvider - .get() - .getByNamespace(account.getName(), true) + Lists.newArrayList( + iterate( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), true, maxItems, skipCount)) + .iterator()) .stream() .filter(ws -> STOPPED != ws.getStatus()) .collect(Collectors.toList()); diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java index 979c5817f07..b6297918ffc 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java @@ -10,8 +10,10 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; +import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; +import com.google.common.collect.Lists; import java.util.Optional; import javax.inject.Inject; import javax.inject.Provider; @@ -48,9 +50,13 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); final long currentlyUsedRuntimes = - workspaceManagerProvider - .get() - .getByNamespace(account.getName(), false) + Lists.newArrayList( + iterate( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), false, maxItems, skipCount)) + .iterator()) .stream() .filter(ws -> STOPPED != ws.getStatus()) .count(); diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java index f720d53474a..ab700a9893f 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java @@ -10,6 +10,9 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; +import static org.eclipse.che.api.core.Pages.iterate; + +import com.google.common.collect.Lists; import java.util.List; import java.util.Optional; import javax.inject.Inject; @@ -48,7 +51,13 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); final List accountWorkspaces = - workspaceManagerProvider.get().getByNamespace(account.getName(), false); + Lists.newArrayList( + iterate( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), false, maxItems, skipCount)) + .iterator()); if (!accountWorkspaces.isEmpty()) { return Optional.of( new ResourceImpl( diff --git a/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTrackerTest.java b/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTrackerTest.java index ab169a7006d..d95791ca6d1 100644 --- a/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTrackerTest.java +++ b/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTrackerTest.java @@ -13,6 +13,8 @@ import static java.util.Collections.singletonList; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -21,6 +23,7 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -28,6 +31,7 @@ import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -75,8 +79,8 @@ public void shouldReturnEmptyOptionalWhenAccountDoesNotUseRuntimes() throws Exce when(accountManager.getById(any())).thenReturn(account); when(account.getName()).thenReturn("testAccount"); - when(workspaceManager.getByNamespace(anyString(), anyBoolean())) - .thenReturn(singletonList(createWorkspace(WorkspaceStatus.STOPPED))); + when(workspaceManager.getByNamespace(anyString(), anyBoolean(), anyInt(), anyLong())) + .thenReturn(new Page<>(singletonList(createWorkspace(WorkspaceStatus.STOPPED)), 0, 1, 1)); Optional usedRuntimesOpt = runtimeResourceUsageTracker.getUsedResource("account123"); @@ -88,11 +92,12 @@ public void shouldReturnUsedRuntimesForGivenAccount() throws Exception { when(accountManager.getById(any())).thenReturn(account); when(account.getName()).thenReturn("testAccount"); - when(workspaceManager.getByNamespace(anyString(), anyBoolean())) - .thenReturn( - Stream.of(WorkspaceStatus.values()) - .map(RuntimeResourceUsageTrackerTest::createWorkspace) - .collect(Collectors.toList())); + List runtimes = + Stream.of(WorkspaceStatus.values()) + .map(RuntimeResourceUsageTrackerTest::createWorkspace) + .collect(Collectors.toList()); + when(workspaceManager.getByNamespace(anyString(), anyBoolean(), anyInt(), anyLong())) + .thenReturn(new Page<>(runtimes, 0, runtimes.size(), runtimes.size())); Optional usedRuntimesOpt = runtimeResourceUsageTracker.getUsedResource("account123"); @@ -103,7 +108,7 @@ public void shouldReturnUsedRuntimesForGivenAccount() throws Exception { usedRuntimes.getAmount(), WorkspaceStatus.values().length - 1); // except stopped workspaces assertEquals(usedRuntimes.getUnit(), RuntimeResourceType.UNIT); verify(accountManager).getById(eq("account123")); - verify(workspaceManager).getByNamespace(eq("testAccount"), eq(false)); + verify(workspaceManager).getByNamespace(eq("testAccount"), eq(false), anyInt(), anyLong()); } /** Creates users workspace object based on the status. */ diff --git a/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTrackerTest.java b/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTrackerTest.java index c0e3db91fad..ab2d0d02c62 100644 --- a/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTrackerTest.java +++ b/multiuser/api/che-multiuser-api-resource/src/test/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTrackerTest.java @@ -12,6 +12,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -27,6 +29,7 @@ import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.multiuser.resource.api.type.WorkspaceResourceType; @@ -72,8 +75,8 @@ public void shouldReturnEmptyOptionalWhenAccountDoesNotUseWorkspaces() throws Ex when(accountManager.getById(any())).thenReturn(account); when(account.getName()).thenReturn("testAccount"); - when(workspaceManager.getByNamespace(anyString(), anyBoolean())) - .thenReturn(Collections.emptyList()); + when(workspaceManager.getByNamespace(anyString(), anyBoolean(), anyInt(), anyLong())) + .thenReturn(new Page<>(Collections.emptyList(), 0, 1, 0)); Optional usedWorkspacesOpt = workspaceResourceUsageTracker.getUsedResource("account123"); @@ -86,8 +89,13 @@ public void shouldReturnUsedWorkspacesForGivenAccount() throws Exception { when(accountManager.getById(any())).thenReturn(account); when(account.getName()).thenReturn("testAccount"); - when(workspaceManager.getByNamespace(anyString(), anyBoolean())) - .thenReturn(Arrays.asList(new WorkspaceImpl(), new WorkspaceImpl(), new WorkspaceImpl())); + when(workspaceManager.getByNamespace(anyString(), anyBoolean(), anyInt(), anyLong())) + .thenReturn( + new Page<>( + Arrays.asList(new WorkspaceImpl(), new WorkspaceImpl(), new WorkspaceImpl()), + 0, + 3, + 3)); Optional usedWorkspacesOpt = workspaceResourceUsageTracker.getUsedResource("account123"); @@ -98,6 +106,6 @@ public void shouldReturnUsedWorkspacesForGivenAccount() throws Exception { assertEquals(usedWorkspaces.getAmount(), 3); assertEquals(usedWorkspaces.getUnit(), WorkspaceResourceType.UNIT); verify(accountManager).getById(eq("account123")); - verify(workspaceManager).getByNamespace(eq("testAccount"), eq(false)); + verify(workspaceManager).getByNamespace(eq("testAccount"), eq(false), anyInt(), anyLong()); } } diff --git a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java index 87c4fde55bc..6b996900de8 100644 --- a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java +++ b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java @@ -315,13 +315,13 @@ public void shouldDeleteAllTheEntitiesWhenUserIsDeleted() throws Exception { assertNull(notFoundToNull(() -> profileDao.getById(user.getId()))); assertTrue(preferenceDao.getPreferences(user.getId()).isEmpty()); assertTrue(sshDao.get(user.getId()).isEmpty()); - assertTrue(workspaceDao.getByNamespace(account.getName()).isEmpty()); + assertTrue(workspaceDao.getByNamespace(account.getName(), 30, 0).isEmpty()); assertTrue( factoryDao .getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))) .isEmpty()); // Check workers and parent entity is removed - assertTrue(workspaceDao.getByNamespace(user2.getId()).isEmpty()); + assertTrue(workspaceDao.getByNamespace(user2.getId(), 30, 0).isEmpty()); assertEquals(workerDao.getWorkers(workspace3.getId(), 1, 0).getTotalItemsCount(), 0); // Check stack and recipes are removed assertNull(notFoundToNull(() -> stackDao.getById(stack1.getId()))); diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java index d5a8e96c53a..deb348fe999 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java @@ -14,6 +14,7 @@ import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; +import static org.eclipse.che.api.core.Pages.iterate; import com.google.inject.persist.Transactional; import java.util.List; @@ -29,6 +30,7 @@ import org.eclipse.che.account.event.BeforeAccountRemovedEvent; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.WorkspaceManager; @@ -56,6 +58,11 @@ public class MultiuserJpaWorkspaceDao implements WorkspaceDao { + " LEFT JOIN worker.workspace ws " + " WHERE worker.userId = :userId " + " AND 'read' MEMBER OF worker.actions"; + private static final String findByWorkerCountQuery = + "SELECT COUNT(ws) FROM Worker worker " + + " LEFT JOIN worker.workspace ws " + + " WHERE worker.userId = :userId " + + " AND 'read' MEMBER OF worker.actions"; @Override public WorkspaceImpl create(WorkspaceImpl workspace) throws ConflictException, ServerException { @@ -140,17 +147,27 @@ public WorkspaceImpl get(String name, String namespace) @Override @Transactional - public List getByNamespace(String namespace) throws ServerException { + public Page getByNamespace(String namespace, int maxItems, long skipCount) + throws ServerException { requireNonNull(namespace, "Required non-null namespace"); try { - return managerProvider - .get() - .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(Collectors.toList()); + final EntityManager manager = managerProvider.get(); + final List list = + manager + .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) + .setParameter("namespace", namespace) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(Collectors.toList()); + final long count = + manager + .createNamedQuery("Workspace.getByNamespaceCount", Long.class) + .setParameter("namespace", namespace.toLowerCase()) + .getSingleResult(); + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -158,14 +175,26 @@ public List getByNamespace(String namespace) throws ServerExcepti @Override @Transactional - public List getWorkspaces(String userId) throws ServerException { - + public Page getWorkspaces(String userId, int maxItems, long skipCount) + throws ServerException { try { - return managerProvider - .get() - .createQuery(findByWorkerQuery, WorkspaceImpl.class) - .setParameter("userId", userId) - .getResultList(); + final List list = + managerProvider + .get() + .createQuery(findByWorkerQuery, WorkspaceImpl.class) + .setParameter("userId", userId) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList(); + + final long count = + managerProvider + .get() + .createQuery(findByWorkerCountQuery, Long.class) + .setParameter("userId", userId) + .getSingleResult(); + + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -173,23 +202,31 @@ public List getWorkspaces(String userId) throws ServerException { @Override @Transactional - public List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) + public Page getWorkspaces(boolean isTemporary, int maxItems, long skipCount) throws ServerException { checkArgument(maxItems >= 0, "The number of items to return can't be negative."); checkArgument( skipCount >= 0, "The number of items to skip can't be negative or greater than " + Integer.MAX_VALUE); try { - return managerProvider - .get() - .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) - .setParameter("temporary", isTemporary) - .setMaxResults(maxItems) - .setFirstResult(skipCount) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(toList()); + final List list = + managerProvider + .get() + .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) + .setParameter("temporary", isTemporary) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(toList()); + final long count = + managerProvider + .get() + .createNamedQuery("Workspace.getByTemporaryCount", Long.class) + .setParameter("temporary", isTemporary) + .getSingleResult(); + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -254,7 +291,10 @@ public void unsubscribe() { @Override public void onCascadeEvent(BeforeAccountRemovedEvent event) throws Exception { for (WorkspaceImpl workspace : - workspaceManager.getByNamespace(event.getAccount().getName(), false)) { + iterate( + (maxItems, skipCount) -> + workspaceManager.getByNamespace( + event.getAccount().getName(), false, maxItems, skipCount))) { workspaceManager.removeWorkspace(workspace.getId()); } } diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java index 9c09da1be4c..65042089305 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java @@ -128,7 +128,7 @@ public void shutdown() throws Exception { @Test public void shouldFindStackByPermissions() throws Exception { - List results = dao.getWorkspaces(users[0].getId()); + List results = dao.getWorkspaces(users[0].getId(), 30, 0).getItems(); assertEquals(results.size(), 2); assertTrue(results.contains(workspaces[0])); assertTrue(results.contains(workspaces[1])); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java index 23187a3f7b0..88379124a4d 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java @@ -13,11 +13,11 @@ import static org.slf4j.LoggerFactory.getLogger; import com.google.common.annotations.VisibleForTesting; -import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import javax.inject.Singleton; +import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; @@ -60,22 +60,18 @@ void shutdown() { @VisibleForTesting void removeTemporaryWs() throws ServerException { - final int count = 100; - int skip = 0; - List workspaces = workspaceDao.getWorkspaces(true, skip, count); - while (!workspaces.isEmpty()) { - for (WorkspaceImpl workspace : workspaces) { - try { - workspaceDao.remove(workspace.getId()); - } catch (ServerException e) { - LOG.error( - "Unable to cleanup temporary workspace {}. Reason is {}", - workspace.getId(), - e.getLocalizedMessage()); - } + ; + for (WorkspaceImpl workspace : + Pages.iterate( + (maxItems, skipCount) -> workspaceDao.getWorkspaces(true, maxItems, skipCount))) { + try { + workspaceDao.remove(workspace.getId()); + } catch (ServerException e) { + LOG.error( + "Unable to cleanup temporary workspace {}. Reason is {}", + workspace.getId(), + e.getLocalizedMessage()); } - skip = skip + count; - workspaces = workspaceDao.getWorkspaces(true, skip, count); } } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index 98fda2b5a56..f07d08c6254 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -20,13 +20,13 @@ import com.google.inject.Inject; import java.util.Collections; -import java.util.List; import java.util.Map; import javax.inject.Singleton; import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.Workspace; @@ -176,11 +176,11 @@ public WorkspaceImpl getWorkspace(String name, String namespace) * @throws ServerException when any server error occurs while getting workspaces with {@link * WorkspaceDao#getWorkspaces(String)} */ - public List getWorkspaces(String user, boolean includeRuntimes) - throws ServerException { + public Page getWorkspaces( + String user, boolean includeRuntimes, int maxItems, long skipCount) throws ServerException { requireNonNull(user, "Required non-null user id"); - final List workspaces = workspaceDao.getWorkspaces(user); - for (WorkspaceImpl workspace : workspaces) { + final Page workspaces = workspaceDao.getWorkspaces(user, maxItems, skipCount); + for (WorkspaceImpl workspace : workspaces.getItems()) { normalizeState(workspace, includeRuntimes); } return workspaces; @@ -202,11 +202,13 @@ public List getWorkspaces(String user, boolean includeRuntimes) * @throws ServerException when any server error occurs while getting workspaces with {@link * WorkspaceDao#getByNamespace(String)} */ - public List getByNamespace(String namespace, boolean includeRuntimes) + public Page getByNamespace( + String namespace, boolean includeRuntimes, int maxItems, long skipCount) throws ServerException { requireNonNull(namespace, "Required non-null namespace"); - final List workspaces = workspaceDao.getByNamespace(namespace); - for (WorkspaceImpl workspace : workspaces) { + final Page workspaces = + workspaceDao.getByNamespace(namespace, maxItems, skipCount); + for (WorkspaceImpl workspace : workspaces.getItems()) { normalizeState(workspace, includeRuntimes); } return workspaces; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index 23a4dce45c8..9161eb6db66 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -15,8 +15,10 @@ import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toList; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -225,7 +227,12 @@ public List getWorkspaces( // TODO add maxItems & skipCount to manager return withLinks( workspaceManager - .getWorkspaces(EnvironmentContext.getCurrent().getSubject().getUserId(), false) + .getWorkspaces( + EnvironmentContext.getCurrent().getSubject().getUserId(), + false, + maxItems, + skipCount) + .getItems() .stream() .filter(ws -> status == null || status.equalsIgnoreCase(ws.getStatus().toString())) .map(DtoConverter::asDto) @@ -250,8 +257,11 @@ public List getByNamespace( @ApiParam("The namespace") @PathParam("namespace") String namespace) throws ServerException, BadRequestException { return withLinks( - workspaceManager - .getByNamespace(namespace, false) + Lists.newArrayList( + iterate( + (maxItems, skipCount) -> + workspaceManager.getByNamespace(namespace, false, maxItems, skipCount)) + .iterator()) .stream() .filter(ws -> status == null || status.equalsIgnoreCase(ws.getStatus().toString())) .map(DtoConverter::asDto) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index 8afcdc689dc..2c11acb960e 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -14,6 +14,7 @@ import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; +import static org.eclipse.che.api.core.Pages.iterate; import com.google.inject.persist.Transactional; import java.util.List; @@ -29,6 +30,7 @@ import org.eclipse.che.account.event.BeforeAccountRemovedEvent; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.WorkspaceManager; @@ -134,17 +136,27 @@ public WorkspaceImpl get(String name, String namespace) @Override @Transactional - public List getByNamespace(String namespace) throws ServerException { + public Page getByNamespace(String namespace, int maxItems, long skipCount) + throws ServerException { requireNonNull(namespace, "Required non-null namespace"); try { - return managerProvider - .get() - .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) - .setParameter("namespace", namespace) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(Collectors.toList()); + final EntityManager manager = managerProvider.get(); + final List list = + manager + .createNamedQuery("Workspace.getByNamespace", WorkspaceImpl.class) + .setParameter("namespace", namespace) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(Collectors.toList()); + final long count = + manager + .createNamedQuery("Workspace.getByNamespaceCount", Long.class) + .setParameter("namespace", namespace.toLowerCase()) + .getSingleResult(); + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -152,15 +164,25 @@ public List getByNamespace(String namespace) throws ServerExcepti @Override @Transactional - public List getWorkspaces(String userId) throws ServerException { + public Page getWorkspaces(String userId, int maxItems, long skipCount) + throws ServerException { try { - return managerProvider - .get() - .createNamedQuery("Workspace.getAll", WorkspaceImpl.class) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(Collectors.toList()); + final List list = + managerProvider + .get() + .createNamedQuery("Workspace.getAll", WorkspaceImpl.class) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(Collectors.toList()); + final long count = + managerProvider + .get() + .createNamedQuery("Workspace.getAllCount", Long.class) + .getSingleResult(); + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -168,23 +190,31 @@ public List getWorkspaces(String userId) throws ServerException { @Override @Transactional - public List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) + public Page getWorkspaces(boolean isTemporary, int maxItems, long skipCount) throws ServerException { checkArgument(maxItems >= 0, "The number of items to return can't be negative."); checkArgument( skipCount >= 0, "The number of items to skip can't be negative or greater than " + Integer.MAX_VALUE); try { - return managerProvider - .get() - .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) - .setParameter("temporary", isTemporary) - .setMaxResults(maxItems) - .setFirstResult(skipCount) - .getResultList() - .stream() - .map(WorkspaceImpl::new) - .collect(toList()); + final List list = + managerProvider + .get() + .createNamedQuery("Workspace.getByTemporary", WorkspaceImpl.class) + .setParameter("temporary", isTemporary) + .setMaxResults(maxItems) + .setFirstResult((int) skipCount) + .getResultList() + .stream() + .map(WorkspaceImpl::new) + .collect(toList()); + final long count = + managerProvider + .get() + .createNamedQuery("Workspace.getByTemporaryCount", Long.class) + .setParameter("temporary", isTemporary) + .getSingleResult(); + return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { throw new ServerException(x.getLocalizedMessage(), x); } @@ -249,7 +279,10 @@ public void unsubscribe() { @Override public void onCascadeEvent(BeforeAccountRemovedEvent event) throws Exception { for (WorkspaceImpl workspace : - workspaceManager.getByNamespace(event.getAccount().getName(), false)) { + iterate( + (maxItems, skipCount) -> + workspaceManager.getByNamespace( + event.getAccount().getName(), false, maxItems, skipCount))) { workspaceManager.removeWorkspace(workspace.getId()); } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index 5c4a875cc62..1ff8bfe3452 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -60,7 +60,16 @@ @NamedQuery(name = "Workspace.getAll", query = "SELECT w FROM Workspace w"), @NamedQuery( name = "Workspace.getByTemporary", - query = "SELECT w FROM Workspace w WHERE w.isTemporary = :temporary" + query = "SELECT w " + "FROM Workspace w " + "WHERE w.isTemporary = :temporary " + ), + @NamedQuery(name = "Workspace.getAllCount", query = "SELECT COUNT(w) FROM Workspace w"), + @NamedQuery( + name = "Workspace.getByNamespaceCount", + query = "SELECT COUNT(w) " + "FROM Workspace w " + "WHERE w.account.name = :namespace " + ), + @NamedQuery( + name = "Workspace.getByTemporaryCount", + query = "SELECT COUNT(w) " + "FROM Workspace w " + "WHERE w.isTemporary = :temporary " ) }) @EntityListeners(WorkspaceImpl.SyncNameOnUpdateAndPersistEventListener.class) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java index c0312cc445a..ebd4b0e570b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java @@ -10,9 +10,9 @@ */ package org.eclipse.che.api.workspace.server.spi; -import java.util.List; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -105,7 +105,8 @@ WorkspaceImpl update(WorkspaceImpl update) * @throws NullPointerException when {@code owner} is null * @throws ServerException when any other error occurs during workspaces fetching */ - List getByNamespace(String namespace) throws ServerException; + Page getByNamespace(String namespace, int maxItems, long skipCount) + throws ServerException; /** * Gets list of workspaces which user can read @@ -114,7 +115,8 @@ WorkspaceImpl update(WorkspaceImpl update) * @return list of workspaces which user can read * @throws ServerException when any other error occurs during workspaces fetching */ - List getWorkspaces(String userId) throws ServerException; + Page getWorkspaces(String userId, int maxItems, long skipCount) + throws ServerException; /** * Gets workspaces by temporary attribute. @@ -127,6 +129,6 @@ WorkspaceImpl update(WorkspaceImpl update) * @throws ServerException when any other error occurs during workspaces fetching * @throws IllegalArgumentException when {@code maxItems} or {@code skipCount} is negative */ - List getWorkspaces(boolean isTemporary, int skipCount, int maxItems) + Page getWorkspaces(boolean isTemporary, int maxItems, long skipCount) throws ServerException; } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java index 7eca27b7bda..9c4d8028a57 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java @@ -11,24 +11,25 @@ package org.eclipse.che.api.workspace.server; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.intThat; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.Listeners; -import org.testng.annotations.Test; /** @author Max Shaposhnik (mshaposhnik@codenvy.com) */ @Listeners(MockitoTestNGListener.class) @@ -40,25 +41,17 @@ public class TemporaryWorkspaceRemoverTest { @InjectMocks private TemporaryWorkspaceRemover remover; - @Test + // @Test public void shouldRemoveTemporaryWorkspaces() throws Exception { doNothing().when(workspaceDao).remove(anyString()); - // As we want to check pagination, we return items 100 when skip count is 0 or 100, - // return 50 items when skip count is 200, and return empty list when skip count is 300. - doReturn(createEntities(100)) - .when(workspaceDao) - .getWorkspaces(eq(true), intThat(integer -> integer.intValue() < 200), anyInt()); - doReturn(createEntities(50)) - .when(workspaceDao) - .getWorkspaces(eq(true), intThat(argument -> ((int) argument) == 200), anyInt()); - doReturn(Collections.emptyList()) - .when(workspaceDao) - .getWorkspaces( - eq(true), intThat(argument -> ((int) argument) > COUNT_OF_WORKSPACES), anyInt()); - + when(workspaceDao.getWorkspaces(eq(true), anyInt(), anyLong())) + .thenReturn(new Page<>(createEntities(250), 0, 50, 250)); + when(workspaceDao.getWorkspaces( + eq(true), intThat(integer -> integer.intValue() > 250), anyLong())) + .thenReturn(new Page<>(Collections.emptyList(), 250, 50, 250)); remover.removeTemporaryWs(); - verify(workspaceDao, times(COUNT_OF_WORKSPACES)).remove(anyString()); + verify(workspaceDao, times(250)).remove(anyString()); } private List createEntities(int number) { diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java index 91098b6d8f5..cb8f4bdbcc0 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java @@ -20,6 +20,8 @@ import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.api.workspace.server.WorkspaceManager.UPDATED_ATTRIBUTE_NAME; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -40,13 +42,13 @@ import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; @@ -208,17 +210,18 @@ public void getsWorkspacesAvailableForUserWithRuntimes() throws Exception { final WorkspaceImpl workspace1 = createAndMockWorkspace(config, NAMESPACE_1); final WorkspaceImpl workspace2 = createAndMockWorkspace(config, NAMESPACE_2); final TestInternalRuntime runtime2 = mockRuntime(workspace2, RUNNING); - when(workspaceDao.getWorkspaces(NAMESPACE_1)).thenReturn(asList(workspace1, workspace2)); + when(workspaceDao.getWorkspaces(eq(NAMESPACE_1), anyInt(), anyLong())) + .thenReturn(new Page<>(asList(workspace1, workspace2), 0, 2, 2)); - final List result = workspaceManager.getWorkspaces(NAMESPACE_1, true); + final Page result = workspaceManager.getWorkspaces(NAMESPACE_1, true, 30, 0); - assertEquals(result.size(), 2); - final WorkspaceImpl res1 = result.get(0); + assertEquals(result.getItems().size(), 2); + final WorkspaceImpl res1 = result.getItems().get(0); assertEquals( res1.getStatus(), STOPPED, "Workspace status wasn't changed from STARTING to STOPPED"); assertNull(res1.getRuntime(), "Workspace has unexpected runtime"); assertFalse(res1.isTemporary(), "Workspace must be permanent"); - final WorkspaceImpl res2 = result.get(1); + final WorkspaceImpl res2 = result.getItems().get(1); assertEquals( res2.getStatus(), RUNNING, @@ -235,25 +238,26 @@ public void getsWorkspacesAvailableForUserWithoutRuntimes() throws Exception { final WorkspaceImpl workspace1 = createAndMockWorkspace(config, NAMESPACE_1); final WorkspaceImpl workspace2 = createAndMockWorkspace(config, NAMESPACE_2); - when(workspaceDao.getWorkspaces(NAMESPACE_1)).thenReturn(asList(workspace1, workspace2)); + when(workspaceDao.getWorkspaces(eq(NAMESPACE_1), anyInt(), anyLong())) + .thenReturn(new Page<>(asList(workspace1, workspace2), 0, 2, 2)); mockRuntimeStatus(workspace1, STOPPED); mockRuntimeStatus(workspace2, RUNNING); doNothing().when(runtimes).injectRuntime(workspace1); // when - final List result = workspaceManager.getWorkspaces(NAMESPACE_1, false); + final Page result = workspaceManager.getWorkspaces(NAMESPACE_1, false, 30, 0); // then - assertEquals(result.size(), 2); + assertEquals(result.getItems().size(), 2); - final WorkspaceImpl res1 = result.get(0); + final WorkspaceImpl res1 = result.getItems().get(0); assertEquals( res1.getStatus(), STOPPED, "Workspace status wasn't changed from STARTING to STOPPED"); assertNull(res1.getRuntime(), "Workspace has unexpected runtime"); assertFalse(res1.isTemporary(), "Workspace must be permanent"); - final WorkspaceImpl res2 = result.get(1); + final WorkspaceImpl res2 = result.getItems().get(1); assertEquals( res2.getStatus(), RUNNING, @@ -269,13 +273,13 @@ public void getsWorkspacesByNamespaceWithoutRuntimes() throws Exception { mockRuntimeStatus(workspace, RUNNING); // when - final List result = - workspaceManager.getByNamespace(workspace.getNamespace(), false); + final Page result = + workspaceManager.getByNamespace(workspace.getNamespace(), false, 30, 0); // then - assertEquals(result.size(), 1); + assertEquals(result.getItems().size(), 1); - final WorkspaceImpl res1 = result.get(0); + final WorkspaceImpl res1 = result.getItems().get(0); assertEquals( res1.getStatus(), RUNNING, @@ -291,13 +295,13 @@ public void getsWorkspacesByNamespaceWithRuntimes() throws Exception { final TestInternalRuntime runtime = mockRuntime(workspace, RUNNING); // when - final List result = - workspaceManager.getByNamespace(workspace.getNamespace(), true); + final Page result = + workspaceManager.getByNamespace(workspace.getNamespace(), true, 30, 0); // then - assertEquals(result.size(), 1); + assertEquals(result.getItems().size(), 1); - final WorkspaceImpl res1 = result.get(0); + final WorkspaceImpl res1 = result.getItems().get(0); assertEquals( res1.getStatus(), RUNNING, @@ -522,10 +526,12 @@ private WorkspaceImpl createAndMockWorkspace(WorkspaceConfig cfg, String namespa when(workspaceDao.get(workspace.getConfig().getName(), workspace.getNamespace())) .thenReturn(workspace); when(workspaceDao.get(workspace.getConfig().getName(), NAMESPACE_1)).thenReturn(workspace); - when(workspaceDao.getByNamespace(workspace.getNamespace())) - .thenReturn(singletonList(workspace)); - when(workspaceDao.getByNamespace(NAMESPACE_1)).thenReturn(singletonList(workspace)); - when(workspaceDao.getWorkspaces(USER_ID)).thenReturn(singletonList(workspace)); + when(workspaceDao.getByNamespace(eq(workspace.getNamespace()), anyInt(), anyLong())) + .thenReturn(new Page<>(singletonList(workspace), 0, 1, 1)); + when(workspaceDao.getByNamespace(eq(NAMESPACE_1), anyInt(), anyLong())) + .thenReturn(new Page<>(singletonList(workspace), 0, 1, 1)); + when(workspaceDao.getWorkspaces(eq(USER_ID), anyInt(), anyLong())) + .thenReturn(new Page<>(singletonList(workspace), 0, 1, 1)); return workspace; } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java index d5d6442c99b..98181986ca1 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java @@ -25,6 +25,8 @@ import static org.everrest.assured.JettyHttpServer.SECURE_PATH; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; @@ -43,6 +45,7 @@ import java.util.Map; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.core.model.workspace.config.ProjectConfig; @@ -595,7 +598,8 @@ public Object[][] invalidWorkspaceKeys() { public void shouldGetWorkspaces() throws Exception { final WorkspaceImpl workspace1 = createWorkspace(createConfigDto()); final WorkspaceImpl workspace2 = createWorkspace(createConfigDto(), STARTING); - when(wsManager.getWorkspaces(USER_ID, false)).thenReturn(asList(workspace1, workspace2)); + when(wsManager.getWorkspaces(eq(USER_ID), eq(false), anyInt(), anyLong())) + .thenReturn(new Page<>(asList(workspace1, workspace2), 0, 2, 2)); final Response response = given() @@ -617,7 +621,8 @@ public void shouldGetWorkspaces() throws Exception { public void shouldGetWorkspacesByNamespace() throws Exception { final WorkspaceImpl workspace1 = createWorkspace(createConfigDto()); final WorkspaceImpl workspace2 = createWorkspace(createConfigDto(), STARTING); - when(wsManager.getByNamespace(NAMESPACE, false)).thenReturn(asList(workspace1, workspace2)); + when(wsManager.getByNamespace(eq(NAMESPACE), eq(false), anyInt(), anyLong())) + .thenReturn(new Page<>(asList(workspace1, workspace2), 0, 2, 2)); final Response response = given() @@ -639,7 +644,8 @@ public void shouldGetWorkspacesByNamespace() throws Exception { public void shouldGetWorkspacesByStatus() throws Exception { final WorkspaceImpl workspace1 = createWorkspace(createConfigDto()); final WorkspaceImpl workspace2 = createWorkspace(createConfigDto(), STARTING); - when(wsManager.getWorkspaces(USER_ID, false)).thenReturn(asList(workspace1, workspace2)); + when(wsManager.getWorkspaces(eq(USER_ID), eq(false), anyInt(), anyLong())) + .thenReturn(new Page<>(asList(workspace1, workspace2), 0, 2, 2)); final Response response = given() diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index 8231b2a6459..ff7e0bfdcbd 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -36,6 +36,7 @@ import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.workspace.server.event.BeforeWorkspaceRemovedEvent; @@ -132,19 +133,19 @@ public void shouldGetWorkspacesByNamespace() throws Exception { assertEquals( workspace1.getNamespace(), workspace2.getNamespace(), "Namespaces must be the same"); - final List found = workspaceDao.getByNamespace(workspace1.getNamespace()); + final Page found = workspaceDao.getByNamespace(workspace1.getNamespace(), 30, 0); - assertEquals(new HashSet<>(found), new HashSet<>(asList(workspace1, workspace2))); + assertEquals(new HashSet<>(found.getItems()), new HashSet<>(asList(workspace1, workspace2))); } @Test public void emptyListShouldBeReturnedWhenThereAreNoWorkspacesInGivenNamespace() throws Exception { - assertTrue(workspaceDao.getByNamespace("non-existing-namespace").isEmpty()); + assertTrue(workspaceDao.getByNamespace("non-existing-namespace", 30, 0).isEmpty()); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNpeWhenGettingWorkspaceByNullNamespace() throws Exception { - workspaceDao.getByNamespace(null); + workspaceDao.getByNamespace(null, 30, 0); } @Test @@ -223,10 +224,11 @@ public void shouldNotRemoveWorkspaceWhenSubscriberThrowsExceptionOnWorkspaceRemo @Test public void shouldGetWorkspacesByNonTemporary() throws Exception { - List result = workspaceDao.getWorkspaces(false, 0, 2); + Page result = workspaceDao.getWorkspaces(false, 2, 0); - assertEquals(result.size(), 2); - assertEquals(new HashSet<>(result), new HashSet<>(asList(workspaces[0], workspaces[1]))); + assertEquals(result.getItems().size(), 2); + assertEquals( + new HashSet<>(result.getItems()), new HashSet<>(asList(workspaces[0], workspaces[1]))); } @Test @@ -235,10 +237,10 @@ public void shouldGetWorkspacesByTemporary() throws Exception { workspace.setTemporary(true); workspaceDao.update(workspace); - List result = workspaceDao.getWorkspaces(true, 0, 0); + Page result = workspaceDao.getWorkspaces(true, 30, 0); - assertEquals(result.size(), 1); - assertEquals(result.iterator().next(), workspaceDao.get(workspace.getId())); + assertEquals(result.getItems().size(), 1); + assertEquals(result.getItems().iterator().next(), workspaceDao.get(workspace.getId())); } @Test(expectedExceptions = IllegalArgumentException.class) diff --git a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java index 772d3cb5ead..f41b285e8ed 100644 --- a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java +++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java @@ -239,7 +239,7 @@ public void shouldDeleteAllTheEntitiesWhenUserAndAccountIsDeleted() throws Excep assertNull(notFoundToNull(() -> profileDao.getById(user.getId()))); assertTrue(preferenceDao.getPreferences(user.getId()).isEmpty()); assertTrue(sshDao.get(user.getId()).isEmpty()); - assertTrue(workspaceDao.getByNamespace(user.getName()).isEmpty()); + assertTrue(workspaceDao.getByNamespace(user.getName(), 30, 0).isEmpty()); } @Test(dataProvider = "beforeUserRemoveRollbackActions") @@ -286,7 +286,7 @@ public void shouldRollbackTransactionWhenFailedToRemoveAnyOfEntriesDuringAccount } // Check all the data rolled back - assertFalse(workspaceDao.getByNamespace(user.getName()).isEmpty()); + assertFalse(workspaceDao.getByNamespace(user.getName(), 30, 0).isEmpty()); wipeTestData(); } From 2dd371cc107322c5d46d90509062f92d9d44b594 Mon Sep 17 00:00:00 2001 From: Mykhailo Kuznietsov Date: Thu, 14 Dec 2017 17:45:56 +0200 Subject: [PATCH 3/7] fixup! Add migration of workspaces storage on Docker infrastructure --- .../webapp/WEB-INF/classes/che/che.properties | 5 + infrastructures/docker/infrastructure/pom.xml | 4 - .../LocalProjectsFolderPathProvider.java | 69 +++------- .../local/projects/LocalProjectsMigrator.java | 94 ++++++++++++++ .../projects/LocalProjectMigratorTest.java | 121 ++++++++++++++++++ .../LocalProjectsFolderPathProviderTest.java | 72 +++++++---- .../tracker/RamResourceUsageTracker.java | 16 +-- .../tracker/RuntimeResourceUsageTracker.java | 16 +-- .../WorkspaceResourceUsageTracker.java | 18 ++- .../workspace/server/WorkspaceService.java | 13 +- .../server/TemporaryWorkspaceRemoverTest.java | 19 ++- 11 files changed, 314 insertions(+), 133 deletions(-) create mode 100644 infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java create mode 100644 infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 3cc6a25986c..fddc199e9e9 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -292,6 +292,11 @@ che.infra.docker.bootstrapper.installer_timeout_sec=180 # Once servers for one installer available - checks stopped. che.infra.docker.bootstrapper.server_check_period_sec=3 +# Enable to perform migration of workpace projects at Che startup. +# Projects, which are stored in directories named after their workspace name, +# will be stored by workspace id instead. +che.workspace.migrate_workspace_projects_on_startup=true + ### INTERNAL # Remove locations where internal message bus events should be propagated to. # For debugging - set to retrieve internal events from external clients. diff --git a/infrastructures/docker/infrastructure/pom.xml b/infrastructures/docker/infrastructure/pom.xml index f00ea1fa5d6..6f98f20f43a 100644 --- a/infrastructures/docker/infrastructure/pom.xml +++ b/infrastructures/docker/infrastructure/pom.xml @@ -42,10 +42,6 @@ com.google.inject.extensions guice-multibindings - - commons-io - commons-io - javax.annotation javax.annotation-api diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java index 1ecf1cd8100..fe11b10c37d 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java @@ -11,7 +11,6 @@ package org.eclipse.che.workspace.infrastructure.docker.local.projects; import static java.lang.String.format; -import static org.eclipse.che.api.core.Pages.iterate; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; @@ -20,10 +19,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; import javax.annotation.PostConstruct; import javax.inject.Named; import javax.inject.Singleton; @@ -31,7 +26,6 @@ import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.util.SystemInfo; -import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils; import org.slf4j.Logger; @@ -55,6 +49,8 @@ public class LocalProjectsFolderPathProvider { private final WorkspaceDao workspaceDao; private final boolean isWindows; + private final boolean migrationOnStartup; + private final LocalProjectsMigrator localProjectsMigrator; /** * Value provide path to directory on host machine where will by all created and mount to the @@ -90,27 +86,36 @@ public class LocalProjectsFolderPathProvider { @Inject public LocalProjectsFolderPathProvider( - @Named("che.workspace.storage") String workspacesMountPoint, WorkspaceDao workspaceDao) + @Named("che.workspace.storage") String workspacesMountPoint, + @Named("che.workspace.migrate_workspace_projects_on_startup") boolean migrationOnStartup, + WorkspaceDao workspaceDao, + LocalProjectsMigrator localProjectsMigrator) throws IOException { this.workspacesMountPoint = workspacesMountPoint; + this.migrationOnStartup = migrationOnStartup; this.workspaceDao = workspaceDao; this.isWindows = SystemInfo.isWindows(); + this.localProjectsMigrator = localProjectsMigrator; } @VisibleForTesting protected LocalProjectsFolderPathProvider( String workspacesMountPoint, String oldWorkspacesMountPoint, + boolean migrationOnStartup, String projectsFolder, boolean createFolders, WorkspaceDao workspaceDao, + LocalProjectsMigrator localProjectsMigrator, boolean isWindows) throws IOException { this.workspaceDao = workspaceDao; this.workspacesMountPoint = workspacesMountPoint; + this.migrationOnStartup = migrationOnStartup; this.hostProjectsFolder = projectsFolder; this.createFolders = createFolders; this.oldWorkspacesMountPoint = oldWorkspacesMountPoint; + this.localProjectsMigrator = localProjectsMigrator; this.isWindows = isWindows; } @@ -186,7 +191,9 @@ void init() throws IOException { ensureExist(hostProjectsFolder, "host.projects.root"); } - performWorkspaceLocationMigration(); + if (migrationOnStartup && !isWindows && hostProjectsFolder == null) { + localProjectsMigrator.performMigration(workspacesMountPoint); + } } private void ensureExist(String path, String prop) throws IOException { @@ -229,50 +236,4 @@ private void ensureExist(String path, String prop) throws IOException { * Get all workspaces, and check if they are stored in workspacesMountPoint by their name, and * migrate them, so they will be stored by id */ - private void performWorkspaceLocationMigration() { - if (!isWindows || hostProjectsFolder != null) { - Map workspaceName2id = getId2NameWorkspaceMapping(); - for (Entry entry : workspaceName2id.entrySet()) { - Path workspaceStoredByNameLocation = - Paths.get(workspacesMountPoint).resolve(entry.getValue()); - if (!Files.exists(workspaceStoredByNameLocation)) { - // migration is not needed for this workspace - continue; - } - LOG.info( - "Starting migration of workspace with id '{}' and name '{}'", - entry.getKey(), - entry.getValue()); - Path workspaceStoredByIdLocation = Paths.get(workspacesMountPoint).resolve(entry.getKey()); - try { - Files.move( - workspaceStoredByNameLocation, - workspaceStoredByIdLocation, - StandardCopyOption.ATOMIC_MOVE); - LOG.info( - "Successfully workspace with id '{}' and name '{}'", - entry.getKey(), - entry.getValue()); - } catch (IOException e) { - LOG.error( - "Failed to workspace with id '{}' and name '{}'", entry.getKey(), entry.getValue()); - } - } - } - } - - private Map getId2NameWorkspaceMapping() { - try { - Map result = new HashMap<>(); - - for (WorkspaceImpl workspace : - iterate( - (maxItems, skipCount) -> workspaceDao.getWorkspaces(false, maxItems, skipCount))) { - result.put(workspace.getId(), workspace.getConfig().getName()); - } - return result; - } catch (ServerException e) { - throw new RuntimeException(e); - } - } } diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java new file mode 100644 index 00000000000..f369dc8ebae --- /dev/null +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.docker.local.projects; + +import static org.eclipse.che.api.core.Pages.iterate; + +import com.google.inject.Inject; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Performs migration of projects that are stored for workspace in directories, named respectively + * by their names, to new + * + * @author Mykhailo Kuznietsov + */ +public class LocalProjectsMigrator { + + private final WorkspaceDao workspaceDao; + + @Inject + public LocalProjectsMigrator(WorkspaceDao workspaceDao) { + this.workspaceDao = workspaceDao; + } + + private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsMigrator.class); + + public void performMigration(String workspaceProjectsRootFolder) { + Map workspaceName2id = getId2NameWorkspaceMapping(); + for (Entry entry : workspaceName2id.entrySet()) { + Path workspaceStoredByNameLocation = + Paths.get(workspaceProjectsRootFolder).resolve(entry.getValue()); + if (!Files.exists(workspaceStoredByNameLocation)) { + // migration is not needed for this workspace + continue; + } + LOG.info( + "Performing migration of workspace with id '{}' and name '{}'", + entry.getKey(), + entry.getValue()); + Path workspaceStoredByIdLocation = + Paths.get(workspaceProjectsRootFolder).resolve(entry.getKey()); + try { + Files.move( + workspaceStoredByNameLocation, + workspaceStoredByIdLocation, + StandardCopyOption.ATOMIC_MOVE); + LOG.info( + "Successfully migrated projects of workspace with id '{}' and name '{}'", + entry.getKey(), + entry.getValue()); + } catch (IOException e) { + LOG.error( + "Failed to migrate projects of workspace with id '{}' and name '{}'", + entry.getKey(), + entry.getValue()); + } + } + } + + private Map getId2NameWorkspaceMapping() { + try { + Map result = new HashMap<>(); + + for (WorkspaceImpl workspace : + iterate( + (maxItems, skipCount) -> workspaceDao.getWorkspaces(false, maxItems, skipCount))) { + result.put(workspace.getId(), workspace.getConfig().getName()); + } + return result; + } catch (ServerException e) { + throw new RuntimeException(e); + } + } +} diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java new file mode 100644 index 00000000000..65ece85827f --- /dev/null +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2012-2017 Red Hat, Inc. + * 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: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.workspace.infrastructure.docker.local.projects; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +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.List; +import org.eclipse.che.api.core.Page; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.eclipse.che.commons.lang.IoUtil; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +/** @author Mihail Kuznyetsov */ +@Listeners(value = {MockitoTestNGListener.class}) +public class LocalProjectMigratorTest { + private static final String WS_ID_PREFIX = "ws_id_"; + private static final String WS_NAME_PREFIX = "ws_name_"; + + private LocalProjectsMigrator localProjectsMigrator; + + @Mock WorkspaceDao workspaceDao; + + private String workspacesRoot; + private File workspacesRootFile; + + @BeforeMethod + public void setUp() throws IOException { + Path tempDirectory = Files.createTempDirectory(getClass().getSimpleName()); + workspacesRoot = tempDirectory.toString(); + workspacesRootFile = tempDirectory.toFile(); + + localProjectsMigrator = new LocalProjectsMigrator(workspaceDao); + } + + @AfterMethod + public void tearDown() throws IOException { + IoUtil.deleteRecursive(workspacesRootFile); + } + + @Test + public void shouldPerformMigrationOnSingleWorkspace() throws Exception { + List workspaces = createWorkspaces(1, "oldWorkspace", true); + when(workspaceDao.getWorkspaces(anyBoolean(), anyInt(), anyLong())) + .thenReturn(new Page<>(workspaces, 0, 1, 1)); + + localProjectsMigrator.performMigration(workspacesRoot); + + Path oldWorkspacePath = + Paths.get(workspacesRoot).resolve(WS_NAME_PREFIX + "ws_name_oldWorkspace1"); + Path newWorkspacePath = Paths.get(workspacesRoot).resolve(WS_ID_PREFIX + "oldWorkspace1"); + + assertFalse(Files.exists(oldWorkspacePath)); + assertTrue(Files.exists(newWorkspacePath)); + } + // + // @Test + // public void shouldMigrateOnlyWorkspacesWithOldLocation() throws Exception { + // List workspaces1 = createWorkspaces(1, "oldWorkspace", true); + // List workspaces2 = createWorkspaces(1, "newWorkspace", false); + // when(workspaceDao.getWorkspaces(anyBoolean(), anyInt(), anyLong())) + // .thenReturn(new Page(workspaces1.addAll(workspaces2), 0, 2, 2)); + // + // localProjectsMigrator.performMigration(workspacesRoot); + // + // Path newWorkspacePath = Paths.get(workspacesRoot).resolve("ws_id_oldWorkspace1"); + // Path oldWorkspacePath = Paths.get(workspacesRoot).resolve("ws_name_oldWorkspace1"); + // + // assertFalse(Files.exists(oldWorkspacePath)); + // assertTrue(Files.exists(newWorkspacePath)); + // } + + private List createWorkspaces( + int amount, String namePrefix, boolean oldProjectsLocation) throws IOException { + List result = new ArrayList<>(); + for (int i = 1; i <= amount; i++) { + String workspaceName = "ws_name_" + namePrefix + i; + String workspaceId = "ws_id_" + namePrefix + i; + + WorkspaceImpl workspace = mock(WorkspaceImpl.class); + WorkspaceConfigImpl workspaceConfig = mock(WorkspaceConfigImpl.class); + when(workspace.getId()).thenReturn(workspaceId); + when(workspace.getConfig()).thenReturn(workspaceConfig); + when(workspace.getConfig().getName()).thenReturn(workspaceName); + + result.add(workspace); + + String workspaceFolder = oldProjectsLocation ? workspaceName : workspaceId; + Files.createDirectories(Paths.get(workspacesRoot).resolve(workspaceFolder)); + Files.createFile(Paths.get(workspacesRoot).resolve(workspaceFolder).resolve("pom.xml")); + } + + return result; + } +} diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java index 942679a04b1..93783a178f7 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java @@ -14,6 +14,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -25,12 +26,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; -import org.apache.commons.io.FileUtils; import org.eclipse.che.api.core.Page; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -47,6 +48,7 @@ public class LocalProjectsFolderPathProviderTest { private static final String WS_NAMESPACE = "che"; @Mock private WorkspaceDao workspaceDao; + @Mock private LocalProjectsMigrator localProjectsMigrator; private String singleFolderForAllWorkspaces; private String oldWorkspacesRoot; @@ -76,7 +78,7 @@ public void setUp() throws Exception { @AfterMethod public void tearDown() throws Exception { - FileUtils.deleteDirectory(workspacesRootFile); + IoUtil.deleteRecursive(workspacesRootFile); } @Test @@ -84,7 +86,8 @@ public void createsFoldersByDefault() throws Exception { assertTrue(workspacesRootFile.delete()); LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider(workspacesRoot, workspaceDao); + new LocalProjectsFolderPathProvider( + workspacesRoot, false, workspaceDao, localProjectsMigrator); provider.init(); @@ -104,9 +107,11 @@ public void createsFoldersIfConfigured() throws Exception { new LocalProjectsFolderPathProvider( workspacesRoot, null, + false, null, true, // <- Create folder if it doesn't exist workspaceDao, + localProjectsMigrator, false); provider.init(); @@ -127,9 +132,11 @@ public void worksIfWorkspaceFolderExists() throws Exception { new LocalProjectsFolderPathProvider( workspacesRoot, null, + false, null, false, // <- Do not create folders workspaceDao, + localProjectsMigrator, false); provider.init(); @@ -150,9 +157,11 @@ public void neitherCheckNorCreateFoldersIfCreationIsDisabled() throws Exception new LocalProjectsFolderPathProvider( workspacesRoot, null, + false, null, false, // <- Do not create folders workspaceDao, + localProjectsMigrator, false); provider.init(); @@ -168,9 +177,11 @@ public void returnSpecificFolderOnOnWindows() throws Exception { new LocalProjectsFolderPathProvider( workspacesRoot, oldWorkspacesRoot, + false, singleFolderForAllWorkspaces, false, workspaceDao, + localProjectsMigrator, true); provider.init(); @@ -186,9 +197,11 @@ public void returnsSingleFolderForAllWorkspacesIfConfigured() throws Exception { new LocalProjectsFolderPathProvider( workspacesRoot, oldWorkspacesRoot, + false, singleFolderForAllWorkspaces, false, workspaceDao, + localProjectsMigrator, false); provider.init(); @@ -201,7 +214,14 @@ public void returnsSingleFolderForAllWorkspacesIfConfigured() throws Exception { public void useOlderFolderIfConfigured() throws Exception { LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider( - workspacesRoot, oldWorkspacesRoot, null, false, workspaceDao, false); + workspacesRoot, + oldWorkspacesRoot, + false, + null, + false, + workspaceDao, + localProjectsMigrator, + false); provider.init(); String providerPath = provider.getPath(WS_ID); @@ -216,7 +236,8 @@ public void useOlderFolderIfConfigured() throws Exception { public void throwsExceptionIfFileIsFoundByWorkspacesPath() throws Exception { assertTrue(Paths.get(workspacesRoot, WS_ID).toFile().createNewFile()); LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider(workspacesRoot, null, null, true, workspaceDao, false); + new LocalProjectsFolderPathProvider( + workspacesRoot, null, false, null, true, workspaceDao, localProjectsMigrator, false); provider.init(); provider.getPath(WS_ID); @@ -231,7 +252,14 @@ public void throwsExceptionIfFileIsFoundByWorkspacesRootPath() throws Exception Path tempFile = Files.createTempFile(getClass().getSimpleName(), null); LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider( - tempFile.toString(), null, null, true, workspaceDao, false); + tempFile.toString(), + null, + false, + null, + true, + workspaceDao, + localProjectsMigrator, + false); provider.init(); } @@ -245,7 +273,14 @@ public void throwsExceptionIfFileIsFoundBySingleWorkspacePath() throws Exception Path tempFile = Files.createTempFile(getClass().getSimpleName(), null); LocalProjectsFolderPathProvider provider = new LocalProjectsFolderPathProvider( - workspacesRoot, oldWorkspacesRoot, tempFile.toString(), true, workspaceDao, false); + workspacesRoot, + oldWorkspacesRoot, + false, + tempFile.toString(), + true, + workspaceDao, + localProjectsMigrator, + false); provider.init(); provider.getPath(WS_ID); @@ -259,7 +294,8 @@ public void throwsIOExceptionIfWorkspaceRetrievalFails() throws Exception { when(workspaceDao.get(WS_NAME, WS_NAMESPACE)) .thenThrow(new ServerException("expected test exception")); LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, true); + new LocalProjectsFolderPathProvider( + workspacesRoot, null, false, null, false, workspaceDao, localProjectsMigrator, true); provider.init(); provider.getPathByName(WS_NAME, WS_NAMESPACE); @@ -271,25 +307,11 @@ public void shouldPerformWorkspaceMigration() throws Exception { Files.createFile(Paths.get(workspacesRoot).resolve(WS_NAME).resolve("pom.xml")); LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, false); - - provider.init(); - - Path expectedNewWorkspacePath = Paths.get(workspacesRoot).resolve(WS_ID); - assertTrue(Files.exists(expectedNewWorkspacePath)); - } - - @Test - public void shouldPerformWorkspaceMigration2() throws Exception { - Files.createDirectories(Paths.get(workspacesRoot).resolve(WS_NAME)); - Files.createFile(Paths.get(workspacesRoot).resolve(WS_NAME).resolve("pom.xml")); - - LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider(workspacesRoot, null, null, false, workspaceDao, false); + new LocalProjectsFolderPathProvider( + workspacesRoot, null, true, null, false, workspaceDao, localProjectsMigrator, false); provider.init(); - Path expectedNewWorkspacePath = Paths.get(workspacesRoot).resolve(WS_ID); - assertTrue(Files.exists(expectedNewWorkspacePath)); + verify(localProjectsMigrator).performMigration(eq(workspacesRoot)); } } diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java index 8848a6405d9..f6b15d79a6b 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RamResourceUsageTracker.java @@ -10,10 +10,8 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; -import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; -import com.google.common.collect.Lists; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -23,6 +21,7 @@ import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; import org.eclipse.che.api.workspace.server.WorkspaceManager; @@ -59,14 +58,11 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); List activeWorkspaces = - Lists.newArrayList( - iterate( - (maxItems, skipCount) -> - workspaceManagerProvider - .get() - .getByNamespace(account.getName(), true, maxItems, skipCount)) - .iterator()) - .stream() + Pages.stream( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), true, maxItems, skipCount)) .filter(ws -> STOPPED != ws.getStatus()) .collect(Collectors.toList()); long currentlyUsedRamMB = 0; diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java index b6297918ffc..9d347960b15 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/RuntimeResourceUsageTracker.java @@ -10,10 +10,8 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; -import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; -import com.google.common.collect.Lists; import java.util.Optional; import javax.inject.Inject; import javax.inject.Provider; @@ -21,6 +19,7 @@ import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.multiuser.resource.api.ResourceUsageTracker; @@ -50,14 +49,11 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); final long currentlyUsedRuntimes = - Lists.newArrayList( - iterate( - (maxItems, skipCount) -> - workspaceManagerProvider - .get() - .getByNamespace(account.getName(), false, maxItems, skipCount)) - .iterator()) - .stream() + Pages.stream( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), false, maxItems, skipCount)) .filter(ws -> STOPPED != ws.getStatus()) .count(); if (currentlyUsedRuntimes > 0) { diff --git a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java index ab700a9893f..46c1149a118 100644 --- a/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java +++ b/multiuser/api/che-multiuser-api-resource/src/main/java/org/eclipse/che/multiuser/resource/api/usage/tracker/WorkspaceResourceUsageTracker.java @@ -10,17 +10,16 @@ */ package org.eclipse.che.multiuser.resource.api.usage.tracker; -import static org.eclipse.che.api.core.Pages.iterate; - -import com.google.common.collect.Lists; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Provider; import javax.inject.Singleton; import org.eclipse.che.account.api.AccountManager; import org.eclipse.che.account.shared.model.Account; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -51,13 +50,12 @@ public Optional getUsedResource(String accountId) throws NotFoundException, ServerException { final Account account = accountManager.getById(accountId); final List accountWorkspaces = - Lists.newArrayList( - iterate( - (maxItems, skipCount) -> - workspaceManagerProvider - .get() - .getByNamespace(account.getName(), false, maxItems, skipCount)) - .iterator()); + Pages.stream( + (maxItems, skipCount) -> + workspaceManagerProvider + .get() + .getByNamespace(account.getName(), false, maxItems, skipCount)) + .collect(Collectors.toList()); if (!accountWorkspaces.isEmpty()) { return Optional.of( new ResourceImpl( diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index 9161eb6db66..72deb58c167 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -15,10 +15,8 @@ import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toList; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; -import static org.eclipse.che.api.core.Pages.iterate; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -47,6 +45,7 @@ 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.Pages; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.Workspace; @@ -224,7 +223,6 @@ public List getWorkspaces( Integer maxItems, @ApiParam("Workspace status") @QueryParam("status") String status) throws ServerException, BadRequestException { - // TODO add maxItems & skipCount to manager return withLinks( workspaceManager .getWorkspaces( @@ -257,12 +255,9 @@ public List getByNamespace( @ApiParam("The namespace") @PathParam("namespace") String namespace) throws ServerException, BadRequestException { return withLinks( - Lists.newArrayList( - iterate( - (maxItems, skipCount) -> - workspaceManager.getByNamespace(namespace, false, maxItems, skipCount)) - .iterator()) - .stream() + Pages.stream( + (maxItems, skipCount) -> + workspaceManager.getByNamespace(namespace, false, maxItems, skipCount)) .filter(ws -> status == null || status.equalsIgnoreCase(ws.getStatus().toString())) .map(DtoConverter::asDto) .collect(toList())); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java index 9c4d8028a57..18a75398f24 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java @@ -14,44 +14,41 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.intThat; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.eclipse.che.api.core.Page; +import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.Listeners; +import org.testng.annotations.Test; /** @author Max Shaposhnik (mshaposhnik@codenvy.com) */ @Listeners(MockitoTestNGListener.class) public class TemporaryWorkspaceRemoverTest { - static final int COUNT_OF_WORKSPACES = 250; + static final int COUNT_OF_WORKSPACES = 100; @Mock private WorkspaceDao workspaceDao; @InjectMocks private TemporaryWorkspaceRemover remover; - // @Test + @Test public void shouldRemoveTemporaryWorkspaces() throws Exception { - doNothing().when(workspaceDao).remove(anyString()); when(workspaceDao.getWorkspaces(eq(true), anyInt(), anyLong())) - .thenReturn(new Page<>(createEntities(250), 0, 50, 250)); - when(workspaceDao.getWorkspaces( - eq(true), intThat(integer -> integer.intValue() > 250), anyLong())) - .thenReturn(new Page<>(Collections.emptyList(), 250, 50, 250)); + .thenReturn( + new Page<>( + createEntities(50), 0, 50, Pages.iterate(null, null))); remover.removeTemporaryWs(); - verify(workspaceDao, times(250)).remove(anyString()); + verify(workspaceDao, times(COUNT_OF_WORKSPACES)).remove(anyString()); } private List createEntities(int number) { From ccee5b0bd57725ce453123a8f440ee275baf77bc Mon Sep 17 00:00:00 2001 From: Mykhailo Kuznietsov Date: Thu, 14 Dec 2017 17:46:07 +0200 Subject: [PATCH 4/7] fixup! fixup! Add migration of workspaces storage on Docker infrastructure --- .../java/org/eclipse/che/api/core/Pages.java | 2 +- .../server/TemporaryWorkspaceRemoverTest.java | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/Pages.java b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/Pages.java index c906b4968d8..ebfae5b3f66 100644 --- a/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/Pages.java +++ b/core/che-core-api-core/src/main/java/org/eclipse/che/api/core/Pages.java @@ -26,7 +26,7 @@ public final class Pages { /** An experimental value used as default page size where necessary. */ - private static final int DEFAULT_PAGE_SIZE = 50; + public static final int DEFAULT_PAGE_SIZE = 50; /** * Defines an interface for page supplier. diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java index 18a75398f24..54da1d3d0d9 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java @@ -10,6 +10,7 @@ */ package org.eclipse.che.api.workspace.server; +import static org.eclipse.che.api.core.Pages.DEFAULT_PAGE_SIZE; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -34,7 +35,7 @@ @Listeners(MockitoTestNGListener.class) public class TemporaryWorkspaceRemoverTest { - static final int COUNT_OF_WORKSPACES = 100; + static final int COUNT_OF_WORKSPACES = 150; @Mock private WorkspaceDao workspaceDao; @@ -43,9 +44,21 @@ public class TemporaryWorkspaceRemoverTest { @Test public void shouldRemoveTemporaryWorkspaces() throws Exception { when(workspaceDao.getWorkspaces(eq(true), anyInt(), anyLong())) - .thenReturn( - new Page<>( - createEntities(50), 0, 50, Pages.iterate(null, null))); + .thenReturn(new Page<>( + createEntities(DEFAULT_PAGE_SIZE), + 0, + DEFAULT_PAGE_SIZE, + COUNT_OF_WORKSPACES)) + .thenReturn(new Page<>( + createEntities(DEFAULT_PAGE_SIZE), + DEFAULT_PAGE_SIZE, + DEFAULT_PAGE_SIZE, + COUNT_OF_WORKSPACES)) + .thenReturn(new Page<>( + createEntities(DEFAULT_PAGE_SIZE), + DEFAULT_PAGE_SIZE * 2, + DEFAULT_PAGE_SIZE, + COUNT_OF_WORKSPACES)); remover.removeTemporaryWs(); verify(workspaceDao, times(COUNT_OF_WORKSPACES)).remove(anyString()); From cfc9af33f1306156ad8cf8658e6005317070ddce Mon Sep 17 00:00:00 2001 From: Oleksandr Garagatyi Date: Tue, 19 Dec 2017 15:47:30 +0200 Subject: [PATCH 5/7] Allow getting workspace storage path inside of Che master container Signed-off-by: Oleksandr Garagatyi --- dockerfiles/che/entrypoint.sh | 3 +- .../LocalProjectsFolderPathProvider.java | 176 +++++++++--------- .../LocalProjectsFolderPathProviderTest.java | 19 -- 3 files changed, 85 insertions(+), 113 deletions(-) diff --git a/dockerfiles/che/entrypoint.sh b/dockerfiles/che/entrypoint.sh index 489eb3d0667..8939f60f6f7 100755 --- a/dockerfiles/che/entrypoint.sh +++ b/dockerfiles/che/entrypoint.sh @@ -230,8 +230,6 @@ init() { sudo chown -R ${CHE_USER} ${CHE_LOGS_DIR} fi - - export CHE_WORKSPACE_STORAGE=/data/workspaces export CHE_DATABASE=/data/storage export CHE_TEMPLATE_STORAGE=/data/templates export CHE_WORKSPACE_AGENT_DEV=${CHE_DATA_HOST}/lib/ws-agent.tar.gz @@ -246,6 +244,7 @@ init() { export CHE_DOCKER_IP_EXTERNAL=${HOSTNAME} fi ### Necessary to allow the container to write projects to the folder + export CHE_WORKSPACE_STORAGE__MASTER__PATH=/data/workspaces export CHE_WORKSPACE_STORAGE="${CHE_DATA_HOST}/workspaces" export CHE_WORKSPACE_STORAGE_CREATE_FOLDERS=false diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java index fe11b10c37d..a9f3ef16697 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProvider.java @@ -27,9 +27,8 @@ import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.core.util.SystemInfo; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Provides path to workspace projects folder on host. @@ -39,18 +38,18 @@ @Singleton public class LocalProjectsFolderPathProvider { - public static final String ALLOW_FOLDERS_CREATION_ENV_VARIABLE = - "CHE_WORKSPACE_STORAGE_CREATE_FOLDERS"; - public static final String WORKSPACE_STORAGE_PATH_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE"; - public static final String WORKSPACE_STORAGE_MIGRATION_FLAG_ENV_VARIABLE = - "che.workspace.migrate_workspaces_stored_by_name"; + static final String ALLOW_FOLDERS_CREATION_PROPERTY = "che.workspace.storage.create.folders"; + static final String WORKSPACE_STORAGE_MIGRATION_FLAG_PROPERTY = + "che.workspace.migrate_workspace_projects_on_startup"; + static final String WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY = "che.workspace.storage"; + static final String CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY = + "che.workspace.storage_master_path"; + static final String SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY = "host.projects.root"; - private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsFolderPathProvider.class); - - private final WorkspaceDao workspaceDao; private final boolean isWindows; private final boolean migrationOnStartup; private final LocalProjectsMigrator localProjectsMigrator; + private final WorkspaceDao workspaceDao; /** * Value provide path to directory on host machine where will by all created and mount to the @@ -58,77 +57,100 @@ public class LocalProjectsFolderPathProvider { * point to the directory described by {@literal che.workspace.projects.storage}. * *

For example: if you set {@literal che.workspaces.storage} to the /home/user/che/workspaces - * after creating new workspace will be created new folder - * /home/user/che/workspaces/{workspaceName} and it will be mount to the dev-machine to {@literal + * after creating new workspace will be created new folder /home/user/che/workspaces/{workspaceId} + * and it will be mount to the machine with projects volume to {@literal * che.workspace.projects.storage} */ - private String workspacesMountPoint; + private final String workspacesMountPoint; + /** - * this value provide path to projects on local host if this value will be set all workspace will + * This value provide path to projects on local host if this value will be set all workspace will * manage same projects from your host */ @Inject(optional = true) - @Named("host.projects.root") - private String hostProjectsFolder; + @Named(SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY) + private String singleMountPointForAllWorkspaces; - /** - * If environment variable with name {@link #ALLOW_FOLDERS_CREATION_ENV_VARIABLE} is equal - * (ignoring case) to {@literal false} then this field is set to false. Otherwise it is set to - * true. It is also possible to overwrite with named constant. - */ @Inject(optional = true) - @Named("che.workspace.storage.create_folders") - private boolean createFolders = true; + @Named(CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY) + private String workspacesMountPointForCheMaster; @Inject(optional = true) - @Named("che.user.workspaces.storage") - private String oldWorkspacesMountPoint; + @Named(ALLOW_FOLDERS_CREATION_PROPERTY) + private boolean createFolders = true; @Inject public LocalProjectsFolderPathProvider( - @Named("che.workspace.storage") String workspacesMountPoint, - @Named("che.workspace.migrate_workspace_projects_on_startup") boolean migrationOnStartup, + @Named(WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY) String workspacesMountPoint, + @Named(WORKSPACE_STORAGE_MIGRATION_FLAG_PROPERTY) boolean migrationOnStartup, WorkspaceDao workspaceDao, LocalProjectsMigrator localProjectsMigrator) throws IOException { - this.workspacesMountPoint = workspacesMountPoint; - this.migrationOnStartup = migrationOnStartup; - this.workspaceDao = workspaceDao; - this.isWindows = SystemInfo.isWindows(); - this.localProjectsMigrator = localProjectsMigrator; + this( + workspacesMountPoint, + null, + migrationOnStartup, + null, + null, + workspaceDao, + localProjectsMigrator, + SystemInfo.isWindows()); } @VisibleForTesting protected LocalProjectsFolderPathProvider( String workspacesMountPoint, - String oldWorkspacesMountPoint, + @Nullable String workspacesMountPointForCheMaster, boolean migrationOnStartup, - String projectsFolder, - boolean createFolders, + @Nullable String singleMountPointForAllWorkspaces, + @Nullable Boolean createFolders, WorkspaceDao workspaceDao, LocalProjectsMigrator localProjectsMigrator, boolean isWindows) throws IOException { this.workspaceDao = workspaceDao; - this.workspacesMountPoint = workspacesMountPoint; this.migrationOnStartup = migrationOnStartup; - this.hostProjectsFolder = projectsFolder; - this.createFolders = createFolders; - this.oldWorkspacesMountPoint = oldWorkspacesMountPoint; - this.localProjectsMigrator = localProjectsMigrator; this.isWindows = isWindows; + this.localProjectsMigrator = localProjectsMigrator; + + if (createFolders != null) { + this.createFolders = createFolders; + } + if (singleMountPointForAllWorkspaces != null) { + this.singleMountPointForAllWorkspaces = singleMountPointForAllWorkspaces; + } + // In case workspace mount path specific for che master is not defined we treat it equal to + // regular workspace mount point + if (workspacesMountPointForCheMaster != null) { + this.workspacesMountPointForCheMaster = workspacesMountPointForCheMaster; + } else { + this.workspacesMountPointForCheMaster = workspacesMountPoint; + } + // Priority of workspace storage path sources: + // If Che is running on Windows + // che-home-location/vfs + // Otherwise + // use value from property injected into constructor + // find root directory for projects in workspaces + if (isWindows) { + final Path vfs = WindowsHostUtils.getCheHome().resolve("vfs"); + this.workspacesMountPoint = vfs.toString(); + } else { + this.workspacesMountPoint = workspacesMountPoint; + } } public String getPath(String workspaceId) throws IOException { - if (!isWindows && hostProjectsFolder != null) { - return hostProjectsFolder; + if (!isWindows && singleMountPointForAllWorkspaces != null) { + return singleMountPointForAllWorkspaces; } return doGetPathById(workspaceId); } - public String getPathByName(String workspaceName, String workspaceNamespace) throws IOException { - if (!isWindows && hostProjectsFolder != null) { - return hostProjectsFolder; + @Deprecated + String getPathByName(String workspaceName, String workspaceNamespace) throws IOException { + if (!isWindows && singleMountPointForAllWorkspaces != null) { + return singleMountPointForAllWorkspaces; } try { @@ -141,58 +163,33 @@ public String getPathByName(String workspaceName, String workspaceNamespace) thr private String doGetPathById(String workspaceId) throws IOException { - final String workspaceFolderPath = - Paths.get(workspacesMountPoint).resolve(workspaceId).toString(); - ensureExist(workspaceFolderPath, null); + String workspaceFolderPath = Paths.get(workspacesMountPoint).resolve(workspaceId).toString(); + // Since Che may be running inside of container and workspaces are mounted not in the same way + // they will be mounted from host to workspace's containers we use Che master specific paths. + // In cases when Che master specific path is not defined it will be equal to the workspace's + // containers one. + String workspaceFolderPathForCheMaster = + Paths.get(workspacesMountPointForCheMaster).resolve(workspaceId).toString(); + ensureExist(workspaceFolderPathForCheMaster, null); return workspaceFolderPath; } @VisibleForTesting @PostConstruct void init() throws IOException { - // check folders creation flag from environment variable - String allowFoldersCreationEnvVar = System.getenv(ALLOW_FOLDERS_CREATION_ENV_VARIABLE); - if ("false".equalsIgnoreCase(allowFoldersCreationEnvVar)) { - createFolders = false; - } - - // Priority of workspace storage path sources: - // If Che is running on Windows - // che-home-location/vfs - // Otherwise - // If environment variable for storage location is set - // use value of that variable - // Otherwise - // If old property of workspace storage is set - // use value of that property for backward compatibility - // Otherwise - // use up-to-date property - // find root directory for projects in workspaces - if (isWindows) { - final Path vfs = WindowsHostUtils.getCheHome().resolve("vfs"); - workspacesMountPoint = vfs.toString(); + // create directories if needed + if (singleMountPointForAllWorkspaces != null) { + ensureExist(singleMountPointForAllWorkspaces, SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY); } else { - String workspaceStorageFromEnv = System.getenv(WORKSPACE_STORAGE_PATH_ENV_VARIABLE); - if (workspaceStorageFromEnv != null) { - workspacesMountPoint = workspaceStorageFromEnv; - } else if (oldWorkspacesMountPoint != null) { - workspacesMountPoint = oldWorkspacesMountPoint; - } - } + ensureExist(workspacesMountPoint, WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY); - // create directories if needed - if (hostProjectsFolder == null) { ensureExist( - workspacesMountPoint, - oldWorkspacesMountPoint == null - ? "che.workspace.storage" - : "che.user.workspaces.storage"); - } else { - ensureExist(hostProjectsFolder, "host.projects.root"); - } + workspacesMountPointForCheMaster, + CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY); - if (migrationOnStartup && !isWindows && hostProjectsFolder == null) { - localProjectsMigrator.performMigration(workspacesMountPoint); + if (migrationOnStartup && !isWindows) { + localProjectsMigrator.performMigration(workspacesMountPointForCheMaster); + } } } @@ -231,9 +228,4 @@ private void ensureExist(String path, String prop) throws IOException { } } } - - /** - * Get all workspaces, and check if they are stored in workspacesMountPoint by their name, and - * migrate them, so they will be stored by id - */ } diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java index 93783a178f7..6e58d2d40b8 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsFolderPathProviderTest.java @@ -210,25 +210,6 @@ public void returnsSingleFolderForAllWorkspacesIfConfigured() throws Exception { assertEquals(providerPath, singleFolderForAllWorkspaces); } - @Test - public void useOlderFolderIfConfigured() throws Exception { - LocalProjectsFolderPathProvider provider = - new LocalProjectsFolderPathProvider( - workspacesRoot, - oldWorkspacesRoot, - false, - null, - false, - workspaceDao, - localProjectsMigrator, - false); - - provider.init(); - String providerPath = provider.getPath(WS_ID); - - assertEquals(providerPath, Paths.get(oldWorkspacesRoot, WS_ID).toString()); - } - @Test( expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Workspace folder '.*' is not directory" From eb7ecf6bd26cef9d3e8c4b6e4c199abad1a21ad5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kuznietsov Date: Fri, 22 Dec 2017 10:15:45 +0200 Subject: [PATCH 6/7] fixup --- .../local/projects/LocalProjectsMigrator.java | 10 +++--- .../projects/LocalProjectMigratorTest.java | 16 ---------- .../spi/jpa/MultiuserJpaWorkspaceDao.java | 2 +- .../server/TemporaryWorkspaceRemover.java | 1 - .../workspace/server/jpa/JpaWorkspaceDao.java | 2 +- .../server/TemporaryWorkspaceRemoverTest.java | 31 +++++++++---------- .../server/spi/tck/WorkspaceDaoTest.java | 6 ++-- 7 files changed, 27 insertions(+), 41 deletions(-) diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java index f369dc8ebae..260b61d4cdd 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java @@ -28,8 +28,9 @@ import org.slf4j.LoggerFactory; /** - * Performs migration of projects that are stored for workspace in directories, named respectively - * by their names, to new + * Performs migration of workspace project files, that are stored in old format (in directories + * named after their workspace name), so they will be stored in folders named after their workspace + * ID. * * @author Mykhailo Kuznietsov */ @@ -45,6 +46,7 @@ public LocalProjectsMigrator(WorkspaceDao workspaceDao) { private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsMigrator.class); public void performMigration(String workspaceProjectsRootFolder) { + LOG.debug("Starting migration of workspace project files"); Map workspaceName2id = getId2NameWorkspaceMapping(); for (Entry entry : workspaceName2id.entrySet()) { Path workspaceStoredByNameLocation = @@ -53,7 +55,7 @@ public void performMigration(String workspaceProjectsRootFolder) { // migration is not needed for this workspace continue; } - LOG.info( + LOG.debug( "Performing migration of workspace with id '{}' and name '{}'", entry.getKey(), entry.getValue()); @@ -69,7 +71,7 @@ public void performMigration(String workspaceProjectsRootFolder) { entry.getKey(), entry.getValue()); } catch (IOException e) { - LOG.error( + LOG.debug( "Failed to migrate projects of workspace with id '{}' and name '{}'", entry.getKey(), entry.getValue()); diff --git a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java index 65ece85827f..0afffdc0260 100644 --- a/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java +++ b/infrastructures/docker/infrastructure/src/test/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectMigratorTest.java @@ -79,22 +79,6 @@ public void shouldPerformMigrationOnSingleWorkspace() throws Exception { assertFalse(Files.exists(oldWorkspacePath)); assertTrue(Files.exists(newWorkspacePath)); } - // - // @Test - // public void shouldMigrateOnlyWorkspacesWithOldLocation() throws Exception { - // List workspaces1 = createWorkspaces(1, "oldWorkspace", true); - // List workspaces2 = createWorkspaces(1, "newWorkspace", false); - // when(workspaceDao.getWorkspaces(anyBoolean(), anyInt(), anyLong())) - // .thenReturn(new Page(workspaces1.addAll(workspaces2), 0, 2, 2)); - // - // localProjectsMigrator.performMigration(workspacesRoot); - // - // Path newWorkspacePath = Paths.get(workspacesRoot).resolve("ws_id_oldWorkspace1"); - // Path oldWorkspacePath = Paths.get(workspacesRoot).resolve("ws_name_oldWorkspace1"); - // - // assertFalse(Files.exists(oldWorkspacePath)); - // assertTrue(Files.exists(newWorkspacePath)); - // } private List createWorkspaces( int amount, String namePrefix, boolean oldProjectsLocation) throws IOException { diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java index deb348fe999..9f135135ef6 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java @@ -165,7 +165,7 @@ public Page getByNamespace(String namespace, int maxItems, long s final long count = manager .createNamedQuery("Workspace.getByNamespaceCount", Long.class) - .setParameter("namespace", namespace.toLowerCase()) + .setParameter("namespace", namespace) .getSingleResult(); return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java index 88379124a4d..0016d527b4b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemover.java @@ -60,7 +60,6 @@ void shutdown() { @VisibleForTesting void removeTemporaryWs() throws ServerException { - ; for (WorkspaceImpl workspace : Pages.iterate( (maxItems, skipCount) -> workspaceDao.getWorkspaces(true, maxItems, skipCount))) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index 2c11acb960e..2bca26ebd31 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -154,7 +154,7 @@ public Page getByNamespace(String namespace, int maxItems, long s final long count = manager .createNamedQuery("Workspace.getByNamespaceCount", Long.class) - .setParameter("namespace", namespace.toLowerCase()) + .setParameter("namespace", namespace) .getSingleResult(); return new Page<>(list, skipCount, maxItems, count); } catch (RuntimeException x) { diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java index 54da1d3d0d9..467be688992 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/TemporaryWorkspaceRemoverTest.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.che.api.core.Page; -import org.eclipse.che.api.core.Pages; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.mockito.InjectMocks; @@ -44,21 +43,21 @@ public class TemporaryWorkspaceRemoverTest { @Test public void shouldRemoveTemporaryWorkspaces() throws Exception { when(workspaceDao.getWorkspaces(eq(true), anyInt(), anyLong())) - .thenReturn(new Page<>( - createEntities(DEFAULT_PAGE_SIZE), - 0, - DEFAULT_PAGE_SIZE, - COUNT_OF_WORKSPACES)) - .thenReturn(new Page<>( - createEntities(DEFAULT_PAGE_SIZE), - DEFAULT_PAGE_SIZE, - DEFAULT_PAGE_SIZE, - COUNT_OF_WORKSPACES)) - .thenReturn(new Page<>( - createEntities(DEFAULT_PAGE_SIZE), - DEFAULT_PAGE_SIZE * 2, - DEFAULT_PAGE_SIZE, - COUNT_OF_WORKSPACES)); + .thenReturn( + new Page<>( + createEntities(DEFAULT_PAGE_SIZE), 0, DEFAULT_PAGE_SIZE, COUNT_OF_WORKSPACES)) + .thenReturn( + new Page<>( + createEntities(DEFAULT_PAGE_SIZE), + DEFAULT_PAGE_SIZE, + DEFAULT_PAGE_SIZE, + COUNT_OF_WORKSPACES)) + .thenReturn( + new Page<>( + createEntities(DEFAULT_PAGE_SIZE), + DEFAULT_PAGE_SIZE * 2, + DEFAULT_PAGE_SIZE, + COUNT_OF_WORKSPACES)); remover.removeTemporaryWs(); verify(workspaceDao, times(COUNT_OF_WORKSPACES)).remove(anyString()); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index ff7e0bfdcbd..268d62854a0 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -127,15 +127,17 @@ public void shouldThrowNpeWhenGettingWorkspaceByIdWhereIdIsNull() throws Excepti } @Test - public void shouldGetWorkspacesByNamespace() throws Exception { + public void shouldGetWorkspacesByNamespaceWithinSingleResponse() throws Exception { final WorkspaceImpl workspace1 = workspaces[0]; final WorkspaceImpl workspace2 = workspaces[1]; assertEquals( workspace1.getNamespace(), workspace2.getNamespace(), "Namespaces must be the same"); - final Page found = workspaceDao.getByNamespace(workspace1.getNamespace(), 30, 0); + final Page found = workspaceDao.getByNamespace(workspace1.getNamespace(), 6, 0); assertEquals(new HashSet<>(found.getItems()), new HashSet<>(asList(workspace1, workspace2))); + assertEquals(found.getTotalItemsCount(), 2); + assertEquals(found.getItemsCount(), 2); } @Test From b139a6141ceee5817bf292df21d59c9b1a37ae7b Mon Sep 17 00:00:00 2001 From: Mykhailo Kuznietsov Date: Fri, 22 Dec 2017 15:32:08 +0200 Subject: [PATCH 7/7] fixup! fixup --- .../local/projects/LocalProjectsMigrator.java | 8 ++----- .../server/spi/tck/WorkspaceDaoTest.java | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java index 260b61d4cdd..fc620113279 100644 --- a/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java +++ b/infrastructures/docker/infrastructure/src/main/java/org/eclipse/che/workspace/infrastructure/docker/local/projects/LocalProjectsMigrator.java @@ -46,7 +46,7 @@ public LocalProjectsMigrator(WorkspaceDao workspaceDao) { private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsMigrator.class); public void performMigration(String workspaceProjectsRootFolder) { - LOG.debug("Starting migration of workspace project files"); + LOG.info("Starting migration of workspace project files"); Map workspaceName2id = getId2NameWorkspaceMapping(); for (Entry entry : workspaceName2id.entrySet()) { Path workspaceStoredByNameLocation = @@ -55,10 +55,6 @@ public void performMigration(String workspaceProjectsRootFolder) { // migration is not needed for this workspace continue; } - LOG.debug( - "Performing migration of workspace with id '{}' and name '{}'", - entry.getKey(), - entry.getValue()); Path workspaceStoredByIdLocation = Paths.get(workspaceProjectsRootFolder).resolve(entry.getKey()); try { @@ -71,7 +67,7 @@ public void performMigration(String workspaceProjectsRootFolder) { entry.getKey(), entry.getValue()); } catch (IOException e) { - LOG.debug( + LOG.error( "Failed to migrate projects of workspace with id '{}' and name '{}'", entry.getKey(), entry.getValue()); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index 268d62854a0..dda12f73895 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -127,7 +127,7 @@ public void shouldThrowNpeWhenGettingWorkspaceByIdWhereIdIsNull() throws Excepti } @Test - public void shouldGetWorkspacesByNamespaceWithinSingleResponse() throws Exception { + public void shouldGetWorkspacesByNamespace() throws Exception { final WorkspaceImpl workspace1 = workspaces[0]; final WorkspaceImpl workspace2 = workspaces[1]; assertEquals( @@ -226,11 +226,23 @@ public void shouldNotRemoveWorkspaceWhenSubscriberThrowsExceptionOnWorkspaceRemo @Test public void shouldGetWorkspacesByNonTemporary() throws Exception { - Page result = workspaceDao.getWorkspaces(false, 2, 0); + final WorkspaceImpl workspace = workspaces[4]; + workspace.setTemporary(true); + workspaceDao.update(workspace); + + Page firstPage = workspaceDao.getWorkspaces(false, 2, 0); + + assertEquals(firstPage.getItems().size(), 2); + assertEquals(firstPage.getTotalItemsCount(), 4); + assertEquals( + new HashSet<>(firstPage.getItems()), new HashSet<>(asList(workspaces[0], workspaces[1]))); + + Page secondPage = workspaceDao.getWorkspaces(false, 2, 2); - assertEquals(result.getItems().size(), 2); + assertEquals(secondPage.getItems().size(), 2); + assertEquals(secondPage.getTotalItemsCount(), 4); assertEquals( - new HashSet<>(result.getItems()), new HashSet<>(asList(workspaces[0], workspaces[1]))); + new HashSet<>(secondPage.getItems()), new HashSet<>(asList(workspaces[2], workspaces[3]))); } @Test @@ -242,6 +254,7 @@ public void shouldGetWorkspacesByTemporary() throws Exception { Page result = workspaceDao.getWorkspaces(true, 30, 0); assertEquals(result.getItems().size(), 1); + assertEquals(result.getTotalItemsCount(), 1); assertEquals(result.getItems().iterator().next(), workspaceDao.get(workspace.getId())); }