2222import org .slf4j .Logger ;
2323import org .slf4j .LoggerFactory ;
2424
25+ import java .io .DataOutput ;
26+ import java .io .DataOutputStream ;
2527import java .io .IOException ;
2628import java .io .InputStream ;
29+ import java .io .OutputStream ;
30+ import java .nio .channels .Channels ;
31+ import java .nio .channels .FileChannel ;
2732import java .nio .file .Files ;
2833import java .nio .file .Path ;
34+ import java .nio .file .StandardCopyOption ;
35+ import java .nio .file .StandardOpenOption ;
2936import java .util .Comparator ;
3037import java .util .Objects ;
3138import java .util .UUID ;
@@ -41,6 +48,12 @@ public class FileSystemResultsWriter implements AllureResultsWriter {
4148
4249 private static final Logger LOGGER = LoggerFactory .getLogger (FileSystemResultsWriter .class );
4350
51+ private static final String TEST_RESULT_ENTITY_NAME = "test result" ;
52+
53+ private static final String TEST_RESULT_CONTAINER_ENTITY_NAME = "test result container" ;
54+
55+ private static final String ATTACHMENT_ENTITY_NAME = "attachment" ;
56+
4457 private final Path outputDirectory ;
4558
4659 private final ObjectMapper mapper ;
@@ -84,13 +97,11 @@ public void write(final TestResult testResult) {
8497 final String testResultName = Objects .isNull (testResult .getUuid ())
8598 ? generateTestResultName ()
8699 : generateTestResultName (testResult .getUuid ());
87- ensureInitialized ();
88100 final Path file = outputDirectory .resolve (testResultName );
89- try {
90- mapper .writeValue (file .toFile (), testResult );
91- } catch (IOException e ) {
92- throw new AllureResultsWriteException ("Could not write Allure test result" , e );
93- }
101+ write (file , TEST_RESULT_ENTITY_NAME , channel -> {
102+ final DataOutput output = new DataOutputStream (Channels .newOutputStream (channel ));
103+ mapper .writeValue (output , testResult );
104+ });
94105 }
95106
96107 /**
@@ -101,26 +112,63 @@ public void write(final TestResultContainer testResultContainer) {
101112 final String testResultContainerName = Objects .isNull (testResultContainer .getUuid ())
102113 ? generateTestResultContainerName ()
103114 : generateTestResultContainerName (testResultContainer .getUuid ());
104- ensureInitialized ();
105115 final Path file = outputDirectory .resolve (testResultContainerName );
106- try {
107- mapper .writeValue (file .toFile (), testResultContainer );
108- } catch (IOException e ) {
109- throw new AllureResultsWriteException ("Could not write Allure test result container" , e );
110- }
116+ write (file , TEST_RESULT_CONTAINER_ENTITY_NAME , channel -> {
117+ final DataOutput output = new DataOutputStream (Channels .newOutputStream (channel ));
118+ mapper .writeValue (output , testResultContainer );
119+ });
111120 }
112121
113122 /**
114123 * {@inheritDoc}
115124 */
116125 @ Override
117126 public void write (final String source , final InputStream attachment ) {
118- ensureInitialized ();
119127 final Path file = outputDirectory .resolve (source );
120128 try (InputStream is = attachment ) {
121- Files .copy (is , file );
129+ write (file , ATTACHMENT_ENTITY_NAME , channel -> {
130+ final OutputStream output = Channels .newOutputStream (channel );
131+ is .transferTo (output );
132+ });
133+ } catch (IOException e ) {
134+ throw new AllureResultsWriteException (getErrorMessage (ATTACHMENT_ENTITY_NAME ), e );
135+ }
136+ }
137+
138+ private void write (final Path file , final String entityName , final ChannelConsumer consumer ) {
139+ ensureInitialized ();
140+ Path tempFile = null ;
141+ try {
142+ tempFile = Files .createTempFile (outputDirectory , ".allure-write-" , ".tmp" );
143+ try (FileChannel channel = FileChannel .open (tempFile , StandardOpenOption .WRITE )) {
144+ consumer .accept (channel );
145+ channel .force (true );
146+ }
147+ Files .move (tempFile , file , StandardCopyOption .REPLACE_EXISTING );
148+ tempFile = null ;
149+ } catch (IOException e ) {
150+ deleteIfExists (tempFile );
151+ throw new AllureResultsWriteException (getErrorMessage (entityName ), e );
152+ }
153+ }
154+
155+ private static String getErrorMessage (final String entityName ) {
156+ return "Could not write Allure " + entityName ;
157+ }
158+
159+ private interface ChannelConsumer {
160+
161+ void accept (FileChannel channel ) throws IOException ;
162+ }
163+
164+ private static void deleteIfExists (final Path file ) {
165+ if (Objects .isNull (file )) {
166+ return ;
167+ }
168+ try {
169+ Files .deleteIfExists (file );
122170 } catch (IOException e ) {
123- throw new AllureResultsWriteException ( "Could not write Allure attachment" , e );
171+ LOGGER . warn ( "Failed to delete temporary Allure result file {}" , file , e );
124172 }
125173 }
126174
0 commit comments