mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 21:20:45 +00:00
Merged dev into feature/bulk-upload-v2
This commit is contained in:
@ -35,9 +35,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ProcessAlertWidget
|
||||
** Unit test for AlertWidgetRenderer
|
||||
*******************************************************************************/
|
||||
class ProcessAlertWidgetTest extends BaseTest
|
||||
class AlertWidgetRendererTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
@ -46,10 +46,10 @@ class ProcessAlertWidgetTest extends BaseTest
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(QContext.getQInstance(), ProcessAlertWidget.class.getPackageName());
|
||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(QContext.getQInstance(), AlertWidgetRenderer.class.getPackageName());
|
||||
|
||||
RenderWidgetInput input = new RenderWidgetInput();
|
||||
input.setWidgetMetaData(QContext.getQInstance().getWidget(ProcessAlertWidget.NAME));
|
||||
input.setWidgetMetaData(QContext.getQInstance().getWidget(AlertWidgetRenderer.NAME));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// make sure we run w/o exceptions (and w/ default outputs) if there are no query params //
|
||||
@ -69,4 +69,4 @@ class ProcessAlertWidgetTest extends BaseTest
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -31,9 +31,13 @@ import java.util.stream.Collectors;
|
||||
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.logging.QCollectingLogger;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
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.dashboard.QWidgetMetaDataInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNodeType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
@ -41,9 +45,13 @@ import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMe
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior;
|
||||
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.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -350,4 +358,118 @@ class MetaDataActionTest extends BaseTest
|
||||
assertTrue(personMemoryTable.getDeletePermission());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testFilter() throws QException
|
||||
{
|
||||
QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(MetaDataAction.class);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// run default version, and assert tables are found //
|
||||
//////////////////////////////////////////////////////
|
||||
MetaDataOutput result = new MetaDataAction().execute(new MetaDataInput());
|
||||
assertFalse(result.getTables().isEmpty(), "should be some tables");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// run again (with the same instance as before) to assert about memoization of the filter based on the QInstance //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
new MetaDataAction().execute(new MetaDataInput());
|
||||
assertThat(collectingLogger.getCollectedMessages()).filteredOn(clm -> clm.getMessage().contains("Using new default")).hasSize(1);
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// set up new instance to use a custom filter, to deny all //
|
||||
/////////////////////////////////////////////////////////////
|
||||
QInstance instance = TestUtils.defineInstance();
|
||||
instance.setMetaDataFilter(new QCodeReference(DenyAllFilter.class));
|
||||
reInitInstanceInContext(instance);
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// re-run, and assert all tables are filtered away //
|
||||
/////////////////////////////////////////////////////
|
||||
result = new MetaDataAction().execute(new MetaDataInput());
|
||||
assertTrue(result.getTables().isEmpty(), "should be no tables");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// run again (with the same instance as before) to assert about memoization of the filter based on the QInstance //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
new MetaDataAction().execute(new MetaDataInput());
|
||||
assertThat(collectingLogger.getCollectedMessages()).filteredOn(clm -> clm.getMessage().contains("filter of type: DenyAllFilter")).hasSize(1);
|
||||
|
||||
QLogger.deactivateCollectingLoggerForClass(MetaDataAction.class);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// run now with the AllowAllFilter, confirm we get tables //
|
||||
////////////////////////////////////////////////////////////
|
||||
instance = TestUtils.defineInstance();
|
||||
instance.setMetaDataFilter(new QCodeReference(AllowAllMetaDataFilter.class));
|
||||
reInitInstanceInContext(instance);
|
||||
result = new MetaDataAction().execute(new MetaDataInput());
|
||||
assertFalse(result.getTables().isEmpty(), "should be some tables");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class DenyAllFilter implements MetaDataFilterInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean allowTable(MetaDataInput input, QTableMetaData table)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean allowProcess(MetaDataInput input, QProcessMetaData process)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean allowReport(MetaDataInput input, QReportMetaData report)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean allowApp(MetaDataInput input, QAppMetaData app)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean allowWidget(MetaDataInput input, QWidgetMetaDataInterface widget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.processes;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReferenceLambda;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.ProcessStepFlow;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStateMachineStep;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for RunProcessAction
|
||||
*******************************************************************************/
|
||||
class RunProcessActionTest extends BaseTest
|
||||
{
|
||||
private static List<String> log = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
void beforeEach()
|
||||
{
|
||||
log.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStateMachineTwoBackendSteps() throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData().withName("test")
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// two-steps - a, points at b; b has no next-step, so it exits //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
.addStep(QStateMachineStep.backendOnly("a", new QBackendStepMetaData().withName("aBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepA");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("b");
|
||||
}))))
|
||||
|
||||
.addStep(QStateMachineStep.backendOnly("b", new QBackendStepMetaData().withName("bBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepB");
|
||||
}))))
|
||||
|
||||
.withStepFlow(ProcessStepFlow.STATE_MACHINE);
|
||||
|
||||
QContext.getQInstance().addProcess(process);
|
||||
|
||||
RunProcessInput input = new RunProcessInput();
|
||||
input.setProcessName("test");
|
||||
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertEquals(List.of("in StepA", "in StepB"), log);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStateMachineTwoFrontendOnlySteps() throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData().withName("test")
|
||||
|
||||
.addStep(QStateMachineStep.frontendOnly("a", new QFrontendStepMetaData().withName("aFrontend")).withDefaultNextStepName("b"))
|
||||
.addStep(QStateMachineStep.frontendOnly("b", new QFrontendStepMetaData().withName("bFrontend")))
|
||||
|
||||
.withStepFlow(ProcessStepFlow.STATE_MACHINE);
|
||||
|
||||
QContext.getQInstance().addProcess(process);
|
||||
|
||||
RunProcessInput input = new RunProcessInput();
|
||||
input.setProcessName("test");
|
||||
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("aFrontend");
|
||||
|
||||
/////////////////////////////
|
||||
// resume after a, go to b //
|
||||
/////////////////////////////
|
||||
input.setStartAfterStep("aFrontend");
|
||||
runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("bFrontend");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStateMachineOneBackendStepReferencingItselfDoesNotInfiniteLoop() throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData().withName("test")
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// set up step that always points back at itself. //
|
||||
// since it never goes to the frontend, it'll stack overflow //
|
||||
// (though we'll catch it ourselves before JVM does) //
|
||||
///////////////////////////////////////////////////////////////
|
||||
.addStep(QStateMachineStep.backendOnly("a", new QBackendStepMetaData().withName("aBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepA");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("a");
|
||||
}))))
|
||||
|
||||
.withStepFlow(ProcessStepFlow.STATE_MACHINE);
|
||||
|
||||
QContext.getQInstance().addProcess(process);
|
||||
|
||||
RunProcessInput input = new RunProcessInput();
|
||||
input.setProcessName("test");
|
||||
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
assertThatThrownBy(() -> new RunProcessAction().execute(input))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("maxStateMachineProcessStepFlowStackDepth of 20");
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// make sure we can set a custom max-stack-depth //
|
||||
///////////////////////////////////////////////////
|
||||
input.addValue("maxStateMachineProcessStepFlowStackDepth", 5);
|
||||
assertThatThrownBy(() -> new RunProcessAction().execute(input))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("maxStateMachineProcessStepFlowStackDepth of 5");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStateMachineTwoBackendStepsReferencingEachOtherDoesNotInfiniteLoop() throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData().withName("test")
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// set up two steps that always points back at each other. //
|
||||
// since it never goes to the frontend, it'll stack overflow //
|
||||
// (though we'll catch it ourselves before JVM does) //
|
||||
///////////////////////////////////////////////////////////////
|
||||
.addStep(QStateMachineStep.backendOnly("a", new QBackendStepMetaData().withName("aBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepA");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("b");
|
||||
}))))
|
||||
|
||||
.addStep(QStateMachineStep.backendOnly("b", new QBackendStepMetaData().withName("bBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepB");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("a");
|
||||
}))))
|
||||
|
||||
.withStepFlow(ProcessStepFlow.STATE_MACHINE);
|
||||
|
||||
QContext.getQInstance().addProcess(process);
|
||||
|
||||
RunProcessInput input = new RunProcessInput();
|
||||
input.setProcessName("test");
|
||||
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
assertThatThrownBy(() -> new RunProcessAction().execute(input))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("maxStateMachineProcessStepFlowStackDepth of 20");
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// make sure we can set a custom max-stack-depth //
|
||||
///////////////////////////////////////////////////
|
||||
input.addValue("maxStateMachineProcessStepFlowStackDepth", 5);
|
||||
assertThatThrownBy(() -> new RunProcessAction().execute(input))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("maxStateMachineProcessStepFlowStackDepth of 5");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testStateSequenceOfFrontendAndBackendSteps() throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData().withName("test")
|
||||
|
||||
.addStep(QStateMachineStep.frontendThenBackend("a",
|
||||
new QFrontendStepMetaData().withName("aFrontend"),
|
||||
new QBackendStepMetaData().withName("aBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepA");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("b");
|
||||
}))))
|
||||
|
||||
.addStep(QStateMachineStep.frontendThenBackend("b",
|
||||
new QFrontendStepMetaData().withName("bFrontend"),
|
||||
new QBackendStepMetaData().withName("bBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepB");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("c");
|
||||
}))))
|
||||
|
||||
.addStep(QStateMachineStep.frontendThenBackend("c",
|
||||
new QFrontendStepMetaData().withName("cFrontend"),
|
||||
new QBackendStepMetaData().withName("cBackend")
|
||||
.withCode(new QCodeReferenceLambda<BackendStep>((runBackendStepInput, runBackendStepOutput) ->
|
||||
{
|
||||
log.add("in StepC");
|
||||
runBackendStepOutput.getProcessState().setNextStepName("d");
|
||||
}))))
|
||||
|
||||
.addStep(QStateMachineStep.frontendOnly("d",
|
||||
new QFrontendStepMetaData().withName("dFrontend")))
|
||||
|
||||
.withStepFlow(ProcessStepFlow.STATE_MACHINE);
|
||||
|
||||
QContext.getQInstance().addProcess(process);
|
||||
|
||||
RunProcessInput input = new RunProcessInput();
|
||||
input.setProcessName("test");
|
||||
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// start the process - we should be sent to aFrontend //
|
||||
////////////////////////////////////////////////////////
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("aFrontend");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// resume after aFrontend - we should run StepA (backend), and then be sent to bFrontend //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
input.setStartAfterStep("aFrontend");
|
||||
runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertEquals(List.of("in StepA"), log);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("bFrontend");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// resume after bFrontend - we should run StepB (backend), and then be sent to cFrontend //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
input.setStartAfterStep("bFrontend");
|
||||
runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertEquals(List.of("in StepA", "in StepB"), log);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("cFrontend");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// resume after cFrontend - we should run StepC (backend), and then be sent to dFrontend //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
input.setStartAfterStep("cFrontend");
|
||||
runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertEquals(List.of("in StepA", "in StepB", "in StepC"), log);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName())
|
||||
.isPresent().get()
|
||||
.isEqualTo("dFrontend");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// if we resume again here, we'll be past the end of the process, so no next-step //
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
input.setStartAfterStep("dFrontend");
|
||||
runProcessOutput = new RunProcessAction().execute(input);
|
||||
assertEquals(List.of("in StepA", "in StepB", "in StepC"), log);
|
||||
assertThat(runProcessOutput.getProcessState().getNextStepName()).isEmpty();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.reporting;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
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.tables.UniqueKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for DistinctFilteringRecordPipe
|
||||
*******************************************************************************/
|
||||
class DistinctFilteringRecordPipeTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testSingleFieldKey() throws QException
|
||||
{
|
||||
DistinctFilteringRecordPipe pipe = new DistinctFilteringRecordPipe(new UniqueKey("id"));
|
||||
pipe.addRecord(new QRecord().withValue("id", 1));
|
||||
pipe.addRecord(new QRecord().withValue("id", 1));
|
||||
assertEquals(1, pipe.consumeAvailableRecords().size());
|
||||
|
||||
pipe.addRecord(new QRecord().withValue("id", 1));
|
||||
assertEquals(0, pipe.consumeAvailableRecords().size());
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testMultiFieldKey() throws QException
|
||||
{
|
||||
DistinctFilteringRecordPipe pipe = new DistinctFilteringRecordPipe(new UniqueKey("type", "name"));
|
||||
|
||||
////////////////////////////
|
||||
// add 3 distinct records //
|
||||
////////////////////////////
|
||||
pipe.addRecord(new QRecord().withValue("type", 1).withValue("name", "A"));
|
||||
pipe.addRecord(new QRecord().withValue("type", 1).withValue("name", "B"));
|
||||
pipe.addRecord(new QRecord().withValue("type", 2).withValue("name", "B"));
|
||||
assertEquals(3, pipe.consumeAvailableRecords().size());
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// now re-add those 3 (should all be discarded) plus one new one //
|
||||
///////////////////////////////////////////////////////////////////
|
||||
pipe.addRecord(new QRecord().withValue("type", 1).withValue("name", "A"));
|
||||
pipe.addRecord(new QRecord().withValue("type", 1).withValue("name", "B"));
|
||||
pipe.addRecord(new QRecord().withValue("type", 2).withValue("name", "B"));
|
||||
pipe.addRecord(new QRecord().withValue("type", 2).withValue("name", "A"));
|
||||
assertEquals(1, pipe.consumeAvailableRecords().size());
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -80,6 +81,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
@ -340,6 +342,16 @@ public class GenerateReportActionTest extends BaseTest
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String runToString(ReportFormat reportFormat, String reportName) throws Exception
|
||||
{
|
||||
return (runToString(reportFormat, reportName, Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String runToString(ReportFormat reportFormat, String reportName, Map<String, Serializable> inputValues) throws Exception
|
||||
{
|
||||
String name = "/tmp/report." + reportFormat.getExtension();
|
||||
try(FileOutputStream fileOutputStream = new FileOutputStream(name))
|
||||
@ -347,7 +359,7 @@ public class GenerateReportActionTest extends BaseTest
|
||||
ReportInput reportInput = new ReportInput();
|
||||
reportInput.setReportName(reportName);
|
||||
reportInput.setReportDestination(new ReportDestination().withReportFormat(reportFormat).withReportOutputStream(fileOutputStream));
|
||||
reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now()));
|
||||
reportInput.setInputValues(inputValues);
|
||||
new GenerateReportAction().execute(reportInput);
|
||||
System.out.println("Wrote File: " + name);
|
||||
return (FileUtils.readFileToString(new File(name), StandardCharsets.UTF_8));
|
||||
@ -978,4 +990,55 @@ public class GenerateReportActionTest extends BaseTest
|
||||
assertThat(row.get("Home State Name")).isEqualTo("IL");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testFilterMissingValue() throws Exception
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define a report in the instance, with an input field - then we'll run it w/o supplying the value //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QReportMetaData report = new QReportMetaData()
|
||||
.withName(REPORT_NAME)
|
||||
.withDataSources(List.of(
|
||||
new QReportDataSource()
|
||||
.withName("persons")
|
||||
.withSourceTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||
.withQueryFilter(new QQueryFilter()
|
||||
.withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.GREATER_THAN, List.of("${input.startDate}"))))))
|
||||
.withViews(List.of(
|
||||
new QReportView()
|
||||
.withName("table1")
|
||||
.withLabel("Table 1")
|
||||
.withDataSourceName("persons")
|
||||
.withType(ReportType.TABLE)
|
||||
.withColumns(List.of(new QReportField().withName("id")))
|
||||
));
|
||||
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
qInstance.addReport(report);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// the report should run, but with the filter removed, so it should find all (6) person records //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
insertPersonRecords(qInstance);
|
||||
String json = runToString(ReportFormat.JSON, report.getName(), Collections.emptyMap());
|
||||
JSONArray reportJsonArray = new JSONArray(json);
|
||||
assertEquals(6, reportJsonArray.length());
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// re-run now, pretending to be a report that wasn't defined in meta-data, but instead was //
|
||||
// ah-hoc-style, in which case, a missing input is defined as, should throw exception. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ReportInput reportInput = new ReportInput();
|
||||
report.setName(null);
|
||||
reportInput.setReportMetaData(report);
|
||||
reportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.JSON).withReportOutputStream(new ByteArrayOutputStream()));
|
||||
assertThatThrownBy(() -> new GenerateReportAction().execute(reportInput))
|
||||
.hasMessageContaining("Missing value for criteria on field: birthDate");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.reporting.excel.fastexcel;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import org.dhatim.fastexcel.StyleSetter;
|
||||
import org.dhatim.fastexcel.Workbook;
|
||||
import org.dhatim.fastexcel.Worksheet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for BoldHeaderAndFooterFastExcelStyler
|
||||
*******************************************************************************/
|
||||
class BoldHeaderAndFooterFastExcelStylerTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** ... kinda just here to add test coverage to the class. I suppose, it
|
||||
** makes sure there's not an NPE inside that method at least...?
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
Workbook workbook = new Workbook(new ByteArrayOutputStream(), "Test", null);
|
||||
Worksheet worksheet = workbook.newWorksheet("Sheet 1");
|
||||
StyleSetter headerStyle = worksheet.range(0, 0, 1, 1).style();
|
||||
new BoldHeaderAndFooterFastExcelStyler().styleHeaderRow(headerStyle);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.scripts;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for QCodeExecutor
|
||||
*******************************************************************************/
|
||||
class QCodeExecutorTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testConvertJavaObject() throws QCodeException
|
||||
{
|
||||
Object input = new Object();
|
||||
Object converted = ((QCodeExecutor) (codeReference, inputContext, executionLogger) -> null).convertJavaObject(input, null);
|
||||
assertSame(input, converted);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testConvertObjectToJava() throws QCodeException
|
||||
{
|
||||
Object input = new Object();
|
||||
Object converted = ((QCodeExecutor) (codeReference, inputContext, executionLogger) -> null).convertObjectToJava(input);
|
||||
assertSame(input, converted);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for AbstractMetaDataProducerBasedQQQApplication
|
||||
*******************************************************************************/
|
||||
class AbstractMetaDataProducerBasedQQQApplicationTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
QInstance qInstance = new TestApplication().defineQInstance();
|
||||
assertEquals(1, qInstance.getTables().size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class TestApplication extends AbstractMetaDataProducerBasedQQQApplication
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String getMetaDataPackageName()
|
||||
{
|
||||
return getClass().getPackage().getName() + ".producers";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
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.tables.QTableMetaData;
|
||||
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.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for AbstractQQQApplication
|
||||
*******************************************************************************/
|
||||
class AbstractQQQApplicationTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
TestApplication testApplication = new TestApplication();
|
||||
QInstance qInstance = testApplication.defineQInstance();
|
||||
assertEquals(1, qInstance.getTables().size());
|
||||
assertTrue(qInstance.getTables().containsKey("testTable"));
|
||||
|
||||
assertThatThrownBy(() -> testApplication.defineValidatedQInstance())
|
||||
.hasMessageContaining("validation");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class TestApplication extends AbstractQQQApplication
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QInstance defineQInstance() throws QException
|
||||
{
|
||||
QInstance qInstance = new QInstance();
|
||||
qInstance.addTable(new QTableMetaData().withName("testTable"));
|
||||
return (qInstance);
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.PersonsByCreateDateBarChart;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ParentWidgetRenderer;
|
||||
import com.kingsrook.qqq.backend.core.actions.metadata.AllowAllMetaDataFilter;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.CancelProcessActionTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.customizers.ReportCustomRecordSourceInterface;
|
||||
@ -139,6 +140,21 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testMetaDataFilter()
|
||||
{
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.setMetaDataFilter(new QCodeReference(QInstanceValidator.class)),
|
||||
"Instance metaDataFilter CodeReference is not of the expected type");
|
||||
|
||||
assertValidationSuccess((qInstance) -> qInstance.setMetaDataFilter(new QCodeReference(AllowAllMetaDataFilter.class)));
|
||||
assertValidationSuccess((qInstance) -> qInstance.setMetaDataFilter(null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an instance with null backends - should throw.
|
||||
**
|
||||
@ -265,6 +281,38 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTableFieldInlinePossibleValueSource()
|
||||
{
|
||||
////////////////////////////////////////////////////
|
||||
// make sure can't have both named and inline PVS //
|
||||
////////////////////////////////////////////////////
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) -> qInstance.getTable("person").getField("homeStateId")
|
||||
.withInlinePossibleValueSource(new QPossibleValueSource().withType(QPossibleValueSourceType.TABLE).withTableName("person")),
|
||||
"both a possibleValueSourceName and an inlinePossibleValueSource");
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// make require inline PVS to be enum type //
|
||||
/////////////////////////////////////////////
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) -> qInstance.getTable("person").getField("homeStateId")
|
||||
.withPossibleValueSourceName(null)
|
||||
.withInlinePossibleValueSource(new QPossibleValueSource().withType(QPossibleValueSourceType.TABLE)),
|
||||
"must have a type of ENUM");
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// make sure validation on the inline PVS happens //
|
||||
////////////////////////////////////////////////////
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) -> qInstance.getTable("person").getField("homeStateId")
|
||||
.withPossibleValueSourceName(null)
|
||||
.withInlinePossibleValueSource(new QPossibleValueSource().withType(QPossibleValueSourceType.ENUM)),
|
||||
"missing enum values");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test that if a process specifies a table that doesn't exist, that it fails.
|
||||
**
|
||||
@ -717,8 +765,8 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
@Test
|
||||
public void test_validateFieldWithMissingPossibleValueSource()
|
||||
{
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").getField("homeStateId").setPossibleValueSourceName("not a real possible value source"),
|
||||
"Unrecognized possibleValueSourceName");
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) -> qInstance.getTable("person").getField("homeStateId").setPossibleValueSourceName("not a real possible value source"),
|
||||
"unrecognized possibleValueSourceName");
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestMetaDataProducer implements MetaDataProducerInterface<QTableMetaData>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
return new QTableMetaData().withName("fromProducer");
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -64,4 +65,19 @@ class EmailMessagingProviderTest extends BaseTest
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testMissingInputs()
|
||||
{
|
||||
assertThatThrownBy(() -> new SendMessageAction().execute(new SendMessageInput()))
|
||||
.hasMessageContaining("provider name was not given");
|
||||
|
||||
assertThatThrownBy(() -> new SendMessageAction().execute(new SendMessageInput().withMessagingProviderName("notFound")))
|
||||
.hasMessageContaining("was not found");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface;
|
||||
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.tables.QTableMetaData;
|
||||
|
||||
|
@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface;
|
||||
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.tables.QTableMetaData;
|
||||
|
||||
|
@ -161,9 +161,19 @@ class RenderSavedReportProcessTest extends BaseTest
|
||||
*******************************************************************************/
|
||||
private static InputStream getInputStream(RunProcessOutput runProcessOutput) throws QException
|
||||
{
|
||||
String storageTableName = runProcessOutput.getValueString("storageTableName");
|
||||
String storageReference = runProcessOutput.getValueString("storageReference");
|
||||
InputStream inputStream = new MemoryStorageAction().getInputStream(new StorageInput(storageTableName).withReference(storageReference));
|
||||
String storageTableName = runProcessOutput.getValueString("storageTableName");
|
||||
String storageReference = runProcessOutput.getValueString("storageReference");
|
||||
|
||||
MemoryStorageAction memoryStorageAction = new MemoryStorageAction();
|
||||
StorageInput storageInput = new StorageInput(storageTableName).withReference(storageReference);
|
||||
InputStream inputStream = memoryStorageAction.getInputStream(storageInput);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// to help add a little bit of class-level code coverage, for the QStorageInterface, call a method //
|
||||
// that has a defualt implementation in there //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
memoryStorageAction.getDownloadURL(storageInput);
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for CountingHash
|
||||
** Unit test for CountingHash
|
||||
*******************************************************************************/
|
||||
class CountingHashTest extends BaseTest
|
||||
{
|
||||
@ -73,4 +73,19 @@ class CountingHashTest extends BaseTest
|
||||
assertEquals(1, alwaysMutable.get("B"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPut()
|
||||
{
|
||||
CountingHash<String> alwaysMutable = new CountingHash<>(Map.of("A", 5));
|
||||
alwaysMutable.put("A", 25);
|
||||
assertEquals(25, alwaysMutable.get("A"));
|
||||
alwaysMutable.put("A");
|
||||
assertEquals(26, alwaysMutable.get("A"));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user