/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.workspace.create;
import com.google.gwt.core.client.Callback;
import com.google.inject.Provider;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.machine.shared.dto.MachineConfigDto;
import org.eclipse.che.api.machine.shared.dto.MachineDto;
import org.eclipse.che.api.machine.shared.dto.MachineLimitsDto;
import org.eclipse.che.api.machine.shared.dto.MachineSourceDto;
import org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
import org.eclipse.che.api.workspace.shared.dto.EnvironmentRecipeDto;
import org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
import org.eclipse.che.commons.test.mockito.answer.SelfReturningAnswer;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.component.Component;
import org.eclipse.che.ide.api.machine.RecipeServiceClient;
import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient;
import org.eclipse.che.ide.context.BrowserAddress;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.workspace.DefaultWorkspaceComponent;
import org.eclipse.che.ide.workspace.WorkspaceComponent;
import org.eclipse.che.ide.workspace.create.CreateWorkspaceView.HidePopupCallBack;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.eclipse.che.ide.workspace.create.CreateWorkspacePresenter.MAX_COUNT;
import static org.eclipse.che.ide.workspace.create.CreateWorkspacePresenter.RECIPE_TYPE;
import static org.eclipse.che.ide.workspace.create.CreateWorkspacePresenter.SKIP_COUNT;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Dmitry Shnurenko
*/
@RunWith(MockitoJUnitRunner.class)
public class CreateWorkspacePresenterTest {
//constructor mocks
@Mock
private CreateWorkspaceView view;
@Mock
private DtoFactory dtoFactory;
@Mock
private WorkspaceServiceClient workspaceClient;
@Mock
private CoreLocalizationConstant locale;
@Mock
private Provider<WorkspaceComponent> wsComponentProvider;
@Mock
private RecipeServiceClient recipeServiceClient;
@Mock
private BrowserAddress browserAddress;
//additional mocks
@Mock
private Callback<Component, Exception> componentCallback;
@Mock
private HidePopupCallBack popupCallBack;
@Mock
private Promise<List<RecipeDescriptor>> recipesPromise;
@Mock
private Promise<WorkspaceDto> userWsPromise;
@Mock
private RecipeDescriptor recipeDescriptor;
@Mock
private DefaultWorkspaceComponent workspaceComponent;
@Mock
private MachineLimitsDto limitsDto;
//DTOs
private MachineConfigDto machineConfigDto;
private WorkspaceConfigDto workspaceConfigDto;
@Mock
private MachineDto machineDto;
@Mock
private MachineSourceDto machineSourceDto;
// Mocks too
private EnvironmentDto environmentDto;
private EnvironmentRecipeDto environmentRecipeDto;
private ExtendedMachineDto extendedMachineDto;
@Mock
private CommandDto commandDto;
@Mock
private WorkspaceDto usersWorkspaceDto;
@Captor
private ArgumentCaptor<Operation<List<RecipeDescriptor>>> recipeOperation;
@Captor
private ArgumentCaptor<Operation<WorkspaceDto>> workspaceOperation;
@Captor
private ArgumentCaptor<Operation<PromiseError>> errorOperation;
@InjectMocks
private CreateWorkspacePresenter presenter;
@Before
public void setUp() {
machineConfigDto = mock(MachineConfigDto.class, new SelfReturningAnswer());
workspaceConfigDto = mock(WorkspaceConfigDto.class, new SelfReturningAnswer());
when(usersWorkspaceDto.getConfig()).thenReturn(workspaceConfigDto);
when(dtoFactory.createDto(MachineSourceDto.class)).thenReturn(machineSourceDto);
when(machineSourceDto.withType(anyString())).thenReturn(machineSourceDto);
when(machineSourceDto.withLocation(anyString())).thenReturn(machineSourceDto);
when(dtoFactory.createDto(MachineLimitsDto.class)).thenReturn(limitsDto);
when(limitsDto.withRam(anyInt())).thenReturn(limitsDto);
when(dtoFactory.createDto(MachineConfigDto.class)).thenReturn(machineConfigDto);
when(dtoFactory.createDto(EnvironmentDto.class)).thenReturn(environmentDto);
when(dtoFactory.createDto(WorkspaceConfigDto.class)).thenReturn(workspaceConfigDto);
when(dtoFactory.createDto(WorkspaceDto.class)).thenReturn(usersWorkspaceDto);
environmentDto = mock(EnvironmentDto.class, new SelfReturningAnswer());
when(dtoFactory.createDto(EnvironmentDto.class)).thenReturn(environmentDto);
environmentRecipeDto = mock(EnvironmentRecipeDto.class, new SelfReturningAnswer());
when(dtoFactory.createDto(EnvironmentRecipeDto.class)).thenReturn(environmentRecipeDto);
extendedMachineDto = mock(ExtendedMachineDto.class, new SelfReturningAnswer());
when(dtoFactory.createDto(ExtendedMachineDto.class)).thenReturn(extendedMachineDto);
when(wsComponentProvider.get()).thenReturn(workspaceComponent);
when(recipeServiceClient.getAllRecipes()).thenReturn(recipesPromise);
when(view.getWorkspaceName()).thenReturn("test");
when(view.getRecipeUrl()).thenReturn("recipe");
}
@Test
public void delegateShouldBeSet() {
verify(view).setDelegate(presenter);
}
@Test
public void dialogShouldBeShown() {
presenter.show(Collections.singletonList(usersWorkspaceDto), componentCallback);
verify(browserAddress).getWorkspaceName();
verify(view).setWorkspaceName(anyString());
verify(view).show();
}
@Test
public void errorLabelShouldBeShownWhenWorkspaceNameLengthIsInCorrect() {
when(view.getWorkspaceName()).thenReturn("te");
presenter.onNameChanged();
verify(locale).createWsNameLengthIsNotCorrect();
verify(locale, never()).createWsNameIsNotCorrect();
verify(locale, never()).createWsNameAlreadyExist();
}
@Test
public void errorLabelShouldBeShownWhenWorkspaceNameIsInCorrect() {
when(view.getWorkspaceName()).thenReturn("test/*");
presenter.onNameChanged();
verify(locale, never()).createWsNameLengthIsNotCorrect();
verify(locale).createWsNameIsNotCorrect();
verify(locale, never()).createWsNameAlreadyExist();
}
@Test
public void errorLabelShouldBeShownWhenWorkspaceNameAlreadyExist() {
when(workspaceConfigDto.getName()).thenReturn("test");
presenter.show(Collections.singletonList(usersWorkspaceDto), componentCallback);
reset(locale);
presenter.onNameChanged();
verify(locale, never()).createWsNameLengthIsNotCorrect();
verify(locale, never()).createWsNameIsNotCorrect();
verify(locale).createWsNameAlreadyExist();
}
@Test
public void errorLabelShouldNotBeShownWhenFormIsCorrect() {
when(view.getRecipeUrl()).thenReturn("http://localhost/correct/url");
presenter.onRecipeUrlChanged();
verify(locale, never()).createWsNameLengthIsNotCorrect();
verify(locale, never()).createWsNameIsNotCorrect();
verify(locale, never()).createWsNameAlreadyExist();
verify(view).showValidationNameError("");
verify(view).setVisibleUrlError(false);
verify(view).setEnableCreateButton(true);
}
@Test
public void errorLabelShouldBeShownWhenRecipeUrlIsNotCorrect() {
when(view.getRecipeUrl()).thenReturn("xxx://localh/correct/url");
presenter.onRecipeUrlChanged();
verify(locale, never()).createWsNameLengthIsNotCorrect();
verify(locale, never()).createWsNameIsNotCorrect();
verify(locale, never()).createWsNameAlreadyExist();
verify(view).showValidationNameError("");
verify(view).setVisibleUrlError(anyBoolean());
}
@Test
public void recipesShouldBeFoundAndShown() throws Exception {
List<RecipeDescriptor> recipes = Collections.singletonList(recipeDescriptor);
callSearchRecipesApplyMethod(recipes);
verify(popupCallBack, never()).hidePopup();
verify(view).showFoundByTagRecipes(recipes);
verify(view).setVisibleTagsError(false);
}
private void callSearchRecipesApplyMethod(List<RecipeDescriptor> recipes) throws Exception {
List<String> tags = Collections.singletonList("test1 test2");
when(view.getTags()).thenReturn(tags);
when(recipeServiceClient.searchRecipes(Matchers.<List<String>>anyObject(),
anyString(),
anyInt(),
anyInt())).thenReturn(recipesPromise);
presenter.onTagsChanged(popupCallBack);
verify(view).getTags();
verify(recipeServiceClient).searchRecipes(tags, RECIPE_TYPE, SKIP_COUNT, MAX_COUNT);
verify(recipesPromise).then(recipeOperation.capture());
recipeOperation.getValue().apply(recipes);
}
@Test
public void errorLabelShouldBeShowWhenRecipesNotFound() throws Exception {
List<RecipeDescriptor> recipes = new ArrayList<>();
callSearchRecipesApplyMethod(recipes);
verify(view).setVisibleTagsError(true);
verify(popupCallBack).hidePopup();
verify(view, never()).showFoundByTagRecipes(Matchers.<List<RecipeDescriptor>>anyObject());
}
@Test
public void predefinedRecipesShouldBeFound() {
presenter.onPredefinedRecipesClicked();
verify(view).showPredefinedRecipes(Matchers.<List<RecipeDescriptor>>anyObject());
}
@Test
public void dialogShouldBeHiddenWhenUserClicksOnCreateButton() {
clickOnCreateButton();
verify(view).hide();
}
private void clickOnCreateButton() {
when(workspaceClient.create(Matchers.<WorkspaceConfigDto>anyObject(), anyString())).thenReturn(userWsPromise);
when(userWsPromise.then(Matchers.<Operation<WorkspaceDto>>anyObject())).thenReturn(userWsPromise);
when(userWsPromise.catchError(Matchers.<Operation<PromiseError>>anyObject())).thenReturn(userWsPromise);
when(recipeServiceClient.getAllRecipes()).thenReturn(recipesPromise);
presenter.show(Collections.singletonList(usersWorkspaceDto), componentCallback);
presenter.onCreateButtonClicked();
verify(recipeServiceClient).getAllRecipes();
verify(recipesPromise).then(Matchers.<Operation<List<RecipeDescriptor>>>anyObject());
verify(view).show();
}
@Test
public void workspaceConfigShouldBeGot() {
when(view.getWorkspaceName()).thenReturn("name");
when(view.getRecipeUrl()).thenReturn("test");
clickOnCreateButton();
verify(view, times(2)).getWorkspaceName();
verify(dtoFactory).createDto(EnvironmentDto.class);
}
@Test
public void workspaceShouldBeCreatedForDevMachine() throws Exception {
when(machineConfigDto.isDev()).thenReturn(true);
callApplyCreateWorkspaceMethod();
verify(wsComponentProvider).get();
verify(workspaceComponent).startWorkspace(usersWorkspaceDto, componentCallback);
}
private void callApplyCreateWorkspaceMethod() throws Exception {
Map<String, EnvironmentDto> environments = new HashMap<>();
environments.put("name", environmentDto);
when(workspaceConfigDto.getDefaultEnv()).thenReturn("name");
when(workspaceConfigDto.getEnvironments()).thenReturn(environments);
clickOnCreateButton();
verify(userWsPromise).then(workspaceOperation.capture());
workspaceOperation.getValue().apply(usersWorkspaceDto);
}
@Test
public void workspaceShouldBeCreatedForNotDevMachine() throws Exception {
when(machineConfigDto.isDev()).thenReturn(false);
callApplyCreateWorkspaceMethod();
verify(workspaceComponent).startWorkspace(usersWorkspaceDto, componentCallback);
}
@Test
public void errorShouldBeCaughtWhenCreatesWorkSpace() throws Exception {
final PromiseError promiseError = mock(PromiseError.class);
clickOnCreateButton();
verify(userWsPromise).catchError(errorOperation.capture());
errorOperation.getValue().apply(promiseError);
//noinspection ThrowableResultOfMethodCallIgnored
verify(promiseError).getCause();
verify(componentCallback).onFailure(Matchers.<Exception>anyObject());
}
}