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.File;
21  import java.io.IOException;
22  import java.io.InputStream;
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  import java.util.UUID;
29  
30  import javax.jdo.util.AbstractTest;
31  import javax.jdo.util.BatchTestRunner;
32  
33  
34  /**
35   * Tests class javax.jdo.Enhancer (Enhancer main class).
36   * <p>
37   */
38  public class EnhancerTest extends AbstractTest {
39  
40      /** The path delimiter for constructing classpaths. */
41      private static String pathDelimiter = System.getProperty("path.separator");
42  
43      /** The maven basedir identifying the directory of the execution environment. */
44      private static String basedir = System.getProperty("basedir");
45  
46      /** */
47      public static void main(String args[]) {
48          BatchTestRunner.run(EnhancerTest.class);
49      }
50  
51      public void testUsageOption() {
52          // invoke enhancer with a usage option
53          InvocationResult result = invokeEnhancer("?");
54          String outputString = result.getOutputString();
55          String errorString = result.getErrorString();
56          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
57          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
58      }
59  
60      public void testHelpOption() {
61          // invoke enhancer with a usage option
62          InvocationResult result = invokeEnhancer("-help");
63          String outputString = result.getOutputString();
64          String errorString = result.getErrorString();
65          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
66          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
67      }
68  
69      public void testHOption() {
70          // invoke enhancer with a usage option
71          InvocationResult result = invokeEnhancer("-h");
72          String outputString = result.getOutputString();
73          String errorString = result.getErrorString();
74          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
75          assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer"));
76      }
77  
78      public void testInvalidOption() {
79          // invoke enhancer with an invalid option
80          InvocationResult result = invokeEnhancer("-poo");
81          assertEquals("Wrong return value ", ENHANCER_USAGE_ERROR, result.getExitValue());
82          String errorString = result.getErrorString();
83          assertTrue("Expected Usage message from err:\n" + errorString, errorString.contains("javax.jdo.Enhancer"));
84      }
85  
86      public void testProperties() {
87          // invoke enhancer with verbose option
88          InvocationResult result = invokeEnhancer("-v");
89          String outputString = result.getOutputString();
90          String errorString = result.getErrorString();
91          assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
92          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VENDOR_NAME));
93          assertTrue("Expected MockEnhancer version message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VERSION_NUMBER));
94          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("Mock Enhancer"));
95          assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2.3.0"));
96          assertTrue("Expected MockEnhancer properties message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("MockKey"));
97      }
98  
99      public void testVOption() {
100         // invoke enhancer with verbose option
101         InvocationResult result = invokeEnhancer("-v");
102         String outputString = result.getOutputString();
103         String errorString = result.getErrorString();
104         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
105         assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer"));
106     }
107 
108     public void testVerboseOption() {
109         // invoke enhancer with verbose option
110         InvocationResult result = invokeEnhancer("-verbose");
111         String outputString = result.getOutputString();
112         String errorString = result.getErrorString();
113         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
114         assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer"));
115     }
116 
117     public void testVerboseClasses() {
118         // invoke enhancer with .class parameter
119         InvocationResult result = invokeEnhancer("-v some.class");
120         String outputString = result.getOutputString();
121         String errorString = result.getErrorString();
122         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
123         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
124         assertTrue("Expected number of classes from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
125     }
126 
127     public void testVerboseJars() {
128         // invoke enhancer with a .jar parameter
129         InvocationResult result = invokeEnhancer("-v some.jar");
130         String outputString = result.getOutputString();
131         String errorString = result.getErrorString();
132         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
133         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
134         assertTrue("Expected number of jars from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
135     }
136 
137     public void testVerboseJDOs() {
138         // invoke enhancer with a .jdo parameter
139         InvocationResult result = invokeEnhancer("-v some.jdo");
140         String outputString = result.getOutputString();
141         String errorString = result.getErrorString();
142         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
143         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
144         assertTrue("Expected number of jdos from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1"));
145     }
146 
147     public void testVerboseAll() {
148         // invoke enhancer with multiple parameters
149         InvocationResult result = invokeEnhancer("-v some.class some.jar some.jdo");
150         String outputString = result.getOutputString();
151         String errorString = result.getErrorString();
152         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
153         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
154         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
155         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
156         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3"));
157     }
158 
159     public void testVerboseCheckonlyAll() {
160         // invoke enhancer with a checkonly option
161         InvocationResult result = invokeEnhancer("-v -checkonly some.class some.jar some.jdo");
162         String outputString = result.getOutputString();
163         String errorString = result.getErrorString();
164         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
165         assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo"));
166         assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar"));
167         assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class"));
168         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3"));
169     }
170 
171     public void testMissingPU() {
172         // invoke enhancer with missing parameter
173         InvocationResult result = invokeEnhancer("-v -pu");
174         assertEquals("Wrong return value ", 3, result.getExitValue());
175     }
176 
177     public void testVerbosePU() {
178         // invoke enhancer with a pu parameter
179         InvocationResult result = invokeEnhancer("-v -pu myPU -pu yourPU");
180         String outputString = result.getOutputString();
181         String errorString = result.getErrorString();
182         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
183         assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("myPU"));
184         assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("yourPU"));
185         assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2"));
186     }
187 
188     public void testClasspath() {
189         // invoke enhancer with a classpath parameter
190         // JDOHelper must be loadable from this path
191         // the File.toURI should append "/" to the path, so only "target/classes" is needed
192         InvocationResult result = invokeEnhancer("-v -cp " + basedir + "/target/classes");
193         String outputString = result.getOutputString();
194         String errorString = result.getErrorString();
195         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
196         assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("target/classes"));
197     }
198 
199     public void testBadClasspath() {
200         // invoke enhancer with a bad classpath parameter
201         // JDOHelper is not loadable from this path
202         InvocationResult result = invokeEnhancer("-v -cp target");
203         String outputString = result.getOutputString();
204         String errorString = result.getErrorString();
205         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 1, result.getExitValue());
206         assertTrue("Expected classpath error message from out:\n" + outputString + " with err:\n" + errorString, errorString.contains("JDOHelper"));
207     }
208 
209     public void testClasspathJar() throws IOException, InterruptedException {
210         // invoke enhancer with a classpath parameter
211         // JDOHelper must be loadable from this path
212         // create the jar file from the target/classes directory
213         String uuid = UUID.randomUUID().toString();
214         File uuidDir = new File(basedir + "/target/" + uuid);
215         uuidDir.mkdirs();
216         String enhancerJar = "target/" + uuid + "/enhancer-test.jar";
217         String enhancerJarPathname = basedir + "/" + enhancerJar;
218         Process create = Runtime.getRuntime().exec("jar -cf " + enhancerJarPathname + " -C " + basedir + "/target/classes .");
219         int returnCode = create.waitFor();
220         assertEquals("jar command returned wrong return code.", 0, returnCode);
221         // find the jdo.jar in target
222         InvocationResult result = invokeEnhancer("-v -cp " + enhancerJarPathname);
223         String outputString = result.getOutputString();
224         String errorString = result.getErrorString();
225         assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue());
226         assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(enhancerJar));
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 }