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