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.FilterOutputStream;
24 import java.io.IOException;
25 import java.io.UncheckedIOException;
26 import java.nio.charset.Charset;
27 import java.nio.file.Files;
28 import java.util.Map;
29 import java.util.concurrent.ConcurrentHashMap;
30
31 import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
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
47 private final File reportsDirectory;
48 private final String reportNameSuffix;
49 private final boolean usePhrasedFileName;
50 private final Integer forkNumber;
51 private final String encoding;
52
53 private final Map<String, FilterOutputStream> outputStreams = new ConcurrentHashMap<>();
54
55 private volatile String reportEntryName;
56
57 public ConsoleOutputFileReporter(
58 File reportsDirectory,
59 String reportNameSuffix,
60 boolean usePhrasedFileName,
61 Integer forkNumber,
62 String encoding) {
63 this.reportsDirectory = reportsDirectory;
64 this.reportNameSuffix = reportNameSuffix;
65 this.usePhrasedFileName = usePhrasedFileName;
66 this.forkNumber = forkNumber;
67 this.encoding = encoding;
68 }
69
70 @Override
71 public void testSetStarting(TestSetReportEntry reportEntry) {
72 String className = usePhrasedFileName ? reportEntry.getSourceText() : reportEntry.getSourceName();
73 reportEntryName = className;
74 try {
75 File file = getReportFile(reportsDirectory, className, reportNameSuffix, "-output.txt");
76 if (!reportsDirectory.exists()) {
77 Files.createDirectories(reportsDirectory.toPath());
78 }
79 if (!Files.exists(file.toPath())) {
80 Files.createFile(file.toPath());
81 }
82 outputStreams.put(
83 className, new BufferedOutputStream(Files.newOutputStream(file.toPath()), STREAM_BUFFER_SIZE));
84 } catch (IOException e) {
85 throw new RuntimeException(e);
86 }
87 }
88
89 @Override
90 public void testSetCompleted(TestSetReportEntry report) {}
91
92 @Override
93 public void close() {
94
95 for (FilterOutputStream stream : outputStreams.values()) {
96 try {
97 stream.close();
98 } catch (IOException e) {
99 dumpException(e);
100 }
101 }
102 }
103
104 @Override
105 public synchronized void writeTestOutput(TestOutputReportEntry reportEntry) {
106 try {
107
108 String targetClassName = extractTestClassFromStack(reportEntry.getStack());
109 if (targetClassName == null) {
110 targetClassName = reportEntryName;
111 }
112
113 if (targetClassName == null) {
114 targetClassName = "null";
115 }
116
117
118 FilterOutputStream os = outputStreams.computeIfAbsent(targetClassName, className -> {
119 try {
120 if (!reportsDirectory.exists()) {
121
122 reportsDirectory.mkdirs();
123 }
124 File file = getReportFile(reportsDirectory, className, reportNameSuffix, "-output.txt");
125 return new BufferedOutputStream(Files.newOutputStream(file.toPath()), STREAM_BUFFER_SIZE);
126 } catch (IOException e) {
127 dumpException(e);
128 throw new UncheckedIOException(e);
129 }
130 });
131
132 String output = reportEntry.getLog();
133 if (output == null) {
134 output = "null";
135 }
136 Charset charset = Charset.forName(encoding);
137 os.write(output.getBytes(charset));
138 if (reportEntry.isNewLine()) {
139 os.write(NL.getBytes(charset));
140 }
141 } catch (IOException e) {
142 dumpException(e);
143 throw new UncheckedIOException(e);
144 }
145 }
146
147
148
149
150
151
152 private String extractTestClassFromStack(String stack) {
153 if (stack == null || stack.isEmpty()) {
154 return null;
155 }
156
157
158 String[] entries = stack.split(";");
159 for (String entry : entries) {
160 int hashIndex = entry.indexOf('#');
161 if (hashIndex > 0) {
162 String className = entry.substring(0, hashIndex);
163 if (outputStreams.containsKey(className)) {
164 return className;
165 }
166 }
167 }
168 return null;
169 }
170
171 private void dumpException(IOException e) {
172 if (forkNumber == null) {
173 InPluginProcessDumpSingleton.getSingleton().dumpException(e, e.getLocalizedMessage(), reportsDirectory);
174 } else {
175 InPluginProcessDumpSingleton.getSingleton()
176 .dumpException(e, e.getLocalizedMessage(), reportsDirectory, forkNumber);
177 }
178 }
179 }