View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.junitcore;
20  
21  import java.util.concurrent.atomic.AtomicReference;
22  
23  import org.apache.maven.surefire.api.report.CategorizedReportEntry;
24  import org.apache.maven.surefire.api.report.ConsoleOutputReceiverForCurrentThread;
25  import org.apache.maven.surefire.api.report.ReportEntry;
26  import org.apache.maven.surefire.api.report.TestOutputReceiver;
27  import org.apache.maven.surefire.api.report.TestOutputReportEntry;
28  import org.apache.maven.surefire.api.report.TestReportListener;
29  
30  /**
31   * Represents the test-state of a single test method that is run.
32   * <br>
33   * Notes about thread safety: This instance is serially confined to 1-3 threads (construction, test-run, reporting),
34   * without any actual parallel access
35   */
36  @Deprecated // remove this class after StatelessXmlReporter is capable of parallel test sets processing
37  class TestMethod implements TestOutputReceiver<TestOutputReportEntry> {
38      private static final InheritableThreadLocal<TestMethod> TEST_METHOD = new InheritableThreadLocal<>();
39  
40      private final AtomicReference<LogicalStream> output = new AtomicReference<>();
41  
42      private final ReportEntry description;
43  
44      private final TestSet testSet;
45  
46      private final long startTime;
47  
48      private volatile long endTime;
49  
50      private volatile ReportEntry testFailure;
51  
52      private volatile ReportEntry testError;
53  
54      private volatile ReportEntry testIgnored;
55  
56      private volatile ReportEntry testAssumption;
57  
58      TestMethod(ReportEntry description, TestSet testSet) {
59          this.description = description;
60          this.testSet = testSet;
61          startTime = System.currentTimeMillis();
62      }
63  
64      void testFinished() {
65          setEndTime();
66      }
67  
68      void testIgnored(ReportEntry description) {
69          testIgnored = description;
70          setEndTime();
71      }
72  
73      void testFailure(ReportEntry failure) {
74          this.testFailure = failure;
75          setEndTime();
76      }
77  
78      void testError(ReportEntry failure) {
79          this.testError = failure;
80          setEndTime();
81      }
82  
83      void testAssumption(ReportEntry failure) {
84          this.testAssumption = failure;
85          setEndTime();
86      }
87  
88      private void setEndTime() {
89          this.endTime = System.currentTimeMillis();
90      }
91  
92      int getElapsed() {
93          return endTime > 0 ? (int) (endTime - startTime) : 0;
94      }
95  
96      long getStartTime() {
97          return startTime;
98      }
99  
100     long getEndTime() {
101         return endTime;
102     }
103 
104     void replay(TestReportListener<TestOutputReportEntry> reporter) {
105         if (testIgnored != null) {
106             reporter.testSkipped(createReportEntry(testIgnored));
107         } else {
108             ReportEntry descriptionReport = createReportEntry(description);
109             reporter.testStarting(descriptionReport);
110             LogicalStream ls = output.get();
111             if (ls != null) {
112                 ls.writeDetails(reporter);
113             }
114 
115             if (testFailure != null) {
116                 reporter.testFailed(createReportEntry(testFailure));
117             } else if (testError != null) {
118                 reporter.testError(createReportEntry(testError));
119             } else if (testAssumption != null) {
120                 reporter.testAssumptionFailure(createReportEntry(testAssumption));
121             } else {
122                 reporter.testSucceeded(descriptionReport);
123             }
124         }
125     }
126 
127     private ReportEntry createReportEntry(ReportEntry reportEntry) {
128         return new CategorizedReportEntry(
129                 reportEntry.getRunMode(),
130                 reportEntry.getTestRunId(),
131                 reportEntry.getSourceName(),
132                 reportEntry.getName(),
133                 reportEntry.getGroup(),
134                 reportEntry.getStackTraceWriter(),
135                 getElapsed(),
136                 reportEntry.getMessage());
137     }
138 
139     void attachToThread() {
140         TEST_METHOD.set(this);
141         ConsoleOutputReceiverForCurrentThread.set(this);
142     }
143 
144     void detachFromCurrentThread() {
145         TEST_METHOD.remove();
146         ConsoleOutputReceiverForCurrentThread.remove();
147     }
148 
149     static TestMethod getThreadTestMethod() {
150         return TEST_METHOD.get();
151     }
152 
153     LogicalStream getLogicalStream() {
154         LogicalStream ls = output.get();
155         if (ls == null) {
156             ls = new LogicalStream();
157             if (!output.compareAndSet(null, ls)) {
158                 ls = output.get();
159             }
160         }
161         return ls;
162     }
163 
164     @Override
165     public void writeTestOutput(TestOutputReportEntry reportEntry) {
166         getLogicalStream().write(reportEntry);
167     }
168 
169     TestSet getTestSet() {
170         return testSet;
171     }
172 }