예제 #1
0
    def test_get_schedules(self):
        timeutils.set_time_override()
        start_time = timeutils.isotime()
        timeutils.advance_time_seconds(30)
        end_time = timeutils.isotime()

        filter_args = {'next_run_after': start_time,
                       'next_run_before': end_time}
        self.client.list_schedules(filter_args=filter_args).AndReturn([])
        self.mox.ReplayAll()
        self.scheduler.get_schedules(start_time, end_time)
        self.mox.VerifyAll()
예제 #2
0
    def test_get_schedules(self):
        timeutils.set_time_override()
        start_time = timeutils.isotime()
        timeutils.advance_time_seconds(30)
        end_time = timeutils.isotime()

        filter_args = {
            'next_run_after': start_time,
            'next_run_before': end_time
        }
        self.client.list_schedules(filter_args=filter_args).AndReturn([])
        self.mox.ReplayAll()
        self.scheduler.get_schedules(start_time, end_time)
        self.mox.VerifyAll()
예제 #3
0
    def test_create_zero_hour(self):
        hour = 0
        fixture = {
            "schedule": {
                "id": unit_utils.SCHEDULE_UUID5,
                "tenant": unit_utils.TENANT1,
                "action": "snapshot",
                "minute": 30,
                "hour": hour,
            }
        }
        expected = fixture["schedule"]
        request = unit_utils.get_fake_request(method="POST")

        actual = self.controller.create(request, fixture)["schedule"]

        self.assertNotEqual(actual.get("id"), None)
        self.assertNotEqual(actual.get("created_at"), None)
        self.assertNotEqual(actual.get("updated_at"), None)
        now = timeutils.utcnow()
        if not (now.hour == hour and now.minute < 30):
            now = now + datetime.timedelta(days=1)
        expected_next_run = timeutils.isotime(now.replace(hour=hour, minute=30, second=0, microsecond=0))
        self.assertEqual(expected_next_run, actual["next_run"])
        self.assertEqual(expected["tenant"], actual["tenant"])
        self.assertEqual(expected["action"], actual["action"])
        self.assertEqual(expected["minute"], actual["minute"])
        self.assertEqual(expected["hour"], actual["hour"])
예제 #4
0
    def test_create_with_next_run(self):

        expected_next_run = timeutils.parse_isotime('1989-01-19T12:00:00Z').\
                                      replace(tzinfo=None)

        def fake_schedule_to_next_run(_schedule, start_time=None):
            self.assertEqual(timeutils.utcnow(), start_time)
            return expected_next_run

        self.stubs.Set(api_utils, 'schedule_to_next_run',
                       fake_schedule_to_next_run)

        self._stub_notifications(None, 'qonos.job.create', 'fake-payload',
                                 'INFO')
        request = unit_utils.get_fake_request(method='POST')
        fixture = {'job': {'schedule_id': self.schedule_1['id'],
                           'next_run':
                           timeutils.isotime(self.schedule_1['next_run'])}}
        job = self.controller.create(request, fixture).get('job')
        self.assertNotEqual(job, None)
        self.assertNotEqual(job.get('id'), None)
        self.assertEqual(job['schedule_id'], self.schedule_1['id'])
        self.assertEqual(job['tenant'], self.schedule_1['tenant'])
        self.assertEqual(job['action'], self.schedule_1['action'])
        self.assertEqual(job['status'], 'QUEUED')
        self.assertEqual(len(job['metadata']), 0)

        schedule = db_api.schedule_get_by_id(self.schedule_1['id'])
        self.assertNotEqual(schedule['next_run'], self.schedule_1['next_run'])
        self.assertEqual(schedule['next_run'], expected_next_run)
        self.assertNotEqual(schedule['last_scheduled'],
                            self.schedule_1.get('last_scheduled'))
        self.assertTrue(schedule.get('last_scheduled'))
예제 #5
0
    def test_create_with_next_run(self):

        expected_next_run = timeutils.parse_isotime('1989-01-19T12:00:00Z')

        def fake_schedule_to_next_run(_schedule, start_time=None):
            self.assertEqual(timeutils.utcnow(), start_time)
            return expected_next_run

        self.stubs.Set(api_utils, 'schedule_to_next_run',
                       fake_schedule_to_next_run)

        self._stub_notifications(None, 'qonos.job.create', 'fake-payload',
                                 'INFO')
        request = unit_utils.get_fake_request(method='POST')
        fixture = {'job': {'schedule_id': self.schedule_1['id'],
                           'next_run':
                           timeutils.isotime(self.schedule_1['next_run'])}}
        job = self.controller.create(request, fixture).get('job')
        self.assertNotEqual(job, None)
        self.assertNotEqual(job.get('id'), None)
        self.assertEqual(job['schedule_id'], self.schedule_1['id'])
        self.assertEqual(job['tenant'], self.schedule_1['tenant'])
        self.assertEqual(job['action'], self.schedule_1['action'])
        self.assertEqual(job['status'], 'QUEUED')
        self.assertEqual(len(job['metadata']), 0)

        schedule = db_api.schedule_get_by_id(self.schedule_1['id'])
        self.assertNotEqual(schedule['next_run'], self.schedule_1['next_run'])
        self.assertEqual(schedule['next_run'], expected_next_run)
        self.assertNotEqual(schedule['last_scheduled'],
                            self.schedule_1.get('last_scheduled'))
        self.assertTrue(schedule.get('last_scheduled'))
예제 #6
0
파일: scheduler.py 프로젝트: cp16net/qonos
    def _run_loop(self, run_once=False):
        next_run = None
        current_run = None

        while self.running:
            current_run = timeutils.isotime()
            next_run = time.time() + CONF.scheduler.job_schedule_interval

            # do work
            with utils.log_warning_and_dismiss_exception(LOG):
                self.enqueue_jobs(end_time=current_run)

            # if shutdown hasn't been requested, do nothing until next run
            if self.running:
                seconds = next_run - time.time()
                if seconds > 0:
                    time.sleep(seconds)
                else:
                    msg = _('Scheduling of jobs took longer than expected.')
                    LOG.warn(msg)

            if run_once:
                break

        LOG.info(_('Scheduler is shutting down'))
예제 #7
0
    def test_create_zero_hour(self):
        hour = 0
        fixture = {'schedule': {
            'id': unit_utils.SCHEDULE_UUID5,
            'tenant': unit_utils.TENANT1,
            'action': 'snapshot',
            'minute': 30,
            'hour': hour,
        }}
        expected = fixture['schedule']
        request = unit_utils.get_fake_request(method='POST')

        actual = self.controller.create(request, fixture)['schedule']

        self.assertNotEqual(actual.get('id'), None)
        self.assertNotEqual(actual.get('created_at'), None)
        self.assertNotEqual(actual.get('updated_at'), None)
        now = timeutils.utcnow()
        if not (now.hour == hour and now.minute < 30):
            now = now + datetime.timedelta(days=1)
        expected_next_run = timeutils.isotime(
            now.replace(hour=hour, minute=30, second=0,
                        microsecond=0))
        self.assertEqual(expected_next_run, actual['next_run'])
        self.assertEqual(expected['tenant'], actual['tenant'])
        self.assertEqual(expected['action'], actual['action'])
        self.assertEqual(expected['minute'], actual['minute'])
        self.assertEqual(expected['hour'], actual['hour'])
예제 #8
0
    def test_create_zero_hour(self):
        hour = 0
        fixture = {'schedule': {
            'id': unit_utils.SCHEDULE_UUID5,
            'tenant': unit_utils.TENANT1,
            'action': 'snapshot',
            'minute': 30,
            'hour': hour,
        }}
        expected = fixture['schedule']
        request = unit_utils.get_fake_request(method='POST')

        actual = self.controller.create(request, fixture)['schedule']

        self.assertNotEqual(actual.get('id'), None)
        self.assertNotEqual(actual.get('created_at'), None)
        self.assertNotEqual(actual.get('updated_at'), None)
        now = timeutils.utcnow()
        if not (now.hour == hour and now.minute < 30):
            now = now + datetime.timedelta(days=1)
        expected_next_run = timeutils.isotime(
            now.replace(hour=hour, minute=30, second=0,
                        microsecond=0))
        self.assertEqual(expected_next_run, actual['next_run'])
        self.assertEqual(expected['tenant'], actual['tenant'])
        self.assertEqual(expected['action'], actual['action'])
        self.assertEqual(expected['minute'], actual['minute'])
        self.assertEqual(expected['hour'], actual['hour'])
예제 #9
0
    def _run_loop(self, run_once=False):
        next_run = None
        current_run = None

        while self.running:
            current_run = timeutils.isotime()
            next_run = time.time() + CONF.scheduler.job_schedule_interval

            # do work
            with utils.log_warning_and_dismiss_exception(LOG):
                self.enqueue_jobs(end_time=current_run)

            # if shutdown hasn't been requested, do nothing until next run
            if self.running:
                seconds = next_run - time.time()
                if seconds > 0:
                    time.sleep(seconds)
                else:
                    msg = _('Scheduling of jobs took longer than expected.')
                    LOG.warn(msg)

            if run_once:
                break

        LOG.info(_('Scheduler is shutting down'))
예제 #10
0
파일: test_jobs.py 프로젝트: amalaba/qonos
    def test_list_with_hard_timeout_filter(self):
        hard_timeout = timeutils.isotime(self.job_1['hard_timeout'])
        path = '?hard_timeout=%s' % hard_timeout

        request = unit_utils.get_fake_request(path=path, method='GET')
        jobs = self.controller.list(request).get('jobs')
        self.assertEqual(len(jobs), 1)
        self.assertEqual(jobs[0]['id'], self.job_1['id'])
예제 #11
0
    def test_get_schedules_no_previous_run(self):
        end_time = timeutils.isotime()

        filter_args = {'next_run_before': end_time}
        self.client.list_schedules(filter_args=filter_args).AndReturn([])
        self.mox.ReplayAll()
        self.scheduler.get_schedules(end_time=end_time)
        self.mox.VerifyAll()
예제 #12
0
    def test_list_with_hard_timeout_filter(self):
        hard_timeout = timeutils.isotime(self.job_1['hard_timeout'])
        path = '?hard_timeout=%s' % hard_timeout

        request = unit_utils.get_fake_request(path=path, method='GET')
        jobs = self.controller.list(request).get('jobs')
        self.assertEqual(len(jobs), 1)
        self.assertEqual(jobs[0]['id'], self.job_1['id'])
예제 #13
0
 def test_list_next_run_filtered_before_less_than_after(self):
     after = self.schedule_3["next_run"]
     before = timeutils.isotime(after - datetime.timedelta(seconds=1))
     path = "?next_run_after=%s&next_run_before=%s"
     path = path % (after, before)
     request = unit_utils.get_fake_request(path=path, method="GET")
     schedules = self.controller.list(request).get("schedules")
     self.assertEqual(len(schedules), 0)
예제 #14
0
    def test_get_schedules_no_previous_run(self):
        end_time = timeutils.isotime()

        filter_args = {'next_run_before': end_time}
        self.client.list_schedules(filter_args=filter_args).AndReturn([])
        self.mox.ReplayAll()
        self.scheduler.get_schedules(end_time=end_time)
        self.mox.VerifyAll()
예제 #15
0
 def test_list_next_run_filtered_before_less_than_after(self):
     after = self.schedule_3['next_run']
     before = timeutils.isotime(after
                     - datetime.timedelta(seconds=1))
     path = '?next_run_after=%s&next_run_before=%s'
     path = path % (after, before)
     request = unit_utils.get_fake_request(path=path, method='GET')
     schedules = self.controller.list(request).get('schedules')
     self.assertEqual(len(schedules), 0)
예제 #16
0
def serialize_datetimes(data):
    """Serializes datetimes to strings in the top level values of a dict."""
    for (k, v) in data.iteritems():
        if isinstance(v, datetime.datetime):
            data[k] = timeutils.isotime(v)
        elif isinstance(v, list):
            for item in v:
                serialize_datetimes(item)
        elif isinstance(v, dict):
            serialize_datetimes(v)
예제 #17
0
파일: utils.py 프로젝트: amalaba/qonos
def serialize_datetimes(data):
    """Serializes datetimes to strings in the top level values of a dict."""
    for (k, v) in data.iteritems():
        if isinstance(v, datetime.datetime):
            data[k] = timeutils.isotime(v)
        elif isinstance(v, list):
            for item in v:
                serialize_datetimes(item)
        elif isinstance(v, dict):
            serialize_datetimes(v)
예제 #18
0
    def test_run_loop(self):
        self.config(job_schedule_interval=5, group='scheduler')
        timeutils.set_time_override()
        current_time = timeutils.isotime()
        called = {'enqueue_jobs': False}

        def fake(end_time=None):  # assert only end_time kwarg is passed
            self.assertEqual(end_time, current_time)
            called['enqueue_jobs'] = True

        self.stubs.Set(self.scheduler, 'enqueue_jobs', fake)
        fake_sleep = lambda x: None
        self.stubs.Set(time, 'sleep', fake_sleep)

        self.scheduler.run(run_once=True)
        self.assertTrue(called['enqueue_jobs'])
예제 #19
0
    def test_run_loop(self):
        self.config(job_schedule_interval=5, group='scheduler')
        timeutils.set_time_override()
        current_time = timeutils.isotime()
        called = {'enqueue_jobs': False}

        def fake(end_time=None):  # assert only end_time kwarg is passed
            self.assertEqual(end_time, current_time)
            called['enqueue_jobs'] = True

        self.stubs.Set(self.scheduler, 'enqueue_jobs', fake)
        fake_sleep = lambda x: None
        self.stubs.Set(time, 'sleep', fake_sleep)

        self.scheduler.run(run_once=True)
        self.assertTrue(called['enqueue_jobs'])
예제 #20
0
    def test_update_tenant(self):

        new_tenant = "new-tenant-name"

        def fake_schedule_to_next_run(*args, **kwargs):
            self.fail("next_run should not be updated")

        self.stubs.Set(api_utils, "schedule_to_next_run", fake_schedule_to_next_run)

        request = unit_utils.get_fake_request(method="PUT")
        update_fixture = {"schedule": {"tenant": new_tenant}}

        updated = self.controller.update(request, self.schedule_1["id"], update_fixture)["schedule"]

        self.assertNotEqual(updated.get("created_at"), None)
        self.assertNotEqual(updated.get("updated_at"), None)
        self.assertEqual(new_tenant, updated["tenant"])
        self.assertEqual(self.schedule_1["action"], updated["action"])
        self.assertEqual(self.schedule_1["minute"], updated["minute"])
        self.assertEqual(updated["next_run"], timeutils.isotime(self.schedule_1["next_run"]))
예제 #21
0
    def test_update_tenant(self):

        new_tenant = 'new-tenant-name'

        def fake_schedule_to_next_run(*args, **kwargs):
            self.fail('next_run should not be updated')

        self.stubs.Set(api_utils, 'schedule_to_next_run',
                       fake_schedule_to_next_run)

        request = unit_utils.get_fake_request(method='PUT')
        update_fixture = {'schedule': {'tenant': new_tenant}}

        updated = self.controller.update(request, self.schedule_1['id'],
                                         update_fixture)['schedule']

        self.assertNotEqual(updated.get('created_at'), None)
        self.assertNotEqual(updated.get('updated_at'), None)
        self.assertEqual(new_tenant, updated['tenant'])
        self.assertEqual(self.schedule_1['action'], updated['action'])
        self.assertEqual(self.schedule_1['minute'], updated['minute'])
        self.assertEqual(updated['next_run'],
                         timeutils.isotime(self.schedule_1['next_run']))
예제 #22
0
    def test_update_tenant(self):

        new_tenant = 'new-tenant-name'

        def fake_schedule_to_next_run(*args, **kwargs):
            self.fail('next_run should not be updated')

        self.stubs.Set(api_utils, 'schedule_to_next_run',
                       fake_schedule_to_next_run)

        request = unit_utils.get_fake_request(method='PUT')
        update_fixture = {'schedule': {'tenant': new_tenant}}

        updated = self.controller.update(request, self.schedule_1['id'],
                                         update_fixture)['schedule']

        self.assertNotEqual(updated.get('created_at'), None)
        self.assertNotEqual(updated.get('updated_at'), None)
        self.assertEqual(new_tenant, updated['tenant'])
        self.assertEqual(self.schedule_1['action'], updated['action'])
        self.assertEqual(self.schedule_1['minute'], updated['minute'])
        self.assertEqual(updated['next_run'],
                         timeutils.isotime(self.schedule_1['next_run']))
예제 #23
0
    def test_schedule_workflow(self):
        schedules = self.client.list_schedules()
        self.assertEqual(len(schedules), 0)

        # create invalid schedule
        request = {'not a schedule': 'yes'}

        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          request)

        # create malformed schedule
        request = 'not a schedule'

        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          request)

        # create schedule with no body
        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          None)
        # create schedule
        request = {
            'schedule':
            {
                'tenant': TENANT1,
                'action': 'snapshot',
                'minute': 30,
                'hour': 12,
                'metadata': {'instance_id': 'my_instance_1'},
            }
        }
        schedule = self.client.create_schedule(request)
        self.assertTrue(schedule['id'])
        self.assertEqual(schedule['tenant'], TENANT1)
        self.assertEqual(schedule['action'], 'snapshot')
        self.assertEqual(schedule['minute'], 30)
        self.assertEqual(schedule['hour'], 12)
        self.assertTrue('metadata' in schedule)
        metadata = schedule['metadata']
        self.assertEqual(1, len(metadata))
        self.assertEqual(metadata['instance_id'], 'my_instance_1')

        # Get schedule
        schedule = self.client.get_schedule(schedule['id'])
        self.assertTrue(schedule['id'])
        self.assertEqual(schedule['tenant'], TENANT1)
        self.assertEqual(schedule['action'], 'snapshot')
        self.assertEqual(schedule['minute'], 30)
        self.assertEqual(schedule['hour'], 12)

        # list schedules
        schedules = self.client.list_schedules()
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, next_run filters
        filters = {}
        filters['next_run_after'] = schedule['next_run']
        filters['next_run_before'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        filters['next_run_after'] = schedule['next_run']
        after_datetime = timeutils.parse_isotime(schedule['next_run'])
        before_datetime = (after_datetime - datetime.timedelta(seconds=1))
        filters['next_run_before'] = timeutils.isotime(before_datetime)
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        # list schedules, next_run_before filters
        filters = {}
        filters['next_run_before'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, next_run_after filters
        filters = {}
        filters['next_run_after'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, tenant filters
        filters = {}
        filters['tenant'] = TENANT1
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filters['tenant'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        # list schedules, metadata filter
        filter = {}
        filter['instance_id'] = 'my_instance_1'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filters['instance_id'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        filter = {}
        filter['instance_name'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 0)

        # test filter by action
        filter = {}
        filter['action'] = 'snapshot'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filter['action'] = 'test_action'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 0)

        # update schedule
        request = {'schedule': {'hour': 14}}
        updated_schedule = self.client.update_schedule(schedule['id'], request)
        self.assertEqual(updated_schedule['id'], schedule['id'])
        self.assertEqual(updated_schedule['tenant'], schedule['tenant'])
        self.assertEqual(updated_schedule['action'], schedule['action'])
        self.assertEqual(updated_schedule['minute'], None)
        self.assertEqual(updated_schedule['month'], None)
        self.assertEqual(updated_schedule['day_of_week'], None)
        self.assertEqual(updated_schedule['day_of_month'], None)
        self.assertEqual(updated_schedule['hour'], request['schedule']['hour'])
        self.assertNotEqual(updated_schedule['hour'], schedule['hour'])
        self.assertNotEqual(updated_schedule['next_run'], schedule['next_run'])

        # update schedule metadata
        request = {'schedule': {'metadata': {'instance_id': 'my_instance_2',
                                             'retention': '3',
                                             }}}
        schedule = self.client.get_schedule(schedule['id'])
        updated_schedule = self.client.update_schedule(schedule['id'], request)
        self.assertEqual(updated_schedule['id'], schedule['id'])
        self.assertEqual(updated_schedule['tenant'], schedule['tenant'])
        self.assertEqual(updated_schedule['action'], schedule['action'])
        self.assertEqual(updated_schedule['hour'], schedule['hour'])
        self.assertEqual(updated_schedule['minute'], schedule['minute'])
        self.assertEqual(updated_schedule['month'], schedule['month'])
        self.assertEqual(updated_schedule['day_of_week'],
                         schedule['day_of_week'])
        self.assertEqual(updated_schedule['day_of_month'],
                         schedule['day_of_month'])
        self.assertTrue('metadata' in updated_schedule)
        metadata = updated_schedule['metadata']
        self.assertEqual(2, len(metadata))
        self.assertEqual(metadata['instance_id'], 'my_instance_2')
        self.assertEqual(metadata['retention'], '3')

        # delete schedule
        self.client.delete_schedule(schedule['id'])

        # make sure schedule no longer exists
        self.assertRaises(client_exc.NotFound, self.client.get_schedule,
                          schedule['id'])
예제 #24
0
    def test_schedule_workflow(self):
        schedules = self.client.list_schedules()
        self.assertEqual(len(schedules), 0)

        # create invalid schedule
        request = {'not a schedule': 'yes'}

        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          request)

        # create malformed schedule
        request = 'not a schedule'

        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          request)

        # create schedule with no body
        self.assertRaises(client_exc.BadRequest, self.client.create_schedule,
                          None)
        # create schedule
        request = {
            'schedule': {
                'tenant': TENANT1,
                'action': 'snapshot',
                'minute': 30,
                'hour': 12,
                'metadata': {
                    'instance_id': 'my_instance_1'
                },
            }
        }
        schedule = self.client.create_schedule(request)
        self.assertTrue(schedule['id'])
        self.assertEqual(schedule['tenant'], TENANT1)
        self.assertEqual(schedule['action'], 'snapshot')
        self.assertEqual(schedule['minute'], 30)
        self.assertEqual(schedule['hour'], 12)
        self.assertTrue('metadata' in schedule)
        metadata = schedule['metadata']
        self.assertEqual(1, len(metadata))
        self.assertEqual(metadata['instance_id'], 'my_instance_1')

        # Get schedule
        schedule = self.client.get_schedule(schedule['id'])
        self.assertTrue(schedule['id'])
        self.assertEqual(schedule['tenant'], TENANT1)
        self.assertEqual(schedule['action'], 'snapshot')
        self.assertEqual(schedule['minute'], 30)
        self.assertEqual(schedule['hour'], 12)

        # list schedules
        schedules = self.client.list_schedules()
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, next_run filters
        filters = {}
        filters['next_run_after'] = schedule['next_run']
        filters['next_run_before'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        filters['next_run_after'] = schedule['next_run']
        after_datetime = timeutils.parse_isotime(schedule['next_run'])
        before_datetime = (after_datetime - datetime.timedelta(seconds=1))
        filters['next_run_before'] = timeutils.isotime(before_datetime)
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        # list schedules, next_run_before filters
        filters = {}
        filters['next_run_before'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, next_run_after filters
        filters = {}
        filters['next_run_after'] = schedule['next_run']
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)

        # list schedules, tenant filters
        filters = {}
        filters['tenant'] = TENANT1
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filters['tenant'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        # list schedules, metadata filter
        filter = {}
        filter['instance_id'] = 'my_instance_1'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filters['instance_id'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filters)
        self.assertEqual(len(schedules), 0)

        filter = {}
        filter['instance_name'] = 'aaaa-bbbb-cccc-dddd'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 0)

        # test filter by action
        filter = {}
        filter['action'] = 'snapshot'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 1)
        self.assertEqual(schedules[0], schedule)
        filter['action'] = 'test_action'
        schedules = self.client.list_schedules(filter_args=filter)
        self.assertEqual(len(schedules), 0)

        # update schedule
        request = {'schedule': {'hour': 14}}
        updated_schedule = self.client.update_schedule(schedule['id'], request)
        self.assertEqual(updated_schedule['id'], schedule['id'])
        self.assertEqual(updated_schedule['tenant'], schedule['tenant'])
        self.assertEqual(updated_schedule['action'], schedule['action'])
        self.assertEqual(updated_schedule['minute'], None)
        self.assertEqual(updated_schedule['month'], None)
        self.assertEqual(updated_schedule['day_of_week'], None)
        self.assertEqual(updated_schedule['day_of_month'], None)
        self.assertEqual(updated_schedule['hour'], request['schedule']['hour'])
        self.assertNotEqual(updated_schedule['hour'], schedule['hour'])
        self.assertNotEqual(updated_schedule['next_run'], schedule['next_run'])

        # update schedule metadata
        request = {
            'schedule': {
                'metadata': {
                    'instance_id': 'my_instance_2',
                    'retention': '3',
                }
            }
        }
        schedule = self.client.get_schedule(schedule['id'])
        updated_schedule = self.client.update_schedule(schedule['id'], request)
        self.assertEqual(updated_schedule['id'], schedule['id'])
        self.assertEqual(updated_schedule['tenant'], schedule['tenant'])
        self.assertEqual(updated_schedule['action'], schedule['action'])
        self.assertEqual(updated_schedule['hour'], schedule['hour'])
        self.assertEqual(updated_schedule['minute'], schedule['minute'])
        self.assertEqual(updated_schedule['month'], schedule['month'])
        self.assertEqual(updated_schedule['day_of_week'],
                         schedule['day_of_week'])
        self.assertEqual(updated_schedule['day_of_month'],
                         schedule['day_of_month'])
        self.assertTrue('metadata' in updated_schedule)
        metadata = updated_schedule['metadata']
        self.assertEqual(2, len(metadata))
        self.assertEqual(metadata['instance_id'], 'my_instance_2')
        self.assertEqual(metadata['retention'], '3')

        # delete schedule
        self.client.delete_schedule(schedule['id'])

        # make sure schedule no longer exists
        self.assertRaises(client_exc.NotFound, self.client.get_schedule,
                          schedule['id'])