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

@ -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();
}
}
}

View File

@ -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())

View File

@ -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);
}
}

View File

@ -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))
{

View File

@ -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
{

View File

@ -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));

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

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());
}
}