/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.http.config;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.expression.Expression;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.http.AbstractHttpInboundTests;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.http.inbound.HttpRequestHandlingController;
import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.servlet.HandlerMapping;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Gunnar Hillert
* @author Artem Bilan
* @author Biju Kunjummen
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
public class HttpInboundChannelAdapterParserTests extends AbstractHttpInboundTests {
@Autowired
private PollableChannel requests;
@Autowired
private HandlerMapping integrationRequestMappingHandlerMapping;
@Autowired
private HttpRequestHandlingMessagingGateway defaultAdapter;
@Autowired
private HttpRequestHandlingMessagingGateway postOnlyAdapter;
@Autowired
@Qualifier("adapterWithCustomConverterWithDefaults")
private HttpRequestHandlingMessagingGateway adapterWithCustomConverterWithDefaults;
@Autowired
private HttpRequestHandlingMessagingGateway putOrDeleteAdapter;
@Autowired
private HttpRequestHandlingMessagingGateway withMappedHeaders;
@Autowired
private HttpRequestHandlingMessagingGateway inboundAdapterWithExpressions;
@Autowired
@Qualifier("adapterWithCustomConverterNoDefaults")
private HttpRequestHandlingMessagingGateway adapterWithCustomConverterNoDefaults;
@Autowired
@Qualifier("adapterNoCustomConverterNoDefaults")
private HttpRequestHandlingMessagingGateway adapterNoCustomConverterNoDefaults;
@Autowired
private HttpRequestHandlingController inboundController;
@Autowired
private HttpRequestHandlingController inboundControllerViewExp;
@Autowired
private MessageChannel autoChannel;
@Autowired @Qualifier("autoChannel.adapter")
private HttpRequestHandlingMessagingGateway autoChannelAdapter;
@Test
@SuppressWarnings("unchecked")
public void getRequestOk() throws Exception {
assertFalse(TestUtils.getPropertyValue(this.defaultAdapter, "autoStartup", Boolean.class));
assertEquals(1001, TestUtils.getPropertyValue(this.defaultAdapter, "phase"));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setParameter("foo", "bar");
MockHttpServletResponse response = new MockHttpServletResponse();
this.defaultAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_SERVICE_UNAVAILABLE, response.getStatus());
this.defaultAdapter.start();
response = new MockHttpServletResponse();
this.defaultAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_SWITCHING_PROTOCOLS, response.getStatus());
Message<?> message = requests.receive(0);
assertNotNull(message);
Object payload = message.getPayload();
assertTrue(payload instanceof MultiValueMap);
MultiValueMap<String, String> map = (MultiValueMap<String, String>) payload;
assertEquals(1, map.size());
assertEquals("foo", map.keySet().iterator().next());
assertEquals(1, map.get("foo").size());
assertEquals("bar", map.getFirst("foo"));
assertNotNull(TestUtils.getPropertyValue(this.defaultAdapter, "errorChannel"));
}
@Test
public void getRequestWithHeaders() throws Exception {
DefaultHttpHeaderMapper headerMapper =
(DefaultHttpHeaderMapper) TestUtils.getPropertyValue(withMappedHeaders, "headerMapper");
HttpHeaders headers = new HttpHeaders();
headers.set("foo", "foo");
headers.set("bar", "bar");
headers.set("baz", "baz");
Map<String, Object> map = headerMapper.toHeaders(headers);
assertTrue(map.size() == 2);
assertEquals("foo", map.get("foo"));
assertEquals("bar", map.get("bar"));
}
@Test
// INT-1677
public void withExpressions() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("text/plain");
request.setParameter("foo", "bar");
request.setContent("hello".getBytes());
String requestURI = "/fname/bill/lname/clinton";
//See org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch
Map<String, String> uriTemplateVariables =
new AntPathMatcher().extractUriTemplateVariables("/fname/{f}/lname/{l}", requestURI);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
request.setRequestURI(requestURI);
MockHttpServletResponse response = new MockHttpServletResponse();
inboundAdapterWithExpressions.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Message<?> message = requests.receive(0);
assertNotNull(message);
Object payload = message.getPayload();
assertTrue(payload instanceof String);
assertEquals("bill", payload);
assertEquals("clinton", message.getHeaders().get("lname"));
}
@Test
public void getRequestNotAllowed() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setParameter("foo", "bar");
request.setRequestURI("/postOnly");
try {
this.integrationRequestMappingHandlerMapping.getHandler(request);
}
catch (HttpRequestMethodNotSupportedException e) {
assertEquals("GET", e.getMethod());
assertArrayEquals(new String[] {"POST"}, e.getSupportedMethods());
}
}
@Test
public void postRequestWithTextContentOk() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("test".getBytes());
request.setContentType("text/plain");
MockHttpServletResponse response = new MockHttpServletResponse();
postOnlyAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Message<?> message = requests.receive(0);
MessageHistory history = MessageHistory.read(message);
assertNotNull(history);
Properties componentHistoryRecord = TestUtils.locateComponentInHistory(history, "postOnlyAdapter", 0);
assertNotNull(componentHistoryRecord);
assertEquals("http:inbound-channel-adapter", componentHistoryRecord.get("type"));
assertNotNull(message);
assertEquals("test", message.getPayload());
}
@Test @DirtiesContext
public void postRequestWithSerializedObjectContentOk() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
Object obj = new TestObject("testObject");
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
new ObjectOutputStream(byteStream).writeObject(obj);
request.setContent(byteStream.toByteArray());
request.setContentType("application/x-java-serialized-object");
MockHttpServletResponse response = new MockHttpServletResponse();
adapterWithCustomConverterWithDefaults.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Message<?> message = requests.receive(0);
assertNotNull(message);
assertTrue(message.getPayload() instanceof TestObject);
assertEquals("testObject", ((TestObject) message.getPayload()).text);
}
@Test
public void putOrDeleteMethodsSupported() throws Exception {
HttpMethod[] supportedMethods =
TestUtils.getPropertyValue(putOrDeleteAdapter, "requestMapping.methods", HttpMethod[].class);
assertEquals(2, supportedMethods.length);
assertArrayEquals(new HttpMethod[]{HttpMethod.PUT, HttpMethod.DELETE}, supportedMethods);
}
@Test
public void testController() throws Exception {
String errorCode = TestUtils.getPropertyValue(inboundController, "errorCode", String.class);
assertEquals("oops", errorCode);
Expression viewExpression = TestUtils.getPropertyValue(inboundController, "viewExpression", Expression.class);
assertEquals("foo", viewExpression.getExpressionString());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setParameter("foo", "bar");
MockHttpServletResponse response = new MockHttpServletResponse();
inboundController.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus());
Message<?> message = requests.receive(0);
assertNotNull(message);
}
@Test
public void testInt2717ControllerWithViewExpression() throws Exception {
Expression viewExpression = TestUtils.getPropertyValue(inboundControllerViewExp, "viewExpression", Expression.class);
assertEquals("'foo'", viewExpression.getExpressionString());
}
@Test
public void testAutoChannel() {
assertSame(autoChannel, TestUtils.getPropertyValue(autoChannelAdapter, "requestChannel"));
}
@Test
public void testInboundAdapterWithMessageConverterDefaults() {
@SuppressWarnings("unchecked")
List<HttpMessageConverter<?>> messageConverters = TestUtils.getPropertyValue(adapterWithCustomConverterWithDefaults, "messageConverters", List.class);
assertTrue("There should be more than 1 message converter. The customized one and the defaults.", messageConverters.size() > 1);
//First converter should be the customized one
assertThat(messageConverters.get(0), instanceOf(SerializingHttpMessageConverter.class));
}
@Test
public void testInboundAdapterWithNoMessageConverterDefaults() {
@SuppressWarnings("unchecked")
List<HttpMessageConverter<?>> messageConverters = TestUtils.getPropertyValue(adapterWithCustomConverterNoDefaults, "messageConverters", List.class);
//First converter should be the customized one
assertThat(messageConverters.get(0), instanceOf(SerializingHttpMessageConverter.class));
assertTrue("There should be only the customized messageconverter registered.", messageConverters.size() == 1);
}
@Test
public void testInboundAdapterWithNoMessageConverterNoDefaults() {
@SuppressWarnings("unchecked")
List<HttpMessageConverter<?>> messageConverters = TestUtils.getPropertyValue(adapterNoCustomConverterNoDefaults, "messageConverters", List.class);
assertTrue("There should be more than 1 message converter. The defaults.", messageConverters.size() > 1);
}
@SuppressWarnings("serial")
private static class TestObject implements Serializable {
String text;
TestObject(String text) {
this.text = text;
}
}
}