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