mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Merged feature/sftp-and-headless-bulk-load into dev
This commit is contained in:
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChildRecordListData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for RecordListWidgetRenderer
|
||||
*******************************************************************************/
|
||||
class RecordListWidgetRendererTest extends BaseTest
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private QWidgetMetaData defineWidget()
|
||||
{
|
||||
return RecordListWidgetRenderer.widgetMetaDataBuilder("testRecordListWidget")
|
||||
.withTableName(TestUtils.TABLE_NAME_SHAPE)
|
||||
.withMaxRows(20)
|
||||
.withLabel("Some Shapes")
|
||||
.withFilter(new QQueryFilter()
|
||||
.withCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, "${input.maxShapeId}")
|
||||
.withCriteria("name", QCriteriaOperator.NOT_EQUALS, "Square")
|
||||
.withOrderBy(new QFilterOrderBy("id", false))
|
||||
).getWidgetMetaData();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testValidation() throws QInstanceValidationException
|
||||
{
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
widgetMetaData.getDefaultValues().remove("tableName");
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
assertThatThrownBy(() -> new QInstanceValidator().validate(qInstance))
|
||||
.isInstanceOf(QInstanceValidationException.class)
|
||||
.hasMessageContaining("defaultValue for tableName must be given");
|
||||
}
|
||||
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
widgetMetaData.getDefaultValues().remove("filter");
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
assertThatThrownBy(() -> new QInstanceValidator().validate(qInstance))
|
||||
.isInstanceOf(QInstanceValidationException.class)
|
||||
.hasMessageContaining("defaultValue for filter must be given");
|
||||
}
|
||||
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
widgetMetaData.getDefaultValues().remove("tableName");
|
||||
widgetMetaData.getDefaultValues().remove("filter");
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
assertThatThrownBy(() -> new QInstanceValidator().validate(qInstance))
|
||||
.isInstanceOf(QInstanceValidationException.class)
|
||||
.hasMessageContaining("defaultValue for filter must be given")
|
||||
.hasMessageContaining("defaultValue for tableName must be given");
|
||||
}
|
||||
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
QQueryFilter filter = (QQueryFilter) widgetMetaData.getDefaultValues().get("filter");
|
||||
filter.addCriteria(new QFilterCriteria("noField", QCriteriaOperator.EQUALS, "noValue"));
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
assertThatThrownBy(() -> new QInstanceValidator().validate(qInstance))
|
||||
.isInstanceOf(QInstanceValidationException.class)
|
||||
.hasMessageContaining("Criteria fieldName noField is not a field in this table");
|
||||
}
|
||||
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
//////////////////////////////////
|
||||
// make sure valid setup passes //
|
||||
//////////////////////////////////
|
||||
new QInstanceValidator().validate(qInstance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testRender() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QWidgetMetaData widgetMetaData = defineWidget();
|
||||
qInstance.addWidget(widgetMetaData);
|
||||
|
||||
TestUtils.insertDefaultShapes(qInstance);
|
||||
TestUtils.insertExtraShapes(qInstance);
|
||||
|
||||
{
|
||||
RecordListWidgetRenderer recordListWidgetRenderer = new RecordListWidgetRenderer();
|
||||
RenderWidgetInput input = new RenderWidgetInput();
|
||||
input.setWidgetMetaData(widgetMetaData);
|
||||
input.setQueryParams(Map.of("maxShapeId", "1"));
|
||||
RenderWidgetOutput output = recordListWidgetRenderer.render(input);
|
||||
|
||||
ChildRecordListData widgetData = (ChildRecordListData) output.getWidgetData();
|
||||
assertEquals(1, widgetData.getTotalRows());
|
||||
assertEquals(1, widgetData.getQueryOutput().getRecords().get(0).getValue("id"));
|
||||
assertEquals("Triangle", widgetData.getQueryOutput().getRecords().get(0).getValue("name"));
|
||||
}
|
||||
|
||||
{
|
||||
RecordListWidgetRenderer recordListWidgetRenderer = new RecordListWidgetRenderer();
|
||||
RenderWidgetInput input = new RenderWidgetInput();
|
||||
input.setWidgetMetaData(widgetMetaData);
|
||||
input.setQueryParams(Map.of("maxShapeId", "4"));
|
||||
RenderWidgetOutput output = recordListWidgetRenderer.render(input);
|
||||
|
||||
ChildRecordListData widgetData = (ChildRecordListData) output.getWidgetData();
|
||||
assertEquals(3, widgetData.getTotalRows());
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// id=2,name=Square was skipped due to NOT_EQUALS Square in the filter //
|
||||
// max-shape-id applied we don't get id=5 or 6 //
|
||||
// and they're ordered as specified in the filter (id desc) //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
assertEquals(4, widgetData.getQueryOutput().getRecords().get(0).getValue("id"));
|
||||
assertEquals("Rectangle", widgetData.getQueryOutput().getRecords().get(0).getValue("name"));
|
||||
|
||||
assertEquals(3, widgetData.getQueryOutput().getRecords().get(1).getValue("id"));
|
||||
assertEquals("Circle", widgetData.getQueryOutput().getRecords().get(1).getValue("name"));
|
||||
|
||||
assertEquals(1, widgetData.getQueryOutput().getRecords().get(2).getValue("id"));
|
||||
assertEquals("Triangle", widgetData.getQueryOutput().getRecords().get(2).getValue("name"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -23,10 +23,14 @@ package com.kingsrook.qqq.backend.core.actions.tables;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
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.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
|
||||
@ -50,4 +54,18 @@ class CountActionTest extends BaseTest
|
||||
CountOutput result = new CountAction().execute(request);
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStaticWrapper() throws QException
|
||||
{
|
||||
TestUtils.insertDefaultShapes(QContext.getQInstance());
|
||||
assertEquals(3, CountAction.execute(TestUtils.TABLE_NAME_SHAPE, null));
|
||||
assertEquals(3, CountAction.execute(TestUtils.TABLE_NAME_SHAPE, new QQueryFilter()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,19 +30,23 @@ import java.time.LocalTime;
|
||||
import java.time.Month;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
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.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DateTimeDisplayValueBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@ -237,4 +241,102 @@ class QValueFormatterTest extends BaseTest
|
||||
assertEquals("2024-04-04 02:12:00 PM CDT", record.getDisplayValue("createDate"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testBlobValuesToDownloadUrls()
|
||||
{
|
||||
byte[] blobBytes = "hello".getBytes();
|
||||
{
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName("testTable")
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("blobField", QFieldType.BLOB)
|
||||
.withFieldAdornment(new FieldAdornment().withType(AdornmentType.FILE_DOWNLOAD)
|
||||
.withValue(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT, "blob-%s.txt")
|
||||
.withValue(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT_FIELDS, new ArrayList<>(List.of("id")))));
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// verify display value gets set to formated file-name + fields //
|
||||
// and raw value becomes URL for downloading the byte //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
QRecord record = new QRecord().withValue("id", 47).withValue("blobField", blobBytes);
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(record));
|
||||
assertEquals("/data/testTable/47/blobField/blob-47.txt", record.getValueString("blobField"));
|
||||
assertEquals("blob-47.txt", record.getDisplayValue("blobField"));
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// verify that w/ no blob value, we don't do anything //
|
||||
////////////////////////////////////////////////////////
|
||||
QRecord recordWithoutBlobValue = new QRecord().withValue("id", 47);
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(recordWithoutBlobValue));
|
||||
assertNull(recordWithoutBlobValue.getValue("blobField"));
|
||||
assertNull(recordWithoutBlobValue.getDisplayValue("blobField"));
|
||||
}
|
||||
|
||||
{
|
||||
FieldAdornment adornment = new FieldAdornment().withType(AdornmentType.FILE_DOWNLOAD)
|
||||
.withValue(AdornmentType.FileDownloadValues.FILE_NAME_FIELD, "fileName");
|
||||
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName("testTable")
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("fileName", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("blobField", QFieldType.BLOB)
|
||||
.withFieldAdornment(adornment));
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// here get the file name directly from one field //
|
||||
////////////////////////////////////////////////////
|
||||
QRecord record = new QRecord().withValue("id", 47).withValue("blobField", blobBytes).withValue("fileName", "myBlob.txt");
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(record));
|
||||
assertEquals("/data/testTable/47/blobField/myBlob.txt", record.getValueString("blobField"));
|
||||
assertEquals("myBlob.txt", record.getDisplayValue("blobField"));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// switch to use dynamic url, rerun, and assert we get the values as they were on the record before the call //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
adornment.withValue(AdornmentType.FileDownloadValues.DOWNLOAD_URL_DYNAMIC, true);
|
||||
record = new QRecord().withValue("id", 47).withValue("blobField", blobBytes).withValue("fileName", "myBlob.txt")
|
||||
.withDisplayValue("blobField:" + AdornmentType.FileDownloadValues.DOWNLOAD_URL_DYNAMIC, "/something-custom/")
|
||||
.withDisplayValue("blobField", "myDisplayValue");
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(record));
|
||||
assertArrayEquals(blobBytes, record.getValueByteArray("blobField"));
|
||||
assertEquals("myDisplayValue", record.getDisplayValue("blobField"));
|
||||
}
|
||||
|
||||
{
|
||||
FieldAdornment adornment = new FieldAdornment().withType(AdornmentType.FILE_DOWNLOAD);
|
||||
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName("testTable")
|
||||
.withLabel("Test Table")
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("blobField", QFieldType.BLOB).withLabel("Blob").withFieldAdornment(adornment));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// w/o file name format or whatever, generate a file name from table & id & field labels //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
QRecord record = new QRecord().withValue("id", 47).withValue("blobField", blobBytes);
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(record));
|
||||
assertEquals("/data/testTable/47/blobField/Test%20Table%2047%20Blob", record.getValueString("blobField"));
|
||||
assertEquals("Test Table 47 Blob", record.getDisplayValue("blobField"));
|
||||
|
||||
////////////////////////////////////////
|
||||
// add a default extension and re-run //
|
||||
////////////////////////////////////////
|
||||
adornment.withValue(AdornmentType.FileDownloadValues.DEFAULT_EXTENSION, "html");
|
||||
record = new QRecord().withValue("id", 47).withValue("blobField", blobBytes);
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(table, List.of(record));
|
||||
assertEquals("/data/testTable/47/blobField/Test%20Table%2047%20Blob.html", record.getValueString("blobField"));
|
||||
assertEquals("Test Table 47 Blob.html", record.getDisplayValue("blobField"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,7 +27,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.instances.enrichment.plugins.QInstanceEnricherPluginInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.instances.enrichment.testplugins.TestEnricherPlugin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
@ -595,27 +596,31 @@ class QInstanceEnricherTest extends BaseTest
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
|
||||
QInstanceEnricher.addEnricherPlugin(new QInstanceEnricherPluginInterface<QFieldMetaData>()
|
||||
{
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void enrich(QFieldMetaData field, QInstance qInstance)
|
||||
{
|
||||
if(field != null)
|
||||
{
|
||||
field.setLabel(field.getLabel() + " Plugged");
|
||||
}
|
||||
}
|
||||
});
|
||||
QInstanceEnricher.addEnricherPlugin(new TestEnricherPlugin());
|
||||
|
||||
new QInstanceEnricher(qInstance).enrich();
|
||||
|
||||
qInstance.getTables().values().forEach(table -> table.getFields().values().forEach(field -> assertThat(field.getLabel()).endsWith("Plugged")));
|
||||
qInstance.getProcesses().values().forEach(process -> process.getInputFields().forEach(field -> assertThat(field.getLabel()).endsWith("Plugged")));
|
||||
qInstance.getProcesses().values().forEach(process -> process.getOutputFields().forEach(field -> assertThat(field.getLabel()).endsWith("Plugged")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testDiscoverAndAddPlugins() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
new QInstanceEnricher(qInstance).enrich();
|
||||
qInstance.getTables().values().forEach(table -> table.getFields().values().forEach(field -> assertThat(field.getLabel()).doesNotEndWith("Plugged")));
|
||||
|
||||
qInstance = TestUtils.defineInstance();
|
||||
QInstanceEnricher.discoverAndAddPluginsInPackage(getClass().getPackageName() + ".enrichment.testplugins");
|
||||
new QInstanceEnricher(qInstance).enrich();
|
||||
qInstance.getTables().values().forEach(table -> table.getFields().values().forEach(field -> assertThat(field.getLabel()).endsWith("Plugged")));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
@ -55,6 +56,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
@ -93,12 +95,15 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.TableAutomationAction;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantSetting;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.variants.BackendVariantsConfig;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleCustomizerInterface;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.AbstractTransformStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.ExtractViaQueryStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.LoadViaDeleteStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeFunction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@ -182,6 +187,143 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testBackendVariants()
|
||||
{
|
||||
BackendVariantSetting setting = new BackendVariantSetting() {};
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)),
|
||||
"Missing backendVariantsConfig in backend [variant] which is marked as usesVariants");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(false)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig())),
|
||||
"Should not have a backendVariantsConfig");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(null)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig())),
|
||||
"Should not have a backendVariantsConfig");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig())),
|
||||
"Missing variantTypeKey in backendVariantsConfig",
|
||||
"Missing optionsTableName in backendVariantsConfig",
|
||||
"Missing or empty backendSettingSourceFieldNameMap");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName("notATable")
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "field")))),
|
||||
"Unrecognized optionsTableName [notATable] in backendVariantsConfig");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withOptionsFilter(new QQueryFilter(new QFilterCriteria("notAField", QCriteriaOperator.EQUALS, 1)))
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "firstName")))),
|
||||
"optionsFilter in backendVariantsConfig in backend [variant]: Criteria fieldName notAField is not a field");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "noSuchField")))),
|
||||
"Unrecognized fieldName [noSuchField] in backendSettingSourceFieldNameMap");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withVariantRecordLookupFunction(new QCodeReference(CustomizerThatIsNotOfTheRightBaseClass.class))
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "no-field-but-okay-custom-supplier"))
|
||||
)),
|
||||
"VariantRecordSupplier in backendVariantsConfig in backend [variant]: CodeReference is not any of the expected types: com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeFunction, java.util.function.Function");
|
||||
|
||||
assertValidationSuccess((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "firstName"))
|
||||
)));
|
||||
|
||||
assertValidationSuccess((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withVariantRecordLookupFunction(new QCodeReference(VariantRecordFunction.class))
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "no-field-but-okay-custom-supplier"))
|
||||
)));
|
||||
|
||||
assertValidationSuccess((qInstance) -> qInstance.addBackend(new QBackendMetaData()
|
||||
.withName("variant")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withVariantTypeKey("myVariant")
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_PERSON)
|
||||
.withVariantRecordLookupFunction(new QCodeReference(VariantRecordUnsafeFunction.class))
|
||||
.withBackendSettingSourceFieldNameMap(Map.of(setting, "no-field-but-okay-custom-supplier"))
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class VariantRecordFunction implements Function<Serializable, QRecord>
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QRecord apply(Serializable serializable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class VariantRecordUnsafeFunction implements UnsafeFunction<Serializable, QRecord, QException>
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QRecord apply(Serializable serializable) throws QException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an instance with null tables - should throw.
|
||||
**
|
||||
@ -2369,7 +2511,7 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
{
|
||||
int noOfReasons = actualReasons == null ? 0 : actualReasons.size();
|
||||
assertEquals(expectedReasons.length, noOfReasons, "Expected number of validation failure reasons.\nExpected reasons: " + String.join(",", expectedReasons)
|
||||
+ "\nActual reasons: " + (noOfReasons > 0 ? String.join("\n", actualReasons) : "--"));
|
||||
+ "\nActual reasons: " + (noOfReasons > 0 ? String.join("\n", actualReasons) : "--"));
|
||||
}
|
||||
|
||||
for(String reason : expectedReasons)
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.instances.enrichment.testplugins;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.instances.enrichment.plugins.QInstanceEnricherPluginInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestEnricherPlugin implements QInstanceEnricherPluginInterface<QFieldMetaData>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void enrich(QFieldMetaData field, QInstance qInstance)
|
||||
{
|
||||
if(field != null)
|
||||
{
|
||||
field.setLabel(field.getLabel() + " Plugged");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -66,7 +66,7 @@ class NowWithOffsetTest extends BaseTest
|
||||
assertThat(twoWeeksFromNowMillis).isCloseTo(now + (14 * DAY_IN_MILLIS), allowedDiff);
|
||||
|
||||
long oneMonthAgoMillis = ((Instant) NowWithOffset.minus(1, ChronoUnit.MONTHS).evaluate(dateTimeField)).toEpochMilli();
|
||||
assertThat(oneMonthAgoMillis).isCloseTo(now - (30 * DAY_IN_MILLIS), allowedDiffPlusOneDay);
|
||||
assertThat(oneMonthAgoMillis).isCloseTo(now - (30 * DAY_IN_MILLIS), allowedDiffPlusTwoDays); // two days, to work on 3/1...
|
||||
|
||||
long twoMonthsFromNowMillis = ((Instant) NowWithOffset.plus(2, ChronoUnit.MONTHS).evaluate(dateTimeField)).toEpochMilli();
|
||||
assertThat(twoMonthsFromNowMillis).isCloseTo(now + (60 * DAY_IN_MILLIS), allowedDiffPlusTwoDays);
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for EmptyMetaDataProducerOutput
|
||||
*******************************************************************************/
|
||||
class EmptyMetaDataProducerOutputTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** sorry, just here to avoid a dip in coverage.
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
QInstance qInstance = new QInstance();
|
||||
new EmptyMetaDataProducerOutput().addSelfToInstance(qInstance);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.qbits;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.TestQBitConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.TestQBitProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.metadata.OtherTableMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.metadata.SomeTableMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for QBitProducer
|
||||
*******************************************************************************/
|
||||
class QBitProducerTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
TestQBitConfig config = new TestQBitConfig()
|
||||
.withOtherTableConfig(ProvidedOrSuppliedTableConfig.provideTableUsingBackendNamed(TestUtils.MEMORY_BACKEND_NAME))
|
||||
.withIsSomeTableEnabled(true)
|
||||
.withSomeSetting("yes")
|
||||
.withTableMetaDataCustomizer((i, table) ->
|
||||
{
|
||||
if(table.getBackendName() == null)
|
||||
{
|
||||
table.setBackendName(TestUtils.DEFAULT_BACKEND_NAME);
|
||||
}
|
||||
|
||||
table.addField(new QFieldMetaData("custom", QFieldType.STRING));
|
||||
|
||||
return (table);
|
||||
});
|
||||
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
new TestQBitProducer().withTestQBitConfig(config).produce(qInstance);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// OtherTable should have been provided by the qbit, with the backend name we told it above (MEMORY) //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QTableMetaData otherTable = qInstance.getTable(OtherTableMetaDataProducer.NAME);
|
||||
assertNotNull(otherTable);
|
||||
assertEquals(TestUtils.MEMORY_BACKEND_NAME, otherTable.getBackendName());
|
||||
assertNotNull(otherTable.getField("custom"));
|
||||
|
||||
QBitMetaData sourceQBit = otherTable.getSourceQBit();
|
||||
assertEquals("testQBit", sourceQBit.getArtifactId());
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// SomeTable should have been provided, w/ backend name set by the customizer //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
QTableMetaData someTable = qInstance.getTable(SomeTableMetaDataProducer.NAME);
|
||||
assertNotNull(someTable);
|
||||
assertEquals(TestUtils.DEFAULT_BACKEND_NAME, someTable.getBackendName());
|
||||
assertNotNull(otherTable.getField("custom"));
|
||||
|
||||
TestQBitConfig qBitConfig = (TestQBitConfig) someTable.getSourceQBitConfig();
|
||||
assertEquals("yes", qBitConfig.getSomeSetting());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testDisableThings() throws QException
|
||||
{
|
||||
TestQBitConfig config = new TestQBitConfig()
|
||||
.withOtherTableConfig(ProvidedOrSuppliedTableConfig.useSuppliedTaleNamed(TestUtils.TABLE_NAME_PERSON_MEMORY))
|
||||
.withIsSomeTableEnabled(false);
|
||||
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
new TestQBitProducer().withTestQBitConfig(config).produce(qInstance);
|
||||
|
||||
//////////////////////////////////////
|
||||
// neither table should be produced //
|
||||
//////////////////////////////////////
|
||||
QTableMetaData otherTable = qInstance.getTable(OtherTableMetaDataProducer.NAME);
|
||||
assertNull(otherTable);
|
||||
|
||||
QTableMetaData someTable = qInstance.getTable(SomeTableMetaDataProducer.NAME);
|
||||
assertNull(someTable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testValidationErrors() throws QException
|
||||
{
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
TestQBitConfig config = new TestQBitConfig();
|
||||
|
||||
assertThatThrownBy(() -> new TestQBitProducer().withTestQBitConfig(config).produce(qInstance))
|
||||
.isInstanceOf(QBitConfigValidationException.class)
|
||||
.hasMessageContaining("otherTableConfig must be set")
|
||||
.hasMessageContaining("isSomeTableEnabled must be set");
|
||||
qInstance.setQBits(new LinkedHashMap<>());
|
||||
|
||||
config.setIsSomeTableEnabled(true);
|
||||
assertThatThrownBy(() -> new TestQBitProducer().withTestQBitConfig(config).produce(qInstance))
|
||||
.isInstanceOf(QBitConfigValidationException.class)
|
||||
.hasMessageContaining("otherTableConfig must be set");
|
||||
qInstance.setQBits(new LinkedHashMap<>());
|
||||
|
||||
config.setOtherTableConfig(ProvidedOrSuppliedTableConfig.useSuppliedTaleNamed(TestUtils.TABLE_NAME_PERSON_MEMORY));
|
||||
new TestQBitProducer().withTestQBitConfig(config).produce(qInstance);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.ProvidedOrSuppliedTableConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestQBitConfig implements QBitConfig
|
||||
{
|
||||
private MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer;
|
||||
|
||||
private Boolean isSomeTableEnabled;
|
||||
private ProvidedOrSuppliedTableConfig otherTableConfig;
|
||||
|
||||
private String someSetting;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void validate(QInstance qInstance, List<String> errors)
|
||||
{
|
||||
assertCondition(otherTableConfig != null, "otherTableConfig must be set", errors);
|
||||
assertCondition(isSomeTableEnabled != null, "isSomeTableEnabled must be set", errors);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for otherTableConfig
|
||||
*******************************************************************************/
|
||||
public ProvidedOrSuppliedTableConfig getOtherTableConfig()
|
||||
{
|
||||
return (this.otherTableConfig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for otherTableConfig
|
||||
*******************************************************************************/
|
||||
public void setOtherTableConfig(ProvidedOrSuppliedTableConfig otherTableConfig)
|
||||
{
|
||||
this.otherTableConfig = otherTableConfig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for otherTableConfig
|
||||
*******************************************************************************/
|
||||
public TestQBitConfig withOtherTableConfig(ProvidedOrSuppliedTableConfig otherTableConfig)
|
||||
{
|
||||
this.otherTableConfig = otherTableConfig;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isSomeTableEnabled
|
||||
*******************************************************************************/
|
||||
public Boolean getIsSomeTableEnabled()
|
||||
{
|
||||
return (this.isSomeTableEnabled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isSomeTableEnabled
|
||||
*******************************************************************************/
|
||||
public void setIsSomeTableEnabled(Boolean isSomeTableEnabled)
|
||||
{
|
||||
this.isSomeTableEnabled = isSomeTableEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for isSomeTableEnabled
|
||||
*******************************************************************************/
|
||||
public TestQBitConfig withIsSomeTableEnabled(Boolean isSomeTableEnabled)
|
||||
{
|
||||
this.isSomeTableEnabled = isSomeTableEnabled;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableMetaDataCustomizer
|
||||
*******************************************************************************/
|
||||
public MetaDataCustomizerInterface<QTableMetaData> getTableMetaDataCustomizer()
|
||||
{
|
||||
return (this.tableMetaDataCustomizer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableMetaDataCustomizer
|
||||
*******************************************************************************/
|
||||
public void setTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
||||
{
|
||||
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableMetaDataCustomizer
|
||||
*******************************************************************************/
|
||||
public TestQBitConfig withTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
||||
{
|
||||
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for someSetting
|
||||
*******************************************************************************/
|
||||
public String getSomeSetting()
|
||||
{
|
||||
return (this.someSetting);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for someSetting
|
||||
*******************************************************************************/
|
||||
public void setSomeSetting(String someSetting)
|
||||
{
|
||||
this.someSetting = someSetting;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for someSetting
|
||||
*******************************************************************************/
|
||||
public TestQBitConfig withSomeSetting(String someSetting)
|
||||
{
|
||||
this.someSetting = someSetting;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerHelper;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitProducer;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestQBitProducer implements QBitProducer
|
||||
{
|
||||
private TestQBitConfig testQBitConfig;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void produce(QInstance qInstance, String namespace) throws QException
|
||||
{
|
||||
QBitMetaData qBitMetaData = new QBitMetaData()
|
||||
.withGroupId("test.com.kingsrook.qbits")
|
||||
.withArtifactId("testQBit")
|
||||
.withVersion("0.1.0")
|
||||
.withNamespace(namespace)
|
||||
.withConfig(testQBitConfig);
|
||||
qInstance.addQBit(qBitMetaData);
|
||||
|
||||
List<MetaDataProducerInterface<?>> producers = MetaDataProducerHelper.findProducers(getClass().getPackageName() + ".metadata");
|
||||
finishProducing(qInstance, qBitMetaData, testQBitConfig, producers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for testQBitConfig
|
||||
*******************************************************************************/
|
||||
public TestQBitConfig getTestQBitConfig()
|
||||
{
|
||||
return (this.testQBitConfig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for testQBitConfig
|
||||
*******************************************************************************/
|
||||
public void setTestQBitConfig(TestQBitConfig testQBitConfig)
|
||||
{
|
||||
this.testQBitConfig = testQBitConfig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for testQBitConfig
|
||||
*******************************************************************************/
|
||||
public TestQBitProducer withTestQBitConfig(TestQBitConfig testQBitConfig)
|
||||
{
|
||||
this.testQBitConfig = testQBitConfig;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitComponentMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.TestQBitConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Meta Data Producer for OtherTable
|
||||
*******************************************************************************/
|
||||
public class OtherTableMetaDataProducer extends QBitComponentMetaDataProducer<QTableMetaData, TestQBitConfig>
|
||||
{
|
||||
public static final String NAME = "otherTable";
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return (getQBitConfig().getOtherTableConfig().getDoProvideTable());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
QTableMetaData qTableMetaData = new QTableMetaData()
|
||||
.withName(NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withBackendName(getQBitConfig().getOtherTableConfig().getBackendName())
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||
|
||||
return (qTableMetaData);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitComponentMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.qbits.testqbit.TestQBitConfig;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Meta Data Producer for SomeTable
|
||||
*******************************************************************************/
|
||||
public class SomeTableMetaDataProducer extends QBitComponentMetaDataProducer<QTableMetaData, TestQBitConfig>
|
||||
{
|
||||
public static final String NAME = "someTable";
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return (getQBitConfig().getIsSomeTableEnabled());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
QTableMetaData qTableMetaData = new QTableMetaData()
|
||||
.withName(NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||
|
||||
return (qTableMetaData);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for SectionFactory
|
||||
*******************************************************************************/
|
||||
class SectionFactoryTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
QFieldSection t1section = SectionFactory.defaultT1("id", "name");
|
||||
assertEquals(SectionFactory.getDefaultT1name(), t1section.getName());
|
||||
assertEquals(SectionFactory.getDefaultT1iconName(), t1section.getIcon().getName());
|
||||
assertEquals(Tier.T1, t1section.getTier());
|
||||
assertEquals(List.of("id", "name"), t1section.getFieldNames());
|
||||
|
||||
QFieldSection t2section = SectionFactory.defaultT2("size", "age");
|
||||
assertEquals(SectionFactory.getDefaultT2name(), t2section.getName());
|
||||
assertEquals(SectionFactory.getDefaultT2iconName(), t2section.getIcon().getName());
|
||||
assertEquals(Tier.T2, t2section.getTier());
|
||||
assertEquals(List.of("size", "age"), t2section.getFieldNames());
|
||||
|
||||
QFieldSection t3section = SectionFactory.defaultT3("createDate", "modifyDate");
|
||||
assertEquals(SectionFactory.getDefaultT3name(), t3section.getName());
|
||||
assertEquals(SectionFactory.getDefaultT3iconName(), t3section.getIcon().getName());
|
||||
assertEquals(Tier.T3, t3section.getTier());
|
||||
assertEquals(List.of("createDate", "modifyDate"), t3section.getFieldNames());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for TablesCustomPossibleValueProvider
|
||||
*******************************************************************************/
|
||||
class TablesCustomPossibleValueProviderTest extends BaseTest
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
void beforeEach()
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("hidden")
|
||||
.withIsHidden(true)
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER)));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("restricted")
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.HAS_ACCESS_PERMISSION))
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER)));
|
||||
|
||||
qInstance.addPossibleValueSource(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(qInstance));
|
||||
|
||||
QContext.init(qInstance, newSession());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGetPossibleValue()
|
||||
{
|
||||
TablesCustomPossibleValueProvider provider = new TablesCustomPossibleValueProvider();
|
||||
|
||||
QPossibleValue<String> possibleValue = provider.getPossibleValue(TestUtils.TABLE_NAME_PERSON);
|
||||
assertEquals(TestUtils.TABLE_NAME_PERSON, possibleValue.getId());
|
||||
assertEquals("Person", possibleValue.getLabel());
|
||||
|
||||
assertNull(provider.getPossibleValue("no-such-table"));
|
||||
assertNull(provider.getPossibleValue("hidden"));
|
||||
assertNull(provider.getPossibleValue("restricted"));
|
||||
|
||||
QContext.getQSession().withPermission("restricted.hasAccess");
|
||||
assertNotNull(provider.getPossibleValue("restricted"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testSearchPossibleValue() throws QException
|
||||
{
|
||||
TablesCustomPossibleValueProvider provider = new TablesCustomPossibleValueProvider();
|
||||
|
||||
List<QPossibleValue<String>> list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME));
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_PERSON));
|
||||
assertThat(list).noneMatch(p -> p.getId().equals("no-such-table"));
|
||||
assertThat(list).noneMatch(p -> p.getId().equals("hidden"));
|
||||
assertThat(list).noneMatch(p -> p.getId().equals("restricted"));
|
||||
assertNull(provider.getPossibleValue("restricted"));
|
||||
|
||||
list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
.withIdList(List.of(TestUtils.TABLE_NAME_PERSON, TestUtils.TABLE_NAME_SHAPE, "hidden")));
|
||||
assertEquals(2, list.size());
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_PERSON));
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_SHAPE));
|
||||
assertThat(list).noneMatch(p -> p.getId().equals("hidden"));
|
||||
|
||||
list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
.withLabelList(List.of("Person", "Shape", "Restricted")));
|
||||
assertEquals(2, list.size());
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_PERSON));
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_SHAPE));
|
||||
assertThat(list).noneMatch(p -> p.getId().equals("restricted"));
|
||||
|
||||
list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
.withSearchTerm("restricted"));
|
||||
assertEquals(0, list.size());
|
||||
|
||||
/////////////////////////////////////////
|
||||
// add permission for restricted table //
|
||||
/////////////////////////////////////////
|
||||
QContext.getQSession().withPermission("restricted.hasAccess");
|
||||
list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
.withSearchTerm("restricted"));
|
||||
assertEquals(1, list.size());
|
||||
|
||||
list = provider.search(new SearchPossibleValueSourceInput()
|
||||
.withPossibleValueSourceName(TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
.withLabelList(List.of("Person", "Shape", "Restricted")));
|
||||
assertEquals(3, list.size());
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_PERSON));
|
||||
assertThat(list).anyMatch(p -> p.getId().equals(TestUtils.TABLE_NAME_SHAPE));
|
||||
assertThat(list).anyMatch(p -> p.getId().equals("restricted"));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.variants;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for BackendVariantsUtil
|
||||
*******************************************************************************/
|
||||
class BackendVariantsUtilTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGetVariantId() throws QException
|
||||
{
|
||||
QBackendMetaData myBackend = getBackendMetaData();
|
||||
|
||||
assertThatThrownBy(() -> BackendVariantsUtil.getVariantId(myBackend))
|
||||
.hasMessageContaining("Could not find Backend Variant information in session under key 'yourSelectedShape' for Backend 'TestBackend'");
|
||||
|
||||
QContext.getQSession().setBackendVariants(Map.of("yourSelectedShape", 1701));
|
||||
assertEquals(1701, BackendVariantsUtil.getVariantId(myBackend));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static QBackendMetaData getBackendMetaData()
|
||||
{
|
||||
QBackendMetaData myBackend = new QBackendMetaData()
|
||||
.withName("TestBackend")
|
||||
.withUsesVariants(true)
|
||||
.withBackendVariantsConfig(new BackendVariantsConfig()
|
||||
.withOptionsTableName(TestUtils.TABLE_NAME_SHAPE)
|
||||
.withVariantTypeKey("yourSelectedShape"));
|
||||
return myBackend;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGetVariantRecord() throws QException
|
||||
{
|
||||
QBackendMetaData myBackend = getBackendMetaData();
|
||||
|
||||
TestUtils.insertDefaultShapes(QContext.getQInstance());
|
||||
|
||||
assertThatThrownBy(() -> BackendVariantsUtil.getVariantRecord(myBackend))
|
||||
.hasMessageContaining("Could not find Backend Variant information in session under key 'yourSelectedShape' for Backend 'TestBackend'");
|
||||
|
||||
QContext.getQSession().setBackendVariants(Map.of("yourSelectedShape", 1701));
|
||||
assertThatThrownBy(() -> BackendVariantsUtil.getVariantRecord(myBackend))
|
||||
.hasMessageContaining("Could not find Backend Variant in table shape with id '1701'");
|
||||
|
||||
QContext.getQSession().setBackendVariants(Map.of("yourSelectedShape", 1));
|
||||
QRecord variantRecord = BackendVariantsUtil.getVariantRecord(myBackend);
|
||||
assertEquals(1, variantRecord.getValueInteger("id"));
|
||||
assertNotNull(variantRecord.getValue("name"));
|
||||
}
|
||||
|
||||
}
|
@ -22,24 +22,21 @@
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.StorageAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryAssert;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.storage.StorageInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.model.BulkLoadProfile;
|
||||
@ -61,6 +58,9 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
*******************************************************************************/
|
||||
class BulkInsertFullProcessTest extends BaseTest
|
||||
{
|
||||
private static final String defaultEmail = "noone@kingsrook.com";
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@ -116,48 +116,20 @@ class BulkInsertFullProcessTest extends BaseTest
|
||||
@Test
|
||||
void test() throws Exception
|
||||
{
|
||||
String defaultEmail = "noone@kingsrook.com";
|
||||
|
||||
///////////////////////////////////////
|
||||
// make sure table is empty to start //
|
||||
///////////////////////////////////////
|
||||
assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY)).isEmpty();
|
||||
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
String processName = "PersonBulkInsertV2";
|
||||
new QInstanceEnricher(qInstance).defineTableBulkInsert(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), processName);
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// start the process - expect to go to the upload step //
|
||||
/////////////////////////////////////////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(processName);
|
||||
runProcessInput.addValue("tableName", TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
RunProcessOutput runProcessOutput = startProcess(runProcessInput);
|
||||
String processUUID = runProcessOutput.getProcessUUID();
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo("upload");
|
||||
|
||||
//////////////////////////////
|
||||
// simulate the file upload //
|
||||
//////////////////////////////
|
||||
String storageReference = UUID.randomUUID() + ".csv";
|
||||
StorageInput storageInput = new StorageInput(TestUtils.TABLE_NAME_MEMORY_STORAGE).withReference(storageReference);
|
||||
try(OutputStream outputStream = new StorageAction().createOutputStream(storageInput))
|
||||
{
|
||||
outputStream.write((getPersonCsvHeaderUsingLabels() + getPersonCsvRow1() + getPersonCsvRow2()).getBytes());
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw (e);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// continue post-upload //
|
||||
//////////////////////////
|
||||
runProcessInput.setProcessUUID(processUUID);
|
||||
runProcessInput.setStartAfterStep("upload");
|
||||
runProcessInput.addValue("theFile", new ArrayList<>(List.of(storageInput)));
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
runProcessOutput = continueProcessPostUpload(runProcessInput, processUUID, simulateFileUpload(2));
|
||||
assertEquals(List.of("Id", "Create Date", "Modify Date", "First Name", "Last Name", "Birth Date", "Email", "Home State", "noOfShoes"), runProcessOutput.getValue("headerValues"));
|
||||
assertEquals(List.of("A", "B", "C", "D", "E", "F", "G", "H", "I"), runProcessOutput.getValue("headerLetters"));
|
||||
|
||||
@ -176,29 +148,10 @@ class BulkInsertFullProcessTest extends BaseTest
|
||||
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo("fileMapping");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// all subsequent steps will want these data - so set up a lambda to set them //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Consumer<RunProcessInput> addProfileToRunProcessInput = (RunProcessInput input) ->
|
||||
{
|
||||
input.addValue("version", "v1");
|
||||
input.addValue("layout", "FLAT");
|
||||
input.addValue("hasHeaderRow", "true");
|
||||
input.addValue("fieldListJSON", JsonUtils.toJson(List.of(
|
||||
new BulkLoadProfileField().withFieldName("firstName").withColumnIndex(3),
|
||||
new BulkLoadProfileField().withFieldName("lastName").withColumnIndex(4),
|
||||
new BulkLoadProfileField().withFieldName("email").withDefaultValue(defaultEmail),
|
||||
new BulkLoadProfileField().withFieldName("homeStateId").withColumnIndex(7).withDoValueMapping(true).withValueMappings(Map.of("Illinois", 1)),
|
||||
new BulkLoadProfileField().withFieldName("noOfShoes").withColumnIndex(8)
|
||||
)));
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// continue post file-mapping //
|
||||
////////////////////////////////
|
||||
runProcessInput.setStartAfterStep("fileMapping");
|
||||
addProfileToRunProcessInput.accept(runProcessInput);
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
runProcessOutput = continueProcessPostFileMapping(runProcessInput);
|
||||
Serializable valueMappingField = runProcessOutput.getValue("valueMappingField");
|
||||
assertThat(valueMappingField).isInstanceOf(QFrontendFieldMetaData.class);
|
||||
assertEquals("homeStateId", ((QFrontendFieldMetaData) valueMappingField).getName());
|
||||
@ -211,23 +164,20 @@ class BulkInsertFullProcessTest extends BaseTest
|
||||
/////////////////////////////////
|
||||
// continue post value-mapping //
|
||||
/////////////////////////////////
|
||||
runProcessInput.setStartAfterStep("valueMapping");
|
||||
runProcessInput.addValue("mappedValuesJSON", JsonUtils.toJson(Map.of("Illinois", 1, "Missouri", 2)));
|
||||
addProfileToRunProcessInput.accept(runProcessInput);
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
runProcessOutput = continueProcessPostValueMapping(runProcessInput);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo("review");
|
||||
|
||||
/////////////////////////////////
|
||||
// continue post review screen //
|
||||
/////////////////////////////////
|
||||
runProcessInput.setStartAfterStep("review");
|
||||
addProfileToRunProcessInput.accept(runProcessInput);
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
runProcessOutput = continueProcessPostReviewScreen(runProcessInput);
|
||||
assertThat(runProcessOutput.getRecords()).hasSize(2);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo("result");
|
||||
assertThat(runProcessOutput.getValues().get(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY)).isNotNull().isInstanceOf(List.class);
|
||||
assertThat(runProcessOutput.getException()).isEmpty();
|
||||
|
||||
ProcessSummaryAssert.assertThat(runProcessOutput).hasLineWithMessageContaining("Inserted Id values between 1 and 2");
|
||||
|
||||
////////////////////////////////////
|
||||
// query for the inserted records //
|
||||
////////////////////////////////////
|
||||
@ -249,4 +199,136 @@ class BulkInsertFullProcessTest extends BaseTest
|
||||
assertNull(records.get(1).getValue("noOfShoes"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testOneRow() throws Exception
|
||||
{
|
||||
///////////////////////////////////////
|
||||
// make sure table is empty to start //
|
||||
///////////////////////////////////////
|
||||
assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY)).isEmpty();
|
||||
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
RunProcessOutput runProcessOutput = startProcess(runProcessInput);
|
||||
String processUUID = runProcessOutput.getProcessUUID();
|
||||
|
||||
continueProcessPostUpload(runProcessInput, processUUID, simulateFileUpload(1));
|
||||
continueProcessPostFileMapping(runProcessInput);
|
||||
continueProcessPostValueMapping(runProcessInput);
|
||||
runProcessOutput = continueProcessPostReviewScreen(runProcessInput);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// all that just so we can make sure this message is right (because it was wrong when we first wrote it, lol) //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ProcessSummaryAssert.assertThat(runProcessOutput).hasLineWithMessageContaining("Inserted Id 1");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static RunProcessOutput continueProcessPostReviewScreen(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
RunProcessOutput runProcessOutput;
|
||||
runProcessInput.setStartAfterStep("review");
|
||||
addProfileToRunProcessInput(runProcessInput);
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
return runProcessOutput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static RunProcessOutput continueProcessPostValueMapping(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
runProcessInput.setStartAfterStep("valueMapping");
|
||||
runProcessInput.addValue("mappedValuesJSON", JsonUtils.toJson(Map.of("Illinois", 1, "Missouri", 2)));
|
||||
addProfileToRunProcessInput(runProcessInput);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
return (runProcessOutput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static RunProcessOutput continueProcessPostFileMapping(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
RunProcessOutput runProcessOutput;
|
||||
runProcessInput.setStartAfterStep("fileMapping");
|
||||
addProfileToRunProcessInput(runProcessInput);
|
||||
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
return runProcessOutput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static RunProcessOutput continueProcessPostUpload(RunProcessInput runProcessInput, String processUUID, StorageInput storageInput) throws QException
|
||||
{
|
||||
runProcessInput.setProcessUUID(processUUID);
|
||||
runProcessInput.setStartAfterStep("upload");
|
||||
runProcessInput.addValue("theFile", new ArrayList<>(List.of(storageInput)));
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
return (runProcessOutput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static StorageInput simulateFileUpload(int noOfRows) throws Exception
|
||||
{
|
||||
String storageReference = UUID.randomUUID() + ".csv";
|
||||
StorageInput storageInput = new StorageInput(TestUtils.TABLE_NAME_MEMORY_STORAGE).withReference(storageReference);
|
||||
try(OutputStream outputStream = new StorageAction().createOutputStream(storageInput))
|
||||
{
|
||||
outputStream.write((getPersonCsvHeaderUsingLabels() + getPersonCsvRow1() + (noOfRows == 2 ? getPersonCsvRow2() : "")).getBytes());
|
||||
}
|
||||
return storageInput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static RunProcessOutput startProcess(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
runProcessInput.setProcessName(TestUtils.TABLE_NAME_PERSON_MEMORY + ".bulkInsert");
|
||||
runProcessInput.addValue("tableName", TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
return runProcessOutput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static void addProfileToRunProcessInput(RunProcessInput input)
|
||||
{
|
||||
input.addValue("version", "v1");
|
||||
input.addValue("layout", "FLAT");
|
||||
input.addValue("hasHeaderRow", "true");
|
||||
input.addValue("fieldListJSON", JsonUtils.toJson(List.of(
|
||||
new BulkLoadProfileField().withFieldName("firstName").withColumnIndex(3),
|
||||
new BulkLoadProfileField().withFieldName("lastName").withColumnIndex(4),
|
||||
new BulkLoadProfileField().withFieldName("email").withDefaultValue(defaultEmail),
|
||||
new BulkLoadProfileField().withFieldName("homeStateId").withColumnIndex(7).withDoValueMapping(true).withValueMappings(Map.of("Illinois", 1)),
|
||||
new BulkLoadProfileField().withFieldName("noOfShoes").withColumnIndex(8)
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.scheduler;
|
||||
|
||||
|
||||
import java.text.ParseException;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for CronDescriber
|
||||
*******************************************************************************/
|
||||
class CronDescriberTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws ParseException
|
||||
{
|
||||
assertEquals("At every second, every minute, every hour, on every day of every month, every day of the week.", CronDescriber.getDescription("* * * * * ?"));
|
||||
assertEquals("At 0 seconds, every minute, every hour, on every day of every month, every day of the week.", CronDescriber.getDescription("0 * * * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, every hour, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 * * * ?"));
|
||||
assertEquals("At 0 seconds, 0 and 30 minutes, every hour, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0,30 * * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 0 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, 1 AM, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 1 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, 11 AM, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 11 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, noon, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 12 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, 1 PM, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 13 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, 11 PM, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 23 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on day 10 of every month, every day of the week.", CronDescriber.getDescription("0 0 0 10 * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on days 10 and 20 of every month, every day of the week.", CronDescriber.getDescription("0 0 0 10,20 * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on days from 10 to 15 of every month, every day of the week.", CronDescriber.getDescription("0 0 0 10-15 * ?"));
|
||||
assertEquals("At from 10 to 15 seconds, 0 minutes, midnight, on every day of every month, every day of the week.", CronDescriber.getDescription("10-15 0 0 * * ?"));
|
||||
assertEquals("At 30 seconds, 30 minutes, from 8 AM to 4 PM, on every day of every month, every day of the week.", CronDescriber.getDescription("30 30 8-16 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on every 3 days starting at 0 of every month, every day of the week.", CronDescriber.getDescription("0 0 0 */3 * ?"));
|
||||
assertEquals("At every 5 seconds starting at 0, 0 minutes, midnight, on every day of every month, every day of the week.", CronDescriber.getDescription("0/5 0 0 * * ?"));
|
||||
assertEquals("At 0 seconds, every 30 minutes starting at 3, midnight, on every day of every month, every day of the week.", CronDescriber.getDescription("0 3/30 0 * * ?"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on every day of every month, Monday, Wednesday, and Friday.", CronDescriber.getDescription("0 0 0 * * MON,WED,FRI"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on every day of every month, from Monday to Friday.", CronDescriber.getDescription("0 0 0 * * MON-FRI"));
|
||||
assertEquals("At 0 seconds, 0 minutes, midnight, on every day of every month, Sunday and Saturday.", CronDescriber.getDescription("0 0 0 * * 1,7"));
|
||||
assertEquals("At 0 seconds, 0 minutes, 2 AM, 6 AM, noon, 4 PM, and 8 PM, on every day of every month, every day of the week.", CronDescriber.getDescription("0 0 2,6,12,16,20 * * ?"));
|
||||
assertEquals("At every 5 seconds starting at 0, 14, 18, 3-39, and 52 minutes, every hour, on every day of January, March, and September, from Monday to Friday, in 2002-2010.", CronDescriber.getDescription("0/5 14,18,3-39,52 * ? JAN,MAR,SEP MON-FRI 2002-2010"));
|
||||
|
||||
assertEquals("At every second, every minute, every hour, on every day of every month, every day of the week.", CronDescriber.getDescription("* * * ? * *"));
|
||||
assertEquals("At every second, every minute, every hour, on every day of January to June, every day of the week.", CronDescriber.getDescription("* * * ? 1-6 *"));
|
||||
assertEquals("At every second, every minute, every hour, on days 1, 3, and 5 of every month, every day of the week.", CronDescriber.getDescription("* * * 1,3,5 * *"));
|
||||
// todo fix has 2-4 hours and 3 PM, s/b 2 AM to 4 AM and 3 PM assertEquals("At every second, every minute, every hour, on days 1, 3, and 5 of every month, every day of the week.", CronDescriber.getDescription("* * 2-4,15 1,3,5 * *"));
|
||||
// hour failing on 3,2-7 (at least in TS side?)
|
||||
// 3,2-7 makes 3,2 to July
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.scheduler;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
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.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for CronExpressionTooltipFieldBehavior
|
||||
*******************************************************************************/
|
||||
class CronExpressionTooltipFieldBehaviorTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
QFieldMetaData field = new QFieldMetaData("cronExpression", QFieldType.STRING);
|
||||
QContext.getQInstance().getTable(TestUtils.TABLE_NAME_SHAPE)
|
||||
.addField(field);
|
||||
|
||||
CronExpressionTooltipFieldBehavior.addToField(field);
|
||||
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SHAPE).withRecord(
|
||||
new QRecord().withValue("name", "Square").withValue("cronExpression", "* * * * * ?")));
|
||||
|
||||
QRecord record = new GetAction().executeForRecord(new GetInput(TestUtils.TABLE_NAME_SHAPE).withPrimaryKey(1).withShouldGenerateDisplayValues(true));
|
||||
assertThat(record.getDisplayValue("cronExpression:" + AdornmentType.TooltipValues.TOOLTIP_DYNAMIC))
|
||||
.contains("every second");
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user