Package com.google.gwt.junit.server

Source Code of com.google.gwt.junit.server.JUnitHostImpl

/*
* Copyright 2008 Google Inc.
*
* 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.google.gwt.junit.server;

import com.google.gwt.junit.JUnitFatalLaunchException;
import com.google.gwt.junit.JUnitMessageQueue;
import com.google.gwt.junit.JUnitShell;
import com.google.gwt.junit.client.TimeoutException;
import com.google.gwt.junit.client.impl.ExceptionWrapper;
import com.google.gwt.junit.client.impl.JUnitHost;
import com.google.gwt.junit.client.impl.JUnitResult;
import com.google.gwt.junit.client.impl.StackTraceWrapper;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.server.rpc.HybridServiceServlet;
import com.google.gwt.user.server.rpc.RPCServletUtils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;

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

/**
* An RPC servlet that serves as a proxy to JUnitTestShell. Enables
* communication between the unit test code running in a browser and the real
* test process.
*/
public class JUnitHostImpl extends HybridServiceServlet implements JUnitHost {

  /**
   * A hook into GWTUnitTestShell, the underlying unit test process.
   */
  private static JUnitMessageQueue sHost = null;

  /**
   * A maximum timeout to wait for the test system to respond with the next
   * test. The test system should respond nearly instantly if there are further
   * tests to run, unless the tests have not yet been compiled.
   */
  private static final int TIME_TO_WAIT_FOR_TESTNAME = 300000;

  /**
   * Tries to grab the GWTUnitTestShell sHost environment to communicate with
   * the real test process.
   */
  private static synchronized JUnitMessageQueue getHost() {
    if (sHost == null) {
      sHost = JUnitShell.getMessageQueue();
      if (sHost == null) {
        throw new InvocationException(
            "Unable to find JUnitShell; is this servlet running under GWTTestCase?");
      }
    }
    return sHost;
  }

  /**
   * Simple helper method to set inaccessible fields via reflection.
   */
  private static <T> void setField(Class<T> cls, String fieldName, T obj,
      Object value) throws SecurityException, NoSuchFieldException,
      IllegalArgumentException, IllegalAccessException {
    Field fld = cls.getDeclaredField(fieldName);
    fld.setAccessible(true);
    fld.set(obj, value);
  }

  public TestBlock getTestBlock(int blockIndex, String userAgent)
      throws TimeoutException {
    return getHost().getTestBlock(getClientId(getThreadLocalRequest()),
        userAgent, blockIndex, TIME_TO_WAIT_FOR_TESTNAME);
  }

  public TestBlock reportResultsAndGetTestBlock(
      HashMap<TestInfo, JUnitResult> results, int testBlock, String userAgent)
      throws TimeoutException {
    for (JUnitResult result : results.values()) {
      initResult(getThreadLocalRequest(), result);
      ExceptionWrapper ew = result.getExceptionWrapper();
      result.setException(deserialize(ew));
    }
    JUnitMessageQueue host = getHost();
    String clientId = getClientId(getThreadLocalRequest());
    host.reportResults(clientId, userAgent, results);
    return host.getTestBlock(clientId, userAgent, testBlock,
        TIME_TO_WAIT_FOR_TESTNAME);
  }

  @Override
  protected void service(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
    String requestURI = request.getRequestURI();
    if (requestURI.endsWith("/junithost/loadError")) {
      String requestPayload = RPCServletUtils.readContentAsUtf8(request);
      JUnitResult result = new JUnitResult();
      initResult(request, result);
      result.setException(new JUnitFatalLaunchException(requestPayload));
      getHost().reportFatalLaunch(getClientId(request), null, result);
    } else {
      super.service(request, response);
    }
  }

  /**
   * Deserializes an ExceptionWrapper back into a Throwable.
   */
  private Throwable deserialize(ExceptionWrapper ew) {
    if (ew == null) {
      return null;
    }

    Throwable ex = null;
    Throwable cause = deserialize(ew.cause);
    try {
      Class<?> exClass = Class.forName(ew.typeName);
      try {
        // try ExType(String, Throwable)
        Constructor<?> ctor = exClass.getDeclaredConstructor(String.class,
            Throwable.class);
        ctor.setAccessible(true);
        ex = (Throwable) ctor.newInstance(ew.message, cause);
      } catch (Throwable e) {
        // try ExType(String)
        try {
          Constructor<?> ctor = exClass.getDeclaredConstructor(String.class);
          ctor.setAccessible(true);
          ex = (Throwable) ctor.newInstance(ew.message);
          ex.initCause(cause);
        } catch (Throwable e2) {
          // try ExType(Throwable)
          try {
            Constructor<?> ctor = exClass.getDeclaredConstructor(Throwable.class);
            ctor.setAccessible(true);
            ex = (Throwable) ctor.newInstance(cause);
            setField(Throwable.class, "detailMessage", ex, ew.message);
          } catch (Throwable e3) {
            // try ExType()
            try {
              Constructor<?> ctor = exClass.getDeclaredConstructor();
              ctor.setAccessible(true);
              ex = (Throwable) ctor.newInstance();
              ex.initCause(cause);
              setField(Throwable.class, "detailMessage", ex, ew.message);
            } catch (Throwable e4) {
              // we're out of options
              this.log("Failed to deserialize getException of type '"
                  + ew.typeName + "'; no available constructor", e4);

              // fall through
            }
          }
        }
      }

    } catch (Throwable e) {
      this.log("Failed to deserialize getException of type '" + ew.typeName
          + "'", e);
    }

    if (ex == null) {
      ex = new RuntimeException(ew.typeName + ": " + ew.message, cause);
    }

    ex.setStackTrace(deserialize(ew.stackTrace));
    return ex;
  }

  /**
   * Deserializes a StackTraceWrapper back into a StackTraceElement.
   */
  private StackTraceElement deserialize(StackTraceWrapper stw) {
    StackTraceElement ste = null;
    Object[] args = new Object[] {
        stw.className, stw.methodName, stw.fileName, stw.lineNumber};
    try {
      try {
        // Try the 4-arg ctor (JRE 1.5)
        Constructor<StackTraceElement> ctor = StackTraceElement.class.getDeclaredConstructor(
            String.class, String.class, String.class, int.class);
        ctor.setAccessible(true);
        ste = ctor.newInstance(args);
      } catch (NoSuchMethodException e) {
        // Okay, see if there's a zero-arg ctor we can use instead (JRE 1.4.2)
        Constructor<StackTraceElement> ctor = StackTraceElement.class.getDeclaredConstructor();
        ctor.setAccessible(true);
        ste = ctor.newInstance();
        setField(StackTraceElement.class, "declaringClass", ste, args[0]);
        setField(StackTraceElement.class, "methodName", ste, args[1]);
        setField(StackTraceElement.class, "fileName", ste, args[2]);
        setField(StackTraceElement.class, "lineNumber", ste, args[3]);
      }
    } catch (Throwable e) {
      this.log("Error creating stack trace", e);
    }
    return ste;
  }

  /**
   * Deserializes a StackTraceWrapper[] back into a StackTraceElement[].
   */
  private StackTraceElement[] deserialize(StackTraceWrapper[] stackTrace) {
    int len = stackTrace.length;
    StackTraceElement[] result = new StackTraceElement[len];
    for (int i = 0; i < len; ++i) {
      result[i] = deserialize(stackTrace[i]);
    }
    return result;
  }

  /**
   * Returns a "client id" for the current request.
   */
  private String getClientId(HttpServletRequest request) {
    String machine = request.getRemoteHost();
    String agent = request.getHeader("User-Agent");
    return machine + " / " + agent;
  }

  private void initResult(HttpServletRequest request, JUnitResult result) {
    String agent = request.getHeader("User-Agent");
    result.setAgent(agent);
    String machine = request.getRemoteHost();
    result.setHost(machine);
  }
}
TOP

Related Classes of com.google.gwt.junit.server.JUnitHostImpl

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.