Package com.medallia.spider.test

Source Code of com.medallia.spider.test.StRenderTestCase$HttpServletResponseResult

/*
* This file is part of the Spider Web Framework.
*
* The Spider Web Framework is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Spider Web Framework is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Spider Web Framework.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.medallia.spider.test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;

import com.medallia.spider.api.StRenderable;
import com.medallia.tiny.Encoding;
import com.medallia.tiny.Implement;
import com.medallia.tiny.Strings;
import com.medallia.tiny.test.TestCaseWithFixtures;


/**
* Abstract TestCase class for test cases that do "black box" testing of the
* modules. The test class should call {@link #action()} to simulate a web
* request; {@link #action(Map)} can be used to send in request parameters.
* <p>
*
* Normally the class name of the test class is used to map to the correct
* module, but the the {@link #action(Class)} can be used instead.
* <p>
*
* Normally each web application creates a common base class for all its
* test cases that takes care of setting up the test environment, e.g.
* create mock objects for the services that are dependency injected.
*
* @param <X> type of the {@link StRenderable} used by the test case
*/
public abstract class StRenderTestCase<X extends StRenderable> extends TestCaseWithFixtures {
 
  /** result of the actionAndRender method - can be either a redirect or the content of the StringTemplate render operation */
  public interface StRenderResult {
    /** @return true if the result is a redirect */
    boolean isRedirect();
    /** @return the redirect */
    String getRedirect();
    /** @return the content of the StringTemplate render operation */
    String getStContent();
    /** @return the binary content if the task produced any */
    byte[] getBinaryContent();
  }
 
  /** @return result of Action - no request parameters */
  protected StRenderResult action() throws Exception {
    return action(Collections.<String, String>emptyMap());
  }
  /** @return result of Action - request parameters passed in the given map */
  protected StRenderResult action(final Map<String, String> params) throws Exception {
    return action(getStRenderableClass(), params);
  }
  /** @return result of Action on the given class - no request parameters */
  protected StRenderResult action(Class<? extends X> renderableClass) throws Exception {
    return action(renderableClass, Collections.<String, String>emptyMap());
  }
 
  /**
   * Create a mock instance of {@link HttpSession} which is returned by the
   * default implementation of {@link #createRequest(Class, Map)} when a
   * session is requested. The default object has no functionality and all
   * methods return null.
   *
   * @return mock instance of {@link HttpSession}
   */
  protected HttpSession createSession() {
    return nullProxyForInterface(HttpSession.class);
  }

  /**
   * Create a mock instance of {@link HttpServletRequest} which is passed to
   * the servlet. The default object has limited functionality (i.e., no
   * attribute storing) and calls {@link #createSession()} when a session is
   * needed. Subclasses can override this method to add functionality as needed.
   *
   * @param renderableClass
   *            action class
   * @param params
   *            request parameters
   * @return mock instance of {@link HttpServletRequest}
   */
  protected HttpServletRequest createRequest(final Class<? extends X> renderableClass, final Map<String, String> params) {
    return new HttpServletRequestWrapper(nullProxyForInterface(HttpServletRequest.class)) {
      private HttpSession session;
      @Override public String getMethod() { return "GET"; }
      @Override public String getRequestURI() { return uriForTask(renderableClass); }
      @Override public String getContextPath() { return ""; }
      @Override public Map getParameterMap() { return params; }
      @Override public Cookie[] getCookies() { return new Cookie[0]; }
      @Override public HttpSession getSession() { return getSession(true); }
      @Override public HttpSession getSession(boolean create) {
        if (session == null && create) {
          session = createSession();
        }
        return session;
      }
      @Override public Object getAttribute(String name) { return null; }
      @Override public Enumeration getAttributeNames() { return Collections.enumeration(Collections.emptySet()); }
      @Override public String getHeader(String name) {
        if ("Referer".equals(name))
          return "http://" + renderableClass.getName() + "-test";
        return super.getHeader(name);
      }
    };
  }
 
  /**
   * Create a mock instance of {@link HttpServletResponse} which is passed to
   * the servlet. The default object has limited functionality (i.e., no
   * cookie storing). Subclasses can override this method to add functionality as
   * needed.
   *
   * @param responseResult
   *            object where the results of actions on the
   *            {@link HttpServletResponse} will be stored.
   * @return mock instance of {@link HttpServletResponse}
   */
  protected HttpServletResponse createResponse(final HttpServletResponseResult responseResult) {
    return new HttpServletResponseWrapper(nullProxyForInterface(HttpServletResponse.class)) {
      @Override public void sendRedirect(String location) throws IOException {
        responseResult.setRedirectLocation(location);
      }
      @Override public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
          @Override public void write(int b) throws IOException {
            responseResult.getOutputStream().write(b);
          }
        };
      }
      @Override public PrintWriter getWriter() throws IOException {
        return new PrintWriter(responseResult.getOutputStream());
      }
      @Override public String encodeURL(String s) { return s; }
      @Override public String getCharacterEncoding() { return "utf8"; }
      @Override public boolean isCommitted() { return false; }
    };
  }
 
  /**
   * Implementation of {@link StRenderResult}; can be passed to
   * {@link #createResponse(HttpServletResponseResult)} to obtain an instance
   * of {@link HttpServletResponse}; actions taken on the
   * {@link HttpServletResponse} object will be reflected in this object.
   */
  public class HttpServletResponseResult implements StRenderResult {
    private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    private String redirectLocation;
   
    /** Set the location redirected to */
    public void setRedirectLocation(String redirectLocation) {
      this.redirectLocation = redirectLocation;
    }

    /** Get an {@link OutputStream} the data can be written to */
    public OutputStream getOutputStream() {
      return bytes;
    }
   
    @Implement public boolean isRedirect() {
      return getRedirect() != null;
    }
   
    @Implement public String getRedirect() {
      return redirectLocation;
    }
   
    @Implement public String getStContent() {
      return Encoding.fromUTF8Bytes(getBinaryContent());
    }
   
    @Implement public byte[] getBinaryContent() {
      return bytes.toByteArray();
    }
  }
 
  /** @return result of Action on the given instance; request parameters can be passed in the given map */
  protected StRenderResult action(final Class<? extends X> renderableClass, final Map<String, String> params) throws Exception {
    HttpServletRequest request = createRequest(renderableClass, params);
    HttpServletResponseResult responseResult = new HttpServletResponseResult();
    servletMock.service(request, createResponse(responseResult));
    return responseResult;
  }
 
  /** @return a {@link Proxy} implementation of the given interface where all methods return null */
  public static <X> X nullProxyForInterface(Class<X> x) {
    return x.cast(Proxy.newProxyInstance(x.getClassLoader(), new Class<?>[] { x }, new InvocationHandler() {
      public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
        return null;
      }
    }));
  }


  /** Mock class for the Servlet */
  public interface ServletMock {
    /** called with mock request and response objects */
    void service(HttpServletRequest req, HttpServletResponse res) throws Exception;
    /** release any allocated resources */
    void destroy();
  }
 
  private ServletMock servletMock;
 
  @Override protected void safeUp() throws Exception {
    this.servletMock = getServletMock();
  }
  @Override protected void safeDown() throws Exception {
    this.servletMock.destroy();
    this.servletMock = null;
  }
 
  /** @return ServletMock that will be used in the test */
  protected abstract ServletMock getServletMock() throws Exception;
 
  /** @return the URI that maps to the given class */
  protected abstract String uriForTask(Class<? extends X> ct);
 
  /** @return the StAction class to be tested; defaults to the enclosing class. */
  @SuppressWarnings("unchecked")
  protected Class<? extends X> getStRenderableClass() {
    Class<? extends StRenderTestCase> testClass = getClass();
    Class<?> stClass = testClass.getEnclosingClass();
    if (stClass == null) {
      String s = testClass.getSimpleName();
      if (s.endsWith("Test")) {
        s = s.substring(0, s.length() - 4);
        List<String> packages = Arrays.asList(testClass.getPackage().getName().split("\\."));
        for (int i = packages.size(); i > 0; i--) {
          try {
            stClass = Class.forName(Strings.join(".", packages.subList(0, i)) + "." + s);
            break;
          } catch (ClassNotFoundException e) {
            // try again
          }
        }
      }
    }
       
    if (stClass == null) {
      throw new RuntimeException("Please override this method");
    }
    return (Class<? extends X>) stClass;
  }
 
  /** special string that can be prepended to each content string to signal that
   * the rest of the string should not be present.
   */
  protected static final String NOT = "!!!";
 
  /** assert that the RenderResult has the given content */
  protected void assertHasContent(StRenderResult rr, String... contents) {
    assertHas(rr.getStContent(), contents);
  }
 
  /** assert that the RenderResult is of type redirect and which has the given redirect */
  protected void assertRedirectTo(StRenderResult rr, String... redirect) {
    assertHas(rr.getRedirect(), redirect);
  }
 
  /** assert that the string has the given content */
  private void assertHas(String str, String... contents) {
    for (String content : contents) {
      if (content != null)
        if (content.startsWith(NOT))
          assertFalse("Found " + content + " in " + str, str.contains(content.substring(NOT.length())));
        else
          assertTrue("Did not find " + content + " in: " +str, str.contains(content));
    }
  }

}
TOP

Related Classes of com.medallia.spider.test.StRenderTestCase$HttpServletResponseResult

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.