Package org.apache.shindig.protocol

Source Code of org.apache.shindig.protocol.JsonRpcServletTest

/*
* 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.protocol;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.isA;
import static org.easymock.classextension.EasyMock.reset;

import org.apache.shindig.common.JsonAssert;
import org.apache.shindig.common.testing.FakeGadgetToken;
import org.apache.shindig.protocol.conversion.BeanJsonConverter;
import org.apache.shindig.protocol.multipart.FormDataItem;
import org.apache.shindig.protocol.multipart.MultipartFormParser;
import org.easymock.IMocksControl;
import org.easymock.classextension.EasyMock;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.inject.Guice;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
*
*/
public class JsonRpcServletTest extends Assert {

  private static final FakeGadgetToken FAKE_GADGET_TOKEN = new FakeGadgetToken()
      .setOwnerId("john.doe").setViewerId("john.doe");

  private static final String IMAGE_FIELDNAME = "profile-photo";
  private static final String IMAGE_DATA = "image data";
  private static final byte[] IMAGE_DATA_BYTES = IMAGE_DATA.getBytes();
  private static final String IMAGE_TYPE = "image/jpeg";

  private HttpServletRequest req;
  private HttpServletResponse res;
  private JsonRpcServlet servlet;
  private MultipartFormParser multipartFormParser;

  private final IMocksControl mockControl = EasyMock.createNiceControl();

  private final ByteArrayOutputStream stream = new ByteArrayOutputStream();
  private final PrintWriter writer = new PrintWriter(stream);
  private final TestHandler handler = new TestHandler();

  @Before
  public void setUp() throws Exception {
    servlet = new JsonRpcServlet();
    req = mockControl.createMock(HttpServletRequest.class);
    res = mockControl.createMock(HttpServletResponse.class);

    multipartFormParser = mockControl.createMock(MultipartFormParser.class);
    EasyMock.expect(multipartFormParser.isMultipartContent(req)).andStubReturn(false);
    servlet.setMultipartFormParser(multipartFormParser);

    BeanJsonConverter converter = new BeanJsonConverter(Guice.createInjector());

    HandlerRegistry registry = new DefaultHandlerRegistry(null, null,
        new HandlerExecutionListener.NoOpHandler());
    registry.addHandlers(Collections.<Object>singleton(handler));

    servlet.setHandlerRegistry(registry);
    servlet.setBeanConverters(converter, null, null);
    handler.setMock(new TestHandler() {
      @Override
      public Object get(RequestItem req) {
        return ImmutableMap.of("foo", "bar");
      }
    });
  }

  private String getOutput() throws IOException {
    writer.close();
    return stream.toString("UTF-8");
  }

  @Test
  public void testMethodRecognition() throws Exception {
    setupRequest("{method:test.get,id:id,params:{userId:5,groupId:@self}}");

    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("{id: 'id', data: {foo:'bar'}}", getOutput());
  }

  @Test
  public void testPostMultipartFormData() throws Exception {
    reset(multipartFormParser);

    handler.setMock(new TestHandler() {
      @Override
      public Object get(RequestItem req) {
        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
        return ImmutableMap.of("image-data", new String(item.get()),
            "image-type", item.getContentType(),
            "image-ref", req.getParameter("image-ref"));
      }
    });
    expect(req.getMethod()).andStubReturn("POST");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
    res.setCharacterEncoding("UTF-8");
    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);

    List<FormDataItem> formItems = Lists.newArrayList();
    String request = "{method:'test.get',id:'id',params:" +
        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
    formItems.add(mockFormDataItem(JsonRpcServlet.REQUEST_PARAM,
        ContentTypes.OUTPUT_JSON_CONTENT_TYPE, request.getBytes(), true));
    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
    expect(multipartFormParser.parse(req)).andReturn(formItems);
    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
        "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
  }

  /**
   * Test that it passes even when content-type is not set for "request" parameter. This would
   * be the case where the request is published via webform.
   */
  @Test
  public void testPostMultipartFormDataWithRequestFieldHavingNoContentType() throws Exception {
    reset(multipartFormParser);

    handler.setMock(new TestHandler() {
      @Override
      public Object get(RequestItem req) {
        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
        return ImmutableMap.of("image-data", new String(item.get()),
            "image-type", item.getContentType(),
            "image-ref", req.getParameter("image-ref"));
      }
    });
    expect(req.getMethod()).andStubReturn("POST");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
    res.setCharacterEncoding("UTF-8");
    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);

    List<FormDataItem> formItems = Lists.newArrayList();
    String request = "{method:'test.get',id:'id',params:" +
        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
    formItems.add(mockFormDataItem("request", null, request.getBytes(), true));
    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
    expect(multipartFormParser.parse(req)).andReturn(formItems);
    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
        "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
  }


  /**
   * Test that any form-data other than "request" does not undergo any content type check.
   */
  @Test
  public void testPostMultipartFormDataOnlyRequestFieldHasContentTypeChecked()
      throws Exception {
    reset(multipartFormParser);

    handler.setMock(new TestHandler() {
      @Override
      public Object get(RequestItem req) {
        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
        return ImmutableMap.of("image-data", new String(item.get()),
            "image-type", item.getContentType(),
            "image-ref", req.getParameter("image-ref"));
      }
    });
    expect(req.getMethod()).andStubReturn("POST");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
    res.setCharacterEncoding("UTF-8");
    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);

    List<FormDataItem> formItems = Lists.newArrayList();
    String request = "{method:'test.get',id:'id',params:" +
        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
    formItems.add(mockFormDataItem("oauth_hash", "application/octet-stream",
        "oauth-hash".getBytes(), true));
    formItems.add(mockFormDataItem("request", null, request.getBytes(), true));
    formItems.add(mockFormDataItem("oauth_signature", "application/octet-stream",
        "oauth_signature".getBytes(), true));
    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
    expect(multipartFormParser.parse(req)).andReturn(formItems);
    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
        "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
  }

  /**
   * Test that "request" field undergoes contentType check, and error is thrown if wrong content
   * type is present.
   */
  @Test
  public void testPostMultipartFormDataRequestFieldIsSubjectedToContentTypeCheck()
      throws Exception {
    reset(multipartFormParser);

    handler.setMock(new TestHandler() {
      @Override
      public Object get(RequestItem req) {
        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
        return ImmutableMap.of("image-data", item.get(),
            "image-type", item.getContentType(),
            "image-ref", req.getParameter("image-ref"));
      }
    });
    expect(req.getMethod()).andStubReturn("POST");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
    res.setCharacterEncoding("UTF-8");
    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);

    List<FormDataItem> formItems = Lists.newArrayList();
    String request = "{method:'test.get',id:'id',params:" +
        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
    formItems.add(mockFormDataItem("request", "application/octet-stream", request.getBytes(),
        true));
    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
    expect(multipartFormParser.parse(req)).andReturn(formItems);
    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    String output = getOutput();
    assertTrue(-1 != output.indexOf("Unsupported Content-Type application/octet-stream"));
  }

  @Test
  public void testInvalidService() throws Exception {
    setupRequest("{method:junk.get,id:id,params:{userId:5,groupId:@self}}");

    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals(
        "{id:id,error:{message:'notImplemented: The method junk.get is not implemented',code:501}}",
        getOutput());
  }


  /**
   * Tests a data handler that returns a failed Future.
   * @throws Exception on failure
   */
  @Test
  public void testFailedRequest() throws Exception {
    setupRequest("{id:id,method:test.futureException}");

    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals(
        "{id:id,error:{message:'badRequest: FAILURE_MESSAGE',code:400}}", getOutput());
  }

  @Test
  public void testBasicBatch() throws Exception {
    setupRequest("[{method:test.get,id:'1'},{method:test.get,id:'2'}]");

    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("[{id:'1',data:{foo:'bar'}},{id:'2',data:{foo:'bar'}}]",
        getOutput());
  }

  @Test
  public void testGetExecution() throws Exception {
    expect(req.getParameterMap()).andStubReturn(
        ImmutableMap.of("method", new String[]{"test.get"}, "id", new String[]{"1"}));
    expect(req.getMethod()).andStubReturn("GET");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    res.setCharacterEncoding("UTF-8");

    expect(res.getWriter()).andReturn(writer);
    expectLastCall();

    mockControl.replay();
    servlet.service(req, res);
    mockControl.verify();

    JsonAssert.assertJsonEquals("{id:'1',data:{foo:'bar'}}", getOutput());
  }

  @Test
  public void testGetJsonResponseWithKey() throws Exception {
    ResponseItem responseItem = new ResponseItem("Name");
    Object result = servlet.getJSONResponse("my-key", responseItem);
    JsonAssert.assertObjectEquals("{id: 'my-key', data: 'Name'}", result);
  }

  @Test
  public void testGetJsonResponseWithoutKey() throws Exception {
    ResponseItem responseItem = new ResponseItem("Name");
    Object result = servlet.getJSONResponse(null, responseItem);
    JsonAssert.assertObjectEquals("{data: 'Name'}", result);
  }

  @Test
  public void testGetJsonResponseErrorWithData() throws Exception {
    ResponseItem responseItem = new ResponseItem(401, "Error Message", "Optional Data");
    Object result = servlet.getJSONResponse(null, responseItem);
    JsonAssert.assertObjectEquals(
        "{error: {message: 'unauthorized: Error Message', data: 'Optional Data', code: 401}}",
        result);
  }

  @Test
  public void testGetJsonResponseErrorWithoutData() throws Exception {
    ResponseItem responseItem = new ResponseItem(401, "Error Message");
    Object result = servlet.getJSONResponse(null, responseItem);
    JsonAssert.assertObjectEquals(
        "{error: {message:'unauthorized: Error Message', code:401}}",
        result);
  }

  private void setupRequest(String json) throws IOException {
    final InputStream in = new ByteArrayInputStream(json.getBytes());
    ServletInputStream stream = new ServletInputStream() {
      @Override
      public int read() throws IOException {
        return in.read();
      }
    };

    expect(req.getInputStream()).andStubReturn(stream);
    expect(req.getMethod()).andStubReturn("POST");
    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
    expect(req.getContentType()).andStubReturn(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
    res.setCharacterEncoding("UTF-8");
    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
  }

  private FormDataItem mockFormDataItem(String fieldName, String contentType, byte content[],
      boolean isFormField) throws IOException {
    InputStream in = new ByteArrayInputStream(content);
    FormDataItem formDataItem = mockControl.createMock(FormDataItem.class);
    expect(formDataItem.getContentType()).andStubReturn(contentType);
    expect(formDataItem.getSize()).andStubReturn((long) content.length);
    expect(formDataItem.get()).andStubReturn(content);
    expect(formDataItem.getAsString()).andStubReturn(new String(content));
    expect(formDataItem.getFieldName()).andStubReturn(fieldName);
    expect(formDataItem.isFormField()).andStubReturn(isFormField);
    expect(formDataItem.getInputStream()).andStubReturn(in);
    return formDataItem;
  }
}
TOP

Related Classes of org.apache.shindig.protocol.JsonRpcServletTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.