# Copyright 2013 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from mock import patch from trove.backup import models as bkup_models from trove.backup import state from trove.common import exception as t_exception from trove.common.instance import ServiceStatuses from trove.common import utils from trove.conductor import manager as conductor_manager from trove.guestagent.common import timeutils from trove.instance import models as t_models from trove.tests.unittests import trove_testtools from trove.tests.unittests.util import util # See LP bug #1255178 OLD_DBB_SAVE = bkup_models.DBBackup.save class ConductorMethodTests(trove_testtools.TestCase): def setUp(self): # See LP bug #1255178 bkup_models.DBBackup.save = OLD_DBB_SAVE super(ConductorMethodTests, self).setUp() util.init_db() self.cond_mgr = conductor_manager.Manager() self.instance_id = utils.generate_uuid() def tearDown(self): super(ConductorMethodTests, self).tearDown() def _create_iss(self): new_id = utils.generate_uuid() iss = t_models.InstanceServiceStatus( id=new_id, instance_id=self.instance_id, status=ServiceStatuses.NEW) iss.save() return new_id def _get_iss(self, id): return t_models.InstanceServiceStatus.find_by(id=id) def _create_backup(self, name='fake backup'): new_id = utils.generate_uuid() backup = bkup_models.DBBackup.create( id=new_id, name=name, description='This is a fake backup object.', tenant_id=utils.generate_uuid(), state=state.BackupState.NEW, instance_id=self.instance_id) backup.save() return new_id def _get_backup(self, id): return bkup_models.DBBackup.find_by(id=id) # --- Tests for heartbeat --- def test_heartbeat_instance_not_found(self): new_id = utils.generate_uuid() self.assertRaises(t_exception.ModelNotFoundError, self.cond_mgr.heartbeat, None, new_id, {}) @patch('trove.conductor.manager.LOG') def test_heartbeat_instance_no_changes(self, mock_logging): iss_id = self._create_iss() old_iss = self._get_iss(iss_id) self.cond_mgr.heartbeat(None, self.instance_id, {}) new_iss = self._get_iss(iss_id) self.assertEqual(old_iss.status_id, new_iss.status_id) self.assertEqual(old_iss.status_description, new_iss.status_description) @patch('trove.conductor.manager.LOG') def test_heartbeat_instance_status_bogus_change(self, mock_logging): iss_id = self._create_iss() old_iss = self._get_iss(iss_id) new_status = 'potato salad' payload = { 'service_status': new_status, } self.assertRaises(ValueError, self.cond_mgr.heartbeat, None, self.instance_id, payload) new_iss = self._get_iss(iss_id) self.assertEqual(old_iss.status_id, new_iss.status_id) self.assertEqual(old_iss.status_description, new_iss.status_description) @patch('trove.conductor.manager.LOG') def test_heartbeat_instance_status_changed(self, mock_logging): iss_id = self._create_iss() payload = {'service_status': ServiceStatuses.BUILDING.description} self.cond_mgr.heartbeat(None, self.instance_id, payload) iss = self._get_iss(iss_id) self.assertEqual(ServiceStatuses.BUILDING, iss.status) # --- Tests for update_backup --- def test_backup_not_found(self): new_bkup_id = utils.generate_uuid() self.assertRaises(t_exception.ModelNotFoundError, self.cond_mgr.update_backup, None, self.instance_id, new_bkup_id) @patch('trove.conductor.manager.LOG') def test_backup_instance_id_nomatch(self, mock_logging): new_iid = utils.generate_uuid() bkup_id = self._create_backup('nomatch') old_name = self._get_backup(bkup_id).name self.cond_mgr.update_backup(None, new_iid, bkup_id, name="remains unchanged") bkup = self._get_backup(bkup_id) self.assertEqual(old_name, bkup.name) @patch('trove.conductor.manager.LOG') def test_backup_bogus_fields_not_changed(self, mock_logging): bkup_id = self._create_backup('bogus') self.cond_mgr.update_backup(None, self.instance_id, bkup_id, not_a_valid_field="INVALID") bkup = self._get_backup(bkup_id) self.assertFalse(hasattr(bkup, 'not_a_valid_field')) @patch('trove.conductor.manager.LOG') def test_backup_real_fields_changed(self, mock_logging): bkup_id = self._create_backup('realrenamed') new_name = "recently renamed" self.cond_mgr.update_backup(None, self.instance_id, bkup_id, name=new_name) bkup = self._get_backup(bkup_id) self.assertEqual(new_name, bkup.name) # --- Tests for discarding old messages --- @patch('trove.conductor.manager.LOG') def test_heartbeat_newer_timestamp_accepted(self, mock_logging): new_p = {'service_status': ServiceStatuses.NEW.description} build_p = {'service_status': ServiceStatuses.BUILDING.description} iss_id = self._create_iss() iss = self._get_iss(iss_id) now = timeutils.float_utcnow() future = now + 60 self.cond_mgr.heartbeat(None, self.instance_id, new_p, sent=now) self.cond_mgr.heartbeat(None, self.instance_id, build_p, sent=future) iss = self._get_iss(iss_id) self.assertEqual(ServiceStatuses.BUILDING, iss.status) @patch('trove.conductor.manager.LOG') def test_heartbeat_older_timestamp_discarded(self, mock_logging): new_p = {'service_status': ServiceStatuses.NEW.description} build_p = {'service_status': ServiceStatuses.BUILDING.description} iss_id = self._create_iss() iss = self._get_iss(iss_id) now = timeutils.float_utcnow() past = now - 60 self.cond_mgr.heartbeat(None, self.instance_id, new_p, sent=past) self.cond_mgr.heartbeat(None, self.instance_id, build_p, sent=past) iss = self._get_iss(iss_id) self.assertEqual(ServiceStatuses.NEW, iss.status) def test_backup_newer_timestamp_accepted(self): old_name = "oldname" new_name = "renamed" bkup_id = self._create_backup(old_name) bkup = self._get_backup(bkup_id) now = timeutils.float_utcnow() future = now + 60 self.cond_mgr.update_backup(None, self.instance_id, bkup_id, sent=now, name=old_name) self.cond_mgr.update_backup(None, self.instance_id, bkup_id, sent=future, name=new_name) bkup = self._get_backup(bkup_id) self.assertEqual(new_name, bkup.name) def test_backup_older_timestamp_discarded(self): old_name = "oldname" new_name = "renamed" bkup_id = self._create_backup(old_name) bkup = self._get_backup(bkup_id) now = timeutils.float_utcnow() past = now - 60 self.cond_mgr.update_backup(None, self.instance_id, bkup_id, sent=now, name=old_name) self.cond_mgr.update_backup(None, self.instance_id, bkup_id, sent=past, name=new_name) bkup = self._get_backup(bkup_id) self.assertEqual(old_name, bkup.name)