You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2011/12/27 08:30:02 UTC

svn commit: r1224875 - in /incubator/lcf/branches/CONNECTORS-335/framework: build.xml core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java

Author: kwright
Date: Tue Dec 27 07:30:02 2011
New Revision: 1224875

URL: http://svn.apache.org/viewvc?rev=1224875&view=rev
Log:
Infrastructure to invoke python virtual browser (as a stopgap to getting the virtual browser ported).

Added:
    incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java   (with props)
Modified:
    incubator/lcf/branches/CONNECTORS-335/framework/build.xml

Modified: incubator/lcf/branches/CONNECTORS-335/framework/build.xml
URL: http://svn.apache.org/viewvc/incubator/lcf/branches/CONNECTORS-335/framework/build.xml?rev=1224875&r1=1224874&r2=1224875&view=diff
==============================================================================
--- incubator/lcf/branches/CONNECTORS-335/framework/build.xml (original)
+++ incubator/lcf/branches/CONNECTORS-335/framework/build.xml Tue Dec 27 07:30:02 2011
@@ -603,7 +603,10 @@
     
     <target name="jar-core-tests" depends="compile-core-tests">
         <mkdir dir="build/test-jar"/>
-        <jar destfile="build/test-jar/mcf-core-tests.jar" basedir="build/core-tests/classes"/>
+        <jar destfile="build/test-jar/mcf-core-tests.jar">
+          <fileset dir="build/core-tests/classes"/>
+          <fileset dir="core/src/test/resource"/>
+        </jar>
     </target>
 
     <target name="jar-agents-tests" depends="compile-agents-tests">
@@ -644,6 +647,24 @@
         </junit>
     </target>
 
+    <target name="run-UI-tests" depends="jar-core-tests">
+        <mkdir dir="test-output"/>
+        <junit fork="true" maxmemory="128m" dir="test-output" outputtoformatters="true" showoutput="true" haltonfailure="true">
+            <classpath>
+                <fileset dir="lib">
+                    <include name="*.jar"/>
+                </fileset>
+                <fileset dir="build/test-jar">
+                    <include name="mcf-core-tests.jar"/>
+                </fileset>
+            </classpath>
+            <formatter type="brief" usefile="false"/>
+
+            <test name="org.apache.manifoldcf.core.tests.HTMLTester" todir="test-output"/>
+            
+        </junit>
+    </target>
+
     <target name="run-tests" depends="compile-tests,run-script-engine-tests"/>
 
     <target name="run-tests-derby" depends="compile-tests">

Added: incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java
URL: http://svn.apache.org/viewvc/incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java?rev=1224875&view=auto
==============================================================================
--- incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java (added)
+++ incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java Tue Dec 27 07:30:02 2011
@@ -0,0 +1,627 @@
+/* $Id$ */
+
+/**
+* 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.manifoldcf.core.tests;
+
+import java.io.*;
+import java.util.*;
+import org.junit.*;
+
+/** This tester sets up a virtual browser and allows a sequence of testing to take place.  It's set
+* up to allow this to be done in Java, even though the tester itself may well be running in Python.
+* The eventual goal is to replace the Python browser emulator with a Java one, but we can't get there
+* all in one goal.
+*
+* The paradigm used is one of a "virtual browser", which basically handles multiple windows and can
+* emulate user activities, such as clicking a link or a button, filling in a field, etc.  Identification
+* of each of these elements may have a language dependence, so I would anticipate that there would
+* need to be a new set of tests for each localization we have.  Presumably it should be possible
+* to come up with a structure at a level above this one in order to meet the goal of having the
+* same test in a different language, so I'm not going to worry about that here.
+*
+* The tester works by basically accumulating a set of "instructions", and then firing them off at the
+* end.  This set of instructions is then executed in an appropriate environment, and test feedback is
+* returned.
+*/
+public class HTMLTester
+{
+  protected File currentTestFile = null;
+  protected OutputStream currentOutputStream = null;
+  protected BufferedWriter currentWriter = null;
+  protected int variableCounter;
+  protected int currentIndentLevel;
+  protected String virtualBrowserVarName;
+  
+  /** Constructor.  Create a test sequence object.
+  */
+  public HTMLTester()
+  {
+  }
+  
+  /** Set up for all tests.  Basically this grabs the necessary stuff out of resources
+  * and writes it to the current directory.
+  */
+  @Before
+  public void setup()
+    throws Exception
+  {
+    copyResource("VirtualBrowser.py");
+    copyResource("Javascript.py");
+    // Delete any test files hanging around from before
+    new File("test.py").delete();
+  }
+  
+  protected void copyResource(String resName)
+    throws Exception
+  {
+    OutputStream os = new FileOutputStream(new File(resName));
+    try
+    {
+      InputStream is = getClass().getResourceAsStream(resName);
+      try
+      {
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os,"UTF-8"));
+        BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
+        while (true)
+        {
+          String line = br.readLine();
+          if (line == null)
+            break;
+          bw.write(line);
+          bw.newLine();
+        }
+        bw.flush();
+      }
+      finally
+      {
+        is.close();
+      }
+    }
+    finally
+    {
+      os.close();
+    }
+  }
+  
+  /** Clean up the files we created.
+  */
+  @After
+  public void teardown()
+    throws Exception
+  {
+    closeAll();
+    new File("Javascript.py").delete();
+    new File("VirtualBrowser.py").delete();
+  }
+  
+  /** Test to test the tester.
+  */
+  @Test
+  public void TesterTest()
+    throws Exception
+  {
+    newTest();
+    executeTest();
+  }
+  
+  /** Close the current output.
+  */
+  protected void closeAll()
+    throws Exception
+  {
+    if (currentWriter != null)
+    {
+      currentWriter.flush();
+      currentWriter = null;
+    }
+    if (currentOutputStream != null)
+    {
+      currentOutputStream.close();
+      currentOutputStream = null;
+    }
+  }
+  
+  /** Begin a new test.  Call this when we're ready to start building a new UI test.
+  */
+  public void newTest()
+    throws Exception
+  {
+    currentTestFile = new File("test.py");
+    currentOutputStream = new FileOutputStream(currentTestFile);
+    currentWriter = new BufferedWriter(new OutputStreamWriter(currentOutputStream,"ASCII"));
+    variableCounter = 0;
+    currentIndentLevel = 0;
+    virtualBrowserVarName = getNextVariableName();
+    
+    emitLine("import sys");
+    emitLine("sys.path.append(\".\")");
+    emitLine("import VirtualBrowser");
+    emitLine("if __name__ == '__main__':");
+    currentIndentLevel++;
+    emitLine("print 'Starting test'");
+    emitLine(virtualBrowserVarName + " = VirtualBrowser.VirtualBrowser()");
+  }
+  
+  /** Execute the test.  The virtual browser will be called and will perform the sequence of
+  * activity described by the test.  If at any point an error occurs, an appropriate exception
+  * will be thrown, with sufficient description to (hopefully) permit the problem to be tracked down.
+  */
+  public void executeTest()
+    throws Exception
+  {
+    closeAll();
+    // Now, execute the python command.
+    Process p = Runtime.getRuntime().exec(new String[]{"python","test.py"});
+    // Read from streams
+    StreamConnector mStdOut = new StreamConnector( p.getErrorStream(), "Stderr: ", System.err );  
+    StreamConnector mErrOut = new StreamConnector( p.getInputStream(), "Stdout: ", System.out );  
+    mStdOut.start();  
+    mErrOut.start(); 
+    int exitCode = p.waitFor();
+    mStdOut.abort();
+    mErrOut.abort();
+    mStdOut.join();
+    mErrOut.join();
+    if (exitCode != 0)
+      throw new Exception("UI test failed; error code: "+exitCode);
+    // After successful execution, remove the test file.
+    if (currentTestFile != null)
+    {
+      currentTestFile.delete();
+      currentTestFile = null;
+    }
+  }
+  
+  /** Create a string description for use later in the test.
+  *@param value is the intended value of the string description.
+  *@return the string description.
+  */
+  public StringDescription createStringDescription(String value)
+    throws Exception
+  {
+    String variableName = getNextVariableName();
+    if (value != null)
+      emitLine(variableName + " = " + quotePythonString(value));
+    else
+      emitLine(variableName + " = None");
+    return new StringDescription(variableName);
+  }
+  
+  /** Open virtual browser window, and send it to a specified URL.
+  *@param url is the desired URL.
+  *@param desiredLocale is the desired locale (which the browser will communicated to the site).
+  *@return the window handle.  Use this whenever a window argument is required later.
+  */
+  public Window openMainWindow(String url, Locale desiredLocale)
+    throws Exception
+  {
+    emitLine(virtualBrowserVarName + ".load_main_window(" + quotePythonString(url) + ")");
+    return findWindow(null);
+  }
+  
+  /** Find a window of a specific name, or null for the main window.
+  *@param windowName is the name of the window, or null.
+  *@return the window handle.
+  */
+  public Window findWindow(StringDescription windowName)
+    throws Exception
+  {
+    String windowVar = getNextVariableName();
+    emitLine(windowVar + " = " + virtualBrowserVarName + ".find_window("+windowName.getVarName()+")");
+    return new Window(windowVar);
+  }
+
+  /** Calculate the next variable name */
+  protected String getNextVariableName()
+  {
+    String rval = "var"+variableCounter;
+    variableCounter++;
+    return rval;
+  }
+  
+  /** Quote a python string */
+  protected String quotePythonString(String value)
+  {
+    StringBuilder sb = new StringBuilder("\"");
+    for (int i = 0 ; i < value.length() ; i++)
+    {
+      char c = value.charAt(i);
+      if (c == '"')
+        sb.append("\\").append(c);
+      else
+        sb.append(c);
+    }
+    sb.append("\"");
+    return sb.toString();
+  }
+  
+  /** Emit a python line.
+  */
+  protected void emitLine(String line)
+    throws IOException
+  {
+    // Append to file with current indent.
+    StringBuilder fullLine = new StringBuilder();
+    for (int i = 0 ; i < currentIndentLevel ; i++)
+    {
+      fullLine.append("    ");
+    }
+    fullLine.append(line);
+    currentWriter.write(fullLine.toString());
+    currentWriter.newLine();
+  }
+  
+  /** Window handle */
+  public class Window
+  {
+    protected String windowVar;
+    
+    /** Create a window instance.
+    */
+    public Window(String windowVar)
+    {
+      this.windowVar = windowVar;
+    }
+    
+    /** Look for a specific match in the current page data, and return the value of the specified group.
+    *@return a description of the string found.  This can be used later in other commands to assess
+    *  correctness of the page, or allow form data to be filled in.
+    */
+    public StringDescription findMatch(String regularExpression, int group)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+
+    /** Same as findMatch, but strips out newlines before it looks.
+    */
+    public StringDescription findMatchNoNewlines(StringDescription regularExpression, int group)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+
+    /** If the match is found, the test will error out.
+    */
+    public void checkNoMatch(StringDescription regularExpression)
+      throws Exception
+    {
+      // MHL
+    }
+    
+    /** Find a link.
+    */
+    public Link findLink(StringDescription altText)
+      throws Exception
+    {
+      String linkVarName = getNextVariableName();
+      emitLine(linkVarName + " = " + windowVar + ".find_link("+altText.getVarName()+")");
+      return new Link(linkVarName);
+    }
+    
+    /** Find a form.
+    */
+    public Form findForm(StringDescription formName)
+      throws Exception
+    {
+      String formVarName = getNextVariableName();
+      emitLine(formVarName + " = " + windowVar + ".find_form("+formName.getVarName()+")");
+      return new Form(formVarName);
+    }
+
+    /** Find a button.
+    */
+    public Button findButton(StringDescription altText)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+    
+    /** Close this window.
+    */
+    public void closeWindow()
+      throws Exception
+    {
+      emitLine(windowVar+".close_window()");
+    }
+  }
+  
+  /** Object representative of a virtual browser link.
+  */
+  public class Link
+  {
+    protected String linkVarName;
+    
+    public Link(String linkVarName)
+    {
+      this.linkVarName = linkVarName;
+    }
+    
+    /** Click the link */
+    public void click()
+      throws Exception
+    {
+      emitLine(linkVarName + ".click()");
+    }
+  }
+  
+  /** Object representative of a virtual browser form.
+  */
+  public class Form
+  {
+    protected String formVarName;
+    
+    public Form(String formVarName)
+    {
+      this.formVarName = formVarName;
+    }
+    
+    /** Find a file browser element, by data variable name.
+    */
+    public FileBrowser findFileBrowser(StringDescription dataName)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+    
+    /** Find a checkbox element, by data variable name and value.
+    */
+    public Checkbox findCheckbox(StringDescription dataName, StringDescription value)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+    
+    /** Find a radio button by variable name and value.
+    */
+    public Radiobutton findRadiobutton(StringDescription dataName, StringDescription value)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+    
+    /** Find a select box by data variable name.
+    */
+    public Selectbox findSelectbox(StringDescription dataName)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+    
+    /** Find a textarea/password field by data variable name.
+    */
+    public Textarea findTextarea(StringDescription dataName)
+      throws Exception
+    {
+      // MHL
+      return null;
+    }
+  }
+  
+  /** Object representative of a file browser.
+  */
+  public class FileBrowser
+  {
+    protected String fileBrowserVarName;
+    
+    public FileBrowser(String fileBrowserVarName)
+    {
+      this.fileBrowserVarName = fileBrowserVarName;
+    }
+    
+    public void setFile(StringDescription fileName, StringDescription contentType)
+      throws Exception
+    {
+      emitLine(fileBrowserVarName + ".set_file("+fileName.getVarName()+","+contentType.getVarName()+")");
+    }
+  }
+  
+  /** Object representative of a checkbox.
+  */
+  public class Checkbox
+  {
+    protected String checkBoxVarName;
+    
+    public Checkbox(String checkBoxVarName)
+    {
+      this.checkBoxVarName = checkBoxVarName;
+    }
+    
+    /** Select this checkbox */
+    public void select()
+      throws Exception
+    {
+      emitLine(checkBoxVarName + ".select()");
+    }
+    
+    /** Deselect this checkbox */
+    public void deselect()
+      throws Exception
+    {
+      emitLine(checkBoxVarName + ".deselect()");
+    }
+  }
+  
+  /** Object representative of a radio button.
+  */
+  public class Radiobutton
+  {
+    protected String radioButtonVarName;
+    
+    public Radiobutton(String radioButtonVarName)
+    {
+      this.radioButtonVarName = radioButtonVarName;
+    }
+    
+    /** Select this radio button */
+    public void select()
+      throws Exception
+    {
+      emitLine(radioButtonVarName + ".select()");
+    }
+  }
+  
+  /** Object representative of  a select box.
+  */
+  public class Selectbox
+  {
+    protected String selectBoxVarName;
+    
+    public Selectbox(String selectBoxVarName)
+    {
+      this.selectBoxVarName = selectBoxVarName;
+    }
+
+    /** Select a value (without CTRL button).
+    * This works like a browser in that selecting in this way turns
+    * off all other current selections. */
+    public void selectValue(StringDescription selectedValue)
+      throws Exception
+    {
+      emitLine(selectBoxVarName + ".select_value(" + selectedValue.getVarName() + ")");
+    }
+
+    /** Select a value using a regular expression (without CTRL button) */
+    public void selectValueRegexp(StringDescription selectedValueRegexp)
+      throws Exception
+    {
+      emitLine(selectBoxVarName + ".select_value_regexp(" + selectedValueRegexp.getVarName() + ")");
+    }
+
+    /** CTRL-select a value.
+    * For multiselect boxes, this adds a new selection to those already
+    * chosen.  For non-multi boxes, it works just like select_value. */
+    public void multiSelectValue(StringDescription selectedValue)
+      throws Exception
+    {
+      emitLine(selectBoxVarName + ".multi_select_value(" + selectedValue.getVarName() + ")");
+    }
+    
+    
+  }
+  
+  /** Object representative of a text area.
+  */
+  public class Textarea
+  {
+    protected String textAreaVarName;
+    
+    public Textarea(String textAreaVarName)
+    {
+      this.textAreaVarName = textAreaVarName;
+    }
+    
+    /** Set the value.
+    */
+    public void setValue(StringDescription textValue)
+      throws Exception
+    {
+      emitLine(textAreaVarName + ".set_value(" + textValue.getVarName() + ")");
+    }
+  }
+  
+  /** Object representative of a virtual browser button.
+  */
+  public class Button
+  {
+    protected String buttonVarName;
+    
+    public Button(String buttonVarName)
+    {
+      this.buttonVarName = buttonVarName;
+    }
+    
+    public void click()
+      throws Exception
+    {
+      emitLine(buttonVarName + ".click()");
+    }
+  }
+  
+  /** String description.  An instance of this class represents a string that will be located as the
+  * browser emulator functions.  It can be used at various places as the test description is built.
+  */
+  public class StringDescription
+  {
+    protected String variableName;
+    
+    public StringDescription(String variableName)
+    {
+      this.variableName = variableName;
+    }
+    
+    public String getVarName()
+    {
+      return variableName;
+    }
+  }
+  
+  /** Connector thread that allows for exec */
+  protected static class StreamConnector extends Thread
+  {
+    protected InputStream inputStream;
+    protected OutputStream outputStream;
+    protected String prefix;
+    protected boolean abortSignal;
+    
+    public StreamConnector(InputStream inputStream, String prefix, OutputStream outputStream)
+    {
+      this.inputStream = inputStream;
+      this.prefix = prefix;
+      this.outputStream = outputStream;
+      abortSignal = false;
+    }
+    
+    public void abort()
+    {
+      abortSignal = true;
+    }
+    
+    public void run()
+    {
+      try
+      {
+        byte[] buffer = new byte[63356];
+        while (true)
+        {
+          if (abortSignal)
+            break;
+          int amt = inputStream.read(buffer);
+          if (amt == -1)
+          {
+            Thread.yield();
+            continue;
+          }
+          outputStream.write(buffer,0,amt);
+        }
+      }
+      catch (IOException e)
+      {
+        e.printStackTrace(System.err);
+      }
+    }
+  }
+  
+}

Propchange: incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/lcf/branches/CONNECTORS-335/framework/core/src/test/java/org/apache/manifoldcf/core/tests/HTMLTester.java
------------------------------------------------------------------------------
    svn:keywords = Id