1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.surefire.report;
20
21 import java.io.BufferedOutputStream;
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.FilterOutputStream;
25 import java.io.IOException;
26 import java.io.UncheckedIOException;
27 import java.nio.charset.Charset;
28 import java.util.concurrent.atomic.AtomicStampedReference;
29
30 import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
31 import org.apache.maven.surefire.api.report.ReportEntry;
32 import org.apache.maven.surefire.api.report.TestOutputReportEntry;
33 import org.apache.maven.surefire.api.report.TestSetReportEntry;
34
35 import static org.apache.maven.plugin.surefire.report.FileReporter.getReportFile;
36 import static org.apache.maven.surefire.api.util.internal.StringUtils.NL;
37
38
39
40
41
42
43
44 public class ConsoleOutputFileReporter implements TestcycleConsoleOutputReceiver {
45 private static final int STREAM_BUFFER_SIZE = 64 * 1024;
46 private static final int OPEN = 0;
47 private static final int CLOSED_TO_REOPEN = 1;
48 private static final int CLOSED = 2;
49
50 private final File reportsDirectory;
51 private final String reportNameSuffix;
52 private final boolean usePhrasedFileName;
53 private final Integer forkNumber;
54 private final String encoding;
55
56 private final AtomicStampedReference<FilterOutputStream> fileOutputStream =
57 new AtomicStampedReference<>(null, OPEN);
58
59 private volatile String reportEntryName;
60
61 public ConsoleOutputFileReporter(
62 File reportsDirectory,
63 String reportNameSuffix,
64 boolean usePhrasedFileName,
65 Integer forkNumber,
66 String encoding) {
67 this.reportsDirectory = reportsDirectory;
68 this.reportNameSuffix = reportNameSuffix;
69 this.usePhrasedFileName = usePhrasedFileName;
70 this.forkNumber = forkNumber;
71 this.encoding = encoding;
72 }
73
74 @Override
75 public synchronized void testSetStarting(TestSetReportEntry reportEntry) {
76 closeNullReportFile(reportEntry);
77 }
78
79 @Override
80 public void testSetCompleted(TestSetReportEntry report) {}
81
82 @Override
83 public synchronized void close() {
84
85 closeReportFile();
86 }
87
88 @Override
89 public synchronized void writeTestOutput(TestOutputReportEntry reportEntry) {
90 try {
91
92
93 int[] status = new int[1];
94 FilterOutputStream os = fileOutputStream.get(status);
95 if (status[0] != CLOSED) {
96 if (os == null) {
97 if (!reportsDirectory.exists()) {
98
99 reportsDirectory.mkdirs();
100 }
101 File file = getReportFile(reportsDirectory, reportEntryName, reportNameSuffix, "-output.txt");
102 os = new BufferedOutputStream(new FileOutputStream(file), STREAM_BUFFER_SIZE);
103 fileOutputStream.set(os, OPEN);
104 }
105 String output = reportEntry.getLog();
106 if (output == null) {
107 output = "null";
108 }
109 Charset charset = Charset.forName(encoding);
110 os.write(output.getBytes(charset));
111 if (reportEntry.isNewLine()) {
112 os.write(NL.getBytes(charset));
113 }
114 }
115 } catch (IOException e) {
116 dumpException(e);
117 throw new UncheckedIOException(e);
118 }
119 }
120
121 @SuppressWarnings("checkstyle:emptyblock")
122 private void closeNullReportFile(ReportEntry reportEntry) {
123 try {
124
125 close(true);
126 } catch (IOException e) {
127 dumpException(e);
128 } finally {
129
130 reportEntryName = usePhrasedFileName ? reportEntry.getSourceText() : reportEntry.getSourceName();
131 }
132 }
133
134 @SuppressWarnings("checkstyle:emptyblock")
135 private void closeReportFile() {
136 try {
137 close(false);
138 } catch (IOException e) {
139 dumpException(e);
140 }
141 }
142
143 private void close(boolean closeReattempt) throws IOException {
144 int[] status = new int[1];
145 FilterOutputStream os = fileOutputStream.get(status);
146 if (status[0] != CLOSED) {
147 fileOutputStream.set(null, closeReattempt ? CLOSED_TO_REOPEN : CLOSED);
148 if (os != null && status[0] == OPEN) {
149 os.close();
150 }
151 }
152 }
153
154 private void dumpException(IOException e) {
155 if (forkNumber == null) {
156 InPluginProcessDumpSingleton.getSingleton().dumpException(e, e.getLocalizedMessage(), reportsDirectory);
157 } else {
158 InPluginProcessDumpSingleton.getSingleton()
159 .dumpException(e, e.getLocalizedMessage(), reportsDirectory, forkNumber);
160 }
161 }
162 }