Package com.google.caja.plugin

Source Code of com.google.caja.plugin.BrowserTestCase$Countdown

// Copyright (C) 2009 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.caja.plugin;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.mortbay.jetty.servlet.Context;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.google.caja.lexer.escaping.Escaping;
import com.google.caja.util.LocalServer;
import com.google.caja.util.TestFlag;
import com.google.caja.util.ThisHostName;
import com.google.common.base.Joiner;

/**
* Test case class with tools for controlling a web browser running pages from
* a local web server.
* <p>
* Browser testing is described in more detail at the
* <a href="http://code.google.com/p/google-caja/wiki/CajaTesting"
*   >CajaTesting wiki page</a>
*
* @author maoziqing@gmail.com (Ziqing Mao)
* @author kpreid@switchb.org (Kevin Reid)
*/
public abstract class BrowserTestCase {
  // Constructed @BeforeClass to share a single web browser.
  private static WebDriverHandle wdh;
  private static int serverPort;
  private static String serverHost;

  protected String testBuildVersion = null;

  private final LocalServer localServer = new LocalServer(
      new LocalServer.ConfigureContextCallback() {
        @Override public void configureContext(Context ctx) {
          addServlets(ctx);
        }
      });

  @BeforeClass
  public static void setUpClass() throws Exception {
    wdh = new WebDriverHandle();
    serverPort = TestFlag.SERVER_PORT.getInt(0);
    serverHost = TestFlag.SERVER_HOSTNAME.getString(null);
    if (serverHost == null) {
      // If we're testing a remote browser, we need a hostname it can
      // use to contact the LocalServer instance.
      if (TestFlag.WEBDRIVER_URL.truthy()) {
        serverHost = ThisHostName.value();
      } else {
        serverHost = "localhost";
      }
    }
  }

  @AfterClass
  public static void tearDownClass() throws Exception {
    wdh.release();
  }

  /**
   * Set a custom build version for testing. This will be used by the cajoling
   * service to stamp outgoing cajoled modules. Set this to <code>null</code>
   * to disable custom test build version and revert to default behavior.
   *
   * @param version the desired test build version.
   */
  protected void setTestBuildVersion(String version) {
    testBuildVersion = version;
  }

  private void debugHook() throws Exception {
    if (!TestFlag.DEBUG_BROWSER.truthy() && !TestFlag.DEBUG_SERVER.truthy()) {
      return;
    }
    serverPort = TestFlag.SERVER_PORT.getInt(8000);
    localServer.start(serverPort);
    String url = testUrl("test-index.html");
    if (TestFlag.DEBUG_BROWSER.truthy()) {
      wdh.begin().get(url);
    }
    Echo.echo("- See " + url);
    Thread.currentThread().join();
  }

  private String testUrl(String name) {
    return "http://" + serverHost + ":" + localServer.getPort()
        + "/ant-testlib/com/google/caja/plugin/" + name;
  }

  protected String runBrowserTest(
      String label, boolean isKnownFailure, String name, String... params)
          throws Exception {
    debugHook();
    String result = "";
    boolean passed = false;
    try {
      localServer.start(serverPort);

      String url = testUrl(name);
      if (params != null && 0 < params.length) {
        url += "?" + Joiner.on("&").join(params);
      }
      Echo.echo("- Running " + url);

      try {
        WebDriver driver = wdh.begin();
        driver.get(url);
        result = driveBrowser(driver);
        passed = true;
      } finally {
        captureResults(label, passed);
        wdh.end(passed || isKnownFailure);
      }
    } catch (Exception e) {
      Echo.rethrow(e);
    } finally {
      localServer.stop();
    }
    return result;
  }

  private void captureResults(String label, boolean passed) {
    if (alwaysCapture(label)) {
      wdh.captureResults("keep." + label);
    } else if (!passed) {
      wdh.captureResults("fail." + label);
    } else if (TestFlag.CAPTURE_PASSES.truthy()) {
      wdh.captureResults("pass." + label);
    }
  }

  protected boolean alwaysCapture(String label) {
    // TODO(felix8a): maybe this should be a flag in browser-tests.json
    return false;
  }

  protected static String escapeUri(String s) {
    StringBuilder sb = new StringBuilder();
    Escaping.escapeUri(s, sb);
    return sb.toString();
  }

  protected static String[] add(String[] arr, String... rest) {
    String[] result = new String[arr.length + rest.length];
    System.arraycopy(arr, 0, result, 0, arr.length);
    System.arraycopy(rest, 0, result, arr.length, rest.length);
    return result;
  }

  /**
   * Do what should be done with the browser.
   */
  protected String driveBrowser(final WebDriver driver) {
    // long timeout: something we're doing is leading to huge unpredictable
    // slowdowns in random test startup; perhaps we're holding onto a lot of ram
    // and  we're losing on swapping/gc time.  unclear.
    countdown(10000, 200, new Countdown() {
      @Override public String toString() { return "startup"; }
      public int run() {
        List<WebElement> readyElements = driver.findElements(
            By.className("readytotest"));
        return readyElements.size() == 0 ? 1 : 0;
      }
    });

    // 4s because test-domado-dom-events has non-click tests that can block
    // for a nontrivial amount of time, so our clicks aren't necessarily
    // processed right away.
    countdown(4000, 200, new Countdown() {
      private List<WebElement> clickingList = null;
      @Override public String toString() {
        return "clicking done (Remaining elements = " +
            renderElements(clickingList) + ")";
      }
      public int run() {
        clickingList = driver.findElements(By.xpath(
            "//*[contains(@class,'clickme')]/*"));
        for (WebElement e : clickingList) {
          // TODO(felix8a): webdriver fails if e has been removed
          e.click();
        }
        return clickingList.size();
      }
    });

    // override point
    waitForCompletion(driver);

    // check the title of the document
    String title = driver.getTitle();
    assertTrue("The title shows " + title, title.contains("all tests passed"));
    return title;
  }

  /**
   * After startup and clicking is done, wait an appropriate amount of time
   * for tests to pass.
   */
  protected void waitForCompletion(final WebDriver driver) {
    countdown(waitForCompletionTimeout(), 200, new Countdown() {
      private List<WebElement> waitingList = null;
      @Override public String toString() {
        return "completion (Remaining elements = " +
            renderElements(waitingList) + ")";
      }
      public int run() {
        // TODO(felix8a): this used to check for just class "waiting", but now
        // "waiting" is redundant and should be removed.
        waitingList = driver.findElements(By.xpath(
            "//*[contains(@class,'testcontainer')"
            + " and not(contains(@class,'done'))"
            + " and not(contains(@class,'manual'))]"));
        return waitingList.size();
      }
    });
  }

  /** Override point */
  @SuppressWarnings("static-method")
  protected int waitForCompletionTimeout() {
    return 10000// ms
  }

  /**
   * Run 'c' every 'intervalMillis' until it returns 0,
   * or 'timeoutMillis' have passed since the value has changed.
   */
  protected static void countdown(
      int timeoutMillis, int intervalMillis, Countdown c) {
    int lastValue = -1;
    long endTime = System.currentTimeMillis() + timeoutMillis;
    int value;
    while ((value = c.run()) != 0) {
      long now = System.currentTimeMillis();
      if (value != lastValue) {
        endTime = now + timeoutMillis;
        lastValue = value;
      }
      if (endTime < now) {
        fail(timeoutMillis + " ms passed while waiting for: " + c);
      }
      try {
        Thread.sleep(intervalMillis);
      } catch (InterruptedException e) {
        // keep going
      }
    }
  }

  protected static String renderElements(List<WebElement> elements) {
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (int i = 0, n = elements.size(); i < n; i++) {
      if (i != 0) { sb.append(", "); }
      WebElement el = elements.get(i);
      sb.append('<').append(el.getTagName());
      String id = el.getAttribute("id");
      if (id != null) {
        sb.append(" id=\"");
        Escaping.escapeXml(id, false, sb);
        sb.append('"');
      }
      String className = el.getAttribute("class");
      if (className != null) {
        sb.append(" class=\"");
        Escaping.escapeXml(className, false, sb);
        sb.append('"');
      }
      sb.append('>');
    }
    sb.append(']');
    return sb.toString();
  }

  /**
   * Add servlets as desired specific to a given test case.
   *
   * @param servlets a Jetty Context to which servlets can be added.
   */
  protected void addServlets(Context servlets) {
    // Adds none but may be overridden.
  }

  public interface Countdown {
    int run();
  }
}
TOP

Related Classes of com.google.caja.plugin.BrowserTestCase$Countdown

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.