text: #    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 oslo_utils import timeutils
  
  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.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.utcnow_ts(microsecond=True)
          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.utcnow_ts(microsecond=True)
          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.utcnow_ts(microsecond=True)
          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.utcnow_ts(microsecond=True)
          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)
  