From notifications-return-7219-apmail-ant-notifications-archive=ant.apache.org@ant.apache.org Tue Feb 03 21:14:24 2009 Return-Path: Delivered-To: apmail-ant-notifications-archive@minotaur.apache.org Received: (qmail 39219 invoked from network); 3 Feb 2009 21:14:24 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 3 Feb 2009 21:14:24 -0000 Received: (qmail 42237 invoked by uid 500); 3 Feb 2009 21:14:23 -0000 Delivered-To: apmail-ant-notifications-archive@ant.apache.org Received: (qmail 42219 invoked by uid 500); 3 Feb 2009 21:14:23 -0000 Mailing-List: contact notifications-help@ant.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ant.apache.org Delivered-To: mailing list notifications@ant.apache.org Received: (qmail 42157 invoked by uid 99); 3 Feb 2009 21:14:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 03 Feb 2009 13:14:23 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 03 Feb 2009 21:14:22 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id CD69623889BB; Tue, 3 Feb 2009 21:14:01 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r740452 - in /ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit: AntUnit.java AntUnitExecutionNotifier.java AntUnitExecutionPlatform.java AntUnitScriptRunner.java ProjectFactory.java Date: Tue, 03 Feb 2009 21:14:00 -0000 To: notifications@ant.apache.org From: gscokart@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090203211401.CD69623889BB@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: gscokart Date: Tue Feb 3 21:13:59 2009 New Revision: 740452 URL: http://svn.apache.org/viewvc?rev=740452&view=rev Log: Refactoring : - Move active/inactive state managment from AntUnitScriptRunner to AntUnit - Split AntUnitExecutionPlatform into a ProjectFactory (required to parse the script) and AntUnitExceutionNotifier (required to run the script) - Move the invocation of the sequence suiteSetUp, test targets suiteTearDown from AntUnit to AntUnitScriptRunner Added: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java (with props) ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java (with props) Removed: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionPlatform.java Modified: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitScriptRunner.java Modified: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java URL: http://svn.apache.org/viewvc/ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java?rev=740452&r1=740451&r2=740452&view=diff ============================================================================== --- ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java (original) +++ ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnit.java Tue Feb 3 21:13:59 2009 @@ -74,11 +74,7 @@ private Union buildFiles; - private AntUnitExecutionPlatform myExecutionPlatform = new AntUnitExecutionPlatform() { - - public Project createProjectForFile(File f) { - return AntUnit.this.createProjectForFile(f); - } + private AntUnitExecutionNotifier notifier = new AntUnitExecutionNotifier() { public void fireEndTest(String targetName) { AntUnit.this.fireEndTest(targetName); @@ -100,9 +96,10 @@ /** * The object responsible for the execution of the unit test. * scriptRunner is invoked to executes the targets and keep the - * reference to the project. + * reference to the project. scriptRunner is defined only when the + * antunit script is running. */ - private AntUnitScriptRunner scriptRunner = new AntUnitScriptRunner(myExecutionPlatform); + private AntUnitScriptRunner scriptRunner; /** * listeners. @@ -225,27 +222,19 @@ /** * Processes a single build file. */ - private void doFile(File f) { + private void doFile(final File f) { log("Running tests in build file " + f, Project.MSG_DEBUG); - scriptRunner.activate(f); - List testTargets = scriptRunner.scanFile(); - - // start test - Throwable caught = null; + ProjectFactory prjFactory = new ProjectFactory() { + public Project createProject() { + return createProjectForFile(f); + } + }; try { - if (!scriptRunner.startSuite()) { - return; - } - Iterator iter = testTargets.iterator(); - while (iter.hasNext()) { - String name = (String) iter.next(); - scriptRunner.runTarget(name); - } - } catch (Throwable e) { - caught = e; + scriptRunner = new AntUnitScriptRunner(prjFactory); + List testTargets = scriptRunner.getTestTartgets(); + scriptRunner.runSuite(testTargets, notifier); } finally { - scriptRunner.endSuite(caught); - scriptRunner.deactivate(); + scriptRunner=null; } } @@ -255,7 +244,7 @@ * @param outputToHandle the output to handle. */ public void handleOutput(String outputToHandle) { - if (scriptRunner.isActive()) { + if (scriptRunner!=null) { scriptRunner.getCurrentProject().demuxOutput(outputToHandle, false); } else { super.handleOutput(outputToHandle); @@ -270,7 +259,7 @@ */ public int handleInput(byte[] buffer, int offset, int length) throws IOException { - if (scriptRunner.isActive()) { + if (scriptRunner!=null) { return scriptRunner.getCurrentProject().demuxInput(buffer, offset, length); } return super.handleInput(buffer, offset, length); @@ -281,7 +270,7 @@ * @param toFlush the output String to flush. */ public void handleFlush(String toFlush) { - if (scriptRunner.isActive()) { + if (scriptRunner!=null) { scriptRunner.getCurrentProject().demuxFlush(toFlush, false); } else { super.handleFlush(toFlush); @@ -293,7 +282,7 @@ * @param errorOutputToHandle the error output to handle. */ public void handleErrorOutput(String errorOutputToHandle) { - if (scriptRunner.isActive()) { + if (scriptRunner!=null) { scriptRunner.getCurrentProject().demuxOutput(errorOutputToHandle, true); } else { super.handleErrorOutput(errorOutputToHandle); @@ -305,7 +294,7 @@ * @param errorOutputToFlush the error output to flush. */ public void handleErrorFlush(String errorOutputToFlush) { - if (scriptRunner.isActive()) { + if (scriptRunner!=null) { scriptRunner.getCurrentProject().demuxFlush(errorOutputToFlush, true); } else { super.handleErrorFlush(errorOutputToFlush); Added: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java URL: http://svn.apache.org/viewvc/ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java?rev=740452&view=auto ============================================================================== --- ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java (added) +++ ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java Tue Feb 3 21:13:59 2009 @@ -0,0 +1,59 @@ +/* + * 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.ant.antunit; + +import java.io.File; + +import org.apache.tools.ant.Project; + +/** + * Provides methods that allow the AntUnitScriptRunner to notify the test progress. + * @since 1.2 + */ +public interface AntUnitExecutionNotifier { + + /** + * invokes start on all registered test listeners. + * @param targetName the name of the target. + */ + public void fireStartTest(String targetName); + + /** + * invokes addFailure on all registered test listeners. + * @param targetName the name of the failed target. + * @param ae the associated AssertionFailedException. + */ + public void fireFail(String targetName, AssertionFailedException ae); + + /** + * invokes addError on all registered test listeners. + * @param targetName the name of the failed target. + * @param t the associated Throwable. + */ + public void fireError(String targetName, Throwable t); + + /** + * invokes endTest on all registered test listeners. + * @param targetName the name of the current target. + */ + public void fireEndTest(String targetName); + +} Propchange: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitExecutionNotifier.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitScriptRunner.java URL: http://svn.apache.org/viewvc/ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitScriptRunner.java?rev=740452&r1=740451&r2=740452&view=diff ============================================================================== --- ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitScriptRunner.java (original) +++ ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/AntUnitScriptRunner.java Tue Feb 3 21:13:59 2009 @@ -1,6 +1,5 @@ package org.apache.ant.antunit; -import java.io.File; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -11,17 +10,13 @@ import org.apache.tools.ant.Project; /** - * Run antunit tests. The lifecycle of this object is : - *
    - *
  1. activate(file) : Indicates the runner that the given file should be used.
  2. - *
  3. scanFile() : Provides you the list of targets.
  4. - *
  5. startSuite() : Start the suite
  6. - *
  7. runTarget(targetName) : Executed one or more time
  8. - *
  9. endSuite() : End the suite
  10. - *
  11. deactivate() Indicates to the runner that the test is finished and all - * resources can be freed
  12. - *
- * Every step is mandatory. + * Run antunit tests suites. This AntUnitScriptRunner is responsible for the + * management of the ant project and the correct invocation the target (taking + * into account properly the [case]setUp and [case]tearDown targets). + * The user can however provide the order of the test targets and or can filter + * the list of test targets to execute. + * The user must also provide its ProjectFactory and an AntUnitExecutionNotifier. + * @since 1.2 */ public class AntUnitScriptRunner { @@ -51,24 +46,11 @@ private static final String SUITETEARDOWN = "suiteTearDown"; /** - * Object used to interact with the environment (for example an ant task or a junit runner) + * Object used to create projects in order to support test isolation. */ - private final AntUnitExecutionPlatform env; - - /** - * Ant script file currently under testing. The file is set at activation, and used - * during all execution every time we want have to create a new project.
- * It is only defined when the project isActive() - */ - private File scriptFile; + private final ProjectFactory prjFactory; /** - * Indicates if the active project is already scanned and if the value the fields - * hasSuiteSetUp, hasSetUp, hasTearDown, hasSuiteTearDown are defined. - */ - private boolean isScanned; - - /** * Indicates if the startSuite method has been invoked. Use to fail fast if the * the caller forget to call the startSuite method */ @@ -77,22 +59,27 @@ /** * Does that script have a setUp target (defined when scanning the script) */ - private boolean hasSetUp; + private final boolean hasSetUp; /** * Does that script have a tearDown target (defined when scanning the script) */ - private boolean hasTearDown; + private final boolean hasTearDown; /** * Does that script has a suiteSetUp target. */ - private boolean hasSuiteSetUp; + private final boolean hasSuiteSetUp; /** * Does that script has a suite tearDown target that should be executed. */ - private boolean hasSuiteTearDown; + private final boolean hasSuiteTearDown; + + /** + * List of target names + */ + private final List testTargets; /** * The project currently used. @@ -108,54 +95,35 @@ /** * Create a new AntScriptRunner on the given environment. - * @param env The environment used to create project and where the test progress will be - * notified. + * @param prjFactory A factory for the ant project that will contains the antunit test to execute. + * The factory might be invoked multiple time in order to provide test isolation. */ - public AntUnitScriptRunner(AntUnitExecutionPlatform env) { - if (env == null) { - throw new AssertionError(); + public AntUnitScriptRunner(ProjectFactory prjFactory) { + this.prjFactory = prjFactory; + Project newProject = getCurrentProject(); + Map targets = newProject.getTargets(); + hasSetUp = targets.containsKey(SETUP); + hasTearDown = targets.containsKey(TEARDOWN); + hasSuiteSetUp = targets.containsKey(SUITESETUP); + hasSuiteTearDown = targets.containsKey(SUITETEARDOWN); + testTargets = new LinkedList(); + Iterator it = targets.keySet().iterator(); + while (it.hasNext()) { + String name = (String) it.next(); + if (name.startsWith(TEST) && !name.equals(TEST)) { + testTargets.add(name); + } } - this.env = env; - } - - /** - * Set the ant script to use. - * @post isActive() - */ - public void activate(File f) { - scriptFile = f; - project = null; - isScanned = false; - isSuiteStarted = false; - } - - /** - * Declare that the current ant script doesn't need to be used anymore. - * @post !isActive() - */ - public void deactivate() { - scriptFile = null; - project = null; - } - - /** - * Indicates if there is a project currently under test. - */ - public boolean isActive() { - return scriptFile != null; } /** * Get the project currently in use. The caller is not allowed to invoke a target or * do anything that would break the isolation of the test targets. - * @pre isActif() */ - public Project getCurrentProject() { - if (!isActive()) { - throw new AssertionError(); - } + public final Project getCurrentProject() { + //Method is final because it is called from the constructor if (project == null) { - project = env.createProjectForFile(scriptFile); + project = prjFactory.createProject(); projectIsDirty = false; } return project; @@ -163,14 +131,10 @@ /** * Get a project that has not yet been used in order to execute a target on it. - * @pre isActive() */ private Project getCleanProject() { - if (!isActive()) { - throw new AssertionError(); - } if (project == null || projectIsDirty) { - project = env.createProjectForFile(scriptFile); + project = prjFactory.createProject(); } //we already set isDirty to true in order to make sure we didn't reuse //this project next time getCleanProject is called. @@ -179,60 +143,34 @@ } /** - * Provides the list of test targets of the active antunit script. - * @pre isActive() - * @return List List of test target names + * @return List List of test targets of the script file */ - public List scanFile() { - if (!isActive()) { - throw new AssertionError(); - } - Project newProject = getCurrentProject(); - Map targets = newProject.getTargets(); - hasSetUp = targets.containsKey(SETUP); - hasTearDown = targets.containsKey(TEARDOWN); - hasSuiteSetUp = targets.containsKey(SUITESETUP); - hasSuiteTearDown = targets.containsKey(SUITETEARDOWN); - List testTargets = new LinkedList(); - Iterator it = targets.keySet().iterator(); - while (it.hasNext()) { - String name = (String) it.next(); - if (name.startsWith(TEST) && !name.equals(TEST)) { - testTargets.add(name); - } - } - isScanned = true; + public List getTestTartgets() { return testTargets; } /** * Provides the name of the active script. - * @pre isAvtive() */ public String getName() { - if (!isActive()) { - throw new AssertionError(); - } return getCurrentProject().getName(); } /** * Executes the suiteSetUp target if presents and report any execution error. + * A failure is reported to the notifier and by returning false. * Note that if the method return false, you are not allowed to run targets. * @return false in case of execution failure. true in case of success. */ - public boolean startSuite() { - if (!isScanned) { - throw new AssertionError(); - } + private boolean startSuite(AntUnitExecutionNotifier notifier) { getCurrentProject().fireBuildStarted(); if (hasSuiteSetUp) { try { Project newProject = getCleanProject(); newProject.executeTarget(SUITESETUP); } catch (BuildException e) { - env.fireStartTest(SUITESETUP); - fireFailOrError(SUITESETUP, e); + notifier.fireStartTest(SUITESETUP); + fireFailOrError(SUITESETUP, e, notifier); return false; } } @@ -242,10 +180,12 @@ /** * Run the specific test target, possibly between the setUp and tearDown targets if - * it exists. Exception or failures are reported to the execution environment. + * it exists. Exception or failures are reported to the notifier. * @param name name of the test target to execute. + * @param notifier will receive execution notifications. + * @pre startSuite has been invoked successfully */ - public void runTarget(String name) { + private void runTarget(String name, AntUnitExecutionNotifier notifier) { if (!isSuiteStarted) { throw new AssertionError(); } @@ -258,23 +198,23 @@ // create and register a logcapturer on the newProject LogCapturer lc = new LogCapturer(newProject); try { - env.fireStartTest(name); + notifier.fireStartTest(name); newProject.executeTargets(v); } catch (BuildException e) { - fireFailOrError(name, e); + fireFailOrError(name, e, notifier); } finally { // fire endTest here instead of the endTarget // event, otherwise an error would be // registered after the endTest event - // endTarget is called before this method's catch block // is reached. - env.fireEndTest(name); + notifier.fireEndTest(name); // clean up if (hasTearDown) { try { newProject.executeTarget(TEARDOWN); } catch (final BuildException e) { - fireFailOrError(name, e); + fireFailOrError(name, e, notifier); } } } @@ -282,20 +222,18 @@ /** * Executes the suiteTearDown target if presents and report any execution error. - * @param caught Any internal exception triggered (and catched) by the caller indicating that - * the this runner could not be invoked as expected. + * @param caught Any internal exception triggered (and caught) by the caller indicating that + * the execution could not be invoked as expected. + * @param notifier will receive execution notifications. */ - public void endSuite(Throwable caught) { - if (!isScanned) { - throw new AssertionError(); - } + private void endSuite(Throwable caught, AntUnitExecutionNotifier notifier) { if (hasSuiteTearDown) { try { Project newProject = getCleanProject(); newProject.executeTarget(SUITETEARDOWN); } catch (BuildException e) { - env.fireStartTest(SUITETEARDOWN); - fireFailOrError(SUITETEARDOWN, e); + notifier.fireStartTest(SUITETEARDOWN); + fireFailOrError(SUITETEARDOWN, e, notifier); } } getCurrentProject().fireBuildFinished(caught); @@ -307,20 +245,45 @@ * or is caused by an AssertionFailedException. If so, fire a failure for * given targetName. Otherwise fire an error. */ - private void fireFailOrError(String targetName, BuildException e) { + private void fireFailOrError(String targetName, BuildException e, + AntUnitExecutionNotifier notifier) { boolean failed = false; Throwable t = e; while (t != null && t instanceof BuildException) { if (t instanceof AssertionFailedException) { failed = true; - env.fireFail(targetName, (AssertionFailedException) t); + notifier.fireFail(targetName, (AssertionFailedException) t); break; } t = ((BuildException) t).getCause(); } if (!failed) { - env.fireError(targetName, e); + notifier.fireError(targetName, e); + } + } + + + /** + * Executes the suite. + * @param suiteTargets An ordered list of test targets. It must be a sublist of getTestTargets + * @param notifier + */ + public void runSuite(List suiteTargets, AntUnitExecutionNotifier notifier) { + Throwable caught = null; + try { + if (!startSuite(notifier)) { + return; + } + Iterator iter = suiteTargets.iterator(); + while (iter.hasNext()) { + String name = (String) iter.next(); + runTarget(name, notifier); + } + } catch (Throwable e) { + caught = e; + } finally { + endSuite(caught, notifier); } } Added: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java URL: http://svn.apache.org/viewvc/ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java?rev=740452&view=auto ============================================================================== --- ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java (added) +++ ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java Tue Feb 3 21:13:59 2009 @@ -0,0 +1,20 @@ +package org.apache.ant.antunit; + +import org.apache.tools.ant.Project; + +/** + * Provides project instances for AntUnit execution.
+ * The aproach to creates a project depends on the context. When invoked from an + * ant project, some elements might be intialized from the parent project. When + * executed in a junit runner, a brand new project must be initialized.
+ * The AntScriptRunner will usually creates multiple project in order to provide test isolation. + * @since 1.2 + */ +public interface ProjectFactory { + + /** + * Creates a new project instance and configures it according to the execution context. + */ + public Project createProject(); + +} Propchange: ant/antlibs/antunit/trunk/src/main/org/apache/ant/antunit/ProjectFactory.java ------------------------------------------------------------------------------ svn:eol-style = native