CE-936 - Test coverage on quartz code

This commit is contained in:
2024-03-12 15:47:15 -05:00
parent 7181643abb
commit b093ff5ece
13 changed files with 614 additions and 42 deletions

View File

@ -309,6 +309,7 @@ public class QScheduleManager
public void unInit()
{
qScheduleManager = null;
schedulers.values().forEach(s -> s.unInit());
schedulers.clear();
}
}

View File

@ -34,12 +34,26 @@ import com.kingsrook.qqq.backend.core.model.metadata.queues.SQSQueueProviderMeta
*******************************************************************************/
public interface QSchedulerInterface
{
/*******************************************************************************
**
*******************************************************************************/
void setupProcess(QProcessMetaData process, Map<String, Serializable> backendVariantData, boolean allowedToStart);
/*******************************************************************************
**
*******************************************************************************/
void setupSqsProvider(SQSQueueProviderMetaData queueProvider, boolean allowedToStart);
/*******************************************************************************
**
*******************************************************************************/
void setupAutomationProviderPerTable(QAutomationProviderMetaData automationProvider, boolean allowedToStart);
/*******************************************************************************
**
*******************************************************************************/
void start();
/*******************************************************************************
**
*******************************************************************************/
@ -51,19 +65,12 @@ public interface QSchedulerInterface
void stop();
/*******************************************************************************
**
** Handle a whole shutdown of the scheduler system (e.g., between unit tests).
*******************************************************************************/
void setupAutomationProviderPerTable(QAutomationProviderMetaData automationProvider, boolean allowedToStart);
default void unInit()
{
/*******************************************************************************
**
*******************************************************************************/
void setupProcess(QProcessMetaData process, Map<String, Serializable> backendVariantData, boolean allowedToStart);
/*******************************************************************************
**
*******************************************************************************/
void start();
}
/*******************************************************************************
** let the scheduler know when the schedule manager is at the start of setting up schedules.

View File

@ -0,0 +1,34 @@
/*
* 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.scheduler.quartz;
import org.quartz.JobDetail;
import org.quartz.Trigger;
/*******************************************************************************
**
*******************************************************************************/
public record QuartzJobAndTriggerWrapper(JobDetail jobDetail, Trigger trigger, Trigger.TriggerState triggerState)
{
}

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.scheduler.quartz;
import java.io.Serializable;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -250,7 +251,7 @@ public class QuartzScheduler implements QSchedulerInterface
}
else
{
long intervalMillis = Objects.requireNonNullElse(scheduleMetaData.getRepeatMillis(), scheduleMetaData.getRepeatSeconds() * 1000);
long intervalMillis = Objects.requireNonNullElseGet(scheduleMetaData.getRepeatMillis(), () -> scheduleMetaData.getRepeatSeconds() * 1000);
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalMillis)
.repeatForever();
@ -376,6 +377,8 @@ public class QuartzScheduler implements QSchedulerInterface
this.scheduler.scheduleJob(jobDetail, trigger);
LOG.info("Scheduled new job: " + jobKey);
}
// todo - think about... clear memoization - but - when this is used in bulk, that's when we want the memo!
}
@ -499,4 +502,46 @@ public class QuartzScheduler implements QSchedulerInterface
{
this.scheduler.resumeJob(new JobKey(jobName, groupName));
}
/*******************************************************************************
**
*******************************************************************************/
List<QuartzJobAndTriggerWrapper> queryQuartz() throws SchedulerException
{
List<QuartzJobAndTriggerWrapper> rs = new ArrayList<>();
List<String> jobGroupNames = scheduler.getJobGroupNames();
for(String group : jobGroupNames)
{
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.groupEquals(group));
for(JobKey jobKey : jobKeys)
{
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
List<? extends Trigger> triggersOfJob = scheduler.getTriggersOfJob(jobKey);
for(Trigger trigger : triggersOfJob)
{
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
rs.add(new QuartzJobAndTriggerWrapper(jobDetail, trigger, triggerState));
}
}
}
return (rs);
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public void unInit()
{
///////////////////////////////////////////////////
// resetting the singleton should be sufficient! //
///////////////////////////////////////////////////
quartzScheduler = null;
}
}

View File

@ -51,12 +51,15 @@ public class QuartzSqsPollerJob implements Job
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
{
String queueProviderName = null;
String queueName = null;
try
{
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String queueProviderName = jobDataMap.getString("queueProviderName");
String queueName = jobDataMap.getString("queueName");
QInstance qInstance = QuartzScheduler.getInstance().getQInstance();
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
queueProviderName = jobDataMap.getString("queueProviderName");
queueName = jobDataMap.getString("queueName");
QInstance qInstance = QuartzScheduler.getInstance().getQInstance();
SQSQueuePoller sqsQueuePoller = new SQSQueuePoller();
sqsQueuePoller.setQueueProviderMetaData((SQSQueueProviderMetaData) qInstance.getQueueProvider(queueProviderName));
@ -67,9 +70,13 @@ public class QuartzSqsPollerJob implements Job
/////////////
// run it. //
/////////////
LOG.debug("Running quartz SQS Poller", logPair("queueName", queueName));
LOG.debug("Running quartz SQS Poller", logPair("queueName", queueName), logPair("queueProviderName", queueProviderName));
sqsQueuePoller.run();
}
catch(Exception e)
{
LOG.warn("Error running SQS Poller", e, logPair("queueName", queueName), logPair("queueProviderName", queueProviderName));
}
finally
{
QContext.clear();

View File

@ -51,13 +51,17 @@ public class QuartzTableAutomationsJob implements Job
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
{
String tableName = null;
String automationProviderName = null;
AutomationStatus automationStatus = null;
try
{
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String tableName = jobDataMap.getString("tableName");
String automationProviderName = jobDataMap.getString("automationProviderName");
AutomationStatus automationStatus = AutomationStatus.valueOf(jobDataMap.getString("automationStatus"));
QInstance qInstance = QuartzScheduler.getInstance().getQInstance();
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
tableName = jobDataMap.getString("tableName");
automationProviderName = jobDataMap.getString("automationProviderName");
automationStatus = AutomationStatus.valueOf(jobDataMap.getString("automationStatus"));
QInstance qInstance = QuartzScheduler.getInstance().getQInstance();
PollingAutomationPerTableRunner.TableActionsInterface tableAction = new PollingAutomationPerTableRunner.TableActions(tableName, automationStatus);
PollingAutomationPerTableRunner runner = new PollingAutomationPerTableRunner(qInstance, automationProviderName, QuartzScheduler.getInstance().getSessionSupplier(), tableAction);
@ -68,6 +72,10 @@ public class QuartzTableAutomationsJob implements Job
LOG.debug("Running Table Automations", logPair("tableName", tableName), logPair("automationStatus", automationStatus));
runner.run();
}
catch(Exception e)
{
LOG.warn("Error running Table Automations", e, logPair("tableName", tableName), logPair("automationStatus", automationStatus));
}
finally
{
QContext.clear();

View File

@ -77,7 +77,7 @@ public class PauseQuartzJobsProcess extends AbstractLoadStep implements MetaData
QuartzScheduler instance = QuartzScheduler.getInstance();
for(QRecord record : runBackendStepInput.getRecords())
{
instance.pauseJob(record.getValueString("JOB_NAME"), record.getValueString("GROUP_NAME"));
instance.pauseJob(record.getValueString("jobName"), record.getValueString("groupName"));
}
}
catch(Exception e)

View File

@ -77,7 +77,7 @@ public class ResumeQuartzJobsProcess extends AbstractLoadStep implements MetaDat
QuartzScheduler instance = QuartzScheduler.getInstance();
for(QRecord record : runBackendStepInput.getRecords())
{
instance.resumeJob(record.getValueString("JOB_NAME"), record.getValueString("GROUP_NAME"));
instance.resumeJob(record.getValueString("jobName"), record.getValueString("groupName"));
}
}
catch(Exception e)

View File

@ -305,7 +305,6 @@ public class SimpleScheduler implements QSchedulerInterface
*******************************************************************************/
static void resetSingleton()
{
simpleScheduler = null;
}
@ -339,4 +338,17 @@ public class SimpleScheduler implements QSchedulerInterface
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public void unInit()
{
//////////////////////////////////////////////////
// resetting the singleton should be sufficient //
//////////////////////////////////////////////////
simpleScheduler = null;
}
}

View File

@ -22,12 +22,29 @@
package com.kingsrook.qqq.backend.core.scheduler.quartz;
import java.util.Properties;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.context.QContext;
import org.junit.jupiter.api.BeforeEach;
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.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.scheduler.QScheduleManager;
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
import org.apache.logging.log4j.Level;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.quartz.SchedulerException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
@ -35,18 +52,14 @@ import org.quartz.SchedulerException;
*******************************************************************************/
class QuartzSchedulerTest extends BaseTest
{
/*******************************************************************************
**
*******************************************************************************/
@BeforeEach
void beforeEach() throws SchedulerException
@AfterEach
void afterEach()
{
Properties quartzProperties = new Properties();
quartzProperties.put("", "");
quartzProperties.put("org.quartz.scheduler.instanceName", "TestScheduler");
quartzProperties.put("org.quartz.threadPool.threadCount", "3");
quartzProperties.put("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");
QuartzScheduler.initInstance(QContext.getQInstance(), "TestScheduler", quartzProperties, QContext::getQSession);
QScheduleManager.getInstance().unInit();
}
@ -55,9 +68,84 @@ class QuartzSchedulerTest extends BaseTest
**
*******************************************************************************/
@Test
void test()
void test() throws Exception
{
try
{
QInstance qInstance = QContext.getQInstance();
QuartzTestUtils.setupInstanceForQuartzTests();
//////////////////////////////////////////////////////////////////////////////////////////////////////
// set these runners to use collecting logger, so we can assert that they did run, and didn't throw //
//////////////////////////////////////////////////////////////////////////////////////////////////////
QCollectingLogger quartzSqsPollerJobLog = QLogger.activateCollectingLoggerForClass(QuartzSqsPollerJob.class);
QCollectingLogger quartzTableAutomationsJobLog = QLogger.activateCollectingLoggerForClass(QuartzTableAutomationsJob.class);
//////////////////////////////////////////
// add a process we can run and observe //
//////////////////////////////////////////
qInstance.addProcess(new QProcessMetaData()
.withName("testScheduledProcess")
.withSchedule(new QScheduleMetaData()
.withSchedulerName(QuartzTestUtils.QUARTZ_SCHEDULER_NAME)
.withRepeatMillis(2)
.withInitialDelaySeconds(0))
.withStepList(List.of(new QBackendStepMetaData()
.withName("step")
.withCode(new QCodeReference(BasicStep.class)))));
//////////////////////////////////////////////////////////////////////////////
// start the schedule manager, which will schedule things, and start quartz //
//////////////////////////////////////////////////////////////////////////////
QSession qSession = QContext.getQSession();
QScheduleManager qScheduleManager = QScheduleManager.initInstance(qInstance, () -> qSession);
qScheduleManager.start();
//////////////////////////////////////////////////
// give a moment for the job to run a few times //
//////////////////////////////////////////////////
SleepUtils.sleep(50, TimeUnit.MILLISECONDS);
qScheduleManager.stopAsync();
System.out.println("Ran: " + BasicStep.counter + " times");
assertTrue(BasicStep.counter > 1, "Scheduled process should have ran at least twice (but only ran [" + BasicStep.counter + "] time(s).");
//////////////////////////////////////////////////////
// make sure poller ran, and didn't issue any warns //
//////////////////////////////////////////////////////
assertThat(quartzSqsPollerJobLog.getCollectedMessages())
.anyMatch(m -> m.getLevel().equals(Level.DEBUG) && m.getMessage().contains("Running quartz SQS Poller"))
.noneMatch(m -> m.getLevel().equals(Level.WARN));
//////////////////////////////////////////////////////
// make sure poller ran, and didn't issue any warns //
//////////////////////////////////////////////////////
assertThat(quartzTableAutomationsJobLog.getCollectedMessages())
.anyMatch(m -> m.getLevel().equals(Level.DEBUG) && m.getMessage().contains("Running Table Automations"))
.noneMatch(m -> m.getLevel().equals(Level.WARN));
}
finally
{
QLogger.deactivateCollectingLoggerForClass(QuartzSqsPollerJob.class);
}
}
/*******************************************************************************
**
*******************************************************************************/
public static class BasicStep implements BackendStep
{
static int counter = 0;
@Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{
counter++;
}
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.scheduler.quartz;
import java.util.List;
import java.util.Properties;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.queues.SQSQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.scheduleing.quartz.QuartzSchedulerMetaData;
import org.quartz.SchedulerException;
/*******************************************************************************
**
*******************************************************************************/
public class QuartzTestUtils
{
public final static String QUARTZ_SCHEDULER_NAME = "TestQuartzScheduler";
/*******************************************************************************
**
*******************************************************************************/
private static Properties getQuartzProperties()
{
Properties quartzProperties = new Properties();
quartzProperties.put("org.quartz.scheduler.instanceName", QUARTZ_SCHEDULER_NAME);
quartzProperties.put("org.quartz.threadPool.threadCount", "3");
quartzProperties.put("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");
return (quartzProperties);
}
/*******************************************************************************
**
*******************************************************************************/
public static void setupInstanceForQuartzTests()
{
QInstance qInstance = QContext.getQInstance();
///////////////////////////////////////////////////
// remove the simple scheduler from the instance //
///////////////////////////////////////////////////
qInstance.getSchedulers().clear();
////////////////////////////////////////////////////////
// add the quartz scheduler meta-data to the instance //
////////////////////////////////////////////////////////
qInstance.addScheduler(new QuartzSchedulerMetaData()
.withProperties(getQuartzProperties())
.withName(QUARTZ_SCHEDULER_NAME));
////////////////////////////////////////////////////////////////////////////////
// set the queue providers & automation providers to use the quartz scheduler //
////////////////////////////////////////////////////////////////////////////////
qInstance.getAutomationProviders().values()
.forEach(ap -> ap.getSchedule().setSchedulerName(QUARTZ_SCHEDULER_NAME));
qInstance.getQueueProviders().values()
.forEach(qp -> ((SQSQueueProviderMetaData) qp).getSchedule().setSchedulerName(QUARTZ_SCHEDULER_NAME));
}
/*******************************************************************************
**
*******************************************************************************/
public static List<QuartzJobAndTriggerWrapper> queryQuartz() throws SchedulerException
{
return QuartzScheduler.getInstance().queryQuartz();
}
}

View File

@ -0,0 +1,277 @@
/*
* 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.scheduler.quartz.processes;
import java.util.List;
import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory;
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
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.processes.RunProcessInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
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.MetaDataProducerHelper;
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.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.scheduler.QScheduleManager;
import com.kingsrook.qqq.backend.core.scheduler.quartz.QuartzJobAndTriggerWrapper;
import com.kingsrook.qqq.backend.core.scheduler.quartz.QuartzScheduler;
import com.kingsrook.qqq.backend.core.scheduler.quartz.QuartzTestUtils;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import static org.assertj.core.api.Assertions.assertThat;
/*******************************************************************************
** Unit tests for the various quartz management processes
*******************************************************************************/
class QuartzJobsProcessTest extends BaseTest
{
/*******************************************************************************
**
*******************************************************************************/
@BeforeEach
void beforeEach() throws QException
{
QInstance qInstance = QContext.getQInstance();
qInstance.addTable(new QTableMetaData()
.withName("quartzTriggers")
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
.withPrimaryKeyField("id")
.withField(new QFieldMetaData("id", QFieldType.LONG)));
MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, QuartzScheduler.class.getPackageName());
QuartzTestUtils.setupInstanceForQuartzTests();
//////////////////////////////////////////////////////////////////////////////
// start the schedule manager, which will schedule things, and start quartz //
//////////////////////////////////////////////////////////////////////////////
QSession qSession = QContext.getQSession();
QScheduleManager qScheduleManager = QScheduleManager.initInstance(qInstance, () -> qSession);
qScheduleManager.start();
}
/*******************************************************************************
**
*******************************************************************************/
@AfterEach
void afterEach()
{
QScheduleManager.getInstance().stop();
QScheduleManager.getInstance().unInit();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testPauseAllQuartzJobs() throws QException, SchedulerException
{
////////////////////////////////////////
// make sure nothing starts as paused //
////////////////////////////////////////
assertNoneArePaused();
///////////////////////////////
// run the pause-all process //
///////////////////////////////
RunProcessInput input = new RunProcessInput();
input.setProcessName(PauseAllQuartzJobsProcess.class.getSimpleName());
new RunProcessAction().execute(input);
//////////////////////////////////////
// assert everything becomes paused //
//////////////////////////////////////
assertAllArePaused();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testResumeAllQuartzJobs() throws QException, SchedulerException
{
///////////////////////////////
// run the pause-all process //
///////////////////////////////
RunProcessInput input = new RunProcessInput();
input.setProcessName(PauseAllQuartzJobsProcess.class.getSimpleName());
new RunProcessAction().execute(input);
//////////////////////////////////////
// assert everything becomes paused //
//////////////////////////////////////
assertAllArePaused();
////////////////////
// run resume all //
////////////////////
input = new RunProcessInput();
input.setProcessName(ResumeAllQuartzJobsProcess.class.getSimpleName());
new RunProcessAction().execute(input);
////////////////////////////////////////
// make sure nothing ends up as paused //
////////////////////////////////////////
assertNoneArePaused();
////////////////////
// pause just one //
////////////////////
List<QuartzJobAndTriggerWrapper> quartzJobAndTriggerWrappers = QuartzTestUtils.queryQuartz();
new InsertAction().execute(new InsertInput("quartzTriggers").withRecord(new QRecord()
.withValue("jobName", quartzJobAndTriggerWrappers.get(0).jobDetail().getKey().getName())
.withValue("groupName", quartzJobAndTriggerWrappers.get(0).jobDetail().getKey().getGroup())
));
input = new RunProcessInput();
input.setProcessName(PauseQuartzJobsProcess.class.getSimpleName());
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
new RunProcessAction().execute(input);
/////////////////////////////////////////////////////////
// make sure at least 1 is paused, some are not paused //
/////////////////////////////////////////////////////////
assertAnyAre(Trigger.TriggerState.PAUSED);
assertAnyAreNot(Trigger.TriggerState.PAUSED);
//////////////////////////
// run resume all again //
//////////////////////////
input = new RunProcessInput();
input.setProcessName(ResumeAllQuartzJobsProcess.class.getSimpleName());
new RunProcessAction().execute(input);
////////////////////////////////////////
// make sure nothing ends up as paused //
////////////////////////////////////////
assertNoneArePaused();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testPauseOneResumeOne() throws QException, SchedulerException
{
/////////////////////////////////////
// make sure nothing starts paused //
/////////////////////////////////////
assertNoneArePaused();
////////////////////
// pause just one //
////////////////////
List<QuartzJobAndTriggerWrapper> quartzJobAndTriggerWrappers = QuartzTestUtils.queryQuartz();
new InsertAction().execute(new InsertInput("quartzTriggers").withRecord(new QRecord()
.withValue("jobName", quartzJobAndTriggerWrappers.get(0).jobDetail().getKey().getName())
.withValue("groupName", quartzJobAndTriggerWrappers.get(0).jobDetail().getKey().getGroup())
));
RunProcessInput input = new RunProcessInput();
input.setProcessName(PauseQuartzJobsProcess.class.getSimpleName());
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
new RunProcessAction().execute(input);
/////////////////////////////////////////////////////////
// make sure at least 1 is paused, some are not paused //
/////////////////////////////////////////////////////////
assertAnyAre(Trigger.TriggerState.PAUSED);
assertAnyAreNot(Trigger.TriggerState.PAUSED);
/////////////////////////////////////////////////////////////////////////////
// now resume the same one (will still be only row in our in-memory table) //
/////////////////////////////////////////////////////////////////////////////
input = new RunProcessInput();
input.setProcessName(ResumeQuartzJobsProcess.class.getSimpleName());
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
new RunProcessAction().execute(input);
//////////////////////////////////////
// make sure nothing ends up paused //
//////////////////////////////////////
assertNoneArePaused();
}
/*******************************************************************************
**
*******************************************************************************/
private static void assertAnyAre(Trigger.TriggerState triggerState) throws SchedulerException
{
assertThat(QuartzTestUtils.queryQuartz()).anyMatch(qjtw -> qjtw.triggerState().equals(triggerState));
}
/*******************************************************************************
**
*******************************************************************************/
private static void assertAnyAreNot(Trigger.TriggerState triggerState) throws SchedulerException
{
assertThat(QuartzTestUtils.queryQuartz()).anyMatch(qjtw -> !qjtw.triggerState().equals(triggerState));
}
/*******************************************************************************
**
*******************************************************************************/
private static void assertNoneArePaused() throws SchedulerException
{
assertThat(QuartzTestUtils.queryQuartz()).noneMatch(qjtw -> qjtw.triggerState().equals(Trigger.TriggerState.PAUSED));
}
/*******************************************************************************
**
*******************************************************************************/
private static void assertAllArePaused() throws SchedulerException
{
assertThat(QuartzTestUtils.queryQuartz()).allMatch(qjtw -> qjtw.triggerState().equals(Trigger.TriggerState.PAUSED));
}
}

View File

@ -58,7 +58,7 @@ class SimpleSchedulerTest extends BaseTest
@AfterEach
void afterEach()
{
SimpleScheduler.resetSingleton();
QScheduleManager.getInstance().unInit();
}
@ -81,7 +81,6 @@ class SimpleSchedulerTest extends BaseTest
assertThat(simpleScheduler.getExecutors()).isNotEmpty();
qScheduleManager.stop();
qScheduleManager.unInit();
}
@ -106,8 +105,7 @@ class SimpleSchedulerTest extends BaseTest
.withInitialDelaySeconds(0))
.withStepList(List.of(new QBackendStepMetaData()
.withName("step")
.withCode(new QCodeReference(BasicStep.class))))
);
.withCode(new QCodeReference(BasicStep.class)))));
BasicStep.counter = 0;
@ -120,7 +118,6 @@ class SimpleSchedulerTest extends BaseTest
//////////////////////////////////////////////////
SleepUtils.sleep(50, TimeUnit.MILLISECONDS);
qScheduleManager.stopAsync();
qScheduleManager.unInit();
System.out.println("Ran: " + BasicStep.counter + " times");
assertTrue(BasicStep.counter > 1, "Scheduled process should have ran at least twice (but only ran [" + BasicStep.counter + "] time(s).");