WorkspaceManager { public void stopWorkspace(String workspaceId, Map<String, String> options) throws ServerException, NotFoundException, ConflictException { requireNonNull(workspaceId, "Required non-null workspace id"); final WorkspaceImpl workspace = normalizeState(workspaceDao.get(workspaceId), true); checkWorkspaceIsRunningOrStarting(workspace); if (!workspace.isTemporary()) { workspace.getAttributes().put(STOPPED_ATTRIBUTE_NAME, Long.toString(currentTimeMillis())); workspace.getAttributes().put(STOPPED_ABNORMALLY_ATTRIBUTE_NAME, Boolean.toString(false)); workspaceDao.update(workspace); } String namespace = workspace.getAttributes().get(WORKSPACE_INFRASTRUCTURE_NAMESPACE_ATTRIBUTE); final String owner = workspace.getRuntime().getOwner(); runtimes .stopAsync(workspace, options) .whenComplete( (aVoid, throwable) -> { if (workspace.isTemporary()) { removeWorkspaceQuietly(workspace.getId()); } try { if (runtimes.getActive(owner).isEmpty()) { recordLastWorkspaceStoppedTime(namespace, owner); } } catch (ServerException | InfrastructureException e) { LOG.error(e.getMessage(), e); } }); } @Inject  WorkspaceManager(
      WorkspaceDao workspaceDao,
      WorkspaceRuntimes runtimes,
      EventService eventService,
      AccountManager accountManager,
      PreferenceManager preferenceManager,
      WorkspaceValidator validator,
      DevfileIntegrityValidator devfileIntegrityValidator); @Traced WorkspaceImpl createWorkspace(
      WorkspaceConfig config, String namespace, Map<String, String> attributes); @Traced WorkspaceImpl createWorkspace(
      Devfile devfile,
      String namespace,
      Map<String, String> attributes,
      FileContentProvider contentProvider); WorkspaceImpl getWorkspace(String key); WorkspaceImpl getWorkspace(String name, String namespace); Page<WorkspaceImpl> getWorkspaces(
      String user, boolean includeRuntimes, int maxItems, long skipCount); Page<WorkspaceImpl> getByNamespace(
      String namespace, boolean includeRuntimes, int maxItems, long skipCount); WorkspaceImpl updateWorkspace(String id, Workspace update); @Traced void removeWorkspace(String workspaceId); WorkspaceImpl startWorkspace(
      String workspaceId, @Nullable String envName, @Nullable Map<String, String> options); WorkspaceImpl startWorkspace(
      WorkspaceConfig config, String namespace, boolean isTemporary, Map<String, String> options); void stopWorkspace(String workspaceId, Map<String, String> options); Set<String> getSupportedRecipes(); long getWorkspacesTotalCount();  }
@Test public void stopsWorkspace() throws Exception { final WorkspaceImpl workspace = createAndMockWorkspace(createConfig(), NAMESPACE_1); mockRuntime(workspace, RUNNING); mockAnyWorkspaceStop(); workspaceManager.stopWorkspace(workspace.getId(), emptyMap()); verify(runtimes).stopAsync(workspace, emptyMap()); verify(workspaceDao).update(workspaceCaptor.capture()); assertNotNull(workspaceCaptor.getValue().getAttributes().get(STOPPED_ATTRIBUTE_NAME)); assertFalse( Boolean.valueOf( workspaceCaptor.getValue().getAttributes().get(STOPPED_ABNORMALLY_ATTRIBUTE_NAME))); }
@Test public void removesTemporaryWorkspaceAfterStop() throws Exception { final WorkspaceImpl workspace = createAndMockWorkspace(); workspace.setTemporary(true); mockRuntime(workspace, RUNNING); mockAnyWorkspaceStop(); workspaceManager.stopWorkspace(workspace.getId(), emptyMap()); verify(runtimes).stopAsync(workspace, emptyMap()); verify(workspaceDao).remove(workspace.getId()); }
@Test public void removesTemporaryWorkspaceAfterStopFailed() throws Exception { final WorkspaceImpl workspace = createAndMockWorkspace(); workspace.setTemporary(true); mockRuntime(workspace, RUNNING); doThrow(new ConflictException("runtime stop failed")) .when(runtimes) .stopAsync(workspace, emptyMap()); mockAnyWorkspaceStop(); workspaceManager.stopWorkspace(workspace.getId(), emptyMap()); verify(workspaceDao).remove(workspace.getId()); }
@Test public void stopsLastWorkspaceShouldUpdatePreferences() throws Exception { final WorkspaceImpl workspace = createAndMockWorkspace(createConfig(), NAMESPACE_1); mockRuntime(workspace, RUNNING); mockAnyWorkspaceStop(); when(runtimes.isAnyActive()).thenReturn(false); long epochSecond = Clock.systemDefaultZone().instant().getEpochSecond(); workspaceManager.stopWorkspace(workspace.getId(), emptyMap()); verify(runtimes).stopAsync(workspace, emptyMap()); verify(workspaceDao).update(workspaceCaptor.capture()); verify(preferenceManager).find("owner"); Map<String, String> pref = new HashMap<>(2); pref.put(LAST_ACTIVITY_TIME, Long.toString(epochSecond)); pref.put(LAST_ACTIVE_INFRASTRUCTURE_NAMESPACE, INFRA_NAMESPACE); verify(preferenceManager).update("owner", pref); }
@Test public void stopsWorkspaceShouldNotUpdatePreferencesIfOtherWorkspaceRunning() throws Exception { final WorkspaceImpl workspace = createAndMockWorkspace(createConfig(), NAMESPACE_1); mockRuntime(workspace, RUNNING); mockAnyWorkspaceStop(); when(runtimes.getActive(anyString())) .thenReturn(ImmutableSet.of(NameGenerator.generate("ws", 5))); long millis = System.currentTimeMillis(); workspaceManager.stopWorkspace(workspace.getId(), emptyMap()); verify(runtimes).stopAsync(workspace, emptyMap()); verify(workspaceDao).update(workspaceCaptor.capture()); Map<String, String> pref = new HashMap<>(2); pref.put(LAST_ACTIVITY_TIME, Long.toString(millis)); pref.put(LAST_ACTIVE_INFRASTRUCTURE_NAMESPACE, INFRA_NAMESPACE); verify(preferenceManager, never()).find("owner"); verify(preferenceManager, never()) .remove("owner", Arrays.asList(LAST_ACTIVITY_TIME, LAST_ACTIVE_INFRASTRUCTURE_NAMESPACE)); }