Source Code Cross Referenced for FastRunner.java in  » Testing » jumble » com » reeltwo » jumble » fast » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » jumble » com.reeltwo.jumble.fast 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.reeltwo.jumble.fast;
002:
003:        import com.reeltwo.jumble.mutation.Mutater;
004:        import com.reeltwo.jumble.mutation.MutatingClassLoader;
005:        import com.reeltwo.jumble.ui.JumbleListener;
006:        import com.reeltwo.jumble.ui.NullListener;
007:        import com.reeltwo.jumble.util.IOThread;
008:        import com.reeltwo.jumble.util.JavaRunner;
009:        import com.reeltwo.jumble.util.JumbleUtils;
010:        import java.io.File;
011:        import java.io.FileInputStream;
012:        import java.io.FileOutputStream;
013:        import java.io.IOException;
014:        import java.io.ObjectInputStream;
015:        import java.io.ObjectOutputStream;
016:        import java.util.ArrayList;
017:        import java.util.HashSet;
018:        import java.util.Iterator;
019:        import java.util.List;
020:        import java.util.Set;
021:        import java.util.StringTokenizer;
022:
023:        /**
024:         * A runner for the <CODE>FastJumbler</CODE>. Runs the FastJumbler in a new
025:         * JVM and detects timeouts.
026:         * 
027:         * @author Tin Pavlinic
028:         * @version $Revision: 516 $
029:         */
030:        public class FastRunner {
031:
032:            /** Filename for the cache */
033:            public static final File CACHE_FILE = new File(System
034:                    .getProperty("user.home"), ".com.reeltwo.jumble-cache.dat");
035:
036:            // Configuration properties
037:
038:            /** Whether to mutate constants */
039:            private boolean mInlineConstants = true;
040:
041:            /** Whether to mutate return values */
042:            private boolean mReturnVals = true;
043:
044:            /** Whether to mutate increments */
045:            private boolean mIncrements = true;
046:
047:            /** Whether to mutate constant pool */
048:            private boolean mCPool = true;
049:
050:            /** Whether to mutate switches */
051:            private boolean mSwitches = true;
052:
053:            private boolean mOrdered = true;
054:
055:            private boolean mVerbose = false;
056:
057:            private boolean mLoadCache = true;
058:
059:            private boolean mSaveCache = true;
060:
061:            private boolean mUseCache = true;
062:
063:            private String mClassPath = System.getProperty("java.class.path");
064:
065:            /** Maximum number of mutations per JVM */
066:            private int mMaxExternalMutations = -1;
067:
068:            /** 
069:             * Index of the first mutation to attempt. Mainly useful for
070:             * testing when there is a problematic mutation. 
071:             */
072:            private int mFirstMutation = 0;
073:
074:            private Set<String> mExcludeMethods = new HashSet<String>();
075:
076:            private List<String> mJvmArgs = new ArrayList<String>();
077:
078:            // State during run
079:
080:            /** The class being tested */
081:            private String mClassName;
082:
083:            private File mCacheFile;
084:
085:            private File mTestSuiteFile;
086:
087:            private JavaRunner mRunner = null;
088:
089:            private Process mChildProcess = null;
090:
091:            private IOThread mIot = null;
092:
093:            private IOThread mEot = null;
094:
095:            private int mMutationCount;
096:
097:            private long mTotalRuntime;
098:
099:            /** The variable storing the failed tests - can get pretty big */
100:            FailedTestMap mCache = null;
101:
102:            public FastRunner() {
103:                // Add a shutdown hook so that if this JVM is interrupted, any
104:                // child process will be destroyed.
105:                Runtime.getRuntime().addShutdownHook(new Thread() {
106:                    public void run() {
107:                        Process childProcess = mChildProcess;
108:                        if (childProcess != null) {
109:                            if (mVerbose) {
110:                                System.err
111:                                        .println("Shutting down child process");
112:                            }
113:                            childProcess.destroy();
114:                        }
115:                    }
116:                });
117:                // This lets us run more mutation tests in each sub-JVM
118:                // without running out of space for classes.  Also consider
119:                // setting setMaxExternalMutations.
120:                mJvmArgs.add("-XX:PermSize=128m");
121:                mJvmArgs.add("-cp");
122:                mJvmArgs.add(System.getProperty("java.class.path"));
123:            }
124:
125:            private JavaRunner getJavaRunner() {
126:                if (mRunner == null) {
127:                    mRunner = new JavaRunner(
128:                            "com.reeltwo.jumble.fast.FastJumbler");
129:                    mRunner.setJvmArguments(mJvmArgs
130:                            .toArray(new String[mJvmArgs.size()]));
131:                }
132:                return mRunner;
133:            }
134:
135:            /**
136:             * Returns the classpath used to load test and source classes.
137:             *
138:             * @return the classpath string.
139:             */
140:            public String getClassPath() {
141:                return mClassPath;
142:            }
143:
144:            /**
145:             * Sets the classpath used to load test and source classes.
146:             *
147:             * @param classpath a <code>String</code> value
148:             */
149:            public void setClassPath(String classpath) {
150:                mClassPath = classpath;
151:                System.setProperty("java.class.path", mClassPath); // Make classpath available to code doing classpath scanning.
152:            }
153:
154:            /**
155:             * Gets whether verbose mode is set.
156:             * 
157:             * @return true if verbose mode is enabled.
158:             */
159:            public boolean isVerbose() {
160:                return mVerbose;
161:            }
162:
163:            /**
164:             * Sets whether verbose mode is enabled.
165:             * 
166:             * @param newVerbose
167:             *          true if verbose mode should be enabled.
168:             */
169:            public void setVerbose(final boolean newVerbose) {
170:                mVerbose = newVerbose;
171:            }
172:
173:            /**
174:             * Gets whether inline constants will be mutated.
175:             * 
176:             * @return true if inline constants will be mutated.
177:             */
178:            public boolean isInlineConstants() {
179:                return mInlineConstants;
180:            }
181:
182:            /**
183:             * Sets whether inline constants will be mutated.
184:             * 
185:             * @param argInlineConstants
186:             *          true if inline constants should be mutated.
187:             */
188:            public void setInlineConstants(final boolean argInlineConstants) {
189:                mInlineConstants = argInlineConstants;
190:            }
191:
192:            /**
193:             * Gets whether return values will be mutated.
194:             * 
195:             * @return true if return values will be mutated.
196:             */
197:            public boolean isReturnVals() {
198:                return mReturnVals;
199:            }
200:
201:            /**
202:             * Sets whether return values will be mutated.
203:             * 
204:             * @param argReturnVals
205:             *          true return values should be mutated.
206:             */
207:            public void setReturnVals(final boolean argReturnVals) {
208:                mReturnVals = argReturnVals;
209:            }
210:
211:            /**
212:             * Gets whether increments will be mutated.
213:             * 
214:             * @return true if increments will be mutated.
215:             */
216:            public boolean isIncrements() {
217:                return mIncrements;
218:            }
219:
220:            /**
221:             * Sets whether increments will be mutated.
222:             * 
223:             * @param argIncrements
224:             *          true if increments will be mutated.
225:             */
226:            public void setIncrements(final boolean argIncrements) {
227:                mIncrements = argIncrements;
228:            }
229:
230:            /**
231:             * Gets whether constant pool will be mutated.
232:             * 
233:             * @return true if constant pool will be mutated.
234:             */
235:            public boolean isCPool() {
236:                return mCPool;
237:            }
238:
239:            /**
240:             * Sets whether constant pool will be mutated.
241:             * 
242:             * @param cpool true if constants will be mutated.
243:             */
244:            public void setCPool(final boolean cpool) {
245:                mCPool = cpool;
246:            }
247:
248:            /**
249:             * Sets whether switches will be mutated.
250:             * 
251:             * @param switches true if switches will be mutated.
252:             */
253:            public void setSwitch(final boolean switches) {
254:                mSwitches = switches;
255:            }
256:
257:            /**
258:             * Gets whether switches will be mutated.
259:             * 
260:             * @return true if switches will be mutated.
261:             */
262:            public boolean isSwitch() {
263:                return mSwitches;
264:            }
265:
266:            /**
267:             * Gets whether tests are ordered by their run time.
268:             * 
269:             * @return true if tests are ordered by their run time.
270:             */
271:            public boolean isOrdered() {
272:                return mOrdered;
273:            }
274:
275:            /**
276:             * Sets whether tests are ordered by their run time.
277:             * 
278:             * @param argOrdered true if tests should be ordered by their run time.
279:             */
280:            public void setOrdered(final boolean argOrdered) {
281:                mOrdered = argOrdered;
282:            }
283:
284:            /**
285:             * Gets the value of loadCache
286:             * 
287:             * @return the value of loadCache
288:             */
289:            public boolean isLoadCache() {
290:                return mLoadCache;
291:            }
292:
293:            /**
294:             * Sets the value of loadCache
295:             * 
296:             * @param argLoadCache
297:             *          Value to assign to loadCache
298:             */
299:            public void setLoadCache(final boolean argLoadCache) {
300:                mLoadCache = argLoadCache;
301:            }
302:
303:            /**
304:             * Gets the value of saveCache
305:             * 
306:             * @return the value of saveCache
307:             */
308:            public boolean isSaveCache() {
309:                return mSaveCache;
310:            }
311:
312:            /**
313:             * Sets the value of saveCache
314:             * 
315:             * @param argSaveCache
316:             *          Value to assign to saveCache
317:             */
318:            public void setSaveCache(final boolean argSaveCache) {
319:                mSaveCache = argSaveCache;
320:            }
321:
322:            /**
323:             * Gets the value of useCache
324:             * 
325:             * @return the value of useCache
326:             */
327:            public boolean isUseCache() {
328:                return mUseCache;
329:            }
330:
331:            /**
332:             * Sets the value of useCache
333:             * 
334:             * @param argUseCache
335:             *          Value to assign to useCache
336:             */
337:            public void setUseCache(final boolean argUseCache) {
338:                mUseCache = argUseCache;
339:            }
340:
341:            /**
342:             * Gets the set of excluded method names
343:             * 
344:             * @return the set of excluded method names
345:             */
346:            public Set<String> getExcludeMethods() {
347:                return mExcludeMethods;
348:            }
349:
350:            /**
351:             * A function which computes the timeout for given that the original test took
352:             * <CODE>runtime</CODE>
353:             * 
354:             * @param runtime
355:             *          the original runtime
356:             * @return the computed timeout
357:             */
358:            public static long computeTimeout(long runtime) {
359:                return runtime * 10 + 2000;
360:            }
361:
362:            private void initCache() throws Exception {
363:                boolean loaded = false;
364:
365:                // Load the cache if it exists and is needed
366:                if (mLoadCache) {
367:                    try {
368:                        ObjectInputStream ois = new ObjectInputStream(
369:                                new FileInputStream(CACHE_FILE));
370:                        mCache = (FailedTestMap) ois.readObject();
371:                        loaded = true;
372:                    } catch (IOException e) {
373:                        loaded = false;
374:                    }
375:                }
376:                if (!loaded) {
377:                    mCache = new FailedTestMap();
378:                }
379:            }
380:
381:            private void updateCache(MutationResult mutation) {
382:                if (mutation.isPassed()) {
383:                    StringTokenizer tokens = new StringTokenizer(mutation
384:                            .getTestDescription(), ":");
385:                    String clazzName = tokens.nextToken();
386:                    assert clazzName.equals(mutation.getClassName());
387:                    String methodName = tokens.nextToken();
388:                    int mutPoint = Integer.parseInt(tokens.nextToken());
389:                    String testName = tokens.nextToken();
390:                    mCache
391:                            .addFailure(clazzName, methodName, mutPoint,
392:                                    testName);
393:                }
394:            }
395:
396:            private boolean writeCache(File f) {
397:                try {
398:                    if (f.exists()) {
399:                        f.delete();
400:                    }
401:                    ObjectOutputStream o = new ObjectOutputStream(
402:                            new FileOutputStream(f));
403:                    o.writeObject(mCache);
404:                    o.close();
405:                    return true;
406:                } catch (IOException e) {
407:                    e.printStackTrace();
408:                    return false;
409:                }
410:            }
411:
412:            public void addExcludeMethod(String methodName) {
413:                mExcludeMethods.add(methodName);
414:            }
415:
416:            public void addJvmArg(String arg) {
417:                if (arg == null) {
418:                    throw new NullPointerException();
419:                }
420:                mJvmArgs.add(arg);
421:            }
422:
423:            public void addSystemProperty(String property) {
424:                if (property == null) {
425:                    throw new NullPointerException();
426:                }
427:                int pos = property.indexOf('=');
428:                if (pos == -1) {
429:                    throw new IllegalArgumentException(
430:                            "Malformed property definition, expected name=value");
431:                }
432:                System.setProperty(property.substring(0, pos), property
433:                        .substring(pos + 1));
434:                mJvmArgs.add("-D" + property);
435:            }
436:
437:            /** Constructs arguments to the FastJumbler */
438:            private String[] createArgs(int currentMutation, int max) {
439:                ArrayList<String> args = new ArrayList<String>();
440:                args.add("--" + FastJumbler.FLAG_CLASSPATH);
441:                args.add(mClassPath);
442:
443:                // mutation point
444:                args.add("--" + FastJumbler.FLAG_START);
445:                args.add(String.valueOf(currentMutation));
446:
447:                // class name
448:                args.add(mClassName);
449:                // test suite filename
450:                args.add(mTestSuiteFile.toString());
451:
452:                if (mUseCache) {
453:                    // Write a temp cache
454:                    if (writeCache(mCacheFile)) {
455:                        args.add(mCacheFile.toString());
456:                    }
457:                }
458:
459:                // exclude methods
460:                if (!mExcludeMethods.isEmpty()) {
461:                    StringBuffer ex = new StringBuffer();
462:                    Iterator it = mExcludeMethods.iterator();
463:                    for (int i = 0; i < mExcludeMethods.size(); i++) {
464:                        if (i == 0) {
465:                            ex.append(it.next());
466:                        } else {
467:                            ex.append("," + it.next());
468:                        }
469:                    }
470:                    args.add("--" + FastJumbler.FLAG_EXCLUDE);
471:                    args.add(ex.toString());
472:                }
473:                // inline constants
474:                if (mInlineConstants) {
475:                    args.add("--" + FastJumbler.FLAG_INLINE_CONSTS);
476:                }
477:                // return values
478:                if (mReturnVals) {
479:                    args.add("--" + FastJumbler.FLAG_RETURN_VALS);
480:                }
481:                // increments
482:                if (mIncrements) {
483:                    args.add("--" + FastJumbler.FLAG_INCREMENTS);
484:                }
485:                // constant pool
486:                if (mCPool) {
487:                    args.add("--" + FastJumbler.FLAG_CPOOL);
488:                }
489:                // switches
490:                if (mSwitches) {
491:                    args.add("--" + FastJumbler.FLAG_SWITCHES);
492:                }
493:                // verbose
494:                if (mVerbose) {
495:                    args.add("--" + FastJumbler.FLAG_VERBOSE);
496:                }
497:
498:                if (max >= 0) {
499:                    args.add("--" + FastJumbler.FLAG_LENGTH);
500:                    args.add("" + max);
501:                }
502:                return args.toArray(new String[args.size()]);
503:            }
504:
505:            private Mutater createMutater(int mutationpoint) {
506:                // Get the number of mutation points from the Jumbler
507:                final Mutater m = new Mutater(mutationpoint);
508:                m.setIgnoredMethods(mExcludeMethods);
509:                m.setMutateIncrements(mIncrements);
510:                m.setMutateCPool(mCPool);
511:                m.setMutateSwitch(mSwitches);
512:                m.setMutateInlineConstants(mInlineConstants);
513:                m.setMutateReturnValues(mReturnVals);
514:                return m;
515:            }
516:
517:            private int countMutationPoints(MutatingClassLoader loader,
518:                    String classname) throws ClassNotFoundException {
519:                return loader.countMutationPoints(classname);
520:            }
521:
522:            private boolean debugOutput(String out, String err) {
523:                if (err != null) {
524:                    System.err.println("Child.err->" + err);
525:                }
526:                if (out != null) {
527:                    System.err.println("Child.out->" + out);
528:                }
529:                return true; // So we can be enabled/disabled via assertion mechanism.
530:            }
531:
532:            private void waitForStart(IOThread iot, IOThread eot)
533:                    throws InterruptedException {
534:                // read the "START" to let us know the JVM has started
535:                // we don't want to time this.
536:                // FIXME this looks dangerous. What if the test can't even get to the point
537:                // of outputting START (e.g. class loading issues)
538:                while (true) {
539:                    String out = iot.getNext();
540:                    String err = eot.getAvailable();
541:                    if (mVerbose) {
542:                        debugOutput(out, err);
543:                    }
544:                    if ((out == null) && (err == null)) {
545:                        Thread.sleep(10);
546:                    } else if (FastJumbler.SIGNAL_START.equals(out)) {
547:                        break;
548:                    } else {
549:                        throw new RuntimeException(
550:                                "com.reeltwo.jumble.fast.FastJumbler returned "
551:                                        + ((out != null) ? out : err
552:                                                + " on stderr")
553:                                        + " instead of "
554:                                        + FastJumbler.SIGNAL_START);
555:                    }
556:                }
557:            }
558:
559:            private void startChildProcess(String[] args) throws IOException,
560:                    InterruptedException {
561:                JavaRunner runner = getJavaRunner();
562:                runner.setArguments(args);
563:                mChildProcess = runner.start();
564:                mIot = new IOThread(mChildProcess.getInputStream());
565:                mIot.setDaemon(true);
566:                mIot.start();
567:                mEot = new IOThread(mChildProcess.getErrorStream());
568:                mEot.setDaemon(true);
569:                mEot.start();
570:                waitForStart(mIot, mEot);
571:            }
572:
573:            /** Reads a mutation result from the child process */
574:            private MutationResult readMutation(int currentMutation,
575:                    long timeout) throws InterruptedException {
576:                long before = System.currentTimeMillis();
577:                long after = before;
578:                String modification = null;
579:                // Run until we have a result or time out
580:                while (true) {
581:                    String out = mIot.getNext();
582:                    if (mVerbose) {
583:                        debugOutput(out, mEot.getAvailable());
584:                    }
585:                    if (out == null) {
586:                        if (after - before > timeout) {
587:                            mChildProcess.destroy();
588:                            mChildProcess = null;
589:                            return new MutationResult(MutationResult.TIMEOUT,
590:                                    mClassName, currentMutation, modification);
591:                        } else {
592:                            Thread.sleep(50);
593:                            after = System.currentTimeMillis();
594:                        }
595:                    } else {
596:                        if (out.startsWith(FastJumbler.SIGNAL_MAX_REACHED)) {
597:                            return null; // Child JVM requested continuing in a new JVM
598:                        } else if (out.startsWith(FastJumbler.INIT_PREFIX)) {
599:                            modification = out
600:                                    .substring(FastJumbler.INIT_PREFIX.length());
601:                        } else {
602:                            MutationResult m = null;
603:                            if (out.startsWith(FastJumbler.PASS_PREFIX)) {
604:                                m = new MutationResult(MutationResult.PASS,
605:                                        mClassName, currentMutation,
606:                                        modification,
607:                                        out.substring(FastJumbler.PASS_PREFIX
608:                                                .length()));
609:                            } else if (out.startsWith(FastJumbler.FAIL_PREFIX)) {
610:                                m = new MutationResult(MutationResult.FAIL,
611:                                        mClassName, currentMutation,
612:                                        modification);
613:                            }
614:                            if (m != null) {
615:                                if (mUseCache) {
616:                                    updateCache(m);
617:                                }
618:                                return m;
619:                            }
620:                        }
621:                    }
622:                }
623:            }
624:
625:            /**
626:             * Runs tests without mutating at all. If all OK, write out testsuitefile for
627:             * later use, otherwise return a JumbleResult
628:             */
629:            private JumbleResult runInitialTests(List<String> testClassNames) {
630:
631:                //System.err.println("Using classpath: " + mClassPath);
632:                MutatingClassLoader jumbler = new MutatingClassLoader(
633:                        mClassName, createMutater(-1), mClassPath);
634:                ClassLoader oldLoader = Thread.currentThread()
635:                        .getContextClassLoader();
636:                Thread.currentThread().setContextClassLoader(jumbler);
637:                try {
638:
639:                    mMutationCount = countMutationPoints(jumbler, mClassName);
640:                    if (mMutationCount == -1) {
641:                        return new InterfaceResult(mClassName);
642:                    }
643:                    TimingTestSuite suite = null;
644:                    try {
645:                        suite = new TimingTestSuite(jumbler, testClassNames
646:                                .toArray(new String[testClassNames.size()]));
647:                    } catch (ClassNotFoundException e) {
648:                        // test class did not exist
649:                        return new MissingTestsTestResult(mClassName,
650:                                testClassNames, mMutationCount);
651:                    }
652:                    //System.err.println("Parent. Starting initial run without mutating");
653:
654:                    JUnitTestResult result = new JUnitTestResult();
655:                    suite.run(result);
656:                    boolean successful = result.wasSuccessful();
657:                    //System.err.println("Parent. Finished");
658:
659:                    // Now, if the tests failed, can return straight away
660:                    if (!successful) {
661:                        if (mVerbose) {
662:                            System.err.println(result);
663:                        }
664:                        return new BrokenTestsTestResult(mClassName,
665:                                testClassNames, mMutationCount);
666:                    }
667:
668:                    // Set the test runtime so we can calculate timeouts when running the
669:                    // mutated tests
670:                    mTotalRuntime = suite.getTotalRuntime();
671:
672:                    // Store the test suite information serialized in a temporary file so
673:                    // FastJumbler can load it.
674:                    Object order = suite.getOrder(mOrdered);
675:                    ObjectOutputStream oos = new ObjectOutputStream(
676:                            new FileOutputStream(mTestSuiteFile));
677:                    oos.writeObject(order);
678:                    oos.close();
679:
680:                    // Now try the tests again in a separate JVM to detect if there
681:                    // are problems due to invocation within a separate JVM.
682:                    mChildProcess = null;
683:                    mIot = null;
684:                    mEot = null;
685:                    startChildProcess(createArgs(-1, 1));
686:                    MutationResult this Result = readMutation(-1,
687:                            computeTimeout(mTotalRuntime));
688:                    if (mChildProcess != null) {
689:                        mChildProcess = null;
690:                    }
691:                    if (this Result == null) {
692:                        // This is a problem due to unknown reasons
693:                        System.err
694:                                .println("WARNING: Child JVM requested restart before completing any mutations!!");
695:                    } else if (this Result.getStatus() == MutationResult.PASS) {
696:                        // This is a problem, we expect a run without any mutations to look like a fail (i.e. all tests pass)
697:                        if (mVerbose) {
698:                            System.err
699:                                    .println("Problem jumbling: Tests failed when running unmutated in external JVM!");
700:                        }
701:                        return new BrokenTestsTestResult(mClassName,
702:                                testClassNames, mMutationCount);
703:                    }
704:
705:                } catch (RuntimeException e) {
706:                    throw e;
707:                } catch (Exception e) {
708:                    RuntimeException r = new IllegalStateException(
709:                            "Problem using reflection to set up run under another classloader");
710:                    r.initCause(e);
711:                    throw r;
712:                } finally {
713:                    Thread.currentThread().setContextClassLoader(oldLoader);
714:                }
715:
716:                return null;
717:            }
718:
719:            /**
720:             * Performs a Jumble run on the specified class with the specified tests.
721:             * 
722:             * @param className
723:             *          the name of the class to Jumble
724:             * @param testClassNames
725:             *          the names of the associated test classes
726:             * @param listener
727:             *          the listener associated with this Jumble run.
728:             * @throws Exception
729:             *           if something goes wrong
730:             * @see JumbleResult
731:             * @see JumbleListener
732:             */
733:            public void runJumble(final String className,
734:                    final List<String> testClassNames, JumbleListener listener)
735:                    throws Exception {
736:                runJumbleProxy(className, testClassNames, listener);
737:            }
738:
739:            /**
740:             * Goes through class names to find out if they can be resolved. Also checks
741:             * that all declared test classes are actually test cases.
742:             * 
743:             * @param out
744:             *          listener where the error is reported.
745:             * @param className
746:             *          name of the class being jumbled.
747:             * @param testClassNames
748:             *          list of test class names.
749:             * @return
750:             */
751:            private boolean checkClasses(JumbleListener out, String className,
752:                    List<String> testClassNames) {
753:                boolean ok = true;
754:
755:                try {
756:                    MutatingClassLoader jumbler = new MutatingClassLoader(
757:                            mClassName, createMutater(-1), mClassPath);
758:                    Class clazz = jumbler.loadClass(className);
759:                    if (!clazz.isInterface()) {
760:                        for (int i = 0; i < testClassNames.size(); i++) {
761:                            String testName = testClassNames.get(i);
762:                            Class test = null;
763:                            try {
764:                                test = jumbler.loadClass(testName);
765:                            } catch (ClassNotFoundException e) {
766:                                ; // Do nothing. No test class is handled elswhere
767:                            }
768:                            if (test != null && !JumbleUtils.isTestClass(test)) {
769:                                out.error(testName + " is not a test class.");
770:                                ok = false;
771:                            }
772:                        }
773:                    }
774:                } catch (ClassNotFoundException e) {
775:                    out.error("Class " + className + " not found.");
776:                    ok = false;
777:                }
778:
779:                return ok;
780:            }
781:
782:            /**
783:             * Performs a Jumble run on the specified class with the specified tests.
784:             * 
785:             * @param className
786:             *          the name of the class to Jumble
787:             * @param testClassNames
788:             *          the names of the associated test classes
789:             * @param listener
790:             *          the listener associated with this Jumble run.
791:             * @return the results of the Jumble run
792:             * @throws Exception
793:             *           if something goes wrong
794:             * @see JumbleResult
795:             * @see JumbleListener
796:             */
797:            private JumbleResult runJumbleProxy(final String className,
798:                    final List<String> testClassNames, JumbleListener listener)
799:                    throws Exception {
800:                if (listener == null) {
801:                    listener = new NullListener();
802:                }
803:
804:                if (!checkClasses(listener, className, testClassNames)) {
805:                    return null;
806:                }
807:
808:                mClassName = className;
809:                mCacheFile = File.createTempFile("cache", ".dat");
810:                mTestSuiteFile = File.createTempFile("testSuite", ".dat");
811:
812:                if (mUseCache) {
813:                    initCache();
814:                }
815:
816:                listener.jumbleRunStarted(mClassName, testClassNames);
817:
818:                JumbleResult initialResult = runInitialTests(testClassNames);
819:                if (initialResult != null) {
820:                    listener
821:                            .performedInitialTest(initialResult, mMutationCount);
822:                    // Jumbling will not happen here
823:                    listener.jumbleRunEnded();
824:                    return initialResult;
825:                }
826:
827:                // compute the timeout
828:                long timeout = computeTimeout(mTotalRuntime);
829:
830:                listener.performedInitialTest(new InitialOKJumbleResult(
831:                        className, testClassNames, timeout), mMutationCount);
832:
833:                mChildProcess = null;
834:                mIot = null;
835:                mEot = null;
836:
837:                final MutationResult[] allMutations = new MutationResult[mMutationCount];
838:                int count = 0;
839:                final int max = getMaxExternalMutations();
840:                for (int currentMutation = getFirstMutation(); currentMutation < mMutationCount; currentMutation++) {
841:                    if (mChildProcess == null) {
842:                        startChildProcess(createArgs(currentMutation, max));
843:                        count = 0;
844:                    }
845:                    MutationResult this Result = readMutation(currentMutation,
846:                            timeout);
847:                    if (this Result == null) {
848:                        mChildProcess = null;
849:                        if (count == 0) {
850:                            System.err
851:                                    .println("WARNING: Child JVM requested restart before completing any mutations!!");
852:                        } else {
853:                            // Restart current mutation in a new JVM
854:                            currentMutation--;
855:                        }
856:                    } else {
857:                        allMutations[currentMutation] = this Result;
858:                        count++;
859:                        if (max >= 0 && count >= max) {
860:                            mChildProcess = null;
861:                        }
862:                        listener.finishedMutation(this Result);
863:                    }
864:                }
865:                if (mChildProcess != null) {
866:                    mChildProcess = null;
867:                }
868:
869:                JumbleResult ret = new NormalJumbleResult(className,
870:                        testClassNames, allMutations, timeout);
871:
872:                // finally, delete the test suite file
873:                if (mTestSuiteFile.exists() && !mTestSuiteFile.delete()) {
874:                    System.err
875:                            .println("Error: could not delete temporary file");
876:                }
877:                // Also delete the temporary cache and save the cache if needed
878:                if (mUseCache) {
879:                    if (mCacheFile.exists() && !mCacheFile.delete()) {
880:                        System.err
881:                                .println("Error: could not delete temporary cache file "
882:                                        + mCacheFile);
883:                    }
884:                    if (mSaveCache) {
885:                        writeCache(CACHE_FILE);
886:                    }
887:                }
888:                listener.jumbleRunEnded();
889:                mCache = null;
890:                return ret;
891:            }
892:
893:            /**
894:             * Gets the maximum number of mutations performed by the external JVM.
895:             * 
896:             * @return the maximum number of external mutations. A negative value implies
897:             *         no maximum.
898:             */
899:            public int getMaxExternalMutations() {
900:                return mMaxExternalMutations;
901:            }
902:
903:            /**
904:             * Sets the maximum number of mutations performed by the external JVM.
905:             * 
906:             * @param maxExternalMutations
907:             *          the maximum number of external mutations. A negative value implies
908:             *          no maximum.
909:             */
910:            public void setMaxExternalMutations(int maxExternalMutations) {
911:                mMaxExternalMutations = maxExternalMutations;
912:            }
913:
914:            /**
915:             * Get the index of the first mutation to attempt.
916:             *
917:             * @return the first mutation index.
918:             */
919:            public int getFirstMutation() {
920:                return mFirstMutation;
921:            }
922:
923:            /**
924:             * Set the index of the first mutation to attempt.
925:             *
926:             * @param newFirstMutation the new FirstMutation value.
927:             */
928:            public void setFirstMutation(final int newFirstMutation) {
929:                mFirstMutation = newFirstMutation;
930:            }
931:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.