Skip to content

Commit d94943d

Browse files
add optional clean results before run (#1253)
1 parent 4e59632 commit d94943d

3 files changed

Lines changed: 140 additions & 4 deletions

File tree

allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,11 @@ private boolean isEmpty(final String s) {
640640
private static FileSystemResultsWriter getDefaultWriter() {
641641
final Properties properties = PropertiesUtils.loadAllureProperties();
642642
final String path = properties.getProperty("allure.results.directory", "allure-results");
643-
return new FileSystemResultsWriter(Paths.get(path));
643+
final boolean cleanBeforeRun = Boolean.parseBoolean(
644+
properties.getProperty("allure.results.clean.before.run", "false"));
645+
final boolean cleanOnlyOnce = Boolean.parseBoolean(
646+
properties.getProperty("allure.results.clean.only.once", "true"));
647+
return new FileSystemResultsWriter(Paths.get(path), cleanBeforeRun, cleanOnlyOnce);
644648
}
645649

646650
private static LifecycleNotifier getDefaultNotifier() {

allure-java-commons/src/main/java/io/qameta/allure/FileSystemResultsWriter.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,46 @@
1919
import io.qameta.allure.internal.Allure2ModelJackson;
2020
import io.qameta.allure.model.TestResult;
2121
import io.qameta.allure.model.TestResultContainer;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
2224

2325
import java.io.IOException;
2426
import java.io.InputStream;
2527
import java.nio.file.Files;
2628
import java.nio.file.Path;
29+
import java.util.Comparator;
2730
import java.util.Objects;
2831
import java.util.UUID;
32+
import java.util.stream.Stream;
33+
import java.util.concurrent.atomic.AtomicBoolean;
2934

3035
/**
3136
* @author charlie (Dmitry Baev).
3237
*/
3338
public class FileSystemResultsWriter implements AllureResultsWriter {
3439

40+
private static final Logger LOGGER = LoggerFactory.getLogger(FileSystemResultsWriter.class);
41+
3542
private final Path outputDirectory;
3643

3744
private final ObjectMapper mapper;
3845

46+
private final boolean cleanBeforeRun;
47+
48+
private final boolean cleanOnlyOnce;
49+
50+
private final AtomicBoolean cleaned = new AtomicBoolean(false);
51+
3952
public FileSystemResultsWriter(final Path outputDirectory) {
53+
this(outputDirectory, false, true);
54+
}
55+
56+
public FileSystemResultsWriter(final Path outputDirectory,
57+
final boolean cleanBeforeRun,
58+
final boolean cleanOnlyOnce) {
4059
this.outputDirectory = outputDirectory;
60+
this.cleanBeforeRun = cleanBeforeRun;
61+
this.cleanOnlyOnce = cleanOnlyOnce;
4162
this.mapper = Allure2ModelJackson.createMapper();
4263
}
4364

@@ -46,7 +67,7 @@ public void write(final TestResult testResult) {
4667
final String testResultName = Objects.isNull(testResult.getUuid())
4768
? generateTestResultName()
4869
: generateTestResultName(testResult.getUuid());
49-
createDirectories(outputDirectory);
70+
ensureInitialized();
5071
final Path file = outputDirectory.resolve(testResultName);
5172
try {
5273
mapper.writeValue(file.toFile(), testResult);
@@ -60,7 +81,7 @@ public void write(final TestResultContainer testResultContainer) {
6081
final String testResultContainerName = Objects.isNull(testResultContainer.getUuid())
6182
? generateTestResultContainerName()
6283
: generateTestResultContainerName(testResultContainer.getUuid());
63-
createDirectories(outputDirectory);
84+
ensureInitialized();
6485
final Path file = outputDirectory.resolve(testResultContainerName);
6586
try {
6687
mapper.writeValue(file.toFile(), testResultContainer);
@@ -71,7 +92,7 @@ public void write(final TestResultContainer testResultContainer) {
7192

7293
@Override
7394
public void write(final String source, final InputStream attachment) {
74-
createDirectories(outputDirectory);
95+
ensureInitialized();
7596
final Path file = outputDirectory.resolve(source);
7697
try (InputStream is = attachment) {
7798
Files.copy(is, file);
@@ -88,6 +109,35 @@ private void createDirectories(final Path directory) {
88109
}
89110
}
90111

112+
private void ensureInitialized() {
113+
createDirectories(outputDirectory);
114+
if (cleanBeforeRun) {
115+
final boolean shouldClean = !cleanOnlyOnce || cleaned.compareAndSet(false, true);
116+
if (shouldClean) {
117+
cleanDirectoryContents(outputDirectory);
118+
}
119+
}
120+
}
121+
122+
private void cleanDirectoryContents(final Path directory) {
123+
if (!Files.exists(directory)) {
124+
return;
125+
}
126+
try (Stream<Path> stream = Files.walk(directory)) {
127+
stream.sorted(Comparator.reverseOrder())
128+
.filter(path -> !path.equals(directory))
129+
.forEach(path -> {
130+
try {
131+
Files.deleteIfExists(path);
132+
} catch (IOException e) {
133+
LOGGER.warn("Failed to delete {} during directory cleanup", path, e);
134+
}
135+
});
136+
} catch (IOException e) {
137+
LOGGER.warn("Failed to clean directory contents: {}", directory, e);
138+
}
139+
}
140+
91141
protected static String generateTestResultName() {
92142
return generateTestResultName(UUID.randomUUID().toString());
93143
}

allure-java-commons/src/test/java/io/qameta/allure/FileSystemResultsWriterTest.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.junit.jupiter.api.Test;
2020
import org.junit.jupiter.api.io.TempDir;
2121

22+
import java.io.IOException;
23+
import java.nio.file.Files;
2224
import java.nio.file.Path;
2325
import java.util.UUID;
2426

@@ -53,4 +55,84 @@ void shouldWriteTestResult(@TempDir final Path folder) {
5355
assertThat(folder.resolve(fileName))
5456
.isRegularFile();
5557
}
58+
59+
@Test
60+
void shouldPreserveOldResultsWhenCleanIsDisabled(@TempDir final Path folder) throws IOException {
61+
Path existingFile = folder.resolve("existing-result.json");
62+
Files.writeString(existingFile, "{}");
63+
64+
FileSystemResultsWriter writer = new FileSystemResultsWriter(folder, false, true);
65+
final String uuid = UUID.randomUUID().toString();
66+
final TestResult testResult = current().nextObject(TestResult.class, "steps").setUuid(uuid);
67+
writer.write(testResult);
68+
69+
assertThat(existingFile).exists();
70+
assertThat(folder.resolve(generateTestResultName(uuid))).exists();
71+
}
72+
73+
@Test
74+
void shouldCleanDirectoryWhenCleanBeforeRunEnabled(@TempDir final Path folder) throws IOException {
75+
Path existingFile = folder.resolve("existing-result.json");
76+
Files.writeString(existingFile, "{}");
77+
78+
FileSystemResultsWriter writer = new FileSystemResultsWriter(folder, true, true);
79+
final String uuid = UUID.randomUUID().toString();
80+
final TestResult testResult = current().nextObject(TestResult.class, "steps").setUuid(uuid);
81+
writer.write(testResult);
82+
83+
assertThat(existingFile).doesNotExist();
84+
assertThat(folder.resolve(generateTestResultName(uuid))).exists();
85+
}
86+
87+
@Test
88+
void shouldCleanOnlyOnceWhenCleanOnlyOnceEnabled(@TempDir final Path folder) throws IOException {
89+
Path existingFile = folder.resolve("existing-result.json");
90+
Files.writeString(existingFile, "{}");
91+
92+
FileSystemResultsWriter writer = new FileSystemResultsWriter(folder, true, true);
93+
94+
final String uuid1 = UUID.randomUUID().toString();
95+
final TestResult testResult1 = current().nextObject(TestResult.class, "steps").setUuid(uuid1);
96+
writer.write(testResult1);
97+
98+
final String uuid2 = UUID.randomUUID().toString();
99+
final TestResult testResult2 = current().nextObject(TestResult.class, "steps").setUuid(uuid2);
100+
writer.write(testResult2);
101+
102+
assertThat(folder.resolve(generateTestResultName(uuid1))).exists();
103+
assertThat(folder.resolve(generateTestResultName(uuid2))).exists();
104+
}
105+
106+
@Test
107+
void shouldCleanOnEveryFirstWriteWhenCleanOnlyOnceDisabled(@TempDir final Path folder) throws IOException {
108+
FileSystemResultsWriter writer1 = new FileSystemResultsWriter(folder, true, false);
109+
final String uuid1 = UUID.randomUUID().toString();
110+
final TestResult testResult1 = current().nextObject(TestResult.class, "steps").setUuid(uuid1);
111+
writer1.write(testResult1);
112+
113+
Path intermediateFile = folder.resolve("intermediate-result.json");
114+
Files.writeString(intermediateFile, "{}");
115+
116+
FileSystemResultsWriter writer2 = new FileSystemResultsWriter(folder, true, false);
117+
final String uuid2 = UUID.randomUUID().toString();
118+
final TestResult testResult2 = current().nextObject(TestResult.class, "steps").setUuid(uuid2);
119+
writer2.write(testResult2);
120+
121+
assertThat(intermediateFile).doesNotExist();
122+
assertThat(folder.resolve(generateTestResultName(uuid2))).exists();
123+
}
124+
125+
@Test
126+
void shouldNotDeleteDirectoryItself(@TempDir final Path folder) throws IOException {
127+
Path existingFile = folder.resolve("existing-result.json");
128+
Files.writeString(existingFile, "{}");
129+
130+
FileSystemResultsWriter writer = new FileSystemResultsWriter(folder, true, true);
131+
final String uuid = UUID.randomUUID().toString();
132+
final TestResult testResult = current().nextObject(TestResult.class, "steps").setUuid(uuid);
133+
writer.write(testResult);
134+
135+
assertThat(folder).isDirectory();
136+
assertThat(folder.resolve(generateTestResultName(uuid))).exists();
137+
}
56138
}

0 commit comments

Comments
 (0)