Skip to content

Commit

Permalink
FilesInDatasetCache
Browse files Browse the repository at this point in the history
  • Loading branch information
janvanmansum committed Dec 6, 2024
1 parent 89642d8 commit d7a4352
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private void moveFiles() throws IOException, DataverseException {
log.debug("Start moving files {} for deposit {}", editFiles.getMoveFiles().size(), depositId);
for (var move : editFiles.getMoveFiles()) {
var fileMeta = filesInDatasetCache.get(move.getFrom());
fileMeta = filesInDatasetCache.getMovedFile(move.getTo(), fileMeta);
fileMeta = filesInDatasetCache.createFileMetaForMovedFile(move.getTo(), fileMeta);
dataverseService.updateFileMetadata(fileMeta.getDataFile().getId(), fileMeta);
filesInDatasetCache.remove(move.getFrom());
filesInDatasetCache.put(fileMeta); // auto-rename is done by getMovedFile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@

/**
* <p>
* Keeps track of the FileMeta objects of files in a dataset. The cache is initialized by downloading the files from the dataset. If you try to initialize the cache again, an IllegalStateException is
* thrown. The client is responsible for adding, removing, and updating the cache.
* Keeps track of the FileMeta objects of files in a dataset. The cache is initialized by downloading the files from the dataset.
* </p>
*/
@Slf4j
Expand Down Expand Up @@ -72,30 +71,39 @@ public void put(@NonNull FileMeta fileMeta) {
filesInDataset.put(getPath(fileMeta), fileMeta);
}

public FileMeta getMovedFile(@NonNull String toPath, @NonNull FileMeta fileMeta) {
/**
* A move operation is in fact a file metadata update operation in which the directory label and label are updated. This method allows to calculate the file metadata for the moved file in the
* dataset. The filepath will be auto-renamed if it is in the renamedFiles map, so the local path from the bag is used.
*
* @param toPath new filepath before auto-rename
* @param fileMeta the FileMeta object for the file in the dataset after the move
* @return the FileMeta object for the moved file in the dataset
*/
public FileMeta createFileMetaForMovedFile(@NonNull String toPath, @NonNull FileMeta fileMeta) {
var newPath = autoRenamePath(toPath);
var dataversePath = new DataversePath(newPath);
fileMeta.setDirectoryLabel(dataversePath.getDirectoryLabel());
fileMeta.setLabel(dataversePath.getLabel());
return fileMeta;
}

private String autoRename(@NonNull FileMeta fileMeta) {
var filepath = getPath(fileMeta);
var renamedFilepath = autoRenamedFiles.get(filepath);
if (renamedFilepath != null) {
filepath = renamedFilepath;
var dataversePath = new DataversePath(renamedFilepath);
fileMeta.setDirectoryLabel(dataversePath.getDirectoryLabel());
fileMeta.setLabel(dataversePath.getLabel());
}
return filepath;
}

/**
* Removes the FileMeta object for the given filepath. The filepath will be auto-renamed if it is in the renamedFiles map, so the local path from the bag is used.
*
* @param filepath before auto-rename
*/
public void remove(@NonNull String filepath) {
filesInDataset.remove(autoRenamePath(filepath));
}

/**
* Download the file metadata from the dataset with the given persistent identifier, initializing the cache. This method can only be called once. Subsequent calls will throw an exception.
*
* @param pid the persistent identifier of the dataset
* @throws IOException if an I/O error occurs
* @throws DataverseException if the Dataverse API returns an error
* @throws IllegalStateException if the cache is already initialized
*/
public void downloadFromDataset(@NonNull String pid) throws IOException, DataverseException {
if (initialized) {
throw new IllegalStateException("Cache already initialized");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,6 @@ public void deleteFiles_throws_exception_when_file_not_found() throws Exception
.hasMessage("File to delete not found in dataset: file4");
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2024 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.dvingest.core.bagprocessor;

import nl.knaw.dans.dvingest.core.service.DataverseService;
import nl.knaw.dans.lib.dataverse.model.file.FileMeta;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class FilesInDatasetCacheNonNullTest {
private final DataverseService dataverseServiceMock = Mockito.mock(DataverseService.class);

@Test
public void constructor_throws_exception_when_dataverseService_is_null() {
assertThatThrownBy(() -> new FilesInDatasetCache(null, Map.of()))
.isInstanceOf(NullPointerException.class);
}

@Test
public void constructor_throws_exception_when_autoRenamedFiles_is_null() {
assertThatThrownBy(() -> new FilesInDatasetCache(dataverseServiceMock, null))
.isInstanceOf(NullPointerException.class);
}

@Test
public void get_throws_exception_when_filepath_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
assertThatThrownBy(() -> filesInDatasetCache.get(null))
.isInstanceOf(NullPointerException.class);
}

@Test
public void put_throws_exception_when_fileMeta_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
assertThatThrownBy(() -> filesInDatasetCache.put(null))
.isInstanceOf(NullPointerException.class);
}

@Test
public void createFileMetaForMovedFile_throws_exception_when_toPath_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
var fileMeta = new FileMeta();
assertThatThrownBy(() -> filesInDatasetCache.createFileMetaForMovedFile(null, fileMeta))
.isInstanceOf(NullPointerException.class);
}

@Test
public void createFileMetaForMovedFile_throws_exception_when_fileMeta_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
assertThatThrownBy(() -> filesInDatasetCache.createFileMetaForMovedFile("path", null))
.isInstanceOf(NullPointerException.class);
}

@Test
public void remove_throws_exception_when_filepath_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
assertThatThrownBy(() -> filesInDatasetCache.remove(null))
.isInstanceOf(NullPointerException.class);
}

@Test
public void downloadFromDataset_throws_exception_when_pid_is_null() {
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
assertThatThrownBy(() -> filesInDatasetCache.downloadFromDataset(null))
.isInstanceOf(NullPointerException.class);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright (C) 2024 DANS - Data Archiving and Networked Services ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.knaw.dans.dvingest.core.bagprocessor;

import nl.knaw.dans.dvingest.core.service.DataverseService;
Expand All @@ -9,6 +24,7 @@
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class FilesInDatasetCacheTest {
private final DataverseService dataverseServiceMock = Mockito.mock(DataverseService.class);
Expand All @@ -34,19 +50,106 @@ public void get_returns_fileMeta_by_filepath() {
}

@Test
public void put_auto_renames_filepath() {
public void get_returns_null_for_nonexistent_filepath() {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());

// When
var result = filesInDatasetCache.get("nonexistent/filepath");

// Then
assertThat(result).isNull();
}

@Test
public void put_adds_fileMeta_to_cache() {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
var fileMeta = new FileMeta();
fileMeta.setLabel("label");
fileMeta.setDirectoryLabel("directoryLabel");

// When
filesInDatasetCache.put(fileMeta);

// Then
assertThat(filesInDatasetCache.get("directoryLabel/label")).isEqualTo(fileMeta);
}

@Test
public void remove_deletes_fileMeta_from_cache() {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
var fileMeta = new FileMeta();
fileMeta.setLabel("label");
fileMeta.setDirectoryLabel("directoryLabel");
filesInDatasetCache.put(fileMeta);

// When
filesInDatasetCache.remove("directoryLabel/label");

// Then
assertThat(filesInDatasetCache.get("directoryLabel/label")).isNull();
}

@Test
public void downloadFromDataset_initializes_cache() throws Exception {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of("directoryLabel/label", "newDirectoryLabel/newLabel"));
var fileMeta = new FileMeta();
fileMeta.setLabel("label");
fileMeta.setDirectoryLabel("directoryLabel");
Mockito.when(dataverseServiceMock.getFiles("pid")).thenReturn(java.util.List.of(fileMeta));
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());

// When
filesInDatasetCache.downloadFromDataset("pid");

// Then
assertThat(filesInDatasetCache.get("directoryLabel/label")).isEqualTo(fileMeta);
}

@Test
public void downloadFromDataset_throws_exception_if_already_initialized() throws Exception {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of());
filesInDatasetCache.downloadFromDataset("pid");

// When / Then
assertThatThrownBy(() -> filesInDatasetCache.downloadFromDataset("pid"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Cache already initialized");
}

@Test
public void createFileMetaForMovedFile_updates_fileMeta_with_new_path() {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of("oldPath/file.txt", "newPath/file.txt"));
var fileMeta = new FileMeta();
fileMeta.setLabel("file.txt");
fileMeta.setDirectoryLabel("oldPath");

// When
var updatedFileMeta = filesInDatasetCache.createFileMetaForMovedFile("newPath/file.txt", fileMeta);

// Then
assertThat(updatedFileMeta.getLabel()).isEqualTo("file.txt");
assertThat(updatedFileMeta.getDirectoryLabel()).isEqualTo("newPath");
}

@Test
public void get_returns_fileMeta_by_old_name_after_rename() {
// Given
var filesInDatasetCache = new FilesInDatasetCache(dataverseServiceMock, Map.of("oldPath/file.txt", "newPath/file.txt"));
var fileMeta = new FileMeta();
fileMeta.setLabel("file.txt");
fileMeta.setDirectoryLabel("newPath");
filesInDatasetCache.put(fileMeta);
var returnedFileMeta = filesInDatasetCache.get("newDirectoryLabel/newLabel");

// When
var result = filesInDatasetCache.get("oldPath/file.txt");

// Then
assertThat(returnedFileMeta).isEqualTo(fileMeta);
assertThat(result).isEqualTo(fileMeta);
}

}
}

0 comments on commit d7a4352

Please sign in to comment.