mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
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:
@ -40,6 +40,8 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
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.actions.tables.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
@ -57,6 +59,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantSett
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantsUtil;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ObjectUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeSupplier;
|
||||
@ -138,7 +142,7 @@ public abstract class AbstractBaseFilesystemAction<FILE>
|
||||
**
|
||||
** @throws FilesystemException if the delete is known to have failed, and the file is thought to still exit
|
||||
*******************************************************************************/
|
||||
public abstract void deleteFile(QInstance instance, QTableMetaData table, String fileReference) throws FilesystemException;
|
||||
public abstract void deleteFile(QTableMetaData table, String fileReference) throws FilesystemException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Move a file from a source path, to a destination path.
|
||||
@ -285,7 +289,7 @@ public abstract class AbstractBaseFilesystemAction<FILE>
|
||||
QueryOutput queryOutput = new QueryOutput(queryInput);
|
||||
|
||||
String requestedPath = null;
|
||||
QQueryFilter filter = queryInput.getFilter();
|
||||
QQueryFilter filter = queryInput.getFilter();
|
||||
if(filter != null && tableDetails.getCardinality().equals(Cardinality.ONE))
|
||||
{
|
||||
if(filter.getCriteria() != null && filter.getCriteria().size() == 1)
|
||||
@ -670,4 +674,57 @@ public abstract class AbstractBaseFilesystemAction<FILE>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected DeleteOutput executeDelete(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
preAction(deleteInput.getBackend());
|
||||
|
||||
DeleteOutput output = new DeleteOutput();
|
||||
output.setRecordsWithErrors(new ArrayList<>());
|
||||
|
||||
QTableMetaData table = deleteInput.getTable();
|
||||
QBackendMetaData backend = deleteInput.getBackend();
|
||||
|
||||
AbstractFilesystemTableBackendDetails tableDetails = getTableBackendDetails(AbstractFilesystemTableBackendDetails.class, table);
|
||||
if(tableDetails.getCardinality().equals(Cardinality.ONE))
|
||||
{
|
||||
int deletedCount = 0;
|
||||
for(Serializable primaryKey : deleteInput.getPrimaryKeys())
|
||||
{
|
||||
try
|
||||
{
|
||||
deleteFile(table, stripDuplicatedSlashes(getFullBasePath(table, backend) + "/" + primaryKey));
|
||||
deletedCount++;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
String message = ObjectUtils.tryElse(() -> ExceptionUtils.getRootException(e).getMessage(), "Message not available");
|
||||
output.addRecordWithError(new QRecord().withValue(table.getPrimaryKeyField(), primaryKey).withError(new SystemErrorStatusMessage("Error deleting file: " + message)));
|
||||
}
|
||||
}
|
||||
output.setDeletedRecordCount(deletedCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new NotImplementedException("Delete is not implemented for filesystem tables with cardinality: " + tableDetails.getCardinality()));
|
||||
}
|
||||
|
||||
return (output);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new QException("Error executing delete: " + e.getMessage(), e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
postAction();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ public class AbstractFilesystemAction extends AbstractBaseFilesystemAction<File>
|
||||
** @throws FilesystemException if the delete is known to have failed, and the file is thought to still exit
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void deleteFile(QInstance instance, QTableMetaData table, String fileReference) throws FilesystemException
|
||||
public void deleteFile(QTableMetaData table, String fileReference) throws FilesystemException
|
||||
{
|
||||
File file = new File(fileReference);
|
||||
if(!file.exists())
|
||||
|
@ -26,13 +26,12 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class FilesystemDeleteAction implements DeleteInterface
|
||||
public class FilesystemDeleteAction extends AbstractFilesystemAction implements DeleteInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
@ -40,21 +39,19 @@ public class FilesystemDeleteAction implements DeleteInterface
|
||||
*******************************************************************************/
|
||||
public DeleteOutput execute(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
throw new NotImplementedException("Filesystem delete not implemented");
|
||||
/*
|
||||
try
|
||||
{
|
||||
DeleteResult rs = new DeleteResult();
|
||||
QTableMetaData table = deleteRequest.getTable();
|
||||
return (executeDelete(deleteInput));
|
||||
}
|
||||
|
||||
|
||||
// return rs;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new QException("Error executing delete: " + e.getMessage(), e);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's update action can & should fetch
|
||||
** records before updating them, e.g., for audits or "not-found-checks"
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public boolean supportsPreFetchQuery()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class BasicETLCleanupSourceFilesStep implements BackendStep
|
||||
if(VALUE_DELETE.equals(moveOrDelete))
|
||||
{
|
||||
LOG.info("Deleting ETL source file: " + sourceFile);
|
||||
actionBase.deleteFile(QContext.getQInstance(), table, sourceFile);
|
||||
actionBase.deleteFile(table, sourceFile);
|
||||
}
|
||||
else if(VALUE_MOVE.equals(moveOrDelete))
|
||||
{
|
||||
|
@ -319,7 +319,7 @@ public class FilesystemImporterStep implements BackendStep
|
||||
{
|
||||
String fullBasePath = sourceActionBase.getFullBasePath(sourceTable, sourceBackend);
|
||||
LOG.info("Removing source file", logPair("path", fullBasePath + "/" + sourceFileName), logPair("sourceTable", sourceTable.getName()));
|
||||
sourceActionBase.deleteFile(QContext.getQInstance(), sourceTable, fullBasePath + "/" + sourceFileName);
|
||||
sourceActionBase.deleteFile(sourceTable, fullBasePath + "/" + sourceFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
@ -247,9 +248,9 @@ public class AbstractS3Action extends AbstractBaseFilesystemAction<S3ObjectSumma
|
||||
** @throws FilesystemException if the delete is known to have failed, and the file is thought to still exit
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void deleteFile(QInstance instance, QTableMetaData table, String fileReference) throws FilesystemException
|
||||
public void deleteFile(QTableMetaData table, String fileReference) throws FilesystemException
|
||||
{
|
||||
QBackendMetaData backend = instance.getBackend(table.getBackendName());
|
||||
QBackendMetaData backend = QContext.getQInstance().getBackend(table.getBackendName());
|
||||
String bucketName = ((S3BackendMetaData) backend).getBucketName();
|
||||
String cleanedPath = stripLeadingSlash(stripDuplicatedSlashes(fileReference));
|
||||
|
||||
|
@ -26,13 +26,12 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class S3DeleteAction implements DeleteInterface
|
||||
public class S3DeleteAction extends AbstractS3Action implements DeleteInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
@ -40,21 +39,19 @@ public class S3DeleteAction implements DeleteInterface
|
||||
*******************************************************************************/
|
||||
public DeleteOutput execute(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
throw new NotImplementedException("S3 delete not implemented");
|
||||
/*
|
||||
try
|
||||
{
|
||||
DeleteResult rs = new DeleteResult();
|
||||
QTableMetaData table = deleteRequest.getTable();
|
||||
return (executeDelete(deleteInput));
|
||||
}
|
||||
|
||||
|
||||
// return rs;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new QException("Error executing delete: " + e.getMessage(), e);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's update action can & should fetch
|
||||
** records before updating them, e.g., for audits or "not-found-checks"
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public boolean supportsPreFetchQuery()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -340,9 +340,16 @@ public class AbstractSFTPAction extends AbstractBaseFilesystemAction<SFTPDirEntr
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void deleteFile(QInstance instance, QTableMetaData table, String fileReference) throws FilesystemException
|
||||
public void deleteFile(QTableMetaData table, String fileReference) throws FilesystemException
|
||||
{
|
||||
throw (new QRuntimeException("Not yet implemented"));
|
||||
try
|
||||
{
|
||||
sftpClient.remove(fileReference);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new FilesystemException("Error deleting file from SFTP", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,13 +26,12 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SFTPDeleteAction implements DeleteInterface
|
||||
public class SFTPDeleteAction extends AbstractSFTPAction implements DeleteInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
@ -40,21 +39,19 @@ public class SFTPDeleteAction implements DeleteInterface
|
||||
*******************************************************************************/
|
||||
public DeleteOutput execute(DeleteInput deleteInput) throws QException
|
||||
{
|
||||
throw new NotImplementedException("SFTP delete not implemented");
|
||||
/*
|
||||
try
|
||||
{
|
||||
DeleteResult rs = new DeleteResult();
|
||||
QTableMetaData table = deleteRequest.getTable();
|
||||
return (executeDelete(deleteInput));
|
||||
}
|
||||
|
||||
|
||||
// return rs;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new QException("Error executing delete: " + e.getMessage(), e);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's update action can & should fetch
|
||||
** records before updating them, e.g., for audits or "not-found-checks"
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public boolean supportsPreFetchQuery()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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(),
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user