Adding queues and queue providers; Adding schedules and ScheduleManager

This commit is contained in:
2022-10-18 09:00:21 -05:00
parent 888239b265
commit 6345846eba
23 changed files with 2172 additions and 43 deletions

View File

@ -28,6 +28,7 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
@ -39,6 +40,7 @@ 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.session.QSession;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
import com.kingsrook.qqq.backend.core.scheduler.StandardScheduledExecutor;
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.AfterEach;
@ -49,9 +51,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for PollingAutomationExecutor
** Unit test for StandardScheduledExecutor
*******************************************************************************/
class PollingAutomationExecutorTest
class StandardScheduledExecutorTest
{
/*******************************************************************************
@ -89,7 +91,7 @@ class PollingAutomationExecutorTest
////////////////////////////////////////////////
// have the polling executor run "for awhile" //
////////////////////////////////////////////////
runPollingAutomationExecutorForAwhile(qInstance);
runPollingAutomationExecutorForAwhile(qInstance, QSession::new);
/////////////////////////////////////////////////
// query for the records - assert their status //
@ -112,8 +114,6 @@ class PollingAutomationExecutorTest
/*******************************************************************************
**
*******************************************************************************/
@ -140,15 +140,14 @@ class PollingAutomationExecutorTest
));
new InsertAction().execute(insertInput);
String uuid = UUID.randomUUID().toString();
String uuid = UUID.randomUUID().toString();
QSession session = new QSession();
session.setIdReference(uuid);
PollingAutomationExecutor.getInstance().setSessionSupplier(() -> session);
////////////////////////////////////////////////
// have the polling executor run "for awhile" //
////////////////////////////////////////////////
runPollingAutomationExecutorForAwhile(qInstance);
runPollingAutomationExecutorForAwhile(qInstance, () -> session);
/////////////////////////////////////////////////////////////////////////////////////////////////////
// assert that the uuid we put in our session was present in the CaptureSessionIdAutomationHandler //
@ -183,12 +182,17 @@ class PollingAutomationExecutorTest
/*******************************************************************************
**
*******************************************************************************/
private void runPollingAutomationExecutorForAwhile(QInstance qInstance)
private void runPollingAutomationExecutorForAwhile(QInstance qInstance, Supplier<QSession> sessionSupplier)
{
PollingAutomationExecutor pollingAutomationExecutor = PollingAutomationExecutor.getInstance();
PollingAutomationRunner pollingAutomationRunner = new PollingAutomationRunner(qInstance, TestUtils.POLLING_AUTOMATION, sessionSupplier);
StandardScheduledExecutor pollingAutomationExecutor = new StandardScheduledExecutor(pollingAutomationRunner);
pollingAutomationExecutor.setInitialDelayMillis(0);
pollingAutomationExecutor.setDelayMillis(100);
pollingAutomationExecutor.start(qInstance, TestUtils.POLLING_AUTOMATION);
pollingAutomationExecutor.setQInstance(qInstance);
pollingAutomationExecutor.setName(TestUtils.POLLING_AUTOMATION);
pollingAutomationExecutor.setSessionSupplier(sessionSupplier);
pollingAutomationExecutor.start();
SleepUtils.sleep(1, TimeUnit.SECONDS);
pollingAutomationExecutor.stop();
}

View File

@ -0,0 +1,131 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.util.List;
import java.util.concurrent.TimeUnit;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
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.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
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.processes.QBackendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.scheduleing.QScheduleMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
** Unit test for ScheduleManager
*******************************************************************************/
class ScheduleManagerTest
{
/*******************************************************************************
**
*******************************************************************************/
@AfterEach
void afterEach()
{
ScheduleManager.resetSingleton();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testStartAndStop()
{
QInstance qInstance = TestUtils.defineInstance();
ScheduleManager scheduleManager = ScheduleManager.getInstance(qInstance);
scheduleManager.start();
assertThat(scheduleManager.getExecutors()).isNotEmpty();
scheduleManager.stopAsync();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testScheduledProcess() throws QInstanceValidationException
{
QInstance qInstance = TestUtils.defineInstance();
new QInstanceValidator().validate(qInstance);
qInstance.getAutomationProviders().clear();
qInstance.getQueueProviders().clear();
qInstance.addProcess(
new QProcessMetaData()
.withName("testScheduledProcess")
.withSchedule(new QScheduleMetaData().withRepeatMillis(2).withInitialDelaySeconds(0))
.withStepList(List.of(new QBackendStepMetaData()
.withName("step")
.withCode(new QCodeReference(BasicStep.class))))
);
BasicStep.counter = 0;
ScheduleManager scheduleManager = ScheduleManager.getInstance(qInstance);
scheduleManager.setSessionSupplier(QSession::new);
scheduleManager.start();
SleepUtils.sleep(50, TimeUnit.MILLISECONDS);
scheduleManager.stopAsync();
System.out.println("Ran: " + BasicStep.counter + " times");
assertTrue(BasicStep.counter > 1, "Scheduled process should have ran at least twice");
}
/*******************************************************************************
**
*******************************************************************************/
public static class BasicStep implements BackendStep
{
static int counter = 0;
@Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{
counter++;
}
}
}

View File

@ -38,6 +38,7 @@ import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
@ -72,6 +73,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMet
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.SQSQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.AutomationStatusTracking;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.AutomationStatusTrackingType;
@ -121,7 +125,8 @@ public class TestUtils
public static final String POSSIBLE_VALUE_SOURCE_CUSTOM = "custom"; // custom-type
public static final String POSSIBLE_VALUE_SOURCE_AUTOMATION_STATUS = "automationStatus";
public static final String POLLING_AUTOMATION = "polling";
public static final String POLLING_AUTOMATION = "polling";
public static final String DEFAULT_QUEUE_PROVIDER = "defaultQueueProvider";
@ -156,6 +161,9 @@ public class TestUtils
qInstance.addAutomationProvider(definePollingAutomationProvider());
qInstance.addQueueProvider(defineSqsProvider());
qInstance.addQueue(defineTestSqsQueue());
defineWidgets(qInstance);
defineApps(qInstance);
@ -841,4 +849,41 @@ public class TestUtils
return (new QPossibleValue<>(idValue, "Custom[" + idValue + "]"));
}
}
/*******************************************************************************
**
*******************************************************************************/
private static QQueueProviderMetaData defineSqsProvider()
{
QMetaDataVariableInterpreter interpreter = new QMetaDataVariableInterpreter();
String accessKey = interpreter.interpret("${env.SQS_ACCESS_KEY}");
String secretKey = interpreter.interpret("${env.SQS_SECRET_KEY}");
String region = interpreter.interpret("${env.SQS_REGION}");
String baseURL = interpreter.interpret("${env.SQS_BASE_URL}");
return (new SQSQueueProviderMetaData()
.withName(DEFAULT_QUEUE_PROVIDER)
.withAccessKey(accessKey)
.withSecretKey(secretKey)
.withRegion(region)
.withBaseURL(baseURL));
}
/*******************************************************************************
**
*******************************************************************************/
private static QQueueMetaData defineTestSqsQueue()
{
return (new QQueueMetaData()
.withName("testSQSQueue")
.withProviderName(DEFAULT_QUEUE_PROVIDER)
.withQueueName("test-queue")
.withProcessName("receiveEasypostTrackerWebhook"));
}
}