mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-21 14:38:43 +00:00
Compare commits
17 Commits
snapshot-f
...
snapshot-i
Author | SHA1 | Date | |
---|---|---|---|
d979c985f6 | |||
6c2c9b83ed | |||
d4df533f5d | |||
e89093f339 | |||
dd57a327dd | |||
107086094a | |||
4f896dde97 | |||
df397ee68c | |||
c452305a99 | |||
fe8af54ee5 | |||
ac37e3492b | |||
7160b87048 | |||
a30d8cb490 | |||
582d375597 | |||
687c5fce41 | |||
71302eefdf | |||
6524f19ff7 |
@ -102,14 +102,14 @@ jobs:
|
||||
mvn_test:
|
||||
executor: localstack/default
|
||||
steps:
|
||||
- localstack/startup
|
||||
## - localstack/startup
|
||||
- install_java17
|
||||
- mvn_verify
|
||||
|
||||
mvn_deploy:
|
||||
executor: localstack/default
|
||||
steps:
|
||||
- localstack/startup
|
||||
## - localstack/startup
|
||||
- install_java17
|
||||
- mvn_verify
|
||||
- mvn_jar_deploy
|
||||
|
@ -319,8 +319,10 @@ public class DMLAuditAction extends AbstractQActionFunction<DMLAuditInput, DMLAu
|
||||
|
||||
if(detailRecord != null)
|
||||
{
|
||||
LOG.debug("Returning with message: " + detailRecord.getValueString("message"));
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// useful if doing dev in here - but overkill for any other time. //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// LOG.debug("Returning with message: " + detailRecord.getValueString("message"));
|
||||
detailRecord.withValue("fieldName", fieldName);
|
||||
return (Optional.of(detailRecord));
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -55,7 +56,7 @@ public interface GetInterface
|
||||
{
|
||||
QTableMetaData table = getInput.getTable();
|
||||
boolean foundMatch = false;
|
||||
for(UniqueKey uniqueKey : table.getUniqueKeys())
|
||||
for(UniqueKey uniqueKey : CollectionUtils.nonNullList(table.getUniqueKeys()))
|
||||
{
|
||||
if(new HashSet<>(uniqueKey.getFieldNames()).equals(getInput.getUniqueKey().keySet()))
|
||||
{
|
||||
|
@ -28,6 +28,9 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.actions.audits.AuditAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLockFilters;
|
||||
@ -52,6 +55,41 @@ public class AuditSingleInput
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AuditSingleInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AuditSingleInput(QTableMetaData table, QRecord record, String auditMessage)
|
||||
{
|
||||
setAuditTableName(table.getName());
|
||||
setRecordId(record.getValueInteger(table.getPrimaryKeyField()));
|
||||
setSecurityKeyValues(AuditAction.getRecordSecurityKeyValues(table, record, Optional.empty()));
|
||||
setMessage(auditMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AuditSingleInput(String tableName, QRecord record, String auditMessage)
|
||||
{
|
||||
this(QContext.getQInstance().getTable(tableName), record, auditMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for auditTableName
|
||||
*******************************************************************************/
|
||||
|
@ -131,6 +131,17 @@ public class ProcessSummaryFilterLink implements ProcessSummaryLineInterface
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return getFullText();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for status
|
||||
**
|
||||
|
@ -182,6 +182,7 @@ public class ProcessSummaryLine implements ProcessSummaryLineInterface
|
||||
** Getter for message
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
|
@ -38,6 +38,10 @@ public interface ProcessSummaryLineInterface extends Serializable
|
||||
*******************************************************************************/
|
||||
Status getStatus();
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
String getMessage();
|
||||
|
||||
/*******************************************************************************
|
||||
** meant to be called by framework, after process is complete, give the
|
||||
|
@ -95,6 +95,17 @@ public class ProcessSummaryRecordLink implements ProcessSummaryLineInterface
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return getFullText();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -89,6 +89,34 @@ public class ExtractViaBasepullQueryStep extends ExtractViaQueryStep
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Let a subclass know if getQueryFilter will use the "default filter" (e.g., from
|
||||
** our base class, which would come from values passed in to the process), or if
|
||||
** the BasePull Query would be used (e.g., for a scheduled job).
|
||||
*******************************************************************************/
|
||||
protected boolean willTheBasePullQueryBeUsed(RunBackendStepInput runBackendStepInput)
|
||||
{
|
||||
try
|
||||
{
|
||||
super.getQueryFilter(runBackendStepInput);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if super.getQueryFilter returned - then - there's a default query to use (e.g., a user selecting rows on a screen). //
|
||||
// this means we won't use the BasePull query, so return a false here. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
return (false);
|
||||
}
|
||||
catch(QException qe)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if we catch here, assume that is because there was no default filter - in which case - we'll use the BasePull Query //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -35,8 +35,10 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
||||
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.actions.audits.AuditSingleInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
@ -73,18 +75,21 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
|
||||
private ProcessSummaryLine okToInsert = StandardProcessSummaryLineProducer.getOkToInsertLine();
|
||||
private ProcessSummaryLine okToUpdate = StandardProcessSummaryLineProducer.getOkToUpdateLine();
|
||||
|
||||
private ProcessSummaryLine willNotInsert = new ProcessSummaryLine(Status.INFO)
|
||||
.withMessageSuffix("because of this process' configuration.")
|
||||
.withSingularFutureMessage("will not be inserted ")
|
||||
.withPluralFutureMessage("will not be inserted ")
|
||||
.withSingularPastMessage("was not inserted ")
|
||||
.withPluralPastMessage("were not inserted ");
|
||||
|
||||
private ProcessSummaryLine willNotUpdate = new ProcessSummaryLine(Status.INFO)
|
||||
.withMessageSuffix("because of this process' configuration.")
|
||||
.withSingularFutureMessage("will not be updated ")
|
||||
.withPluralFutureMessage("will not be updated ")
|
||||
.withSingularPastMessage("was not updated ")
|
||||
.withPluralPastMessage("were not updated ");
|
||||
|
||||
private ProcessSummaryLine errorMissingKeyField = new ProcessSummaryLine(Status.ERROR)
|
||||
.withMessageSuffix("missing a value for the key field.")
|
||||
.withSingularFutureMessage("will not be synced, because it is ")
|
||||
@ -92,7 +97,15 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
.withSingularPastMessage("was not synced, because it is ")
|
||||
.withPluralPastMessage("were not synced, because they are ");
|
||||
|
||||
private ProcessSummaryLine unspecifiedError = new ProcessSummaryLine(Status.ERROR)
|
||||
.withMessageSuffix("of an unexpected error: ")
|
||||
.withSingularFutureMessage("will not be synced, ")
|
||||
.withPluralFutureMessage("will not be synced, ")
|
||||
.withSingularPastMessage("was not synced, ")
|
||||
.withPluralPastMessage("were not synced, ");
|
||||
|
||||
protected RunBackendStepInput runBackendStepInput = null;
|
||||
protected RunBackendStepOutput runBackendStepOutput = null;
|
||||
protected RecordLookupHelper recordLookupHelper = null;
|
||||
|
||||
private QPossibleValueTranslator possibleValueTranslator;
|
||||
@ -105,16 +118,17 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
@Override
|
||||
public ArrayList<ProcessSummaryLineInterface> getProcessSummary(RunBackendStepOutput runBackendStepOutput, boolean isForResultScreen)
|
||||
{
|
||||
ArrayList<ProcessSummaryLineInterface> processSummaryLineList = StandardProcessSummaryLineProducer.toArrayList(okToInsert, okToUpdate, errorMissingKeyField);
|
||||
if(willNotInsert.getCount() > 0)
|
||||
{
|
||||
processSummaryLineList.add(willNotInsert);
|
||||
return StandardProcessSummaryLineProducer.toArrayList(okToInsert, okToUpdate, errorMissingKeyField, unspecifiedError, willNotInsert, willNotUpdate);
|
||||
}
|
||||
if(willNotUpdate.getCount() > 0)
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected ArrayList<ProcessSummaryLineInterface> getErrorProcessSummaryLines(RunBackendStepOutput runBackendStepOutput, boolean isForResultScreen)
|
||||
{
|
||||
processSummaryLineList.add(willNotUpdate);
|
||||
}
|
||||
return (processSummaryLineList);
|
||||
return StandardProcessSummaryLineProducer.toArrayList(errorMissingKeyField, unspecifiedError);
|
||||
}
|
||||
|
||||
|
||||
@ -193,6 +207,7 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
}
|
||||
|
||||
this.runBackendStepInput = runBackendStepInput;
|
||||
this.runBackendStepOutput = runBackendStepOutput;
|
||||
|
||||
SyncProcessConfig config = getSyncProcessConfig();
|
||||
|
||||
@ -242,6 +257,7 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
Set<Serializable> processedSourceKeys = new HashSet<>();
|
||||
for(QRecord sourceRecord : runBackendStepInput.getRecords())
|
||||
{
|
||||
Serializable sourcePrimaryKey = sourceRecord.getValue(QContext.getQInstance().getTable(config.sourceTable).getPrimaryKeyField());
|
||||
Serializable sourceKeyValue = sourceRecord.getValue(sourceTableKeyField);
|
||||
if(processedSourceKeys.contains(sourceKeyValue))
|
||||
{
|
||||
@ -252,7 +268,7 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
|
||||
if(sourceKeyValue == null || "".equals(sourceKeyValue))
|
||||
{
|
||||
errorMissingKeyField.incrementCount();
|
||||
errorMissingKeyField.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
|
||||
try
|
||||
{
|
||||
@ -271,43 +287,58 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
//////////////////////////////////////////////////////////////
|
||||
// look for the existing record, to determine insert/update //
|
||||
//////////////////////////////////////////////////////////////
|
||||
try
|
||||
{
|
||||
QRecord existingRecord = getExistingRecord(existingRecordsByForeignKey, destinationForeignKeyField, sourceKeyValue);
|
||||
|
||||
QRecord recordToStore;
|
||||
if(existingRecord != null && config.performUpdates)
|
||||
{
|
||||
recordToStore = existingRecord;
|
||||
okToUpdate.incrementCount();
|
||||
}
|
||||
else if(existingRecord == null && config.performInserts)
|
||||
{
|
||||
recordToStore = new QRecord();
|
||||
okToInsert.incrementCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(existingRecord != null)
|
||||
{
|
||||
LOG.info("Skipping storing existing record because this sync process is set to not perform updates");
|
||||
willNotInsert.incrementCount();
|
||||
willNotInsert.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Skipping storing new record because this sync process is set to not perform inserts");
|
||||
willNotUpdate.incrementCount();
|
||||
willNotUpdate.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// if we received a record to store add to the output records //
|
||||
////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// if we received a record to store add to the output records and summary lines //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
recordToStore = populateRecordToStore(runBackendStepInput, recordToStore, sourceRecord);
|
||||
if(recordToStore != null)
|
||||
{
|
||||
if(existingRecord != null)
|
||||
{
|
||||
okToUpdate.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
okToInsert.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
}
|
||||
|
||||
runBackendStepOutput.addRecord(recordToStore);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
unspecifiedError.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||
unspecifiedError.setMessageSuffix(unspecifiedError.getMessageSuffix() + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// populate possible-values for review screen //
|
||||
@ -426,4 +457,17 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Let the subclass "easily" add an audit to be inserted on the Execute step.
|
||||
*******************************************************************************/
|
||||
protected void addAuditForExecuteStep(AuditSingleInput auditSingleInput)
|
||||
{
|
||||
if(StreamedETLWithFrontendProcess.STEP_NAME_EXECUTE.equals(this.runBackendStepInput.getStepName()))
|
||||
{
|
||||
this.runBackendStepOutput.addAuditSingleInput(auditSingleInput);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,14 +23,17 @@ package com.kingsrook.qqq.backend.core.processes.implementations.basepull;
|
||||
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
@ -71,4 +74,27 @@ class ExtractViaBasepullQueryStepTest extends BaseTest
|
||||
assertTrue(queryFilter.getOrderBys().get(0).getIsAscending());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testWillTheBasePullQueryBeUsed()
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// only time the base-pull query will be used is if there isn't a filter or records in the process input. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertTrue(new ExtractViaBasepullQueryStep().willTheBasePullQueryBeUsed(new RunBackendStepInput()));
|
||||
|
||||
assertFalse(new ExtractViaBasepullQueryStep().willTheBasePullQueryBeUsed(new RunBackendStepInput()
|
||||
.withValues(Map.of("recordIds", "1,2,3", StreamedETLWithFrontendProcess.FIELD_SOURCE_TABLE, "person"))));
|
||||
|
||||
assertFalse(new ExtractViaBasepullQueryStep().willTheBasePullQueryBeUsed(new RunBackendStepInput()
|
||||
.withValues(Map.of(StreamedETLWithFrontendProcess.FIELD_DEFAULT_QUERY_FILTER, new QQueryFilter()))));
|
||||
|
||||
assertFalse(new ExtractViaBasepullQueryStep().willTheBasePullQueryBeUsed(new RunBackendStepInput()
|
||||
.withValues(Map.of("queryFilterJson", "{}"))));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
@ -786,7 +787,7 @@ public class BaseAPIActionUtil
|
||||
try(CloseableHttpClient client = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build())
|
||||
{
|
||||
HttpPost request = new HttpPost(fullURL);
|
||||
request.setEntity(new StringEntity(postBody));
|
||||
request.setEntity(new StringEntity(postBody, getCharsetForEntity()));
|
||||
|
||||
if(setCredentialsInHeader)
|
||||
{
|
||||
@ -829,6 +830,16 @@ public class BaseAPIActionUtil
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Let a subclass change what charset to use for entities (bodies) being posted/put/etc.
|
||||
*******************************************************************************/
|
||||
protected static Charset getCharsetForEntity()
|
||||
{
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** one-line method, factored out so mock/tests can override
|
||||
*******************************************************************************/
|
||||
@ -914,7 +925,7 @@ public class BaseAPIActionUtil
|
||||
body.put(wrapperObjectName, new JSONObject(json));
|
||||
json = body.toString();
|
||||
}
|
||||
return (new StringEntity(json));
|
||||
return (new StringEntity(json, getCharsetForEntity()));
|
||||
}
|
||||
|
||||
|
||||
@ -943,7 +954,7 @@ public class BaseAPIActionUtil
|
||||
body.put(wrapperObjectName, new JSONArray(json));
|
||||
json = body.toString();
|
||||
}
|
||||
return (new StringEntity(json));
|
||||
return (new StringEntity(json, getCharsetForEntity()));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -63,14 +63,18 @@ import com.kingsrook.qqq.backend.module.api.model.OutboundAPILog;
|
||||
import com.kingsrook.qqq.backend.module.api.model.OutboundAPILogMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.module.api.model.metadata.APIBackendMetaData;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -339,10 +343,32 @@ class BaseAPIActionUtilTest extends BaseTest
|
||||
mockApiUtilsHelper.enqueueMockResponse("""
|
||||
{"id": 6}
|
||||
""");
|
||||
mockApiUtilsHelper.withMockRequestAsserter(httpRequestBase ->
|
||||
{
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequestBase) httpRequestBase).getEntity();
|
||||
byte[] bytes = entity.getContent().readAllBytes();
|
||||
String requestBody = new String(bytes, StandardCharsets.UTF_8);
|
||||
|
||||
///////////////////////////////////////
|
||||
// default ISO-8559-1: ... a0 ... //
|
||||
// updated UTF-8: ... c2 a0 ... //
|
||||
///////////////////////////////////////
|
||||
byte previousByte = 0;
|
||||
for(byte b : bytes)
|
||||
{
|
||||
if(b == (byte) 0xa0 && previousByte != (byte) 0xc2)
|
||||
{
|
||||
fail("Found byte 0xa0 (without being prefixed by 0xc2) - so this is invalid UTF-8!");
|
||||
}
|
||||
previousByte = b;
|
||||
}
|
||||
|
||||
assertThat(requestBody).contains("van Houten");
|
||||
});
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(TestUtils.MOCK_TABLE_NAME);
|
||||
insertInput.setRecords(List.of(new QRecord().withValue("name", "Milhouse")));
|
||||
insertInput.setRecords(List.of(new QRecord().withValue("name", "Milhouse van Houten")));
|
||||
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||
assertEquals(6, insertOutput.getRecords().get(0).getValueInteger("id"));
|
||||
}
|
||||
|
@ -33,7 +33,9 @@
|
||||
|
||||
<properties>
|
||||
<!-- props specifically to this module -->
|
||||
<!-- none at this time -->
|
||||
|
||||
<!-- temp - disable this when localstack is fixed -->
|
||||
<coverage.haltOnFailure>false</coverage.haltOnFailure>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -44,6 +44,7 @@ import com.kingsrook.qqq.backend.module.filesystem.s3.S3BackendModuleSubclassFor
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.actions.AbstractS3Action;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.model.metadata.S3BackendMetaData;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.model.metadata.S3TableBackendDetails;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -52,6 +53,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
/*******************************************************************************
|
||||
** Unit test for FilesystemSyncProcess using S3 backend
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
class FilesystemSyncProcessS3Test extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -31,12 +31,14 @@ import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.exceptions.FilesystemException;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.actions.AbstractS3Action;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for S3BackendModule
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3BackendModuleTest extends BaseS3Test
|
||||
{
|
||||
private final String PATH_THAT_WONT_EXIST = "some/path/that/wont/exist";
|
||||
|
@ -28,12 +28,14 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3CountActionTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -26,6 +26,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@ -33,6 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3DeleteActionTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemRecordBackendD
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@ -44,6 +45,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3InsertActionTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -29,12 +29,14 @@ import com.kingsrook.qqq.backend.module.filesystem.TestUtils;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.base.FilesystemRecordBackendDetailFields;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3QueryActionTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -26,6 +26,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@ -33,6 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3UpdateActionTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -28,6 +28,7 @@ import java.util.List;
|
||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||
import com.kingsrook.qqq.backend.module.filesystem.s3.BaseS3Test;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ -35,6 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled("Because localstack won't start")
|
||||
public class S3UtilsTest extends BaseS3Test
|
||||
{
|
||||
|
||||
|
@ -193,8 +193,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
{
|
||||
try
|
||||
{
|
||||
QFieldMetaData field = table.getField(fieldName);
|
||||
if(field != null)
|
||||
if(table.getFields().containsKey(fieldName))
|
||||
{
|
||||
record.setValue(fieldName, value);
|
||||
}
|
||||
|
@ -859,6 +859,9 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
|
||||
apiProcessMetaDataList.add(Pair.of(apiProcessMetaData, processMetaData));
|
||||
}
|
||||
|
||||
apiProcessMetaDataList.sort(Comparator.comparing(apiProcessMetaDataQProcessMetaDataPair -> getProcessSummary(apiProcessMetaDataQProcessMetaDataPair.getA(), apiProcessMetaDataQProcessMetaDataPair.getB())));
|
||||
|
||||
return (apiProcessMetaDataList);
|
||||
}
|
||||
|
||||
@ -885,7 +888,7 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
Method methodForProcess = new Method()
|
||||
.withOperationId(apiProcessMetaData.getApiProcessName())
|
||||
.withTags(tags)
|
||||
.withSummary(ObjectUtils.requireConditionElse(apiProcessMetaData.getSummary(), StringUtils::hasContent, processMetaData.getLabel()))
|
||||
.withSummary(getProcessSummary(apiProcessMetaData, processMetaData))
|
||||
.withDescription(description)
|
||||
.withSecurity(getSecurity(apiInstanceMetaData, processMetaData.getName()));
|
||||
|
||||
@ -1018,6 +1021,16 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static String getProcessSummary(ApiProcessMetaData apiProcessMetaData, QProcessMetaData processMetaData)
|
||||
{
|
||||
return ObjectUtils.requireConditionElse(apiProcessMetaData.getSummary(), StringUtils::hasContent, processMetaData.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1029,7 +1042,7 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
Method methodForProcess = new Method()
|
||||
.withOperationId("getStatusFor" + StringUtils.ucFirst(apiProcessMetaData.getApiProcessName()))
|
||||
.withTags(tags)
|
||||
.withSummary("Get Status of Job: " + ObjectUtils.requireConditionElse(apiProcessMetaData.getSummary(), StringUtils::hasContent, processMetaData.getLabel()))
|
||||
.withSummary("Get Status of Job: " + getProcessSummary(apiProcessMetaData, processMetaData))
|
||||
.withDescription("Get the status for a previous asynchronous call to the process named " + processMetaData.getLabel())
|
||||
.withSecurity(getSecurity(apiInstanceMetaData, processMetaData.getName()));
|
||||
|
||||
@ -1158,6 +1171,12 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
|
||||
apiProcessMetaDataList.add(Pair.of(apiProcessMetaData, processMetaData));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// sort by process summary (for stability, and just to be better) //
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
apiProcessMetaDataList.sort(Comparator.comparing(apiProcessMetaDataQProcessMetaDataPair -> getProcessSummary(apiProcessMetaDataQProcessMetaDataPair.getA(), apiProcessMetaDataQProcessMetaDataPair.getB())));
|
||||
|
||||
return (apiProcessMetaDataList);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user