View Javadoc

1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.report.RunListener;
23  import org.apache.maven.surefire.report.ReportEntry;
24  import org.apache.maven.surefire.report.ReporterConfiguration;
25  import org.apache.maven.surefire.report.ReporterException;
26  import org.apache.maven.surefire.report.ReporterFactory;
27  import org.apache.maven.surefire.testset.TestSetFailedException;
28  
29  import java.io.IOException;
30  import java.util.Map;
31  
32  /**
33   * @author Kristian Rosenvold
34   */
35  public abstract class ConcurrentReporterManager
36      implements RunListener
37  {
38      private final Map<String, TestSet> classMethodCounts;
39  
40      private final ReporterConfiguration reporterConfiguration;
41  
42      private final ThreadLocal<RunListener> reporterManagerThreadLocal = new ThreadLocal<RunListener>();
43  
44      private final boolean reportImmediately;
45  
46      private final ConcurrentPrintStream out = new ConcurrentPrintStream( true );
47  
48      private final ConcurrentPrintStream err = new ConcurrentPrintStream( false );
49  
50      private final ReporterFactory reporterFactory;
51  
52      ConcurrentReporterManager( ReporterFactory reporterFactory, boolean reportImmediately,
53                                 ReporterConfiguration reporterConfiguration, Map<String, TestSet> classMethodCounts )
54          throws TestSetFailedException
55      {
56          this.reportImmediately = reportImmediately;
57          this.reporterFactory = reporterFactory;
58          this.reporterConfiguration = reporterConfiguration;
59          this.classMethodCounts = classMethodCounts;
60  
61          // We must create the first reporterManager here, even though we will never use it.
62          // There is some room for improvement here
63          this.reporterFactory.createReporter();
64          // Important: We must capture System.out/System.err AFTER the  reportManager captures stdout/stderr
65          // because we know how to demultiplex correctly. The redirection in reporterManager is basically
66          // ignored/unused because we use ConcurrentPrintStream.
67          System.setOut( out );
68          System.setErr( err );
69      }
70  
71      public void testSetStarting( ReportEntry description )
72      {
73      }
74  
75      public void testSetCompleted( ReportEntry result )
76          throws ReporterException
77      {
78          for ( TestSet testSet : classMethodCounts.values() )
79          {
80              testSet.replay( getReporterManager() );
81          }
82          try
83          {
84              out.writeTo( reporterConfiguration.getOriginalSystemOut() );
85              err.writeTo( reporterConfiguration.getOriginalSystemErr() );
86          }
87          catch ( IOException e )
88          {
89              throw new ReporterException( "When writing reports", e );
90          }
91      }
92  
93      public void testFailed( ReportEntry failure )
94      {
95          getOrCreateTestMethod( failure ).testFailure( failure );
96      }
97  
98      public void testError( ReportEntry failure )
99      {
100         getOrCreateTestMethod( failure ).testError( failure );
101     }
102 
103     public void testSkipped( ReportEntry description )
104     {
105         TestSet testSet = getTestSet( description );
106         TestMethod testMethod = getTestSet( description ).createTestMethod( description );
107         testMethod.testIgnored( description );
108         testSet.incrementFinishedTests( getReporterManager(), reportImmediately );
109     }
110 
111     public void testAssumptionFailure( ReportEntry failure )
112     {
113         getOrCreateTestMethod( failure ).testIgnored( failure );
114     }
115 
116     public void testStarting( ReportEntry description )
117     {
118         TestSet testSet = getTestSet( description );
119         final TestMethod testMethod = testSet.createTestMethod( description );
120         testMethod.attachToThread();
121 
122         checkIfTestSetCanBeReported( testSet );
123         testSet.attachToThread();
124     }
125 
126     public void testSucceeded( ReportEntry report )
127     {
128         getTestMethod().testFinished();
129         TestSet.getThreadTestSet().incrementFinishedTests( getReporterManager(), reportImmediately );
130         detachTestMethodFromThread();
131     }
132 
133     private TestMethod getOrCreateTestMethod( ReportEntry description )
134     {
135         TestMethod threadTestMethod = TestMethod.getThreadTestMethod();
136         if ( threadTestMethod != null )
137         {
138             return threadTestMethod;
139         }
140         TestSet testSet = getTestSet( description );
141         return testSet.createTestMethod( description );
142     }
143 
144     protected abstract void checkIfTestSetCanBeReported( TestSet testSetForTest );
145 
146     TestMethod getTestMethod()
147     {
148         return TestMethod.getThreadTestMethod();
149     }
150 
151     void detachTestMethodFromThread()
152     {
153         TestMethod.detachFromCurrentThread();
154     }
155 
156     TestSet getTestSet( ReportEntry description )
157     {
158         return classMethodCounts.get( description.getSourceName() );
159     }
160 
161     RunListener getReporterManager()
162     {
163         RunListener reporterManager = reporterManagerThreadLocal.get();
164         if ( reporterManager == null )
165         {
166             reporterManager = reporterFactory.createReporter();
167             reporterManagerThreadLocal.set( reporterManager );
168         }
169         return reporterManager;
170     }
171 
172     public static ConcurrentReporterManager createInstance( Map<String, TestSet> classMethodCounts,
173                                                             ReporterFactory reporterManagerFactory,
174                                                             ReporterConfiguration reporterConfiguration,
175                                                             boolean parallelClasses, boolean parallelBoth )
176         throws TestSetFailedException
177     {
178         if ( parallelClasses )
179         {
180             return new ClassesParallelRunListener( classMethodCounts, reporterManagerFactory, reporterConfiguration );
181         }
182         return new MethodsParallelRunListener( classMethodCounts, reporterManagerFactory, reporterConfiguration,
183                                                !parallelBoth );
184     }
185 
186 }