예제 #1
0
    def test_existing(self, mock_get_collection):
        mock_update = mock_get_collection.return_value.update
        fake_id = bson.ObjectId()
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', id=fake_id)

        call.save()

        expected = call.as_dict()
        del expected['_id']
        mock_update.assert_called_once_with({'_id': fake_id}, expected)
예제 #2
0
    def test_expected_runs_positive(self, mock_time):
        # specify a start time and current time such that we know the difference
        mock_time.return_value = 1389307330.966561
        call = ScheduledCall('2014-01-09T17:15Z/PT1H',
                             'pulp.tasks.dosomething')

        expected_runs = call._calculate_times()[5]

        # we know that it's been more than 5 hours since the first scheduled run
        self.assertEqual(expected_runs, 5)
예제 #3
0
    def test_new(self, mock_get_collection):
        mock_insert = mock_get_collection.return_value.insert
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        call.save()

        expected = call.as_dict()
        expected['_id'] = bson.ObjectId(expected['_id'])
        mock_insert.assert_called_once_with(expected, safe=True)
        self.assertFalse(call._new)
예제 #4
0
    def test_first_run_string(self):
        first_run = dateutils.format_iso8601_datetime(
            datetime.utcnow().replace(tzinfo=dateutils.utc_tz()) +
            timedelta(days=1))

        call = ScheduledCall('PT1M',
                             'pulp.tasks.dosomething',
                             first_run=first_run)

        self.assertEqual(first_run, call.first_run)
예제 #5
0
파일: repo.py 프로젝트: taftsanders/pulp
    def create(cls,
               repo_id,
               importer_id,
               sync_options,
               schedule,
               failure_threshold=None,
               enabled=True):
        """
        Create a new sync schedule for a given repository using the given importer.

        :param repo_id:         unique ID for a repository
        :type  repo_id:         basestring
        :param importer_id:     unique ID for an importer
        :type  importer_id:     basestring
        :param sync_options:    dictionary that contains the key 'override_config',
                                whose value should be passed as the 'overrides'
                                parameter to the sync task. This wasn't originally
                                documented, so it isn't clear why overrides value
                                couldn't be passed directly.
        :type  sync_options:    dict
        :param schedule_data:   dictionary that contains the key 'schedule', whose
                                value is an ISO8601 string. This wasn't originally
                                documented, so it isn't clear why the string itself
                                couldn't have been passed directly.
        :type  schedule_data:   dict

        :return:    new schedule instance
        :rtype:     pulp.server.db.model.dispatch.ScheduledCall
        """
        # validate the input
        importer_controller.get_valid_importer(repo_id, importer_id)
        utils.validate_keys(sync_options, _SYNC_OPTION_KEYS)
        utils.validate_initial_schedule_options(schedule, failure_threshold,
                                                enabled)

        task = repo_controller.queue_sync_with_auto_publish.name
        args = [repo_id]
        kwargs = {'overrides': sync_options['override_config']}
        resource = importer_controller.build_resource_tag(repo_id, importer_id)
        schedule = ScheduledCall(schedule,
                                 task,
                                 args=args,
                                 kwargs=kwargs,
                                 resource=resource,
                                 failure_threshold=failure_threshold,
                                 enabled=enabled)
        schedule.save()
        try:
            importer_controller.get_valid_importer(repo_id, importer_id)
        except exceptions.MissingResource:
            # back out of this whole thing, since the importer disappeared
            utils.delete(schedule.id)
            raise

        return schedule
예제 #6
0
    def test_first_run_saved(self):
        """
        Test that when the first run is passed in from historical data.
        """
        call = ScheduledCall('PT1H', 'pulp.tasks.dosomething', first_run='2014-01-03T10:15Z')

        first_run_s = call._calculate_times()[1]

        # make sure this gives us a timestamp for the date and time
        # specified above
        self.assertEqual(first_run_s, 1388744100)
예제 #7
0
    def test_expected_runs_future(self, mock_time):
        # specify a start time and current time such that the start appears to
        # be in the future
        mock_time.return_value = 1389307330.966561
        call = ScheduledCall('2014-01-19T17:15Z/PT1H', 'pulp.tasks.dosomething')

        expected_runs = call._calculate_times()[5]

        # the first run is scheduled in the future (relative to the mock time),
        # so there should not be any runs.
        self.assertEqual(expected_runs, 0)
예제 #8
0
    def test_future(self, mock_time):
        mock_time.return_value = 1389307330.966561
        call = ScheduledCall('2014-01-19T17:15Z/PT1H', 'pulp.tasks.dosomething')

        next_run = call.calculate_next_run()

        # make sure the next run is equal to the specified first run.
        # don't want to compare a generated ISO8601 string directly, because there
        # could be subtle variations that are valid but break string equality.
        self.assertEqual(dateutils.parse_iso8601_interval(call.iso_schedule)[1],
                         dateutils.parse_iso8601_datetime(next_run))
예제 #9
0
    def test_first_run_datetime(self):
        first_run = datetime.utcnow().replace(
            tzinfo=dateutils.utc_tz()) + timedelta(days=1)

        call = ScheduledCall('PT1M',
                             'pulp.tasks.dosomething',
                             first_run=first_run)

        # make sure it is an ISO8601 string with the correct value
        self.assertTrue(isinstance(call.first_run, basestring))
        self.assertEqual(dateutils.format_iso8601_datetime(first_run),
                         call.first_run)
예제 #10
0
    def test_with_past_runs(self, mock_time):
        # setup an hourly call that first ran not quite 2 hours ago, ran again
        # less than one hour ago, and should be scheduled to run at the end of
        # this hour
        mock_time.return_value = 1389389758.547976
        call = ScheduledCall('2014-01-10T20:00Z/PT1H', 'pulp.tasks.dosomething',
                             total_run_count=2, last_run_at='2014-01-10T21:00Z')

        next_run = call.calculate_next_run()

        self.assertEqual(dateutils.parse_iso8601_datetime('2014-01-10T22:00Z'),
                         dateutils.parse_iso8601_datetime(next_run))
예제 #11
0
    def test_past_runs_not_due(self, mock_time):
        mock_time.return_value = 1389389758  # 2014-01-10T21:35:58
        # This call ran at the top of the hour, so it does not need to run again
        # until the top of the next hour.
        call = ScheduledCall('2014-01-10T20:00Z/PT1H', 'pulp.tasks.dosomething',
                             last_run_at='2014-01-10T21:00Z', total_run_count=2)
        entry = call.as_schedule_entry()

        is_due, seconds = entry.is_due()

        self.assertFalse(is_due)
        # this was hand-calculated as the remaining time until the next hourly run
        self.assertEqual(seconds, 1442)
예제 #12
0
    def test_past_runs_due(self, mock_time):
        mock_time.return_value = 1389389758  # 2014-01-10T21:35:58
        # This call did not run at the top of the hour, so it is overdue and should
        # run now. Its next run will be back on the normal hourly schedule, at
        # the top of the next hour.
        call = ScheduledCall('2014-01-10T20:00Z/PT1H', 'pulp.tasks.dosomething',
                             last_run_at='2014-01-10T20:00Z', total_run_count=1)
        entry = call.as_schedule_entry()

        is_due, seconds = entry.is_due()

        self.assertTrue(is_due)
        # this was hand-calculated as the remaining time until the next hourly run
        self.assertEqual(seconds, 1442)
예제 #13
0
def update(schedule_id, delta):
    """
    Updates the schedule with unique ID schedule_id. This only allows updating
    of fields in ScheduledCall.USER_UPDATE_FIELDS.

    :param schedule_id: a unique ID for a schedule
    :type  schedule_id: basestring
    :param delta:       a dictionary of keys with values that should be modified
                        on the schedule.
    :type  delta:       dict

    :return:    instance of ScheduledCall representing the post-update state
    :rtype      ScheduledCall

    :raise  exceptions.UnsupportedValue
    :raise  exceptions.MissingResource
    """
    unknown_keys = set(delta.keys()) - ScheduledCall.USER_UPDATE_FIELDS
    if unknown_keys:
        raise exceptions.UnsupportedValue(list(unknown_keys))

    delta['last_updated'] = time.time()

    # bz 1139703 - if we update iso_schedule, update the pickled object as well
    if 'iso_schedule' in delta:
        interval, start_time, occurrences = dateutils.parse_iso8601_interval(
            delta['iso_schedule'])
        delta['schedule'] = pickle.dumps(CelerySchedule(interval))

        # set first_run and next_run so that the schedule update will take effect
        new_schedule_call = ScheduledCall(delta['iso_schedule'],
                                          'dummytaskname')
        delta['first_run'] = new_schedule_call.first_run
        delta['next_run'] = new_schedule_call.next_run

    try:
        spec = {'_id': ObjectId(schedule_id)}
    except InvalidId:
        # During schedule update, MissingResource should be raised even if
        # schedule_id is invalid object_id.
        raise exceptions.MissingResource(schedule_id=schedule_id)
    schedule = ScheduledCall.get_collection().find_and_modify(
        query=spec, update={'$set': delta}, safe=True, new=True)
    if schedule is None:
        raise exceptions.MissingResource(schedule_id=schedule_id)
    return ScheduledCall.from_db(schedule)
예제 #14
0
    def test_with_months_duration(self, mock_time):
        """
        Test calculating the next run when the interval is a Duration object and uses months
        """
        last_runs = ('2015-01-01T10:00Z', '2015-02-01T10:00Z', '2015-03-01T10:00Z',
                     '2015-04-01T10:00Z')
        expected_next_runs = ('2015-02-01T10:00Z', '2015-03-01T10:00Z', '2015-04-01T10:00Z',
                              '2015-05-01T10:00Z')
        times = (
            1422784799.0,  # Just before 2015-02-01T10:00Z UTC
            1425203999.0,  # Just before 2015-03-01T10:00Z UTC
            1427882399.0,  # Just before 2015-04-01T10:00Z UTC
            1430474399.0,  # Just before 2015-05-01T10:00Z UTC
        )

        for last_run, current_time, expected_next_run in zip(last_runs, times, expected_next_runs):
            mock_time.return_value = current_time
            call = ScheduledCall('2014-12-01T10:00Z/P1M', 'pulp.tasks.dosomething',
                                 total_run_count=2, last_run_at=last_run)
            next_run = call.calculate_next_run()

            self.assertEqual(dateutils.parse_iso8601_datetime(expected_next_run),
                             dateutils.parse_iso8601_datetime(next_run))
예제 #15
0
    def test_with_years_duration(self, mock_time):
        """
        Test calculating the next run when the interval is a Duration object and uses years
        """
        last_runs = ('2015-01-01T10:00Z', '2016-01-01T10:00Z', '2017-01-01T10:00Z',
                     '2018-01-01T10:00Z')
        expected_next_runs = ('2016-01-01T10:00Z', '2017-01-01T10:00Z', '2018-01-01T10:00Z',
                              '2019-01-01T10:00Z')
        times = (
            1451642000.0,  # Just before 2016-01-01T10:00Z UTC
            1483264000.0,  # Just before 2017-01-01T10:00Z UTC
            1514800000.0,  # Just before 2018-01-01T10:00Z UTC
            1546336000.0,  # Just before 2019-01-01T10:00Z UTC
        )

        for last_run, current_time, expected_next_run in zip(last_runs, times, expected_next_runs):
            mock_time.return_value = current_time
            call = ScheduledCall('2014-01-01T10:00Z/P1M', 'pulp.tasks.dosomething',
                                 total_run_count=2, last_run_at=last_run)
            next_run = call.calculate_next_run()

            self.assertEqual(dateutils.parse_iso8601_datetime(expected_next_run),
                             dateutils.parse_iso8601_datetime(next_run))
예제 #16
0
 def test_id_added_to_kwargs(self):
     call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')
     self.assertEqual(call.kwargs['scheduled_call_id'], call.id)
예제 #17
0
    def test_expected_runs_zero(self):
        call = ScheduledCall('PT1H', 'pulp.tasks.dosomething')

        expected_runs = call._calculate_times()[5]

        self.assertEqual(expected_runs, 0)
예제 #18
0
    def test_pass_in_schedule(self):
        schedule = pickle.dumps(CelerySchedule(60))

        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', schedule=schedule)

        self.assertEqual(call.schedule, schedule)
예제 #19
0
    def test_next_run_ignored(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', next_run='foo')

        self.assertTrue(call.next_run != 'foo')
예제 #20
0
    def test_remaining_runs_in_string(self):
        call = ScheduledCall('R3/PT1M', 'pulp.tasks.dosomething')

        self.assertEqual(call.remaining_runs, 3)
예제 #21
0
    def test_remaining_runs_passed_int(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', remaining_runs=2)

        self.assertEqual(call.remaining_runs, 2)
예제 #22
0
    def test_new(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        # make sure the call generates its own object ID
        self.assertTrue(len(call.id) > 0)
        self.assertTrue(isinstance(call._id, bson.ObjectId))
예제 #23
0
    def test_create_principal(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        # See PrincipalManager.get_principal(). It returns either a User or
        # a dict. Not my idea.
        self.assertTrue(isinstance(call.principal, (User, dict)))
예제 #24
0
    def test_pass_in_principal(self):
        principal = User('me', 'letmein')
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', principal=principal)

        self.assertEqual(call.principal, principal)
예제 #25
0
    def test_captures_scheduled_call(self):
        call = ScheduledCall('2014-01-19T17:15Z/PT1H', 'pulp.tasks.dosomething')
        entry = call.as_schedule_entry()

        self.assertTrue(hasattr(entry, '_scheduled_call'))
        self.assertTrue(entry._scheduled_call is call)
예제 #26
0
    def test_next_run_calculated(self, mock_calc):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething', next_run='foo')

        self.assertEqual(call.next_run, mock_calc.return_value)
        mock_calc.assert_called_once_with()
예제 #27
0
 def setUp(self):
     super(TestScheduleEntryIsDue, self).setUp()
     self.call = ScheduledCall('2014-01-19T17:15Z/PT1H', 'pulp.tasks.dosomething',
                               remaining_runs=5)
     self.entry = self.call.as_schedule_entry()
예제 #28
0
    def test_returns_dict(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        self.assertTrue(isinstance(call.for_display(), dict))
예제 #29
0
    def test_remaining_runs_none(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        self.assertTrue(call.remaining_runs is None)
예제 #30
0
    def test_pass_in_task_name(self):
        call = ScheduledCall('PT1M', 'pulp.tasks.dosomething')

        self.assertEqual(call.task, 'pulp.tasks.dosomething')