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