/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Lesser General Public License for more details. * * Copyright (c) 2002-2017 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.scheduler2.quartz; import org.junit.Before; import org.junit.Test; import org.pentaho.platform.api.action.IAction; import org.pentaho.platform.api.scheduler2.ComplexJobTrigger; import org.pentaho.platform.api.scheduler2.IBackgroundExecutionStreamProvider; import org.pentaho.platform.api.scheduler2.IJobFilter; import org.pentaho.platform.api.scheduler2.IJobTrigger; import org.pentaho.platform.api.scheduler2.IScheduler; import org.pentaho.platform.api.scheduler2.ISchedulerListener; import org.pentaho.platform.api.scheduler2.Job; import org.pentaho.platform.api.scheduler2.SchedulerException; import org.pentaho.platform.api.scheduler2.SimpleJobTrigger; import org.pentaho.platform.engine.core.system.boot.PlatformInitializationException; import org.quartz.CronTrigger; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.SimpleTrigger; import org.quartz.Trigger; import java.io.Serializable; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import static junit.framework.Assert.*; import static org.mockito.Mockito.*; @SuppressWarnings( "nls" ) public class QuartzSchedulerIT { private static final String CRON_EXPRESSION = "1 0 0 * * ? *"; private static final String USER_NAME = "userName"; private static final String JOB_NAME = "jobName"; private static final String JOB_ID = USER_NAME + "\t" + JOB_NAME + "\t" + System.currentTimeMillis(); private QuartzScheduler scheduler; private Scheduler quartzScheduler; private final Map<String, Serializable> jobDetails = new HashMap<>(); @Before public void init() throws SchedulerException, PlatformInitializationException, org.quartz.SchedulerException { final SchedulerFactory schedulerFactory = mock( SchedulerFactory.class ); quartzScheduler = mock( Scheduler.class ); when( schedulerFactory.getScheduler() ).thenReturn( quartzScheduler ); scheduler = spy( new QuartzScheduler( schedulerFactory ) ); when( scheduler.getCurrentUser() ).thenReturn( USER_NAME ); jobDetails.clear(); jobDetails.put( QuartzScheduler.RESERVEDMAPKEY_ACTIONCLASS, "RESERVEDMAPKEY_ACTIONCLASS" ); jobDetails.put( QuartzScheduler.RESERVEDMAPKEY_STREAMPROVIDER, "RESERVEDMAPKEY_STREAMPROVIDER" ); jobDetails.put( QuartzScheduler.RESERVEDMAPKEY_UIPASSPARAM, "RESERVEDMAPKEY_UIPASSPARAM" ); } @Test public void getQuartzSchedulerTest() throws Exception { assertEquals( quartzScheduler, scheduler.getQuartzScheduler() ); } @Test public void createJobTest() throws Exception { String actionId = "actionId"; ComplexJobTrigger trigger = getComplexJobTrigger(); IBackgroundExecutionStreamProvider outputStreamProvider = mock( IBackgroundExecutionStreamProvider.class ); final Job job = scheduler.createJob( JOB_NAME, actionId, null, trigger, outputStreamProvider ); assertNotNull( job ); assertEquals( Job.JobState.NORMAL, job.getState() ); assertTrue( job.getJobParams().containsKey( QuartzScheduler.RESERVEDMAPKEY_ACTIONID ) ); assertEquals( actionId, job.getJobParams().get( QuartzScheduler.RESERVEDMAPKEY_ACTIONID ) ); assertTrue( job.getJobParams().containsKey( QuartzScheduler.RESERVEDMAPKEY_STREAMPROVIDER ) ); assertEquals( outputStreamProvider, job.getJobParams().get( QuartzScheduler.RESERVEDMAPKEY_STREAMPROVIDER ) ); assertTrue( job.getJobParams().containsKey( QuartzScheduler.RESERVEDMAPKEY_LINEAGE_ID ) ); assertNotNull( job.getJobParams().get( QuartzScheduler.RESERVEDMAPKEY_LINEAGE_ID ) ); assertTrue( job.getJobParams().containsKey( QuartzScheduler.RESERVEDMAPKEY_ACTIONUSER ) ); assertEquals( USER_NAME, job.getJobParams().get( QuartzScheduler.RESERVEDMAPKEY_ACTIONUSER ) ); } @Test public void createJobTest_ForUser() throws Exception { String actionId = "actionId"; ComplexJobTrigger trigger = getComplexJobTrigger(); IBackgroundExecutionStreamProvider outputStreamProvider = mock( IBackgroundExecutionStreamProvider.class ); Map<String, Serializable> paramMap = new HashMap<>(); paramMap.put( QuartzScheduler.RESERVEDMAPKEY_ACTIONUSER, "ninja" ); final Job job = scheduler.createJob( JOB_NAME, paramMap, trigger, outputStreamProvider ); assertNotNull( job ); assertEquals( "ninja", job.getUserName() ); assertEquals( Job.JobState.NORMAL, job.getState() ); } @Test public void createQuartzTriggerComplexTriggerTest() throws Exception { final Trigger quartzTrigger = QuartzScheduler.createQuartzTrigger( getComplexJobTrigger(), getJobKey() ); assertNotNull( quartzTrigger ); assertTrue( quartzTrigger instanceof CronTrigger ); assertEquals( SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW, quartzTrigger.getMisfireInstruction() ); assertEquals( CRON_EXPRESSION, ( (CronTrigger) quartzTrigger ).getCronExpression() ); assertEquals( USER_NAME, quartzTrigger.getGroup() ); } @Test public void createQuartzTriggerSimpleTriggerTest() throws Exception { final Calendar calendar = Calendar.getInstance(); Date startTime = calendar.getTime(); calendar.add( Calendar.MONTH, 1 ); Date endTime = calendar.getTime(); int repeatCount = 5; long repeatIntervalSeconds = 10; final SimpleJobTrigger simpleJobTrigger = new SimpleJobTrigger( startTime, endTime, repeatCount, repeatIntervalSeconds ); final Trigger quartzTrigger = QuartzScheduler.createQuartzTrigger( simpleJobTrigger, getJobKey() ); assertNotNull( quartzTrigger ); assertTrue( quartzTrigger instanceof SimpleTrigger ); assertEquals( SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT, quartzTrigger.getMisfireInstruction() ); assertEquals( USER_NAME, quartzTrigger.getGroup() ); SimpleTrigger simpleTrigger = (SimpleTrigger) quartzTrigger; assertEquals( startTime, simpleTrigger.getStartTime() ); assertEquals( endTime, simpleTrigger.getEndTime() ); assertEquals( repeatCount, simpleTrigger.getRepeatCount() ); assertEquals( repeatIntervalSeconds * 1000, simpleTrigger.getRepeatInterval() ); } @Test( expected = SchedulerException.class ) public void createQuartzTriggerNotDefinedTriggerTest() throws Exception { final IJobTrigger trigger = mock( IJobTrigger.class ); QuartzScheduler.createQuartzTrigger( trigger, getJobKey() ); } @Test public void updateJobTest() throws Exception { final JobDetail jobDetail = setJobDataMap( USER_NAME ); scheduler.updateJob( JOB_ID, new HashMap<String, Serializable>(), getComplexJobTrigger() ); verify( quartzScheduler, times( 1 ) ).addJob( eq( jobDetail ), eq( true ) ); verify( quartzScheduler, times( 1 ) ).rescheduleJob( eq( JOB_ID ), eq( USER_NAME ), any( Trigger.class ) ); } @Test public void triggerNowTest() throws Exception { final SimpleTrigger simpleTrigger = mock( SimpleTrigger.class ); final CronTrigger cronTrigger = mock( CronTrigger.class ); when( quartzScheduler.getTriggersOfJob( eq( JOB_ID ), eq( USER_NAME ) ) ).thenReturn( new Trigger[] { simpleTrigger, cronTrigger } ); scheduler.triggerNow( JOB_ID ); verify( simpleTrigger, times( 1 ) ).setPreviousFireTime( any( Date.class ) ); verify( cronTrigger, times( 1 ) ).setPreviousFireTime( any( Date.class ) ); verify( quartzScheduler, times( 1 ) ).rescheduleJob( eq( JOB_ID ), eq( USER_NAME ), eq( simpleTrigger ) ); verify( quartzScheduler, times( 1 ) ).rescheduleJob( eq( JOB_ID ), eq( USER_NAME ), eq( cronTrigger ) ); verify( quartzScheduler, times( 1 ) ).triggerJob( eq( JOB_ID ), eq( USER_NAME ) ); } @Test public void getJobTest() throws Exception { final CronTrigger cronTrigger = mock( CronTrigger.class ); when( cronTrigger.getCronExpression() ).thenReturn( CRON_EXPRESSION ); when( quartzScheduler.getTriggersOfJob( eq( JOB_ID ), eq( USER_NAME ) ) ).thenReturn( new Trigger[] { cronTrigger } ); setJobDataMap( USER_NAME ); final Job job = scheduler.getJob( JOB_ID ); assertEquals( JOB_ID, job.getJobId() ); assertEquals( jobDetails, job.getJobParams() ); assertEquals( USER_NAME, job.getUserName() ); assertEquals( JOB_NAME, job.getJobName() ); assertEquals( Job.JobState.NORMAL, job.getState() ); } @Test public void getJobsTest() throws Exception { final IJobFilter jobFilter = mock( IJobFilter.class ); when( jobFilter.accept( any( Job.class ) ) ).thenReturn( true ); final String groupName = "groupName"; when( quartzScheduler.getJobGroupNames() ).thenReturn( new String[] { groupName } ); when( quartzScheduler.getJobNames( eq( groupName ) ) ).thenReturn( new String[] { JOB_ID } ); final Trigger trigger = mock( Trigger.class ); Date date1 = new Date(); when( trigger.getPreviousFireTime() ).thenReturn( new Date( ) ); when( trigger.getFireTimeAfter( any( Date.class ) ) ).thenReturn( date1 ); when( trigger.getNextFireTime() ).thenReturn( date1 ); final Trigger trigger2 = mock( Trigger.class ); when( trigger2.getGroup() ).thenReturn( "MANUAL_TRIGGER" ); when( quartzScheduler.getTriggersOfJob( eq( JOB_ID ), eq( groupName ) ) ).thenReturn( new Trigger[] { trigger, trigger2 } ); setJobDataMap( groupName ); final List<Job> jobs = scheduler.getJobs( jobFilter ); assertNotNull( jobs ); assertEquals( 1, jobs.size() ); Job job = jobs.get( 0 ); assertEquals( groupName, job.getGroupName() ); assertEquals( USER_NAME, job.getUserName() ); assertEquals( jobDetails, job.getJobParams() ); assertEquals( JOB_ID, job.getJobId() ); assertEquals( JOB_NAME, job.getJobName() ); assertEquals( trigger.getPreviousFireTime(), job.getLastRun() ); assertEquals( trigger.getNextFireTime(), job.getNextRun() ); } private JobDetail setJobDataMap( String groupName ) throws org.quartz.SchedulerException { final JobDetail jobDetail = new JobDetail( JOB_ID, USER_NAME, BlockingQuartzJob.class ); jobDetail.setJobDataMap( new JobDataMap( jobDetails ) ); when( quartzScheduler.getJobDetail( eq( JOB_ID ), eq( groupName ) ) ).thenReturn( jobDetail ); return jobDetail; } @Test public void pauseTest() throws Exception { scheduler.pause(); verify( quartzScheduler, times( 1 ) ).standby(); } @Test public void pauseJobTest() throws Exception { scheduler.pauseJob( JOB_ID ); verify( quartzScheduler, times( 1 ) ).pauseJob( eq( JOB_ID ), eq( USER_NAME ) ); } @Test public void removeJobTest() throws Exception { scheduler.removeJob( JOB_ID ); verify( quartzScheduler, times( 1 ) ).deleteJob( eq( JOB_ID ), eq( USER_NAME ) ); } @Test public void startTest() throws Exception { scheduler.start(); verify( quartzScheduler, times( 1 ) ).start(); } @Test public void resumeJobTest() throws Exception { scheduler.resumeJob( JOB_ID ); verify( quartzScheduler, times( 1 ) ).resumeJob( eq( JOB_ID ), eq( USER_NAME ) ); } @Test public void getStatusTest() throws Exception { when( quartzScheduler.isInStandbyMode() ).thenReturn( true ); assertEquals( IScheduler.SchedulerStatus.PAUSED, scheduler.getStatus() ); when( quartzScheduler.isInStandbyMode() ).thenReturn( false ); when( quartzScheduler.isStarted() ).thenReturn( true ); assertEquals( IScheduler.SchedulerStatus.RUNNING, scheduler.getStatus() ); when( quartzScheduler.isInStandbyMode() ).thenThrow( new org.quartz.SchedulerException() ); try { scheduler.getStatus(); fail(); } catch ( SchedulerException e ) { // it's expected } } @Test public void shutdownTest() throws Exception { scheduler.shutdown(); verify( quartzScheduler, times( 1 ) ).shutdown( eq( true ) ); } @Test public void fireJobCompletedTest() throws Exception { final IAction actionBean = mock( IAction.class ); final String actionUser = "actionUser"; final ISchedulerListener schedulerListener = mock( ISchedulerListener.class ); scheduler.addListener( schedulerListener ); final Map<String, Serializable> params = new HashMap<>(); final IBackgroundExecutionStreamProvider streamProvider = mock( IBackgroundExecutionStreamProvider.class ); scheduler.fireJobCompleted( actionBean, actionUser, params, streamProvider ); verify( schedulerListener, times( 1 ) ).jobCompleted( eq( actionBean ), eq( actionUser ), eq( params ), eq( streamProvider ) ); } private QuartzJobKey getJobKey() throws SchedulerException { return new QuartzJobKey( JOB_NAME, USER_NAME ); } private ComplexJobTrigger getComplexJobTrigger() { final ComplexJobTrigger trigger = new ComplexJobTrigger(); trigger.setSecondRecurrence( 1 ); return trigger; } }