Implement and test DeleteAction functionality

- Unified `deleteFile` API across storage modules by removing unused `QInstance` parameter.
- Added implementations for S3, SFTP, and local filesystem deleteAction.
This commit is contained in:
2025-02-20 14:29:08 -06:00
parent 44236f4309
commit d401cc9ae1
15 changed files with 259 additions and 73 deletions

View File

@ -165,7 +165,7 @@ public class FilesystemBackendModuleTest
List<File> filesBeforeDelete = new AbstractFilesystemAction().listFiles(table, qInstance.getBackendForTable(table.getName()));
FilesystemBackendModule filesystemBackendModule = new FilesystemBackendModule();
filesystemBackendModule.getActionBase().deleteFile(qInstance, table, filesBeforeDelete.get(0).getAbsolutePath());
filesystemBackendModule.getActionBase().deleteFile(table, filesBeforeDelete.get(0).getAbsolutePath());
List<File> filesAfterDelete = new AbstractFilesystemAction().listFiles(table, qInstance.getBackendForTable(table.getName()));
Assertions.assertEquals(filesBeforeDelete.size() - 1, filesAfterDelete.size(),
@ -191,7 +191,7 @@ public class FilesystemBackendModuleTest
List<File> filesBeforeDelete = new AbstractFilesystemAction().listFiles(table, qInstance.getBackendForTable(table.getName()));
FilesystemBackendModule filesystemBackendModule = new FilesystemBackendModule();
filesystemBackendModule.getActionBase().deleteFile(qInstance, table, PATH_THAT_WONT_EXIST);
filesystemBackendModule.getActionBase().deleteFile(table, PATH_THAT_WONT_EXIST);
List<File> filesAfterDelete = new AbstractFilesystemAction().listFiles(table, qInstance.getBackendForTable(table.getName()));
Assertions.assertEquals(filesBeforeDelete.size(), filesAfterDelete.size(),

View File

@ -22,11 +22,19 @@
package com.kingsrook.qqq.backend.module.filesystem.local.actions;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
import org.apache.commons.lang.NotImplementedException;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
@ -34,14 +42,25 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
*******************************************************************************/
public class FilesystemDeleteActionTest extends FilesystemActionTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
public void test() throws QException
public void testSuccessfulDeleteMultiple() throws QException
{
assertThrows(NotImplementedException.class, () -> new FilesystemDeleteAction().execute(new DeleteInput()));
int initialCount = new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_BLOB_LOCAL_FS)).getCount();
String filename1 = "A.txt";
String filename2 = "B.txt";
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_BLOB_LOCAL_FS).withRecords(List.of(
new QRecord().withValue("fileName", filename1).withValue("contents", "bytes"),
new QRecord().withValue("fileName", filename2).withValue("contents", "bytes"))));
assertEquals(initialCount + 2, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_BLOB_LOCAL_FS)).getCount());
DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(TestUtils.TABLE_NAME_BLOB_LOCAL_FS).withPrimaryKeys(List.of(filename1, filename2)));
assertEquals(2, deleteOutput.getDeletedRecordCount());
assertEquals(0, deleteOutput.getRecordsWithErrors().size());
assertEquals(initialCount, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_BLOB_LOCAL_FS)).getCount());
}
}

View File

@ -147,7 +147,7 @@ public class S3BackendModuleTest extends BaseS3Test
S3BackendModule s3BackendModule = new S3BackendModule();
AbstractS3Action actionBase = (AbstractS3Action) s3BackendModule.getActionBase();
actionBase.setS3Utils(getS3Utils());
actionBase.deleteFile(qInstance, table, s3ObjectSummariesBeforeDelete.get(0).getKey());
actionBase.deleteFile(table, s3ObjectSummariesBeforeDelete.get(0).getKey());
List<S3ObjectSummary> s3ObjectSummariesAfterDelete = getS3Utils().listObjectsInBucketMatchingGlob(BUCKET_NAME, TEST_FOLDER, "");
Assertions.assertEquals(s3ObjectSummariesBeforeDelete.size() - 1, s3ObjectSummariesAfterDelete.size(),
@ -176,7 +176,7 @@ public class S3BackendModuleTest extends BaseS3Test
AbstractS3Action actionBase = (AbstractS3Action) s3BackendModule.getActionBase();
actionBase.setS3Utils(getS3Utils());
String path = "//" + s3ObjectSummariesBeforeDelete.get(0).getKey().replaceAll("/", "//");
actionBase.deleteFile(qInstance, table, "//" + path);
actionBase.deleteFile(table, "//" + path);
List<S3ObjectSummary> s3ObjectSummariesAfterDelete = getS3Utils().listObjectsInBucketMatchingGlob(BUCKET_NAME, TEST_FOLDER, "");
Assertions.assertEquals(s3ObjectSummariesBeforeDelete.size() - 1, s3ObjectSummariesAfterDelete.size(),
@ -203,7 +203,7 @@ public class S3BackendModuleTest extends BaseS3Test
S3BackendModule s3BackendModule = new S3BackendModule();
AbstractS3Action actionBase = (AbstractS3Action) s3BackendModule.getActionBase();
actionBase.setS3Utils(getS3Utils());
actionBase.deleteFile(qInstance, table, PATH_THAT_WONT_EXIST);
actionBase.deleteFile(table, PATH_THAT_WONT_EXIST);
List<S3ObjectSummary> s3ObjectSummariesAfterDelete = getS3Utils().listObjectsInBucketMatchingGlob(BUCKET_NAME, TEST_FOLDER, "");
Assertions.assertEquals(s3ObjectSummariesBeforeDelete.size(), s3ObjectSummariesAfterDelete.size(),

View File

@ -22,12 +22,19 @@
package com.kingsrook.qqq.backend.module.filesystem.s3.actions;
import java.util.List;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
import org.apache.commons.lang.NotImplementedException;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
@ -42,7 +49,42 @@ public class S3DeleteActionTest extends BaseS3Test
@Test
public void test() throws QException
{
assertThrows(NotImplementedException.class, () -> new S3DeleteAction().execute(new DeleteInput()));
QInstance qInstance = TestUtils.defineInstance();
int initialCount = count(TestUtils.TABLE_NAME_BLOB_S3);
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_BLOB_S3);
insertInput.setRecords(List.of(
new QRecord().withValue("fileName", "file2.txt").withValue("contents", "Hi, Bob.")));
S3InsertAction insertAction = new S3InsertAction();
insertAction.setS3Utils(getS3Utils());
insertAction.execute(insertInput);
assertEquals(initialCount + 1, count(TestUtils.TABLE_NAME_BLOB_S3));
S3DeleteAction deleteAction = new S3DeleteAction();
deleteAction.setS3Utils(getS3Utils());
DeleteOutput deleteOutput = deleteAction.execute(new DeleteInput(TestUtils.TABLE_NAME_BLOB_S3).withPrimaryKeys(List.of("file2.txt")));
assertEquals(1, deleteOutput.getDeletedRecordCount());
assertEquals(0, deleteOutput.getRecordsWithErrors().size());
assertEquals(initialCount, count(TestUtils.TABLE_NAME_BLOB_S3));
}
/***************************************************************************
**
***************************************************************************/
private Integer count(String tableName) throws QException
{
CountInput countInput = new CountInput();
countInput.setTableName(tableName);
S3CountAction s3CountAction = new S3CountAction();
s3CountAction.setS3Utils(getS3Utils());
CountOutput countOutput = s3CountAction.execute(countInput);
return countOutput.getCount();
}
}

View File

@ -43,8 +43,8 @@ public class BaseSFTPTest extends BaseTest
public static final String TABLE_FOLDER = "files";
public static final String REMOTE_DIR = "/home/" + USERNAME + "/" + BACKEND_FOLDER + "/" + TABLE_FOLDER;
private static GenericContainer<?> sftpContainer;
private static Integer currentPort;
protected static GenericContainer<?> sftpContainer;
private static Integer currentPort;
@ -71,6 +71,7 @@ public class BaseSFTPTest extends BaseTest
}
/***************************************************************************
**
***************************************************************************/
@ -80,6 +81,7 @@ public class BaseSFTPTest extends BaseTest
}
/***************************************************************************
**
***************************************************************************/
@ -89,6 +91,7 @@ public class BaseSFTPTest extends BaseTest
}
/***************************************************************************
**
***************************************************************************/

View File

@ -22,12 +22,23 @@
package com.kingsrook.qqq.backend.module.filesystem.sftp.actions;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
import com.kingsrook.qqq.backend.module.filesystem.sftp.BaseSFTPTest;
import org.apache.commons.lang.NotImplementedException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
@ -35,14 +46,69 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
*******************************************************************************/
public class SFTPDeleteActionTest extends BaseSFTPTest
{
private String filesBasename = "delete-test-";
/*******************************************************************************
**
*******************************************************************************/
@BeforeEach
@AfterEach
void beforeAndAfterEach() throws Exception
{
rmrfInContainer(REMOTE_DIR + "/" + filesBasename + "*");
}
/*******************************************************************************
**
*******************************************************************************/
@Test
public void test() throws QException
public void testSuccessfulDeleteMultiple() throws QException
{
assertThrows(NotImplementedException.class, () -> new SFTPDeleteAction().execute(new DeleteInput()));
int initialCount = new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount();
String filename1 = filesBasename + "A.txt";
String filename2 = filesBasename + "B.txt";
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SFTP_FILE).withRecords(List.of(
new QRecord().withValue("fileName", filename1).withValue("contents", "bytes"),
new QRecord().withValue("fileName", filename2).withValue("contents", "bytes"))));
assertEquals(initialCount + 2, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount());
DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(TestUtils.TABLE_NAME_SFTP_FILE).withPrimaryKeys(List.of(filename1, filename2)));
assertEquals(2, deleteOutput.getDeletedRecordCount());
assertEquals(0, deleteOutput.getRecordsWithErrors().size());
assertEquals(initialCount, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
public void testFailedDelete() throws Exception
{
int initialCount = new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount();
String filename1 = filesBasename + "C.txt";
String filename2 = filesBasename + "D.txt";
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SFTP_FILE).withRecords(List.of(
new QRecord().withValue("fileName", filename1).withValue("contents", "bytes"),
new QRecord().withValue("fileName", filename2).withValue("contents", "bytes"))));
assertEquals(initialCount + 2, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount());
sftpContainer.execInContainer("chmod", "000", REMOTE_DIR);
DeleteOutput deleteOutput = new DeleteAction().execute(new DeleteInput(TestUtils.TABLE_NAME_SFTP_FILE).withPrimaryKeys(List.of(filename1, filename2)));
sftpContainer.execInContainer("chmod", "777", REMOTE_DIR);
assertEquals(0, deleteOutput.getDeletedRecordCount());
assertEquals(2, deleteOutput.getRecordsWithErrors().size());
assertThat(deleteOutput.getRecordsWithErrors().get(0).getErrorsAsString()).contains("Error deleting file: Permission denied");
assertThat(deleteOutput.getRecordsWithErrors().get(1).getErrorsAsString()).contains("Error deleting file: Permission denied");
assertEquals(initialCount + 2, new CountAction().execute(new CountInput(TestUtils.TABLE_NAME_SFTP_FILE)).getCount());
}
}