KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > test > ExecHarness


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb.test;
33
34 import java.io.BufferedInputStream JavaDoc;
35 import java.io.File JavaDoc;
36 import java.io.FileInputStream JavaDoc;
37 import java.io.FileNotFoundException JavaDoc;
38 import java.io.FileOutputStream JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.InputStream JavaDoc;
41 import java.io.OutputStream JavaDoc;
42 import java.util.List JavaDoc;
43
44 // $Id: ExecHarness.java,v 1.10 2005/10/23 19:25:13 fredt Exp $
45

46 /**
47  * Utilities that test classes can call to execute a specified command and to
48  * evaluate the exit status and output of said execution.
49  * harnessInstance.exec() executes the given program (Java or not).
50  * Any time thereafter, harnessInstance can be interrogated for exit
51  * status and text output.
52  *
53  * ExecHarness can emulate user interaction with SqlTool, but you can
54  * not use ExecHarness interactively.
55  *
56  * To execute java classes, you can either give the classpath by setting the
57  * environmental var before running this program, or by giving the classpath
58  * switch to the target program. Classpath switches used for invoking
59  * this ExecHarness class WILL NOT EFFECT java executions by ExecHarness.
60  * E.g. the java invocation
61  * "java org.hsqldb.test.ExecHarness java -cp newcp Cname" will give Cname
62  * classpath of 'newcp', but the following WILL NOT:
63  * "java -cp newcp org.hsqldb.test.ExecHarness java Cname".
64  * It's often easier to just set (and export if necessary) CLASSPATH before
65  * invoking ExecHarness.
66  *
67  * Same applies to java System Properties. You must supply them after the
68  * 2nd "java".
69  *
70  * @see main() for an example of use.
71  */

72 public class ExecHarness {
73
74     /*
75      * In general, for output from the program, we use Strings so that we can
76      * use regexes with them.
77      * For my current needs, I just need to be able to supply stdin to the
78      * target program by a file, so that's all I'm implementing for stdin
79      * right now.
80      */

81     private static final String JavaDoc SYNTAX_MSG =
82         "SYNTAX: java org.hsqldb.test.ExecHarness targetprogram [args...]";
83     private static final int MAX_PROG_OUTPUT = 10240;
84
85     /**
86      * To test the ExecHarness class itself.
87      * (Basically, a sanity check).
88      *
89      * Note that we always exec another process. This makes it safe to
90      * execute Java classes which may call System.exit().
91      *
92      * @param sa sa[0] is the program to be run.
93      * Remaining arguments will be passed as command-line args
94      * to the sa[0] program.
95      */

96     public static void main(String JavaDoc[] sa)
97     throws IOException JavaDoc, FileNotFoundException JavaDoc, InterruptedException JavaDoc {
98
99         byte[] localBa = new byte[10240];
100
101         if (sa.length < 1) {
102             System.err.println(SYNTAX_MSG);
103             System.exit(1);
104         }
105
106         String JavaDoc progname = sa[0];
107
108         System.err.println(
109             "Enter any input that you want passed to SqlTool via stdin\n"
110             + "(end with EOF, like Ctrl-D or Ctrl-Z+ENTER):");
111
112         File JavaDoc tmpFile = File.createTempFile("ExecHarness-", ".input");
113         String JavaDoc specifiedCharSet = System.getProperty("harness.charset");
114         String JavaDoc charset = ((specifiedCharSet == null) ? DEFAULT_CHARSET
115                                                      : specifiedCharSet);
116         FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(tmpFile);
117         int i;
118
119         while ((i = System.in.read(localBa)) > 0) {
120             fos.write(localBa, 0, i);
121         }
122
123         fos.close();
124
125         ExecHarness harness = new ExecHarness(progname);
126
127         harness.setArgs(shift(sa));
128         harness.setInput(tmpFile);
129         harness.exec();
130         tmpFile.delete();
131
132         int retval = harness.getExitValue();
133
134         System.err.println(
135             "STDOUT ******************************************");
136         System.out.print(harness.getStdout());
137         System.err.println(
138             "ERROUT ******************************************");
139         System.err.print(harness.getErrout());
140         System.err.println(
141             "*************************************************");
142         System.err.println(progname + " exited with value " + retval);
143         harness.clear();
144         System.exit(retval);
145     }
146
147     File JavaDoc input = null;
148     String JavaDoc program = null;
149     int exitValue = 0;
150     boolean executed = false;
151
152     // I'm sure there's a better way to do this. Can't think of it right now.
153
String JavaDoc[] mtStringArray = {};
154     String JavaDoc[] args = mtStringArray;
155
156     // The extra 1 is so we can request 1 more byte than we want.
157
// If that read is satisfied, we know that we read > MAX_PROG_OUTPUT.
158
private byte[] ba = new byte[MAX_PROG_OUTPUT + 1];
159     private String JavaDoc stdout = null;
160     private String JavaDoc errout = null;
161     private static final String JavaDoc DEFAULT_CHARSET = "US-ASCII";
162
163     /*
164      * Execute associated program synchronously, but in a separate process.
165      * Would be easy to run it asynchronously, but I think this is more
166      * useful as-is for unit testing purposes.
167      * To run a Java class, give args like
168      * <PRE>{ "java", "org.hsqldb.util.SqlTool", "mem" }</PRE>
169      *
170      * Intentionally passes through many exceptions so that the unit testing
171      * tool may properly process these are errors of the testing procedure,
172      * not a failed test.
173      *
174      * In addition to passed-through exceptions, this method will throw
175      * an IOException if the invoked program generates > 10 k of output
176      * to either stdout or errout.
177      */

178     public void exec() throws IOException JavaDoc, InterruptedException JavaDoc {
179
180         InputStream JavaDoc stream;
181         int i;
182         int writePointer;
183
184         if (executed) {
185             throw new IllegalStateException JavaDoc("You have already executed '"
186                                             + program + "'. Run clear().");
187         }
188
189         Process JavaDoc proc = Runtime.getRuntime().exec(unshift(program, args));
190         OutputStream JavaDoc outputStream = proc.getOutputStream();
191
192         if (input != null) {
193             BufferedInputStream JavaDoc bis =
194                 new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(input));
195
196             while ((i = bis.read(ba)) > 0) {
197                 outputStream.write(ba, 0, i);
198             }
199         }
200
201         outputStream.close();
202
203         stream = proc.getInputStream();
204         writePointer = 0;
205
206         while ((i = stream.read(ba, writePointer, ba.length - writePointer))
207                 > 0) {
208             writePointer += i;
209         }
210
211         if (i > -1) {
212             throw new IOException JavaDoc(program + " generated > " + (ba.length - 1)
213                                   + " bytes of standard output");
214         }
215
216         stream.close();
217
218         executed = true; // At this point we are changing state. No going back.
219
stdout = new String JavaDoc(ba, 0, writePointer);
220         stream = proc.getErrorStream();
221         writePointer = 0;
222
223         while ((i = stream.read(ba, writePointer, ba.length - writePointer))
224                 > 0) {
225             writePointer += i;
226         }
227
228         if (i > -1) {
229             throw new IOException JavaDoc(program + " generated > " + (ba.length - 1)
230                                   + " bytes of error output");
231         }
232
233         stream.close();
234
235         errout = new String JavaDoc(ba, 0, writePointer);
236         exitValue = proc.waitFor();
237     }
238
239     /*
240      * You must run this method before preparing an ExecHarness for re-use
241      * (I.e. to exec() again).
242      */

243     public void clear() {
244
245         // TODO: Release output buffers.
246
args = mtStringArray;
247         executed = false;
248         stdout = errout = null;
249         input = null;
250     }
251
252     public String JavaDoc getStdout() {
253         return stdout;
254     }
255
256     public String JavaDoc getErrout() {
257         return errout;
258     }
259
260     /**
261      * @param inFile There is no size limit on the input file.
262      */

263     public void setInput(File JavaDoc inFile) throws IllegalStateException JavaDoc {
264
265         if (executed) {
266             throw new IllegalStateException JavaDoc("You have already executed '"
267                                             + program + "'. Run clear().");
268         }
269
270         input = inFile;
271     }
272
273     public void setArgs(String JavaDoc[] inArgs) throws IllegalStateException JavaDoc {
274
275         if (executed) {
276             throw new IllegalStateException JavaDoc("You have already executed '"
277                                             + program + "'. Run clear().");
278         }
279
280         args = inArgs;
281     }
282
283     public void setArgs(List JavaDoc list) throws IllegalStateException JavaDoc {
284         setArgs(listToPrimitiveArray(list));
285     }
286
287     int getExitValue() throws IllegalStateException JavaDoc {
288
289         if (!executed) {
290             throw new IllegalStateException JavaDoc("You have not executed '"
291                                             + program + "' yet");
292         }
293
294         return exitValue;
295     }
296
297     /**
298      * Create an ExecHarness instance which can invoke the given program.
299      *
300      * @param inName Name of the external program (like "cat" or "java").
301      */

302     public ExecHarness(String JavaDoc inName) {
303         program = inName;
304     }
305
306     /**
307      * These utility methods really belong in a class in the util package.
308      */

309     public static String JavaDoc[] unshift(String JavaDoc newHead, String JavaDoc[] saIn) {
310
311         String JavaDoc[] saOut = new String JavaDoc[saIn.length + 1];
312
313         saOut[0] = newHead;
314
315         for (int i = 1; i < saOut.length; i++) {
316             saOut[i] = saIn[i - 1];
317         }
318
319         return saOut;
320     }
321
322     public static String JavaDoc[] shift(String JavaDoc[] saIn) {
323
324         String JavaDoc[] saOut = new String JavaDoc[saIn.length - 1];
325
326         for (int i = 0; i < saOut.length; i++) {
327             saOut[i] = saIn[i + 1];
328         }
329
330         return saOut;
331     }
332
333     public static String JavaDoc[] listToPrimitiveArray(List JavaDoc list) {
334
335         String JavaDoc[] saOut = new String JavaDoc[list.size()];
336
337         for (int i = 0; i < list.size(); i++) {
338             saOut[i] = (String JavaDoc) list.get(i);
339         }
340
341         return saOut;
342     }
343
344     public static String JavaDoc[] push(String JavaDoc newTail, String JavaDoc[] saIn) {
345
346         String JavaDoc[] saOut = new String JavaDoc[saIn.length + 1];
347
348         for (int i = 0; i < saIn.length; i++) {
349             saOut[i] = saIn[i];
350         }
351
352         saOut[saOut.length - 1] = newTail;
353
354         return saOut;
355     }
356
357     public static String JavaDoc[] pop(String JavaDoc[] saIn) {
358
359         String JavaDoc[] saOut = new String JavaDoc[saIn.length - 1];
360
361         for (int i = 0; i < saOut.length; i++) {
362             saOut[i] = saIn[i];
363         }
364
365         return saOut;
366     }
367
368     public static String JavaDoc stringArrayToString(String JavaDoc[] sa) {
369
370         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("{");
371
372         for (int i = 0; i < sa.length; i++) {
373             if (i > 0) {
374                 sb.append(',');
375             }
376
377             sb.append(sa[i]);
378         }
379
380         return sb.toString() + '}';
381     }
382 }
383
Popular Tags