/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonSyntaxException;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
import org.eclipse.che.api.factory.server.FactoryService.FactoryParametersResolverHolder;
import org.eclipse.che.api.factory.server.builder.FactoryBuilder;
import org.eclipse.che.api.factory.server.impl.SourceStorageParametersValidator;
import org.eclipse.che.api.factory.server.model.impl.AuthorImpl;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.user.server.PreferenceManager;
import org.eclipse.che.api.user.server.UserManager;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl;
import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
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.shared.dto.EnvironmentDto;
import org.eclipse.che.api.workspace.shared.dto.ExtendedMachineDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.json.JsonHelper;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.eclipse.che.dto.server.DtoFactory;
import org.everrest.assured.EverrestJetty;
import org.everrest.core.Filter;
import org.everrest.core.GenericContainerRequest;
import org.everrest.core.RequestFilter;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import javax.ws.rs.core.UriInfo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.jayway.restassured.RestAssured.given;
import static java.lang.String.format;
import static java.lang.String.valueOf;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.stream.Collectors.toSet;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static org.eclipse.che.api.factory.server.DtoConverter.asDto;
import static org.eclipse.che.api.factory.server.FactoryService.VALIDATE_QUERY_PARAMETER;
import static org.eclipse.che.dto.server.DtoFactory.cloneDto;
import static org.eclipse.che.dto.server.DtoFactory.newDto;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyMapOf;
import static org.mockito.Matchers.anySetOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
/**
* Tests for {@link FactoryService}.
*
* @author Anton Korneta
*/
@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class})
public class FactoryServiceTest {
private static final String SERVICE_PATH = "/factory";
private static final String FACTORY_ID = "correctFactoryId";
private static final String FACTORY_NAME = "factory";
private static final String USER_ID = "userId";
private static final String USER_EMAIL = "email";
private static final String WORKSPACE_NAME = "workspace";
private static final String PROJECT_SOURCE_TYPE = "git";
private static final String PROJECT_SOURCE_LOCATION = "https://github.com/codenvy/platform-api.git";
private static final String FACTORY_IMAGE_MIME_TYPE = "image/jpeg";
private static final String IMAGE_NAME = "image12";
private static final DtoFactory DTO = DtoFactory.getInstance();
@Mock
private FactoryManager factoryManager;
@Mock
private FactoryCreateValidator createValidator;
@Mock
private FactoryAcceptValidator acceptValidator;
@Mock
private PreferenceManager preferenceManager;
@Mock
private UserManager userManager;
@Mock
private FactoryEditValidator editValidator;
@Mock
private WorkspaceManager workspaceManager;
@Mock
private FactoryParametersResolverHolder factoryParametersResolverHolder;
@Mock
private UriInfo uriInfo;
private FactoryBuilder factoryBuilderSpy;
private User user;
private Set<FactoryParametersResolver> factoryParametersResolvers;
private FactoryService service;
@SuppressWarnings("unused")
private ApiExceptionMapper apiExceptionMapper;
@SuppressWarnings("unused")
private EnvironmentFilter environmentFilter;
@BeforeMethod
public void setUp() throws Exception {
factoryBuilderSpy = spy(new FactoryBuilder(new SourceStorageParametersValidator()));
factoryParametersResolvers = new HashSet<>();
doNothing().when(factoryBuilderSpy).checkValid(any(FactoryDto.class));
doNothing().when(factoryBuilderSpy).checkValid(any(FactoryDto.class), anyBoolean());
when(factoryParametersResolverHolder.getFactoryParametersResolvers()).thenReturn(factoryParametersResolvers);
user = new UserImpl(USER_ID, USER_EMAIL, ADMIN_USER_NAME);
when(userManager.getById(anyString())).thenReturn(user);
when(preferenceManager.find(USER_ID)).thenReturn(ImmutableMap.of("preference", "value"));
service = new FactoryService(factoryManager,
userManager,
preferenceManager,
createValidator,
acceptValidator,
editValidator,
factoryBuilderSpy,
workspaceManager,
factoryParametersResolverHolder);
}
@Filter
public static class EnvironmentFilter implements RequestFilter {
public void doFilter(GenericContainerRequest request) {
EnvironmentContext context = EnvironmentContext.getCurrent();
context.setSubject(new SubjectImpl(ADMIN_USER_NAME, USER_ID, ADMIN_USER_PASSWORD, false));
}
}
@Test
public void shouldSaveFactoryWithImagesFromFormData() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
when(factoryManager.saveFactory(any(FactoryDto.class), anySetOf(FactoryImage.class))).thenReturn(factory);
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
doReturn(factoryDto).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", JsonHelper.toJson(factoryDto), APPLICATION_JSON)
.multiPart("image", getImagePath().toFile(), FACTORY_IMAGE_MIME_TYPE)
.expect()
.statusCode(200)
.when()
.post(SERVICE_PATH);
final FactoryDto result = getFromResponse(response, FactoryDto.class);
final boolean found = result.getLinks()
.stream()
.anyMatch(link -> link.getRel().equals("image")
&& link.getProduces().equals(FACTORY_IMAGE_MIME_TYPE)
&& !link.getHref().isEmpty());
factoryDto.withLinks(result.getLinks())
.getCreator()
.withCreated(result.getCreator().getCreated());
assertEquals(result, factoryDto);
assertTrue(found);
}
@Test
public void shouldSaveFactoryFromFormDataWithoutImages() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
when(factoryManager.saveFactory(any(FactoryDto.class), anySetOf(FactoryImage.class))).thenReturn(factory);
doReturn(factoryDto).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", JsonHelper.toJson(factoryDto), APPLICATION_JSON)
.expect()
.statusCode(200)
.when()
.post(SERVICE_PATH);
final FactoryDto result = getFromResponse(response, FactoryDto.class);
factoryDto.withLinks(result.getLinks())
.getCreator()
.withCreated(result.getCreator().getCreated());
assertEquals(result, factoryDto);
}
@Test
public void shouldSaveFactoryWithImagesWhenImagesWithoutContent() throws Exception {
final Factory factory = createFactory();
when(factoryManager.saveFactory(any(FactoryDto.class), anySetOf(FactoryImage.class))).thenReturn(factory);
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
final FactoryDto factoryDto = asDto(factory, user);
doReturn(factoryDto).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", DTO.toJson(factoryDto), APPLICATION_JSON)
.multiPart("image", File.createTempFile("img", ".jpeg"), "image/jpeg")
.expect()
.statusCode(200)
.when()
.post(SERVICE_PATH);
final FactoryDto result = getFromResponse(response, FactoryDto.class);
verify(factoryManager).saveFactory(any(FactoryDto.class), anySetOf(FactoryImage.class));
factoryDto.withLinks(result.getLinks())
.getCreator()
.withCreated(result.getCreator().getCreated());
assertEquals(result, factoryDto);
}
@Test
public void shouldThrowBadRequestExceptionWhenInvalidFactorySectionProvided() throws Exception {
doThrow(new JsonSyntaxException("Invalid json")).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", "invalid content", FACTORY_IMAGE_MIME_TYPE)
.expect()
.statusCode(400)
.when()
.post(SERVICE_PATH);
final ServiceError err = getFromResponse(response, ServiceError.class);
assertEquals(err.getMessage(), "Invalid JSON value of the field 'factory' provided");
}
@Test
public void shouldThrowBadRequestExceptionWhenNoFactorySectionProvided() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("some data", "some content", FACTORY_IMAGE_MIME_TYPE)
.expect()
.statusCode(400)
.when()
.post(SERVICE_PATH);
final ServiceError err = getFromResponse(response, ServiceError.class);
assertEquals(err.getMessage(), "factory configuration required");
}
@Test
public void shouldThrowServerExceptionWhenProvidedFactoryDataInvalid() throws Exception {
final String errMessage = "eof";
doThrow(new IOException(errMessage)).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", "any content", FACTORY_IMAGE_MIME_TYPE)
.expect()
.statusCode(500)
.when()
.post(SERVICE_PATH);
final ServiceError err = getFromResponse(response, ServiceError.class);
assertEquals(err.getMessage(), errMessage);
}
@Test
public void shouldSaveFactoryWithoutImages() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
when(factoryManager.saveFactory(any(FactoryDto.class))).thenReturn(factory);
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(ContentType.JSON)
.body(factoryDto)
.expect()
.statusCode(200)
.post(SERVICE_PATH);
assertEquals(getFromResponse(response, FactoryDto.class).withLinks(emptyList()), factoryDto);
}
@Test
public void shouldThrowBadRequestExceptionWhenFactoryConfigurationNotProvided() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(ContentType.JSON)
.expect()
.statusCode(400)
.post(SERVICE_PATH);
final String errMessage = getFromResponse(response, ServiceError.class).getMessage();
assertEquals(errMessage, "Factory configuration required");
}
@Test
public void shouldReturnFactoryByIdentifierWithoutValidation() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
when(factoryManager.getFactoryImages(FACTORY_ID)).thenReturn(emptySet());
final Response response = given().when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(getFromResponse(response, FactoryDto.class).withLinks(emptyList()), factoryDto);
}
@Test
public void shouldReturnFactoryByIdentifierWithValidation() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
when(factoryManager.getFactoryImages(FACTORY_ID)).thenReturn(emptySet());
doNothing().when(acceptValidator).validateOnAccept(any(FactoryDto.class));
final Response response = given().when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/" + FACTORY_ID + "?validate=true");
assertEquals(getFromResponse(response, FactoryDto.class).withLinks(emptyList()), factoryDto);
}
@Test
public void shouldThrowNotFoundExceptionWhenFactoryIsNotExist() throws Exception {
final String errMessage = format("Factory with id %s is not found", FACTORY_ID);
doThrow(new NotFoundException(errMessage)).when(factoryManager)
.getById(anyString());
final Response response = given().expect()
.statusCode(404)
.when()
.get(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(getFromResponse(response, ServiceError.class).getMessage(), errMessage);
}
@Test
public void shouldReturnFactoryListByNameAttribute() throws Exception {
final Factory factory = createFactory();
when(factoryManager.getByAttribute(1, 0, ImmutableList.of(Pair.of("factory.name", factory.getName()))))
.thenReturn(ImmutableList.of(factory));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/find?maxItems=1&skipCount=0&factory.name=" + factory.getName());
final List<FactoryDto> res = unwrapDtoList(response, FactoryDto.class);
assertEquals(res.size(), 1);
assertEquals(res.get(0).withLinks(emptyList()), asDto(factory, user));
}
@Test
public void shouldReturnFactoryListByCreatorAttribute() throws Exception {
final Factory factory1 = createNamedFactory("factory1");
final Factory factory2 = createNamedFactory("factory2");
when(factoryManager.getByAttribute(2, 0, ImmutableList.of(Pair.of("factory.creator.name", user.getName()))))
.thenReturn(ImmutableList.of(factory1, factory2));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/find?maxItems=2&skipCount=0&factory.creator.name=" + user.getName());
final Set<FactoryDto> res = unwrapDtoList(response, FactoryDto.class).stream()
.map(f -> f.withLinks(emptyList()))
.collect(toSet());
assertEquals(res.size(), 2);
assertTrue(res.containsAll(ImmutableList.of(asDto(factory1, user), asDto(factory2, user))));
}
@Test
public void shouldThrowBadRequestWhenGettingFactoryByEmptyAttributeList() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.when()
.expect()
.get(SERVICE_PATH + "/find?maxItems=1&skipCount=0");
assertEquals(response.getStatusCode(), 400);
assertEquals(DTO.createDtoFromJson(response.getBody().asString(), ServiceError.class)
.getMessage(), "Query must contain at least one attribute");
}
@Test
public void shouldBeAbleToUpdateFactory() throws Exception {
final Factory existed = createFactory();
final Factory update = createFactoryWithStorage(null, "git", "https://github.com/codenvy/platform-api1.git");
when(factoryManager.getById(FACTORY_ID)).thenReturn(existed);
when(factoryManager.updateFactory(any())).thenReturn(update);
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.body(JsonHelper.toJson(asDto(existed, user)))
.when()
.expect()
.statusCode(200)
.put(SERVICE_PATH + "/" + FACTORY_ID);
final FactoryDto result = getFromResponse(response, FactoryDto.class);
verify(factoryManager, times(1)).updateFactory(any());
assertEquals(result.withLinks(emptyList()), asDto(update, user));
}
@Test
public void shouldThrowNotFoundExceptionWhenUpdatingNonExistingFactory() throws Exception {
final Factory factory = createFactoryWithStorage(FACTORY_NAME,
"git",
"https://github.com/codenvy/platform-api.git");
doThrow(new NotFoundException(format("Factory with id %s is not found.", FACTORY_ID))).when(factoryManager)
.getById(anyString());
final Response response = given().auth().basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.body(JsonHelper.toJson(factory))
.when()
.put(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(response.getStatusCode(), 404);
assertEquals(DTO.createDtoFromJson(response.getBody().asString(), ServiceError.class).getMessage(),
format("Factory with id %s is not found.", FACTORY_ID));
}
@Test
public void shouldNotBeAbleToUpdateANullFactory() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType(APPLICATION_JSON)
.when()
.put(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(response.getStatusCode(), 400);
assertEquals(DTO.createDtoFromJson(response.getBody().asString(), ServiceError.class)
.getMessage(), "Factory configuration required");
}
@Test
public void shouldRemoveFactoryByGivenIdentifier() throws Exception {
final Factory factory = createFactory();
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.param("id", FACTORY_ID)
.expect()
.statusCode(204)
.when()
.delete(SERVICE_PATH + "/" + FACTORY_ID);
verify(factoryManager).removeFactory(FACTORY_ID);
}
@Test
public void shouldNotThrowAnyExceptionWhenRemovingNonExistingFactory() throws Exception {
doNothing().when(factoryManager).removeFactory(anyString());
Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.param("id", FACTORY_ID)
.when()
.delete(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(response.getStatusCode(), 204);
}
@Test
public void shouldGenerateFactoryJsonIncludeGivenProjects() throws Exception {
// given
final String wsId = "workspace123234";
WorkspaceImpl.WorkspaceImplBuilder ws = WorkspaceImpl.builder();
WorkspaceConfigImpl.WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
ws.setId(wsId);
wsConfig.setProjects(Arrays.asList(DTO.createDto(ProjectConfigDto.class)
.withPath("/proj1")
.withSource(DTO.createDto(SourceStorageDto.class)
.withType("git")
.withLocation("location")),
DTO.createDto(ProjectConfigDto.class)
.withPath("/proj2")
.withSource(DTO.createDto(SourceStorageDto.class)
.withType("git")
.withLocation("location"))));
wsConfig.setName("wsname");
wsConfig.setEnvironments(singletonMap("env1", DTO.createDto(EnvironmentDto.class)));
wsConfig.setDefaultEnv("env1");
ws.setStatus(WorkspaceStatus.RUNNING);
wsConfig.setCommands(singletonList(DTO.createDto(CommandDto.class)
.withName("MCI")
.withType("mvn")
.withCommandLine("clean install")));
ws.setConfig(wsConfig.build());
WorkspaceImpl usersWorkspace = ws.build();
when(workspaceManager.getWorkspace(eq(wsId))).thenReturn(usersWorkspace);
// when
Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get("/private" + SERVICE_PATH + "/workspace/" + wsId);
// then
assertEquals(response.getStatusCode(), 200);
FactoryDto result = DTO.createDtoFromJson(response.getBody().asString(), FactoryDto.class);
assertEquals(result.getWorkspace().getProjects().size(), 2);
}
@Test
public void shouldReturnFactoryImageWithGivenName() throws Exception {
final byte[] imageContent = Files.readAllBytes(getImagePath());
final FactoryImage image = new FactoryImage(imageContent, FACTORY_IMAGE_MIME_TYPE, IMAGE_NAME);
when(factoryManager.getFactoryImages(FACTORY_ID, IMAGE_NAME)).thenReturn(ImmutableSet.of(image));
final Response response = given().when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/" + FACTORY_ID + "/image?imgId=" + IMAGE_NAME);
assertEquals(response.getContentType(), FACTORY_IMAGE_MIME_TYPE);
assertEquals(response.getHeader("content-length"), String.valueOf(imageContent.length));
assertEquals(response.asByteArray(), imageContent);
}
@Test
public void shouldReturnFirstFoundFactoryImageWhenImageNameNotSpecified() throws Exception {
final byte[] imageContent = Files.readAllBytes(getImagePath());
final FactoryImage image = new FactoryImage(imageContent, FACTORY_IMAGE_MIME_TYPE, IMAGE_NAME);
when(factoryManager.getFactoryImages(FACTORY_ID)).thenReturn(ImmutableSet.of(image));
final Response response = given().when()
.expect()
.statusCode(200)
.get(SERVICE_PATH + "/" + FACTORY_ID + "/image");
assertEquals(response.getContentType(), "image/jpeg");
assertEquals(response.getHeader("content-length"), String.valueOf(imageContent.length));
assertEquals(response.asByteArray(), imageContent);
}
@Test
public void shouldThrowNotFoundExceptionWhenFactoryImageWithGivenIdentifierIsNotExist() throws Exception {
final String errMessage = "Image with name " + IMAGE_NAME + " is not found";
when(factoryManager.getFactoryImages(FACTORY_ID, IMAGE_NAME)).thenThrow(new NotFoundException(errMessage));
final Response response = given().expect()
.statusCode(404)
.when()
.get(SERVICE_PATH + "/" + FACTORY_ID + "/image?imgId=" + IMAGE_NAME);
assertEquals(getFromResponse(response, ServiceError.class).getMessage(), errMessage);
}
@Test
public void shouldBeAbleToReturnUrlSnippet() throws Exception {
final String result = "snippet";
when(factoryManager.getFactorySnippet(anyString(), anyString(), any(URI.class))).thenReturn(result);
given().expect()
.statusCode(200)
.contentType(TEXT_PLAIN)
.body(equalTo(result))
.when()
.get(SERVICE_PATH + "/" + FACTORY_ID + "/snippet?type=url");
}
@Test
public void shouldNotGenerateFactoryIfNoProjectsWithSourceStorage() throws Exception {
// given
final String wsId = "workspace123234";
WorkspaceImpl.WorkspaceImplBuilder ws = WorkspaceImpl.builder();
WorkspaceConfigImpl.WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
ws.setId(wsId);
wsConfig.setProjects(Arrays.asList(DTO.createDto(ProjectConfigDto.class)
.withPath("/proj1"),
DTO.createDto(ProjectConfigDto.class)
.withPath("/proj2")));
wsConfig.setName("wsname");
wsConfig.setEnvironments(singletonMap("env1", DTO.createDto(EnvironmentDto.class)));
wsConfig.setDefaultEnv("env1");
ws.setStatus(WorkspaceStatus.RUNNING);
wsConfig.setCommands(singletonList(
DTO.createDto(CommandDto.class).withName("MCI").withType("mvn").withCommandLine("clean install")));
ws.setConfig(wsConfig.build());
WorkspaceImpl usersWorkspace = ws.build();
when(workspaceManager.getWorkspace(eq(wsId))).thenReturn(usersWorkspace);
// when
Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get(SERVICE_PATH + "/workspace/" + wsId);
// then
assertEquals(response.getStatusCode(), BAD_REQUEST.getStatusCode());
}
@Test
public void shouldResponse404OnGetSnippetIfFactoryDoesNotExist() throws Exception {
// given
doThrow(new NotFoundException("Factory URL with id " + FACTORY_ID + " is not found."))
.when(factoryManager).getFactorySnippet(anyString(), anyString(), any());
// when, then
final Response response = given().expect()
.statusCode(404)
.when()
.get(SERVICE_PATH + "/" + FACTORY_ID + "/snippet?type=url");
assertEquals(getFromResponse(response, ServiceError.class).getMessage(),
"Factory URL with id " + FACTORY_ID + " is not found.");
}
/**
* Checks that the user can remove an existing factory
*/
@Test
public void shouldBeAbleToRemoveFactory() throws Exception {
final Factory factory = createFactory();
when(factoryManager.getById(FACTORY_ID)).thenReturn(factory);
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.param("id", FACTORY_ID)
.when()
.delete(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(response.getStatusCode(), 204);
// check there was a call on the remove operation with expected ID
verify(factoryManager).removeFactory(FACTORY_ID);
}
@Test
public void shouldNotThrowExceptionWhenRemoveNoExistingFactory() throws Exception {
doNothing().when(factoryManager).removeFactory(FACTORY_ID);
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.param("id", FACTORY_ID)
.when()
.delete(SERVICE_PATH + "/" + FACTORY_ID);
assertEquals(response.getStatusCode(), 204);
}
@Test
public void checkValidateResolver() throws Exception {
final FactoryParametersResolver dummyResolver = Mockito.mock(FactoryParametersResolver.class);
factoryParametersResolvers.add(dummyResolver);
// invalid factory
final String invalidFactoryMessage = "invalid factory";
doThrow(new BadRequestException(invalidFactoryMessage)).when(acceptValidator).validateOnAccept(any());
// create factory
final FactoryDto expectFactory = DTO.createDto(FactoryDto.class).withV("4.0").withName("matchingResolverFactory");
// accept resolver
when(dummyResolver.accept(anyMapOf(String.class, String.class))).thenReturn(true);
when(dummyResolver.createFactory(anyMapOf(String.class, String.class))).thenReturn(expectFactory);
// when
final Map<String, String> map = new HashMap<>();
final Response response = given().contentType(ContentType.JSON)
.when()
.body(map)
.queryParam(VALIDATE_QUERY_PARAMETER, valueOf(true))
.post(SERVICE_PATH + "/resolver");
// then check we have a not found
assertEquals(response.getStatusCode(), BAD_REQUEST.getStatusCode());
assertTrue(response.getBody().prettyPrint().contains(invalidFactoryMessage));
// check we call resolvers
verify(dummyResolver).accept(anyMapOf(String.class, String.class));
verify(dummyResolver).createFactory(anyMapOf(String.class, String.class));
// check we call validator
verify(acceptValidator).validateOnAccept(any());
}
@Test
public void shouldAddExecAgentOnSaveFactoryFromFormData() throws Exception {
final Factory factory = createFactory();
final FactoryDto factoryDto = asDto(factory, user);
EnvironmentDto environment = newDto(EnvironmentDto.class);
ExtendedMachineDto machine = newDto(ExtendedMachineDto.class);
factoryDto.getWorkspace().setEnvironments(ImmutableMap.of("e1", cloneDto(environment).withMachines(
ImmutableMap.of("m1", cloneDto(machine).withAgents(asList("org.eclipse.che.terminal",
"org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")),
"m2", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.terminal",
"org.eclipse.che.ls.json")),
"m3", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")))
),
"e2", cloneDto(environment).withMachines(
ImmutableMap.of("m4", cloneDto(machine).withAgents(asList("org.eclipse.che.terminal",
"org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")),
"m5", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")))
)));
Map<String, EnvironmentDto> expectedEnvs = ImmutableMap.of("e1", cloneDto(environment).withMachines(
ImmutableMap.of("m1", cloneDto(machine).withAgents(asList("org.eclipse.che.terminal",
"org.eclipse.che.ls.php",
"org.eclipse.che.ls.json",
"org.eclipse.che.exec")),
"m2", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.terminal",
"org.eclipse.che.ls.json",
"org.eclipse.che.exec")),
"m3", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")))
),
"e2", cloneDto(environment).withMachines(
ImmutableMap.of("m4", cloneDto(machine).withAgents(asList("org.eclipse.che.terminal",
"org.eclipse.che.ls.php",
"org.eclipse.che.ls.json",
"org.eclipse.che.exec")),
"m5", cloneDto(machine).withAgents(asList("org.eclipse.che.ls.php",
"org.eclipse.che.ls.json")))
));
when(factoryManager.saveFactory(any(FactoryDto.class),
anySetOf(FactoryImage.class)))
.thenAnswer(invocation -> new FactoryImpl((Factory)invocation.getArguments()[0], null));
doReturn(factoryDto).when(factoryBuilderSpy).build(any(InputStream.class));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.multiPart("factory", JsonHelper.toJson(factoryDto), APPLICATION_JSON)
// .expect()
// .statusCode(200)
.when()
.post(SERVICE_PATH);
final FactoryDto result = getFromResponse(response, FactoryDto.class);
Map<String, EnvironmentDto> actualEnvs = result.getWorkspace().getEnvironments();
assertEquals(actualEnvs, expectedEnvs);
}
private Factory createFactory() {
return createNamedFactory(FACTORY_NAME);
}
private Factory createNamedFactory(String name) {
return createFactoryWithStorage(name, PROJECT_SOURCE_TYPE, PROJECT_SOURCE_LOCATION);
}
private Factory createFactoryWithStorage(String name, String type, String location) {
return FactoryImpl.builder()
.setId(FACTORY_ID)
.setVersion("4.0")
.setWorkspace(createWorkspaceConfig(type, location))
.setCreator(new AuthorImpl(USER_ID, 12L))
.setName(name)
.build();
}
private static WorkspaceConfig createWorkspaceConfig(String type, String location) {
return WorkspaceConfigImpl.builder()
.setName(WORKSPACE_NAME)
.setEnvironments(singletonMap("env1", new EnvironmentImpl(createEnvDto())))
.setProjects(createProjects(type, location))
.build();
}
private static EnvironmentDto createEnvDto() {
final EnvironmentRecipeImpl environmentRecipe = new EnvironmentRecipeImpl();
environmentRecipe.setType("type");
environmentRecipe.setContent("content");
environmentRecipe.setContentType("compose");
environmentRecipe.setLocation("location");
final EnvironmentImpl env = new EnvironmentImpl();
final ExtendedMachineImpl extendedMachine = new ExtendedMachineImpl();
extendedMachine.setAgents(singletonList("agent"));
extendedMachine.setAttributes(singletonMap("att1", "value"));
extendedMachine.setServers(singletonMap("agent", new ServerConf2Impl("5555",
"https",
singletonMap("prop1", "value1"))));
env.setRecipe(environmentRecipe);
env.setMachines(singletonMap("machine1", extendedMachine));
return org.eclipse.che.api.workspace.server.DtoConverter.asDto(env);
}
private static List<ProjectConfig> createProjects(String type, String location) {
final ProjectConfigImpl projectConfig = new ProjectConfigImpl();
projectConfig.setSource(new SourceStorageImpl(type, location, null));
return ImmutableList.of(projectConfig);
}
private static <T> T getFromResponse(Response response, Class<T> clazz) throws Exception {
return DTO.createDtoFromJson(response.getBody().asInputStream(), clazz);
}
private static <T> List<T> unwrapDtoList(Response response, Class<T> dtoClass) {
return FluentIterable.from(DtoFactory.getInstance().createListDtoFromJson(response.body().print(), dtoClass)).toList();
}
private static Path getImagePath() throws Exception {
final URL res = currentThread().getContextClassLoader().getResource("100x100_image.jpeg");
assertNotNull(res);
return Paths.get(res.toURI());
}
}