001: /*
002: * ========================================================================
003: *
004: * Copyright 2001-2004 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.integration.ant;
021:
022: import java.net.URL;
023:
024: import org.apache.cactus.integration.ant.container.ContainerRunner;
025: import org.apache.cactus.integration.ant.container.GenericContainer;
026: import org.apache.cactus.integration.ant.util.AntLog;
027: import org.apache.cactus.integration.ant.util.DefaultAntTaskFactory;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Task;
030:
031: /**
032: * Task to automate running in-container unit test. It has the following
033: * syntax when used in Ant :
034: * <code><pre>
035: * <runservertests testURL="&t;url>"
036: * starttarget="<start target name>"
037: * stoptarget="<stop target name>"
038: * testtarget="<test target name>"/>
039: * </pre></code>
040: * where <code><url></code> is the URL that is used by this task to
041: * ensure that the server is running. Indeed, the algorithm is as follow :
042: * <ul>
043: * <li>Checks if server is running by trying to open an HTTP connection to
044: * the URL,</li>
045: * <li>If it fails, call the start target and loop until the HTTP connection
046: * the URL can be established,</li>
047: * <li>Call the test target. This target is supposed to start the test,
048: * usually by running the junit Ant task,</li>
049: * <li>When the tests are finished, call the stop target to stop the server.
050: * Note: The stop target is called only if the server was not already running
051: * when this task was executed.</li>
052: * </ul>
053: *
054: * @since Cactus 1.5
055: * @version $Id: RunServerTestsTask.java 239003 2004-05-31 20:05:27Z vmassol $
056: */
057: public class RunServerTestsTask extends Task {
058:
059: // Instance Variables ------------------------------------------------------
060:
061: /**
062: * The generic container.
063: */
064: private GenericContainer container = new GenericContainer();
065:
066: /**
067: * The hook that is called when the tests should be run.
068: */
069: private GenericContainer.Hook testHook;
070:
071: /**
072: * The URL that is continuously pinged to verify if the server is running.
073: */
074: private URL testURL;
075:
076: /**
077: * Timeout after which we stop trying to connect to the test URL (in ms).
078: */
079: private long timeout = 180000;
080:
081: // Task Implementation -----------------------------------------------------
082:
083: /**
084: * @see Task#execute()
085: */
086: public void execute() throws BuildException {
087: if (!this .container.isStartUpSet()) {
088: throw new BuildException(
089: "You must specify either a nested [start] "
090: + "element or the [starttarget] attribute");
091: }
092:
093: if (!this .container.isShutDownSet()) {
094: throw new BuildException(
095: "You must specify either a nested [stop] "
096: + "element or the [stoptarget] attribute");
097: }
098:
099: if (this .testHook == null) {
100: throw new BuildException(
101: "You must specify either a nested [test] "
102: + "element or the [testtarget] attribute");
103: }
104:
105: // Verify that a test URL has been specified
106: if (this .testURL == null) {
107: throw new BuildException(
108: "The [testurl] attribute must be specified");
109: }
110:
111: this .container.setAntTaskFactory(new DefaultAntTaskFactory(
112: getProject(), getTaskName(), getLocation(),
113: getOwningTarget()));
114:
115: ContainerRunner runner = new ContainerRunner(this .container);
116: runner.setLog(new AntLog(this ));
117: runner.setURL(this .testURL);
118: runner.setTimeout(this .timeout);
119: runner.startUpContainer();
120: try {
121: this .testHook.execute();
122: } finally {
123: runner.shutDownContainer();
124: }
125: }
126:
127: // Public Methods ----------------------------------------------------------
128:
129: /**
130: * Creates a nested start element.
131: *
132: * @return The start element
133: */
134: public final GenericContainer.Hook createStart() {
135: if (this .container.isStartUpSet()) {
136: throw new BuildException(
137: "This task supports only one nested [start] element");
138: }
139: return this .container.createStartUp();
140: }
141:
142: /**
143: * Sets the target to call to start the server.
144: *
145: * @param theStartTarget the Ant target to call
146: */
147: public void setStartTarget(String theStartTarget) {
148: if (this .container.isStartUpSet()) {
149: throw new BuildException(
150: "Either specify the [starttarget] "
151: + "attribute or the nested [start] element, but not both");
152: }
153: this .container.setStartUpTarget(theStartTarget);
154: }
155:
156: /**
157: * Creates a nested stop element.
158: *
159: * @return The stop element
160: */
161: public final GenericContainer.Hook createStop() {
162: if (this .container.isShutDownSet()) {
163: throw new BuildException(
164: "This task supports only one nested [stop] element");
165: }
166: return this .container.createShutDown();
167: }
168:
169: /**
170: * Sets the target to call to stop the server.
171: *
172: * @param theStopTarget the Ant target to call
173: */
174: public void setStopTarget(String theStopTarget) {
175: if (this .container.isShutDownSet()) {
176: throw new BuildException(
177: "Either specify the [stoptarget] "
178: + "attribute or the nested [stop] element, but not both");
179: }
180: this .container.setShutDownTarget(theStopTarget);
181: }
182:
183: /**
184: * Creates a nested test element.
185: *
186: * @return The test element
187: */
188: public final GenericContainer.Hook createTest() {
189: if (this .testHook != null) {
190: throw new BuildException(
191: "This task supports only one nested [test] element");
192: }
193: this .testHook = container.new Hook();
194: return this .testHook;
195: }
196:
197: /**
198: * Sets the target to call to run the tests.
199: *
200: * @param theTestTarget the Ant target to call
201: */
202: public void setTestTarget(String theTestTarget) {
203: if (this .testHook != null) {
204: throw new BuildException(
205: "Either specify the [testtarget] "
206: + "attribute or the nested [test] element, but not both");
207: }
208: this .testHook = container.new Hook();
209: this .testHook.setTarget(theTestTarget);
210: }
211:
212: /**
213: * Sets the URL to call for testing if the server is running.
214: *
215: * @param theTestURL the test URL to ping
216: */
217: public void setTestURL(URL theTestURL) {
218: this .testURL = theTestURL;
219: }
220:
221: /**
222: * @param theTimeout the timeout after which we stop trying to call the test
223: * URL.
224: */
225: public void setTimeout(long theTimeout) {
226: this.timeout = theTimeout;
227: }
228:
229: }
|