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.ReportEntry;
23  import org.apache.maven.surefire.report.RunListener;
24  import org.apache.maven.surefire.report.SimpleReportEntry;
25  import org.apache.maven.surefire.report.TestSetReportEntry;
26  
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Map;
30  import java.util.concurrent.ConcurrentLinkedQueue;
31  import java.util.concurrent.atomic.AtomicBoolean;
32  import java.util.concurrent.atomic.AtomicInteger;
33  
34  import static org.apache.maven.surefire.util.internal.ObjectUtils.systemProps;
35  
36  /**
37   * * Represents the test-state of a testset that is run.
38   */
39  public class TestSet
40  {
41      private static final InheritableThreadLocal<TestSet> TEST_SET = new InheritableThreadLocal<>();
42  
43      private final String testClassName;
44  
45      private final Collection<TestMethod> testMethods = new ConcurrentLinkedQueue<>();
46  
47      private final AtomicBoolean played = new AtomicBoolean();
48  
49      private final AtomicInteger numberOfCompletedChildren = new AtomicInteger();
50  
51      // While the two parameters may seem duplicated, it is not entirely the case,
52      // since numberOfTests has the correct value from the start, while testMethods grows as method execution starts.
53  
54      private final AtomicInteger numberOfTests = new AtomicInteger();
55  
56      private volatile boolean allScheduled;
57  
58      public TestSet( String testClassName )
59      {
60          this.testClassName = testClassName;
61      }
62  
63      public void replay( RunListener target )
64      {
65          if ( played.compareAndSet( false, true ) )
66          {
67              try
68              {
69                  TestSetReportEntry report = createReportEntryStarted();
70  
71                  target.testSetStarting( report );
72  
73                  long startTime = 0;
74                  long endTime = 0;
75                  for ( TestMethod testMethod : testMethods )
76                  {
77                      if ( startTime == 0 || testMethod.getStartTime() < startTime )
78                      {
79                          startTime = testMethod.getStartTime();
80                      }
81  
82                      if ( endTime == 0 || testMethod.getEndTime() > endTime )
83                      {
84                          endTime = testMethod.getEndTime();
85                      }
86  
87                      testMethod.replay( target );
88                  }
89  
90                  int elapsed = (int) ( endTime - startTime );
91  
92                  report = createReportEntryCompleted( elapsed );
93  
94                  target.testSetCompleted( report );
95              }
96              catch ( Exception e )
97              {
98                  throw new RuntimeException( e );
99              }
100         }
101     }
102 
103     public TestMethod createThreadAttachedTestMethod( ReportEntry description )
104     {
105         TestMethod testMethod = new TestMethod( description, this );
106         addTestMethod( testMethod );
107         testMethod.attachToThread();
108         return testMethod;
109     }
110 
111     private TestSetReportEntry createReportEntryStarted()
112     {
113         return createReportEntry( null, Collections.<String, String>emptyMap() );
114     }
115 
116     private TestSetReportEntry createReportEntryCompleted( int elapsed )
117     {
118         return createReportEntry( elapsed, systemProps() );
119     }
120 
121     private TestSetReportEntry createReportEntry( Integer elapsed, Map<String, String> systemProps )
122     {
123         return new SimpleReportEntry( testClassName, null, testClassName, null, null, elapsed, systemProps );
124     }
125 
126     public void incrementTestMethodCount()
127     {
128         numberOfTests.incrementAndGet();
129     }
130 
131     private void addTestMethod( TestMethod testMethod )
132     {
133         testMethods.add( testMethod );
134     }
135 
136     public void incrementFinishedTests( RunListener reporterManager, boolean reportImmediately )
137     {
138         numberOfCompletedChildren.incrementAndGet();
139         if ( allScheduled && isAllTestsDone() && reportImmediately )
140         {
141             replay( reporterManager );
142         }
143     }
144 
145     public void setAllScheduled( RunListener reporterManager )
146     {
147         allScheduled = true;
148         if ( isAllTestsDone() )
149         {
150             replay( reporterManager );
151         }
152     }
153 
154     private boolean isAllTestsDone()
155     {
156         return numberOfTests.get() == numberOfCompletedChildren.get();
157     }
158 
159     public void attachToThread()
160     {
161         TEST_SET.set( this );
162     }
163 
164     public static TestSet getThreadTestSet()
165     {
166         return TEST_SET.get();
167     }
168 }