Skip to content

Commit

Permalink
feature: Reports retention by date
Browse files Browse the repository at this point in the history
  • Loading branch information
giulong committed Dec 25, 2024
1 parent beddefa commit b6926a8
Show file tree
Hide file tree
Showing 8 changed files with 487 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ void cleanupOldReportsIn(final String folder) {
return;
}

retention.deleteOldArtifactsFrom(List.of(folderContent), this);
retention.deleteArtifactsFrom(List.of(folderContent), this);
}

ExtentColor getColorOf(final Status status) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
Expand Down Expand Up @@ -94,6 +97,10 @@ public Path delete(final Path path) {
return path;
}

public Path delete(final File file) {
return delete(file.toPath());
}

@SneakyThrows
public Path deleteContentOf(final Path directory) {
return Files.createDirectories(delete(directory));
Expand Down Expand Up @@ -125,4 +132,9 @@ public String sanitize(final String name) {

return stringBuilder.toString();
}

@SneakyThrows
public FileTime getCreationTimeOf(final File file) {
return Files.readAttributes(file.toPath(), BasicFileAttributes.class).creationTime();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static java.lang.Integer.MAX_VALUE;
import static java.lang.Math.clamp;
import static java.lang.Math.max;
import static java.time.ZoneId.systemDefault;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.Comparator.comparing;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.partitioningBy;

@Slf4j
@Getter
Expand All @@ -25,31 +33,61 @@ public class Retention {

@SuppressWarnings("FieldMayBeFinal")
@JsonPropertyDescription("Number of reports to retain. Older ones will be deleted")
private int total = Integer.MAX_VALUE;
private int total = MAX_VALUE;

@SuppressWarnings("unused")
@JsonPropertyDescription("Number of successful reports to retain. Older ones will be deleted")
private int successful;

public void deleteOldArtifactsFrom(final List<File> files, final CanProduceMetadata metadataProducer) {
final int currentCount = files.size();
final int toKeep = clamp(total, 0, currentCount);
final int toDelete = max(0, currentCount - toKeep);
final FixedSizeQueue<File> successfulQueue = metadataManager.getSuccessfulQueueOf(metadataProducer);
@SuppressWarnings("FieldMayBeFinal")
@JsonPropertyDescription("Number of days after which reports will be deleted")
private int days = MAX_VALUE;

log.debug("Reports to keep: total {}, successful {}. Reports already present: {} -> {} will be kept, {} will be deleted",
total, successful, currentCount, toKeep, toDelete);
public void deleteArtifactsFrom(final List<File> files, final CanProduceMetadata metadataProducer) {
final FixedSizeQueue<File> successfulQueue = metadataManager.getSuccessfulQueueOf(metadataProducer);
final int successfulLimit = max(0, successful);

log.debug("Finding at most {} successful files among {}", successfulLimit, files.size());
final List<File> successfulFilesToKeep = files
.stream()
.filter(file -> successfulQueue.contains(file.getAbsoluteFile()))
.limit(successful)
.limit(successfulLimit)
.toList();

files
final int successfulToKeep = successfulFilesToKeep.size();
final int remainingTotalToKeep = max(0, total - successfulToKeep);
final Map<Boolean, List<File>> partitionedFiles = files
.stream()
.filter(not(successfulFilesToKeep::contains))
.limit(toDelete)
.forEach(file -> log.trace("File '{}' deleted? {}", file, fileUtils.delete(file.toPath())));
.sorted(comparing(fileUtils::getCreationTimeOf))
.collect(partitioningBy(this::isOld));

final List<File> youngFiles = partitionedFiles.get(false);

log.debug("Deleting young artifacts. Successful to keep: {}, Among {}, at most {} will be kept", successfulToKeep, youngFiles.size(), remainingTotalToKeep);
deleteFrom(youngFiles, remainingTotalToKeep);

log.debug("Deleting all remaining old artifacts");
deleteFrom(partitionedFiles.get(true), 0);
}

void deleteFrom(final List<File> files, final int maxToKeep) {
final int size = files.size();
final int toKeep = clamp(maxToKeep, 0, size);
final int toDelete = size - toKeep;

log.debug("Files are {}. {} will be kept, {} will be deleted", size, toKeep, toDelete);
files.stream().limit(toDelete).forEach(fileUtils::delete);
}

boolean isOld(final File file) {
final FileTime creationTime = fileUtils.getCreationTimeOf(file);
final LocalDateTime dateTime = LocalDateTime.ofInstant(creationTime.toInstant(), systemDefault());
final LocalDateTime today = LocalDateTime.now();
final long difference = DAYS.between(dateTime, today);
final boolean old = difference >= days;

log.debug("Report '{}' with date {} was generated {} days ago. Retention days are {}. Is it old? {}", file, dateTime, difference, days, old);
return old;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.Arrays;
import java.util.List;

import static java.util.Comparator.comparingLong;
import static java.util.function.Predicate.not;

@Slf4j
Expand Down Expand Up @@ -63,10 +62,9 @@ public void cleanupOldReports() {
.stream(folderContent)
.filter(not(File::isDirectory))
.filter(file -> file.getName().endsWith(extension))
.sorted(comparingLong(File::lastModified))
.toList();

retention.deleteOldArtifactsFrom(files, this);
retention.deleteArtifactsFrom(files, this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ void sessionClosed() {
verify(extentReports).flush();

// cleanupOldReports
verify(retention).deleteOldArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
verify(retention).deleteArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
}

@Test
Expand Down Expand Up @@ -334,7 +334,7 @@ void sessionClosedOpenReport() throws IOException {
verify(extentReports).flush();

// cleanupOldReports
verify(retention).deleteOldArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
verify(retention).deleteArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
verify(desktop).open(file1);
}

Expand All @@ -345,7 +345,7 @@ void cleanupOldReportsIn() {

extentReporter.cleanupOldReportsIn(REPORT_FOLDER);

verify(retention).deleteOldArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
verify(retention).deleteArtifactsFrom(List.of(file1, file2, directory1, directory2), extentReporter);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Map;
import java.util.stream.Stream;

Expand All @@ -24,6 +27,21 @@

class FileUtilsTest {

@Mock
private BasicFileAttributes basicFileAttributes;

@Mock
private FileTime creationTime;

@Mock
private Path path;

@Mock
private Path parentPath;

@Mock
private File file;

@InjectMocks
private FileUtils fileUtils;

Expand Down Expand Up @@ -136,6 +154,17 @@ static Stream<Arguments> deleteValuesProvider() throws IOException {
arguments(Files.createTempDirectory("downloadsFolder"), true));
}

@Test
@DisplayName("overloaded delete that takes a file should delegate to the one taking its path")
void deleteFile() throws IOException {
final File directory = Files.createTempDirectory("downloadsFolder").toFile();
directory.deleteOnExit();

assertEquals(directory.toPath(), fileUtils.delete(directory));

assertFalse(directory.exists());
}

@DisplayName("delete should delete the provided directory, recreate it, and return the reference to it")
@ParameterizedTest(name = "with value {0} which is existing? {1}")
@MethodSource("deleteValuesProvider")
Expand All @@ -152,9 +181,6 @@ void deleteContentOf(final Path directory, final boolean existing) {
@DisplayName("write should write the provided content to a file in the provided path, creating the parent folders if needed")
void write() {
final MockedStatic<Files> filesMockedStatic = mockStatic(Files.class);
final Path path = mock();
final Path parentPath = mock();
final File file = mock();
final String content = "content";

when(path.getParent()).thenReturn(parentPath);
Expand All @@ -174,9 +200,6 @@ void writeString() {
final MockedStatic<Files> filesMockedStatic = mockStatic(Files.class);
final MockedStatic<Path> pathMockedStatic = mockStatic(Path.class);
final String stringPath = "stringPath";
final Path path = mock();
final Path parentPath = mock();
final File file = mock();
final String content = "content";

when(Path.of(stringPath)).thenReturn(path);
Expand All @@ -200,4 +223,18 @@ void sanitize() {

assertEquals(sanitizedName, fileUtils.sanitize(name));
}

@Test
@DisplayName("getCreationTimeOf should return the creation time of the provided file")
void getCreationTimeOf() throws IOException {
final MockedStatic<Files> filesMockedStatic = mockStatic(Files.class);

when(file.toPath()).thenReturn(path);
when(Files.readAttributes(path, BasicFileAttributes.class)).thenReturn(basicFileAttributes);
when(basicFileAttributes.creationTime()).thenReturn(creationTime);

assertEquals(creationTime, fileUtils.getCreationTimeOf(file));

filesMockedStatic.close();
}
}
Loading

0 comments on commit b6926a8

Please sign in to comment.