1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  package javax.jdo;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  
23  import java.io.InputStreamReader;
24  import java.io.Reader;
25  import java.nio.CharBuffer;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import static javax.jdo.Constants.ENHANCER_USAGE_ERROR;
30  import static javax.jdo.Constants.PROPERTY_ENHANCER_VENDOR_NAME;
31  import static javax.jdo.Constants.PROPERTY_ENHANCER_VERSION_NUMBER;
32  
33  import javax.jdo.util.AbstractTest;
34  import javax.jdo.util.BatchTestRunner;
35  
36  
37  /**
38   * Tests class javax.jdo.Enhancer (Enhancer main class).
39   * <p>
40   */
41  public class EnhancerTest extends AbstractTest {
42  
43      /** The path delimiter for constructing classpaths. */
44      private static String pathDelimiter = System.getProperty("path.separator");
45  
46      /** The maven basedir identifying the directory of the execution environment. */
47      private static String basedir = System.getProperty("basedir");
48  
49      /** */
50      public static void main(String args[]) {
51          BatchTestRunner.run(EnhancerTest.class);
52      }
53  
54      public void testUsageOption() {
55          // invoke enhancer with a usage option
56          InvocationResult result = invokeEnhancer("?");
57          String outputString = result.getOutputString();
58          String errorString = result.getErrorString();
59          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
60          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
61      }
62  
63      public void testHelpOption() {
64          // invoke enhancer with a usage option
65          InvocationResult result = invokeEnhancer("-help");
66          String outputString = result.getOutputString();
67          String errorString = result.getErrorString();
68          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
69          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
70      }
71  
72      public void testHOption() {
73          // invoke enhancer with a usage option
74          InvocationResult result = invokeEnhancer("-h");
75          String outputString = result.getOutputString();
76          String errorString = result.getErrorString();
77          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
78          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
79      }
80  
81      public void testInvalidOption() {
82          // invoke enhancer with an invalid option
83          InvocationResult result = invokeEnhancer("-poo");
84          assertEquals("Wrong return value ", ENHANCER_USAGE_ERROR, result.getExitValue());
85          String errorString = result.getErrorString();
86          assertTrue("Expected Usage message from err:\n" + errorString, errorString.contains("javax.jdo.Enhancer"));
87      }
88  
89      public void testProperties() {
90          // invoke enhancer with verbose option
91          InvocationResult result = invokeEnhancer("-v");
92          String outputString = result.getOutputString();
93          String errorString = result.getErrorString();
94          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
95          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VENDOR_NAME));
96          assertTrue("Expected MockEnhancer version message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VERSION_NUMBER));
97          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("Mock Enhancer"));
98          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2.3.0"));
99          assertTrue("Expected MockEnhancer properties message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("MockKey"));
100     }
101 
102     public void testVOption() {
103         // invoke enhancer with verbose option
104         InvocationResult result = invokeEnhancer("-v");
105         String outputString = result.getOutputString();
106         String errorString = result.getErrorString();
107         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
108         assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer"));
109     }
110 
111     public void testVerboseOption() {
112         // invoke enhancer with verbose option
113         InvocationResult result = invokeEnhancer("-verbose");
114         String outputString = result.getOutputString();
115         String errorString = result.getErrorString();
116         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
117         assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer"));
118     }
119 
120     public void testVerboseClasses() {
121         // invoke enhancer with .class parameter
122         InvocationResult result = invokeEnhancer("-v some.class");
123         String outputString = result.getOutputString();
124         String errorString = result.getErrorString();
125         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
126         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
127         assertTrue("Expected number of classes from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
128     }
129 
130     public void testVerboseJars() {
131         // invoke enhancer with a .jar parameter
132         InvocationResult result = invokeEnhancer("-v some.jar");
133         String outputString = result.getOutputString();
134         String errorString = result.getErrorString();
135         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
136         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
137         assertTrue("Expected number of jars from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
138     }
139 
140     public void testVerboseJDOs() {
141         // invoke enhancer with a .jdo parameter
142         InvocationResult result = invokeEnhancer("-v some.jdo");
143         String outputString = result.getOutputString();
144         String errorString = result.getErrorString();
145         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
146         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
147         assertTrue("Expected number of jdos from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
148     }
149 
150     public void testVerboseAll() {
151         // invoke enhancer with multiple parameters
152         InvocationResult result = invokeEnhancer("-v some.class some.jar some.jdo");
153         String outputString = result.getOutputString();
154         String errorString = result.getErrorString();
155         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
156         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
157         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
158         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
159         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3"));
160     }
161 
162     public void testVerboseCheckonlyAll() {
163         // invoke enhancer with a checkonly option
164         InvocationResult result = invokeEnhancer("-v -checkonly some.class some.jar some.jdo");
165         String outputString = result.getOutputString();
166         String errorString = result.getErrorString();
167         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
168         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
169         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
170         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
171         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3"));
172     }
173 
174     public void testMissingPU() {
175         // invoke enhancer with missing parameter
176         InvocationResult result = invokeEnhancer("-v -pu");
177         assertEquals("Wrong return value ", 3, result.getExitValue());
178     }
179 
180     public void testVerbosePU() {
181         // invoke enhancer with a pu parameter
182         InvocationResult result = invokeEnhancer("-v -pu myPU -pu yourPU");
183         String outputString = result.getOutputString();
184         String errorString = result.getErrorString();
185         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
186         assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("myPU"));
187         assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("yourPU"));
188         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2"));
189     }
190 
191     public void testClasspath() {
192         // invoke enhancer with a classpath parameter
193         // JDOHelper must be loadable from this path
194         // the File.toURI should append "/" to the path, so only "target/classes" is needed
195         InvocationResult result = invokeEnhancer("-v -cp " + basedir + "/target/classes");
196         String outputString = result.getOutputString();
197         String errorString = result.getErrorString();
198         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
199         assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("target/classes"));
200     }
201 
202     public void testBadClasspath() {
203         // invoke enhancer with a bad classpath parameter
204         // JDOHelper is not loadable from this path
205         InvocationResult result = invokeEnhancer("-v -cp target");
206         String outputString = result.getOutputString();
207         String errorString = result.getErrorString();
208         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 1, result.getExitValue());
209         assertTrue("Expected classpath error message from out:\n" + outputString + " with err:\n" + errorString, errorString.contains("JDOHelper"));
210     }
211 
212     public void testClasspathJar() throws IOException, InterruptedException {
213         // invoke enhancer with a classpath parameter
214         // JDOHelper must be loadable from this path
215         // create the jar file from the target/classes directory
216         Process create = Runtime.getRuntime().exec("jar -cf " + basedir + "/target/enhancer-test.jar -C " + basedir + "/target/classes .");
217         int returnCode = create.waitFor();
218         assertEquals("jar command returned wrong return code.", 0, returnCode);
219         // find the jdo.jar in target
220         InvocationResult result = invokeEnhancer("-v -cp " + basedir + "/target/enhancer-test.jar");
221         String outputString = result.getOutputString();
222         String errorString = result.getErrorString();
223         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
224         assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("target/enhancer-test.jar"));
225         // remove the jar file if successful
226         Runtime.getRuntime().exec("rm target/enhancer-test.jar").waitFor();
227     }
228 
229     public void testOutputDirectory() {
230         // invoke enhancer with an output directory parameter
231         InvocationResult result = invokeEnhancer("-v -d some/output/directory");
232         String outputString = result.getOutputString();
233         String errorString = result.getErrorString();
234         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
235         assertTrue("Expected directory message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some/output/directory"));
236     }
237 
238     public void testMissingOutputDirectory() {
239         // invoke enhancer with missing parameter
240         InvocationResult result = invokeEnhancer("-v -d");
241         assertEquals("Wrong return value ", 3, result.getExitValue());
242     }
243 
244     public void testDir() {
245         // invoke enhancer with directory and not recurse
246         InvocationResult result = invokeEnhancer("-v " + basedir + "/target/test-classes/enhancer-test-dir");
247         String outputString = result.getOutputString();
248         String errorString = result.getErrorString();
249         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
250         assertTrue("Expected directory enhancer-test-dir in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("enhancer-test-dir"));
251         assertTrue("Expected file file1.jdo in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file1.jdo"));
252         assertTrue("Expected file file2.class in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file2.class"));
253         assertTrue("Expected file file3.jar in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file3.jar"));
254         assertFalse("Expected no directory enhancer-test-subdir in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("enhancer-test-subdir"));
255         assertTrue("Expected 3 files to be enhanced in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3"));
256     }
257 
258     public void testDirRecurse() {
259         // invoke enhancer with directory and recurse
260         InvocationResult result = invokeEnhancer("-v -r " + basedir + "/target/test-classes/enhancer-test-dir");
261         String outputString = result.getOutputString();
262         String errorString = result.getErrorString();
263         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
264         assertTrue("Expected directory enhancer-test-dir in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("enhancer-test-dir"));
265         assertTrue("Expected directory enhancer-test-subdir in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("enhancer-test-subdir"));
266         assertTrue("Expected file file1.jdo in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file1.jdo"));
267         assertTrue("Expected file file2.class in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file2.class"));
268         assertTrue("Expected file file3.jar in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file3.jar"));
269         assertTrue("Expected file file4.jdo in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file4.jdo"));
270         assertTrue("Expected file file5.class in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file5.class"));
271         assertTrue("Expected file file6.jar in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("file6.jar"));
272         assertTrue("Expected 6 files to be enhanced in message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("6"));
273     }
274 
275     private InvocationResult invokeEnhancer(String string) {
276         InvocationResult result = new InvocationResult();
277         try {
278             // create the java command to invoke the Enhancer
279             List<String> commands = new ArrayList<String>();
280             // find the java command in the user's path
281             commands.add("java");
282             commands.add("-cp");
283             commands.add("" + basedir + "/target/classes" + pathDelimiter + "" + basedir + "/target/test-classes");
284             commands.add("javax.jdo.Enhancer");
285             // add the test options (from the method parameter) to the java command
286             String[] optionArray = string.split(" ");
287             for (String option: optionArray) {
288                 commands.add(option);
289             }
290             String[] cmdarray = commands.toArray(new String[commands.size()]);
291             ProcessBuilder builder = new ProcessBuilder(cmdarray);
292             Process proc = builder.start();
293             InputStream stdout = proc.getInputStream();
294             InputStream stderr = proc.getErrorStream();
295             CharBuffer outBuffer = CharBuffer.allocate(1000000);
296             CharBuffer errBuffer = CharBuffer.allocate(1000000);
297             Thread outputThread = createReaderThread(stdout, outBuffer);
298             Thread errorThread = createReaderThread(stderr, errBuffer);
299             int exitValue = proc.waitFor();
300             result.setExitValue(exitValue);
301             errorThread.join(10000); // wait ten seconds to get stderr after process terminates
302             outputThread.join(10000); // wait ten seconds to get stdout after process terminates
303             result.setErrorString(errBuffer.toString());
304             result.setOutputString(outBuffer.toString());
305             // wait until the Enhancer command finishes
306         } catch (InterruptedException ex) {
307             throw new RuntimeException("InterruptedException", ex);
308         } catch (IOException ex) {
309             throw new RuntimeException("IOException", ex);
310         } catch (JDOException jdoex) {
311             jdoex.printStackTrace();
312             Throwable[] throwables = jdoex.getNestedExceptions();
313             System.out.println("Exception throwables of size: " + throwables.length);
314             for (Throwable throwable: throwables) {
315                 throwable.printStackTrace();
316             }
317         }
318         return result;
319     }
320 
321     private Thread createReaderThread(final InputStream input, final CharBuffer output) {
322         final Reader reader = new InputStreamReader(input);
323         Thread thread = new Thread(
324                 new Runnable() {
325                     public void run() {
326                         int count = 0;
327                         int outputBytesRead = 0;
328                         try {
329                             while (-1 != (outputBytesRead = reader.read(output))) {
330                                 count += outputBytesRead;
331                             }
332                         } catch (IOException e) {
333                             e.printStackTrace();
334                         } finally {
335                             output.flip();
336                         }
337                     }
338                 });
339         thread.start();
340         return thread;
341     }
342 
343     class InvocationResult {
344         private int exitValue;
345         private String errorString;
346         private String outputString;
347 
348         int getExitValue() {
349             return exitValue;
350         }
351 
352         private void setExitValue(int exitValue) {
353             this.exitValue = exitValue;
354         }
355 
356         private void setErrorString(String errorString) {
357             this.errorString = errorString;
358         }
359 
360         String getErrorString() {
361             return errorString;
362         }
363 
364         private void setOutputString(String outputString) {
365             this.outputString = outputString;
366         }
367 
368         String getOutputString() {
369             return outputString;
370         }
371 
372     }
373 
374 }