/******************************************************************************* * 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.core.rest; import com.google.common.collect.ImmutableMap; import com.google.common.reflect.TypeToken; import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.core.rest.shared.dto.Link; import org.eclipse.che.api.core.util.LinksHelper; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.commons.subject.SubjectImpl; import org.eclipse.che.dto.server.JsonArrayImpl; import org.eclipse.che.dto.shared.JsonArray; import org.eclipse.che.dto.shared.JsonStringMap; import org.everrest.assured.EverrestJetty; import org.everrest.core.Filter; import org.everrest.core.GenericContainerRequest; import org.everrest.core.RequestFilter; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.testng.MockitoTestNGListener; import org.testng.ITestContext; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.HttpMethod; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.eclipse.che.api.core.util.LinksHelper.createLink; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; /** * Tests of {@link DefaultHttpJsonRequest}. * * @author Yevhenii Voevodin */ @Listeners({MockitoTestNGListener.class, EverrestJetty.class}) public class DefaultHttpJsonRequestTest { @SuppressWarnings("unused") // used by EverrestJetty private static final EnvironmentFilter FILTER = new EnvironmentFilter(); @SuppressWarnings("unused") // used by EverrestJetty private static final ApiExceptionMapper EXCEPTION_MAPPER = new ApiExceptionMapper(); @SuppressWarnings("unused") // used by EverrestJetty private static final TestService TEST_SERVICE = new TestService(); private static final Subject TEST_SUBJECT = new SubjectImpl("name", "id", "token", false); private static final String DEFAULT_URL = "http://localhost:8080"; @Captor private ArgumentCaptor<Map<String, String>> mapCaptor; @Captor private ArgumentCaptor<List<Link>> listCaptor; private DefaultHttpJsonRequest request; @BeforeMethod private void prepareDefaultResponse() throws Exception { request = spy(new DefaultHttpJsonRequest(DEFAULT_URL)); request.setMethod("GET"); prepareResponse(""); } @Test public void shouldUseUrlAndMethodFromTheLinks() throws Exception { final Link link = createLink("POST", DEFAULT_URL, "rel"); final DefaultHttpJsonRequest request = spy(new DefaultHttpJsonRequest(link)); doReturn(new DefaultHttpJsonResponse("", 200)).when(request) .doRequest(anyInt(), anyString(), anyString(), anyObject(), any(), anyString()); request.request(); verify(request).doRequest(0, DEFAULT_URL, "POST", null, null, null); } @Test public void shouldBeAbleToMakeRequest() throws Exception { final Object body = new JsonArrayImpl<>(singletonList("element")); request.setMethod("PUT") .setBody(body) .setTimeout(10_000_000) .addQueryParam("name", "value") .addQueryParam("name2", "value2") .request(); verify(request).doRequest(10_000_000, "http://localhost:8080", "PUT", body, asList(Pair.of("name", "value"), Pair.of("name2", "value2")), null); } @Test public void shouldBeAbleToUseStringMapAsRequestBody() throws Exception { final Map<String, String> body = new HashMap<>(); body.put("name", "value"); body.put("name2", "value2"); request.setMethod("POST") .setBody(body) .request(); verify(request).doRequest(eq(0), eq("http://localhost:8080"), eq("POST"), mapCaptor.capture(), eq(null), eq(null)); assertTrue(mapCaptor.getValue() instanceof JsonStringMap); assertEquals(mapCaptor.getValue(), body); } @Test public void shouldBeAbleToUseListOfJsonSerializableElementsAsRequestBody() throws Exception { final List<Link> body = singletonList(createLink("POST", "http://localhost:8080", "rel")); request.setMethod("POST") .setBody(body) .request(); verify(request).doRequest(eq(0), eq("http://localhost:8080"), eq("POST"), listCaptor.capture(), eq(null), eq(null)); assertTrue(listCaptor.getValue() instanceof JsonArray); assertEquals(listCaptor.getValue(), body); } @Test public void defaultMethodIsGet() throws Exception { request.request(); verify(request).doRequest(0, DEFAULT_URL, HttpMethod.GET, null, null, null); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionIfSetMethodArgumentIsNull() throws Exception { new DefaultHttpJsonRequest("http://localhost:8080").setMethod(null); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenObjectBodyIsNull() throws Exception { final Object obj = null; new DefaultHttpJsonRequest("http://localhost:8080").setBody(obj); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenListBodyIsNull() throws Exception { final List<String> list = null; new DefaultHttpJsonRequest("http://localhost:8080").setBody(list); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenMapBodyIsNull() throws Exception { final Map<String, String> map = null; new DefaultHttpJsonRequest("http://localhost:8080").setBody(map); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenQueryParamNameIsNull() throws Exception { new DefaultHttpJsonRequest("http://localhost:8080").addQueryParam(null, "value"); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenQueryParamValueIsNull() throws Exception { new DefaultHttpJsonRequest("http://localhost:8080").addQueryParam("name", null); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenQueryParamsAreNull() throws Exception { new DefaultHttpJsonRequest("http://localhost:8080").addQueryParams(null); } @Test(expectedExceptions = NullPointerException.class) public void shouldThrowNullPointerExceptionWhenLinkHrefIsNull() throws Exception { new DefaultHttpJsonRequest(createLink("GET", null, null)); } @Test(expectedExceptions = BadRequestException.class) public void shouldThrowBadRequestExceptionWhenResponseCodeIs400(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/400/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = UnauthorizedException.class) public void shouldThrowUnauthorizedExceptionWhenResponseCodeIs401(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/401/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = ForbiddenException.class) public void shouldThrowForbiddenExceptionWhenResponseCodeIs403(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/403/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = NotFoundException.class) public void shouldThrowNotFoundExceptionWhenResponseCodeIs404(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/404/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = ConflictException.class) public void shouldThrowConflictExceptionWhenResponseCodeIs409(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/409/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = ServerException.class) public void shouldThrowServerExceptionWhenResponseCodeIs500(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/500/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = ServerException.class) public void shouldThrowServerExceptionWhenResponseWithAnyOtherResponseCode(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/501/response-code-test").useGetMethod().request(); } @Test(expectedExceptions = IOException.class) public void shouldThrowIOExceptionIfServerReturnsTypeDifferentFromApplicationJson(ITestContext ctx) throws Exception { new DefaultHttpJsonRequest(getUrl(ctx) + "/text-plain").useGetMethod().request(); } @Test public void shouldReadJsonObjectBodyAsString(ITestContext ctx) throws Exception { final DefaultHttpJsonRequest request = new DefaultHttpJsonRequest(getUrl(ctx) + "/application-json"); request.useGetMethod(); assertEquals(request.request().asString(), TestService.JSON_OBJECT); } @Test public void shouldEncodeRequestUrlInDefaultHttpJsonRequestAndDecodeInService(ITestContext ctx) throws Exception { final String base = getUrl(ctx) + "/decode"; final HttpJsonResponse response = new DefaultHttpJsonRequest(base).addQueryParam("query", "some white spaces !!") .useGetMethod() .request(); final String url = base + "?query=some white spaces !!"; assertEquals(url, response.asString()); } @Test public void shouldSendJsonObjectBody(ITestContext ctx) throws Exception { final DefaultHttpJsonRequest request = new DefaultHttpJsonRequest(getUrl(ctx) + "/application-json"); final Link link = LinksHelper.createLink("GET", "localhost:8080/application-json", "rel"); final List<Link> links = request.usePostMethod() .setBody(Collections.singletonList(link)) .request() .asList(Link.class); assertEquals(links, Collections.singletonList(link)); } @Test public void shouldSendQueryParameters(ITestContext ctx) throws Exception { final DefaultHttpJsonRequest request = new DefaultHttpJsonRequest(getUrl(ctx) + "/query-parameters"); final Map<String, String> map = request.usePutMethod() .addQueryParam("param1", "value1") .addQueryParam("param2", "value2") .request() .asProperties(); assertEquals(map, ImmutableMap.of("param1", "value1", "param2", "value2")); } @Test public void shouldSendMultipleQueryParameters(ITestContext ctx) throws Exception { final DefaultHttpJsonRequest request = new DefaultHttpJsonRequest(getUrl(ctx) + "/multi-query-parameters"); @SuppressWarnings("unchecked") final Map<String, List<String>> map = request.usePutMethod() .addQueryParam("param1", "value1") .addQueryParam("param1", "value2") .request() .as(Map.class, new TypeToken<Map<String, List<String>>>() {}.getType()); assertEquals(map.get("param1"), asList("value1", "value2")); } @Test public void shouldUseTokenFromCurrentContextForAuthorization(ITestContext ctx) throws Exception { final EnvironmentContext context = new EnvironmentContext(); context.setSubject(TEST_SUBJECT); EnvironmentContext.setCurrent(context); new DefaultHttpJsonRequest(getUrl(ctx) + "/token").usePostMethod().request(); } @Filter public static class EnvironmentFilter implements RequestFilter { public void doFilter(GenericContainerRequest request) { EnvironmentContext.getCurrent().setSubject(TEST_SUBJECT); } } private String getUrl(ITestContext ctx) { return "http://localhost:" + ctx.getAttribute(EverrestJetty.JETTY_PORT) + "/rest/test"; } private void prepareResponse(String response) throws Exception { doReturn(new DefaultHttpJsonResponse(response, 200)).when(request).doRequest(anyInt(), anyString(), anyString(), anyObject(), any(), anyString()); } }