/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.shindig.social.opensocial.service;
import org.apache.shindig.common.testing.FakeGadgetToken;
import org.apache.shindig.common.testing.FakeHttpServletRequest;
import org.apache.shindig.common.util.ImmediateFuture;
import org.apache.shindig.social.EasyMockTestCase;
import org.apache.shindig.social.ResponseError;
import org.apache.shindig.social.SocialApiTestsGuiceModule;
import org.apache.shindig.social.core.util.BeanJsonConverter;
import org.apache.shindig.social.core.util.BeanXStreamAtomConverter;
import org.apache.shindig.social.core.util.BeanXStreamConverter;
import org.apache.shindig.social.core.util.xstream.XStream081Configuration;
import org.apache.shindig.social.opensocial.spi.SocialSpiException;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provider;
import org.easymock.classextension.EasyMock;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.util.concurrent.ExecutionException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DataServiceServletTest extends EasyMockTestCase {
private static final FakeGadgetToken FAKE_GADGET_TOKEN = new FakeGadgetToken()
.setOwnerId("john.doe").setViewerId("john.doe");
private HttpServletRequest req;
private HttpServletResponse res;
private DataServiceServlet servlet;
private PersonHandler peopleHandler;
private ActivityHandler activityHandler;
private AppDataHandler appDataHandler;
private BeanJsonConverter jsonConverter;
private final ServletInputStream dummyPostData = new ServletInputStream() {
@Override public int read() {
return -1;
}
};
@Override protected void setUp() throws Exception {
servlet = new DataServiceServlet();
req = EasyMock.createMock(HttpServletRequest.class);
res = EasyMock.createMock(HttpServletResponse.class);
jsonConverter = EasyMock.createMock(BeanJsonConverter.class);
BeanXStreamConverter xmlConverter = EasyMock.createMock(BeanXStreamConverter.class);
BeanXStreamAtomConverter atomConverter = EasyMock.createMock(BeanXStreamAtomConverter.class);
peopleHandler = EasyMock.createMock(PersonHandler.class);
activityHandler = EasyMock.createMock(ActivityHandler.class);
appDataHandler = EasyMock.createMock(AppDataHandler.class);
EasyMock.expect(jsonConverter.getContentType()).andReturn("application/json");
EasyMock.expect(xmlConverter.getContentType()).andReturn("application/xml");
EasyMock.expect(atomConverter.getContentType()).andReturn("application/atom+xml");
HandlerDispatcher dispatcher = new StandardHandlerDispatcher(constant(peopleHandler),
constant(activityHandler), constant(appDataHandler));
servlet.setHandlerDispatcher(dispatcher);
servlet.setBeanConverters(jsonConverter, xmlConverter, atomConverter);
}
// TODO: replace with Providers.of() when Guice version is upgraded
private static <T> Provider<T> constant(final T value) {
return new Provider<T>() {
public T get() {
return value;
}
};
}
public void testPeopleUriRecognition() throws Exception {
verifyHandlerWasFoundForPathInfo('/'
+ DataServiceServlet.PEOPLE_ROUTE + "/5/@self", peopleHandler);
}
public void testActivitiesUriRecognition() throws Exception {
verifyHandlerWasFoundForPathInfo('/'
+ DataServiceServlet.ACTIVITY_ROUTE + "/5/@self", activityHandler);
}
public void testAppDataUriRecognition() throws Exception {
verifyHandlerWasFoundForPathInfo('/'
+ DataServiceServlet.APPDATA_ROUTE + "/5/@self", appDataHandler);
}
public void testMethodOverride() throws Exception {
String route = '/' + DataServiceServlet.APPDATA_ROUTE;
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "POST", "GET", "GET");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "POST", "", "POST");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "POST", null, "POST");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "POST", "POST", "POST");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "GET", null, "GET");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "DELETE", null, "DELETE");
verifyHandlerWasFoundForPathInfo(route, appDataHandler, "PUT", null, "PUT");
}
/**
* Tests a data handler that returns a failed Future
*/
public void testFailedRequest() throws Exception {
String route = '/' + DataServiceServlet.APPDATA_ROUTE;
setupRequest(route, "GET", null);
EasyMock.expect(appDataHandler.handleItem(EasyMock.isA(RestfulRequestItem.class)));
EasyMock.expectLastCall().andReturn(
ImmediateFuture.errorInstance(new RuntimeException("FAILED")));
res.sendError(500, "FAILED");
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
EasyMock.replay(req, res, appDataHandler, jsonConverter);
servlet.service(req, res);
EasyMock.verify(req, res, appDataHandler, jsonConverter);
EasyMock.reset(req, res, appDataHandler, jsonConverter);
}
private void verifyHandlerWasFoundForPathInfo(String peoplePathInfo, DataRequestHandler handler)
throws Exception {
String post = "POST";
verifyHandlerWasFoundForPathInfo(peoplePathInfo, handler, post, post, post);
}
private void verifyHandlerWasFoundForPathInfo(String pathInfo, DataRequestHandler handler,
String actualMethod, String overrideMethod, String expectedMethod) throws Exception {
setupRequest(pathInfo, actualMethod, overrideMethod);
String jsonObject = "my lovely json";
EasyMock.expect(handler.handleItem(EasyMock.isA(RequestItem.class)));
EasyMock.expectLastCall().andReturn(ImmediateFuture.newInstance(jsonObject));
EasyMock.expect(jsonConverter.convertToString(ImmutableMap.of("entry", jsonObject)))
.andReturn("{ 'entry' : " + jsonObject + " }");
PrintWriter writerMock = EasyMock.createMock(PrintWriter.class);
EasyMock.expect(res.getWriter()).andReturn(writerMock);
writerMock.write(jsonObject);
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
EasyMock.replay(req, res, handler, jsonConverter);
servlet.service(req, res);
EasyMock.verify(req, res, handler, jsonConverter);
EasyMock.reset(req, res, handler, jsonConverter);
// ick, this resets for the next call...
EasyMock.expect(jsonConverter.getContentType()).andReturn("application/json");
}
private void setupRequest(String pathInfo, String actualMethod, String overrideMethod)
throws IOException {
EasyMock.expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
if (!("GET").equals(overrideMethod) && !("HEAD").equals(overrideMethod)) {
EasyMock.expect(req.getInputStream()).andStubReturn(dummyPostData);
}
EasyMock.expect(req.getPathInfo()).andStubReturn(pathInfo);
EasyMock.expect(req.getMethod()).andStubReturn(actualMethod);
EasyMock.expect(req.getParameterNames()).andStubReturn(new StringTokenizer(""));
EasyMock.expect(req.getParameter(RestfulRequestItem.X_HTTP_METHOD_OVERRIDE)).andReturn(
overrideMethod).times(2);
EasyMock.expect(req.getParameter(DataServiceServlet.FORMAT_PARAM)).andReturn(null);
EasyMock.expect(req.getAttribute(EasyMock.isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
}
public void testInvalidRoute() throws Exception {
RestfulRequestItem requestItem = new RestfulRequestItem("/ahhh!", "GET", null,
FAKE_GADGET_TOKEN, jsonConverter);
try {
servlet.handleRequestItem(requestItem, new FakeHttpServletRequest()).get();
fail();
} catch (ExecutionException ee) {
assertTrue(ee.getCause() instanceof SocialSpiException);
assertEquals(ResponseError.NOT_IMPLEMENTED, ((SocialSpiException) ee.getCause()).getError());
}
}
public void testGetConverterForRequest() throws Exception {
Injector injector = Guice.createInjector(new SocialApiTestsGuiceModule());
BeanJsonConverter json = new BeanJsonConverter(injector);
BeanXStreamConverter xml = new BeanXStreamConverter(new XStream081Configuration(injector));
BeanXStreamAtomConverter atom = new BeanXStreamAtomConverter(new XStream081Configuration(injector));
servlet.setBeanConverters(json, xml, atom);
assertConverter(atom, "atom");
assertConverter(xml, "xml");
assertConverter(json, "");
assertConverter(json, null);
assertConverter(json, "ahhhh!");
}
public void testGetConverterForRequestContentType() throws Exception {
Injector injector = Guice.createInjector(new SocialApiTestsGuiceModule());
BeanJsonConverter json = new BeanJsonConverter(injector);
BeanXStreamConverter xml = new BeanXStreamConverter(new XStream081Configuration(injector));
BeanXStreamAtomConverter atom = new BeanXStreamAtomConverter(new XStream081Configuration(injector));
servlet.setBeanConverters(json, xml, atom);
assertConverterForContentType(atom, "application/atom+xml");
assertConverterForContentType(xml, "application/xml");
assertConverterForContentType(json, "");
assertConverterForContentType(json, null);
assertConverterForContentType(json, "abcd!");
}
private void assertConverter(BeanConverter converter, String format) {
EasyMock.expect(req.getParameter(DataServiceServlet.FORMAT_PARAM))
.andReturn(format);
EasyMock.replay(req);
assertEquals(converter, servlet.getConverterForRequest(req));
EasyMock.verify(req);
EasyMock.reset(req);
}
private void assertConverterForContentType(BeanConverter converter,
String contentType) {
EasyMock.expect(req.getHeader(DataServiceServlet.CONTENT_TYPE)).andReturn(
contentType);
EasyMock.replay(req);
assertEquals(converter, servlet.getConverterForRequest(req));
EasyMock.verify(req);
EasyMock.reset(req);
}
}