def testScheduleWeeklyStartMultiDay(sim): """Test weekly schedules with multiple days.""" configId = sim.createConfig().getId() # Create 2 schedules: Mon/Wed/Fri/Sun and Tue/Thu/Sat. scheduledTimes = [] for i, dayString in enumerate(('1010101', '0101010')): startTime = int( time.mktime((2007, 1, 1 + i, 13, 1 + i * 2, 0, 0, 1, 0))) scheduledTimes.append(startTime) schedId = 'WeeklyStartMultiDay_%d' % i sim.createSchedule(schedId, False, startTime, ScheduleRepeat.WEEKLY, days=dayString, configFactory=sharedConfigFactory(configId)) scheduled = sim.databases.scheduleDB.get(schedId) assert getScheduleStatus(sim.databases.configDB, scheduled) == 'ok' # Run simulation for 2 weeks. sim.wait(2 * secondsPerWeek, check=lambda: None) # Validate the results. assert set(sim.databases.jobDB) == set(sim.jobs) creationTimes = [job['timestamp'] for job in sim.jobs] assert len(creationTimes) == 14 assert len(scheduledTimes) == 2 for i in range(2): assert creationTimes[i] == scheduledTimes[i], \ 'Job did not start at scheduled time' for day in range(7): assert creationTimes[7 + day] - creationTimes[day] == secondsPerWeek, \ 'There is not exactly 1 week between two job runs'
def testScheduleWeeklyStartCorrection(sim): """Test weekly schedule for which the start time should be corrected to the next available selected day. """ configId = sim.createConfig().getId() def timeOnDay(day): return int(time.mktime((2007, 1, day, 13, 0, 0, 0, 1, 0))) # Create 3 schedules always for Wednesday: # 1st is dated 2007-01-01, should be corrected to 2007-01-03 # 2nd is dated 2007-01-03, should not changed # 3rd is dated 2007-01-05, should be corrected to 2007-01-10 scheduledTimes = [] for scheduledDay, correctedDay in (1, 3), (3, 3), (5, 10): startTime = timeOnDay(scheduledDay) schedId = 'WeeklyStartCorrection_%d' % scheduledDay scheduledTimes.append((schedId, startTime, timeOnDay(correctedDay))) sim.createSchedule(schedId, False, startTime, ScheduleRepeat.WEEKLY, days='0010000', configFactory=sharedConfigFactory(configId)) scheduled = sim.databases.scheduleDB.get(schedId) assert getScheduleStatus(sim.databases.configDB, scheduled) == 'ok' # Run simulation for 4 weeks. sim.wait(4 * secondsPerWeek, check=lambda: None) # Validate the results. assert set(sim.databases.jobDB) == set(sim.jobs) for schedId, scheduledTime, correctedTime in scheduledTimes: jobsFromSchedule = [ job for job in sim.jobs if job.getScheduledBy() == schedId ] assert 3 <= len(jobsFromSchedule) <= 4, jobsFromSchedule prevCreationTime = None for job in jobsFromSchedule: creationTime = job['timestamp'] if prevCreationTime is None: assert scheduledTime <= creationTime, '%s > %s' % \ ( formatTime(scheduledTime), formatTime(creationTime) ) assert creationTime == correctedTime, '%s != %s' % \ ( formatTime(creationTime), formatTime(correctedTime) ) else: assert creationTime - prevCreationTime == secondsPerWeek, \ 'There is not exactly 1 week between two job runs' prevCreationTime = creationTime
def statusDescription(scheduled: Scheduled, configDB: ConfigDB) -> XMLContent: status = getScheduleStatus(configDB, scheduled) if status == 'error': return xhtml.br.join( ( 'configuration ', xhtml.b[ createConfigDetailsLink(configDB, configId) ], ' is inconsistent' ) for configId in scheduled.getMatchingConfigIds(configDB) if not configDB[configId].hasValidInputs() ) else: return { 'running': 'jobs from last run have not finished yet', 'warning': 'no matching configurations', 'ok': 'waiting for next run', }.get(status, status)
def testScheduleDailyStart(sim): """Test daily schedule.""" # Schedule starts Monday 2007-01-01 at 13:01. startTime = int(time.mktime((2007, 1, 1, 13, 1, 0, 0, 0, 0))) sim.prepare(startTime - sim.preparedTime, sequence=ScheduleRepeat.DAILY) assert getScheduleStatus(sim.databases.configDB, sim.scheduled) == 'ok' # Run simulation for 1 week. # No checks are done during the simulation. sim.wait(secondsPerWeek, check=lambda: None) # Validate the results. creationTimes = [job['timestamp'] for job in sim.jobs] assert len(creationTimes) == 7 for i in range(6): assert creationTimes[i + 1] - creationTimes[i] == secondsPerDay, \ 'There are not 24*60*60 seconds between two job runs'
def checkStatus(self): schedule = self.scheduled if schedule is None: return assert schedule.isRunning() == (self.__nrCreatedJobs > self.__nrFinishedJobs) assert schedule.isDone() == self.__isDone if self.__missingConfig: assert len(schedule.getMatchingConfigIds( self.databases.configDB)) == 0 assert schedule.isSuspended() == self.__suspended assert getScheduleStatus(self.databases.configDB, schedule) == self.expectedStatus() assert len(self.databases.jobDB) == self.__nrCreatedJobs finishedJobs = [ job for job in self.databases.jobDB if job.isExecutionFinished() ] assert len(finishedJobs) == self.__nrFinishedJobs
def testScheduleWeeklyStart(sim): """Test weekly schedules with one day each.""" configId = sim.createConfig().getId() # Create 7 schedules: one for each day of the week with a different # start time. scheduledTimes = [] for day in range(7): # Schedule starts Monday 2007-01-01 at 13:01, # Tuesday 2007-01-02 at 13:03 etc. startTime = int( time.mktime((2007, 1, 1 + day, 13, 1 + day * 2, 0, 0, 1, 0))) scheduledTimes.append(startTime) schedId = 'WeeklyStart_%d' % day sim.createSchedule(schedId, False, startTime, ScheduleRepeat.WEEKLY, days='0' * day + '1' + '0' * (6 - day), configFactory=sharedConfigFactory(configId)) scheduled = sim.databases.scheduleDB.get(schedId) assert getScheduleStatus(sim.databases.configDB, scheduled) == 'ok' # Run simulation for 2 weeks. sim.wait(2 * secondsPerWeek, check=lambda: None) # Validate the results. assert set(sim.databases.jobDB) == set(sim.jobs) creationTimes = [job['timestamp'] for job in sim.jobs] assert len(creationTimes) == 14 assert len(scheduledTimes) == 7 for day in range(7): assert creationTimes[day] == scheduledTimes[day], \ 'Job did not start at scheduled time' assert creationTimes[7 + day] - creationTimes[day] == secondsPerWeek, \ 'There is not exactly 1 week between two job runs'
def iterRows(self, **kwargs: object) -> Iterator[XMLContent]: proc = cast(ScheduleDetails_GET.Processor, kwargs['proc']) scheduled = proc.scheduled configDB = proc.configDB configId = scheduled.configId if configId is None: yield 'Tag', TagsTable.instance.present(**kwargs) else: yield 'Configuration', ( createConfigDetailsLink(configDB, configId, 'view'), ' or ', pageLink('FastExecute', ConfigIdArgs(configId = configId))[ 'execute' ], f' configuration "{configId}"' ) yield 'Last run', createLastJobLink(scheduled) yield 'Next run', describeNextRun(scheduled) repeat = scheduled.repeat yield 'Repeat', repeat if repeat is ScheduleRepeat.WEEKLY: yield 'Days', ', '.join(stringToListDays(scheduled.dayFlags)) elif repeat is ScheduleRepeat.CONTINUOUSLY: minDelay = scheduled.minDelay yield 'Minimum delay', \ f"{minDelay:d} {pluralize('minute', minDelay)}" elif repeat is ScheduleRepeat.TRIGGERED: yield 'Triggered', 'yes' if scheduled['trigger'] else 'no' yield 'Triggers', xhtml.br.join( sorted(scheduled.tags.getTagValues('sf.trigger')) ) if proc.userDB.showOwners: yield 'Owner', scheduled.owner or '-' yield 'Comment', xhtml.br.join(scheduled.comment.splitlines()) yield row(class_ = getScheduleStatus(configDB, scheduled))[ 'Status', statusDescription(scheduled, configDB) ]
def iterRowStyles( # pylint: disable=unused-argument self, rowNr: int, record: Scheduled, **kwargs: object) -> Iterator[str]: proc = cast(ScheduleIndex_GET.Processor, kwargs['proc']) yield getScheduleStatus(proc.configDB, record)