/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.webx.servlet;
import static com.alibaba.citrus.springext.util.SpringExtUtil.*;
import static com.alibaba.citrus.test.TestUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.ServletException;
import com.alibaba.citrus.service.pipeline.PipelineContext;
import com.alibaba.citrus.service.requestcontext.RequestContext;
import com.alibaba.citrus.service.requestcontext.rundata.RunData;
import com.alibaba.citrus.service.requestcontext.support.AbstractRequestContextFactory;
import com.alibaba.citrus.webx.AbstractWebxTests;
import com.alibaba.citrus.webx.BadRequestException;
import com.alibaba.citrus.webx.ResourceNotFoundException;
import com.alibaba.citrus.webx.handler.RequestHandler;
import com.alibaba.citrus.webx.handler.RequestHandlerContext;
import com.alibaba.citrus.webx.handler.RequestHandlerMapping;
import com.alibaba.citrus.webx.impl.WebxRootControllerImpl;
import com.alibaba.citrus.webx.pipeline.TestValve;
import com.alibaba.citrus.webx.pipeline.ValveRunner;
import com.alibaba.citrus.webx.util.ErrorHandlerHelper;
import com.meterware.httpunit.HeadMethodWebRequest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.web.context.WebApplicationContext;
public class WebxRootControllerTests extends AbstractWebxTests {
private WebxFrameworkFilter filter;
private WebxRootControllerImpl controller;
@Before
public void init() throws Exception {
// 特别测试当有/contextPath存在时,passthru参数正确工作
prepareWebClient(null, "/myapps");
filter = (WebxFrameworkFilter) client.newInvocation("http://www.taobao.com/myapps/app1").getFilter();
controller = (WebxRootControllerImpl) filter.getWebxComponents().getWebxRootController();
setErrorHandler(controller, new TestErrorHandler());
}
@Test
public void passthru() throws Exception {
// passthru
invokeServlet("/myapps/app1/plaintext.txt");
assertEquals(200, clientResponseCode);
assertEquals("hello, app1", clientResponseContent); // text from plain text file
// 普通request
invokeServlet("/myapps/app1/plaintext2.txt");
assertEquals(200, clientResponseCode);
assertEquals("hello!", clientResponseContent.trim()); // text from valve
}
@Test
public void requestContextFailed() throws Exception {
requestContextFactoryHolder.set(new AbstractRequestContextFactory() {
@Override
public RequestContext getRequestContextWrapper(RequestContext wrappedContext) {
throw new IllegalArgumentException("ouch!");
}
public String[] getFeatures() {
return null;
}
public FeatureOrder[] featureOrders() {
return null;
}
});
invokeServlet("/myapps/app1/test.htm");
assertEquals(500, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertThat(clientResponseContent,
containsAll("<pre>", "</pre>", IllegalArgumentException.class.getName(), "ouch!"));
}
@Test
public void internalRequest_illegal() throws Exception {
// internal
invokeServlet("/myapps/internal/notexist");
// 由main handler接手,然后抛出异常
assertEquals(404, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertThat(
clientResponseContent,
containsAll("<pre>", "</pre>", ResourceNotFoundException.class.getName(),
"Resource Not Found: notexist"));
}
@Test
public void internalRequest_error() throws Exception {
invokeServlet("/myapps/internal/error");
assertEquals(200, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertEquals(null, trimToNull(clientResponseContent));
}
@Test
public void nonInternalRequest() throws Exception {
invokeServlet("/myapps/app1/internal.htm");
assertEquals(200, clientResponseCode);
assertThat(clientResponseContent, containsAll("hello!"));
}
@Test
public void internalRequestMapping() throws Exception {
WebApplicationContext context = controller.getComponents().getParentApplicationContext();
class Holder {
@Autowired
private RequestHandlerMapping mapping;
}
Holder holder = autowireAndInitialize(new Holder(), context, AbstractBeanDefinition.AUTOWIRE_AUTODETECT,
"holder");
assertArrayEquals(new String[] { "Webx/Info/Environment+Variables", "Webx/Info/System+Properties",
"Webx/Info/Request+Info", "Webx/Info/System+Info", "Webx/Schema" },
holder.mapping.getRequestHandlerNames());
}
@Test
public void valve_breakToTop() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
pipelineContext.breakPipeline(0);
}
});
invokeServlet("/myapps/app1/plaintext.txt");
assertEquals(200, clientResponseCode);
assertEquals("text/plain", clientResponse.getContentType());
assertThat(clientResponseContent, containsAll("hello, app1"));
}
@Test
public void valve_exception() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
throw new IllegalStateException("wrong!");
}
});
invokeServlet("/myapps/app1/test.htm");
assertEquals(500, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertThat(clientResponseContent,
containsAll("<pre>", "</pre>", IllegalStateException.class.getName(), "wrong!"));
}
@Test
public void valve_not_found_exception() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
throw new ResourceNotFoundException("not found!");
}
});
invokeServlet("/myapps/app1/test.htm");
assertEquals(404, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertThat(clientResponseContent,
containsAll("<pre>", "</pre>", ResourceNotFoundException.class.getName(), "not found!"));
}
@Test
public void valve_bad_request_exception() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
throw new BadRequestException("bad request!");
}
});
invokeServlet("/myapps/app1/test.htm");
assertEquals(400, clientResponseCode);
assertEquals("text/html", clientResponse.getContentType());
assertThat(clientResponseContent,
containsAll("<pre>", "</pre>", BadRequestException.class.getName(), "bad request!"));
}
@Test
public void valve_exception_exception() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
throw new IllegalStateException("wrong!");
}
});
setErrorHandler(controller, new RequestHandler() {
public void handleRequest(RequestHandlerContext ctx) throws Exception {
throw new IllegalArgumentException("wrong again!");
}
});
try {
invokeServlet("/myapps/app1/test.htm");
fail();
} catch (ServletException e) {
// 真正的servlet engine在这里会显示web.xml中的错误页面,而测试时只会接收异常。
assertThat(e, exception(IllegalStateException.class)); // 所抛出的是第一个应用产生的异常
assertThat(e, not(exception(IllegalArgumentException.class))); // 而不是第二个errorHandler产生的异常
}
}
@Test
public void valve_exception_exception_2() throws Exception {
TestValve.runnerHolder.set(new ValveRunner() {
public void run(RunData rundata, PipelineContext pipelineContext) throws Exception {
throw new IllegalStateException("wrong!");
}
});
setErrorHandler(controller, new RequestHandler() {
public void handleRequest(RequestHandlerContext ctx) throws Exception {
throw new ServletException(ErrorHandlerHelper.getInstance(ctx.getRequest()).getException());
}
});
try {
invokeServlet("/myapps/app1/test.htm");
fail();
} catch (ServletException e) {
// 真正的servlet engine在这里会显示web.xml中的错误页面,而测试时只会接收异常。
assertThat(e, exception(IllegalStateException.class));
}
}
@Test
public void head() throws Exception {
clientResponse = client.getResponse(new HeadMethodWebRequest("http://localhost/myapps/app1/internal.htm"));
clientResponseCode = clientResponse.getResponseCode();
clientResponseContent = clientResponse.getText();
assertEquals(200, clientResponseCode);
assertEquals(null, trimToNull(clientResponseContent));
}
@Test
public void loadInternalRequestHandlers() throws Exception {
Map<String, RequestHandler> handlers;
// names are normalized and sorted
// skipped empty name/class
// skipped reserved name: error
// skipped abstract and wrong type
handlers = loadInternalHandlers("internal-request-handlers-test-1");
assertArrayEquals(new String[] { "aa/bb/cc", "aa/cc" }, handlers.keySet().toArray(new String[0]));
}
@SuppressWarnings("unchecked")
private Map<String, RequestHandler> loadInternalHandlers(String location) throws Exception {
location = "META-INF/" + location;
Object internalHandlerMapping = getFieldValue(controller, "internalHandlerMapping", null); // of inner type InternalHandlerMapping
Method loadInternalHandlers = getAccessibleMethod(internalHandlerMapping.getClass(), "loadInternalHandlers",
new Class<?>[] { String.class });
return (Map<String, RequestHandler>) loadInternalHandlers.invoke(internalHandlerMapping, location);
}
}