Exemplo n.º 1
0
    def create(self, name, version):
        """
        Create and return a MigrationTracker with specified name and version.

        :param name:    The name of the package that the MigrationTracker is tracking.
        :type  name:    str
        :param version: The version we want to store on the new MigrationTracker.
        :type  version: int
        :rtype:         pulp.server.db.model.migration_tracker.MigrationTracker
        """
        new_mt = MigrationTracker(name=name, version=version)
        new_mt.save()
        return new_mt
Exemplo n.º 2
0
    def create(self, name, version):
        """
        Create and return a MigrationTracker with specified name and version.

        :param name:    The name of the package that the MigrationTracker is tracking.
        :type  name:    str
        :param version: The version we want to store on the new MigrationTracker.
        :type  version: int
        :rtype:         pulp.server.db.model.migration_tracker.MigrationTracker
        """
        new_mt = MigrationTracker(name=name, version=version)
        new_mt.save()
        return new_mt
Exemplo n.º 3
0
 def test__initialize_pulp(self):
     """
     _initialize_pulp() should raise an Exception if any of the packages aren't at their latest
     version.
     """
     # It is unusual to put an import in the middle of a test, but unfortunately this import will
     # call start_logging() before our test super class can override the logging settings, and
     # thus all the logging will be done to /var/log instead of to /tmp. Moving the import here
     # from the top of the file solves the problem, though not elegantly.
     from pulp.server.webservices.application import _initialize_pulp
     # Make sure we start out with a clean slate
     self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
     # Make sure that our mock works. There are three valid packages.
     self.assertEquals(len(models.get_migration_packages()), 4)
     # Set all versions back to 0
     for package in models.get_migration_packages():
         package._migration_tracker.version = 0
         package._migration_tracker.save()
     # Let's make sure we raise the exception
     try:
         _initialize_pulp()
         self.fail('_initialize_pulp() should have raised an Exception, but did not.')
     except Exception, e:
         self.assertEqual(str(e), ('There are unapplied migrations. Please '
                                   'run the database management utility to apply them.'))
Exemplo n.º 4
0
    def test_current_version_too_high(self, mocked_file_config, getLogger):
        """
        Set the current package version higher than latest available version, then sit back and eat
        popcorn.
        """
        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are four valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions to ridiculously high values
        for package in models.get_migration_packages():
            package._migration_tracker.version = 9999999
            package._migration_tracker.save()
        error_code = manage.main()
        self.assertEqual(error_code, os.EX_DATAERR)

        # There should have been a critical log about the Exception
        expected_messages = ('The database for migration package unit.server.db.migration_packages.'
                             'platform is at version 9999999, which is larger than the latest '
                             'version available, 1.')
        critical_messages = ''.join([mock_call[1][0] for mock_call in logger.critical.mock_calls])
        for msg in expected_messages:
            self.assertTrue(msg in critical_messages)
Exemplo n.º 5
0
    def test_migrate_with_dry_run_flag(self, mock_file_config,
                                       mocked_apply_migration, getLogger):
        """
        Test that when a dry run is performed, no migrations actually occur.
        """
        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                          0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        result = manage.main()

        # Test that none of the mock objects were actually called
        migration_modules_called = [
            mock_call[1][1].name
            for mock_call in mocked_apply_migration.mock_calls
        ]
        self.assertEquals(0, len(migration_modules_called))
        self.assertEquals(1, result)
        for package in models.get_migration_packages():
            self.assertEqual(package.current_version, 0)
Exemplo n.º 6
0
    def test_current_version_too_high(self, mocked_file_config, getLogger):
        """
        Set the current package version higher than latest available version, then sit back and eat
        popcorn.
        """
        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are four valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions to ridiculously high values
        for package in models.get_migration_packages():
            package._migration_tracker.version = 9999999
            package._migration_tracker.save()
        error_code = manage.main()
        self.assertEqual(error_code, os.EX_DATAERR)

        # There should have been a critical log about the Exception
        expected_messages = ('The database for migration package unit.server.db.migration_packages.'
                             'platform is at version 9999999, which is larger than the latest '
                             'version available, 1.')
        critical_messages = ''.join([mock_call[1][0] for mock_call in logger.critical.mock_calls])
        for msg in expected_messages:
            self.assertTrue(msg in critical_messages)
Exemplo n.º 7
0
 def test_current_version_too_high(self, mocked_file_config, mocked_logger,
                                   mocked_stdout, mocked_stderr):
     """
     Set the current package version higher than latest available version, then sit back and eat
     popcorn.
     """
     # Make sure we start out with a clean slate
     self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                       0)
     # Make sure that our mock works. There are four valid packages.
     self.assertEquals(len(models.get_migration_packages()), 4)
     # Set all versions to ridiculously high values
     for package in models.get_migration_packages():
         package._migration_tracker.version = 9999999
         package._migration_tracker.save()
     error_code = manage.main()
     self.assertEqual(error_code, os.EX_DATAERR)
     # There should have been a print to stderr about the Exception
     expected_stderr_calls = [(
         'The database for migration package unit.server.db.migration_packages.platform is at '
         'version 9999999, which is larger than the latest version available, 1.'
     ), '\n']
     stderr_calls = [
         mock_call[1][0] for mock_call in mocked_stderr.mock_calls
     ]
     self.assertEquals(stderr_calls, expected_stderr_calls)
Exemplo n.º 8
0
    def test_migrate(self, mock_file_config, mocked_apply_migration,
                     getLogger):
        """
        Let's set all the packages to be at version 0, and then check that the migrations get
        called in the correct order.
        """

        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                          0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        manage.main()

        # There should have been a critical log about the Exception
        expected_messages = (
            'Applying migration unit.server.db.migration_packages.raise_exception.0002_oh_no '
            'failed.\n\nHalting migrations due to a migration failure.',
            "Bet you didn\'t see this coming.")
        critical_messages = ''.join(
            [mock_call[1][0] for mock_call in logger.critical.mock_calls])
        for msg in expected_messages:
            self.assertTrue(msg in critical_messages)

        migration_modules_called = [
            mock_call[1][1].name
            for mock_call in mocked_apply_migration.mock_calls
        ]
        # Note that none of the migrations that don't meet our criteria show up in this list. Also,
        # Note that migration_packages.raise_exception.0003_shouldnt_run doesn't appear
        # since migration_packages.raise_exception.0002_oh_no raised an Exception. Note
        # also that even though the raise_exception package raised an Exception, we still run all
        # the z migrations because we don't want one package to break another.
        expected_migration_modules_called = [
            'unit.server.db.migration_packages.platform.0001_stuff_and_junk',
            'unit.server.db.migration_packages.raise_exception.0001_works_fine',
            'unit.server.db.migration_packages.raise_exception.0002_oh_no'
        ]
        self.assertEquals(migration_modules_called,
                          expected_migration_modules_called)
        # Assert that our precious versions have been updated correctly
        for package in models.get_migration_packages():
            if package.name == 'unit.server.db.migration_packages.platform':
                self.assertEqual(package.current_version,
                                 package.latest_available_version)
            elif package.name == 'unit.server.db.migration_packages.raise_exception':
                # The raised Exception should have prevented us from getting past version 1
                self.assertEquals(package.current_version, 1)
            else:
                # raise_exception should cause the migrations to stop
                self.assertEqual(package.current_version, 0)
Exemplo n.º 9
0
    def test_migrate(self, file_config_mock, logger_mock,
                     mocked_apply_migration, mocked_stdout, mocked_stderr):
        """
        Let's set all the packages to be at version 0, and then check that the migrations get
        called in the correct order.
        """
        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                          0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        manage.main()

        # There should have been a print to stderr about the Exception
        expected_stderr_calls = [(
            'Applying migration unit.server.db.migration_packages.raise_exception.0002_oh_no '
            'failed.'), ' ', ' See log for details.', '\n']
        stderr_calls = [
            mock_call[1][0] for mock_call in mocked_stderr.mock_calls
        ]
        self.assertEquals(stderr_calls, expected_stderr_calls)

        migration_modules_called = [
            mock_call[1][1].name
            for mock_call in mocked_apply_migration.mock_calls
        ]
        # Note that none of the migrations that don't meet our criteria show up in this list. Also,
        # Note that migration_packages.raise_exception.0003_shouldnt_run doesn't appear
        # since migration_packages.raise_exception.0002_oh_no raised an Exception. Note
        # also that even though the raise_exception package raised an Exception, we still run all
        # the z migrations because we don't want one package to break another.
        expected_migration_modules_called = [
            'unit.server.db.migration_packages.platform.0001_stuff_and_junk',
            'unit.server.db.migration_packages.raise_exception.0001_works_fine',
            'unit.server.db.migration_packages.raise_exception.0002_oh_no',
            'unit.server.db.migration_packages.z.0001_test',
            'unit.server.db.migration_packages.z.0002_test',
            'unit.server.db.migration_packages.z.0003_test'
        ]
        self.assertEquals(migration_modules_called,
                          expected_migration_modules_called)
        # Assert that our precious versions have been updated correctly
        for package in models.get_migration_packages():
            if package.name != 'unit.server.db.migration_packages.raise_exception':
                self.assertEqual(package.current_version,
                                 package.latest_available_version)
            else:
                # The raised Exception should have prevented us from getting past version 1
                self.assertEqual(package.current_version, 1)
Exemplo n.º 10
0
    def test_migrate(self, mock_file_config, mocked_apply_migration, getLogger):
        """
        Let's set all the packages to be at version 0, and then check that the migrations get
        called in the correct order.
        """

        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        manage.main()

        # There should have been a critical log about the Exception
        expected_messages = (
            'Applying migration unit.server.db.migration_packages.raise_exception.0002_oh_no '
            'failed.\n\nHalting migrations due to a migration failure.',
            "Bet you didn\'t see this coming."
        )
        critical_messages = ''.join([mock_call[1][0] for mock_call in logger.critical.mock_calls])
        for msg in expected_messages:
            self.assertTrue(msg in critical_messages)

        migration_modules_called = [
            mock_call[1][1].name for mock_call in mocked_apply_migration.mock_calls]
        # Note that none of the migrations that don't meet our criteria show up in this list. Also,
        # Note that migration_packages.raise_exception.0003_shouldnt_run doesn't appear
        # since migration_packages.raise_exception.0002_oh_no raised an Exception. Note
        # also that even though the raise_exception package raised an Exception, we still run all
        # the z migrations because we don't want one package to break another.
        expected_migration_modules_called = [
            'unit.server.db.migration_packages.platform.0001_stuff_and_junk',
            'unit.server.db.migration_packages.raise_exception.0001_works_fine',
            'unit.server.db.migration_packages.raise_exception.0002_oh_no']
        self.assertEquals(migration_modules_called, expected_migration_modules_called)
        # Assert that our precious versions have been updated correctly
        for package in models.get_migration_packages():
            if package.name == 'unit.server.db.migration_packages.platform':
                self.assertEqual(package.current_version, package.latest_available_version)
            elif package.name == 'unit.server.db.migration_packages.raise_exception':
                # The raised Exception should have prevented us from getting past version 1
                self.assertEquals(package.current_version, 1)
            else:
                # raise_exception should cause the migrations to stop
                self.assertEqual(package.current_version, 0)
Exemplo n.º 11
0
Arquivo: models.py Projeto: kaos/pulp
    def __init__(self, python_package):
        """
        Initialize the MigrationPackage to represent the Python migration package passed in.

        :param python_package: The Python package this object should represent
        :type  python_package: package
        """
        self._package = python_package
        # This is an object representation of the DB object that keeps track of the migration
        # version that has been applied

        try:
            self._migration_tracker = MigrationTracker.objects().get(name=self.name)
        except DoesNotExist:
            self._migration_tracker = MigrationTracker(name=self.name)
            self._migration_tracker.save()

        # Calculate the latest available version
        available_versions = self.available_versions
        if available_versions:
            self.latest_available_version = available_versions[-1]
        else:
            self.latest_available_version = 0
Exemplo n.º 12
0
    def get(self, name):
        """
        Retrieve a MigrationTracker from the database by name.

        :param name: The name of the MigrationTracker that we wish to retrieve.
        :type  name: str
        :rtype:      pulp.server.db.model.migration_tracker.MigrationTracker
        """
        migration_tracker = self._collection.find_one({'name': name})
        if migration_tracker is not None:
            migration_tracker = MigrationTracker(
                name=migration_tracker['name'],
                version=migration_tracker['version'])
            return migration_tracker
        raise DoesNotExist('MigrationTracker with id %s does not exist.')
Exemplo n.º 13
0
    def __init__(self, python_package):
        """
        Initialize the MigrationPackage to represent the Python migration package passed in.

        :param python_package: The Python package this object should represent
        :type  python_package: package
        """
        self._package = python_package
        # This is an object representation of the DB object that keeps track of the migration
        # version that has been applied

        try:
            self._migration_tracker = MigrationTracker.objects().get(
                name=self.name)
        except DoesNotExist:
            self._migration_tracker = MigrationTracker(name=self.name)
            self._migration_tracker.save()

        # Calculate the latest available version
        available_versions = self.available_versions
        if available_versions:
            self.latest_available_version = available_versions[-1]
        else:
            self.latest_available_version = 0
Exemplo n.º 14
0
 def test_migrate_with_test_flag(self, start_logging_mock,
                                 mocked_apply_migration, mocked_stderr):
     """
     Let's set all the packages to be at version 0, and then check that the migrations get called
     in the correct order. We will also set the --test flag and ensure that the migration
     versions do not get updated.
     """
     # Make sure we start out with a clean slate
     self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                       0)
     # Make sure that our mock works. There are three valid packages.
     self.assertEquals(len(models.get_migration_packages()), 4)
     # Set all versions back to 0
     for package in models.get_migration_packages():
         package._migration_tracker.version = 0
         package._migration_tracker.save()
     manage.main()
     # There should have been a print to stderr about the Exception
     expected_stderr_calls = [
         'Applying migration data.test_migration_packages.raise_exception.0002_oh_no failed.',
         ' ', ' See log for details.', '\n'
     ]
     stderr_calls = [call[1][0] for call in mocked_stderr.mock_calls]
     self.assertEquals(stderr_calls, expected_stderr_calls)
     migration_modules_called = [
         call[1][1].name for call in mocked_apply_migration.mock_calls
     ]
     # Note that none of the migrations that don't meet our criteria show up in this list. Also,
     # Note that data.test_migration_packages.raise_exception.0003_shouldnt_run doesn't appear
     # since data.test_migration_packages.raise_exception.0002_oh_no raised an Exception. Note
     # also that even though the raise_exception package raised an Exception, we still run all
     # the z migrations because we don't want one package to break another.
     expected_migration_modules_called = [
         'data.test_migration_packages.platform.0001_stuff_and_junk',
         'data.test_migration_packages.raise_exception.0001_works_fine',
         'data.test_migration_packages.raise_exception.0002_oh_no',
         'data.test_migration_packages.z.0001_test',
         'data.test_migration_packages.z.0002_test',
         'data.test_migration_packages.z.0003_test'
     ]
     self.assertEquals(migration_modules_called,
                       expected_migration_modules_called)
     # Assert that our precious versions have not been updated, since we have the --test flag
     for package in models.get_migration_packages():
         self.assertEqual(package.current_version, 0)
Exemplo n.º 15
0
    def test_migrate(self, file_config_mock, logger_mock, mocked_apply_migration, mocked_stdout,
                     mocked_stderr):
        """
        Let's set all the packages to be at version 0, and then check that the migrations get
        called in the correct order.
        """
        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        manage.main()

        # There should have been a print to stderr about the Exception
        expected_stderr_calls = [
            ('Applying migration unit.server.db.migration_packages.raise_exception.0002_oh_no '
             'failed.'), ' ', ' See log for details.', '\n']
        stderr_calls = [mock_call[1][0] for mock_call in mocked_stderr.mock_calls]
        self.assertEquals(stderr_calls, expected_stderr_calls)

        migration_modules_called = [
            mock_call[1][1].name for mock_call in mocked_apply_migration.mock_calls]
        # Note that none of the migrations that don't meet our criteria show up in this list. Also,
        # Note that migration_packages.raise_exception.0003_shouldnt_run doesn't appear
        # since migration_packages.raise_exception.0002_oh_no raised an Exception. Note
        # also that even though the raise_exception package raised an Exception, we still run all
        # the z migrations because we don't want one package to break another.
        expected_migration_modules_called = [
            'unit.server.db.migration_packages.platform.0001_stuff_and_junk',
            'unit.server.db.migration_packages.raise_exception.0001_works_fine',
            'unit.server.db.migration_packages.raise_exception.0002_oh_no',
            'unit.server.db.migration_packages.z.0001_test',
            'unit.server.db.migration_packages.z.0002_test',
            'unit.server.db.migration_packages.z.0003_test']
        self.assertEquals(migration_modules_called, expected_migration_modules_called)
        # Assert that our precious versions have been updated correctly
        for package in models.get_migration_packages():
            if package.name != 'unit.server.db.migration_packages.raise_exception':
                self.assertEqual(package.current_version, package.latest_available_version)
            else:
                # The raised Exception should have prevented us from getting past version 1
                self.assertEqual(package.current_version, 1)
Exemplo n.º 16
0
    def test_migrate_with_new_packages(self, start_logging_mock, logger_mock, mocked_stderr):
        """
        Adding new packages to a system that doesn't have any trackers should advance
        each package to the latest available version, applying all migrate() functions along the way.
        """
        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are four valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        manage.main()

        for package in models.get_migration_packages():
            if 'raise_exception' in str(package):
                # The Exception raising package should get to version 1, because version 2 raises
                self.assertEqual(package.current_version, 1)
            else:
                # All other packages should reach their top versions
                self.assertEqual(package.current_version, package.latest_available_version)
Exemplo n.º 17
0
 def test_save(self):
     # Make sure we are starting off clean
     self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                       0)
     # Instantiate a MigrationTracker
     mt = MigrationTracker('meaning_of_life', 41)
     # At this point there should not be a MigrationTracker in the database
     self.assertEquals(mt._collection.find({}).count(), 0)
     # saving the mt should add it to the DB
     mt.save()
     self.assertEquals(mt._collection.find({}).count(), 1)
     mt_bson = mt._collection.find_one({'name': 'meaning_of_life'})
     self.assertEquals(mt_bson['name'], 'meaning_of_life')
     self.assertEquals(mt_bson['version'], 41)
     # now let's update the version to 42, the correct meaning of life
     mt.version = 42
     mt.save()
     # see if the updated meaning of life made it to the DB
     self.assertEquals(mt._collection.find({}).count(), 1)
     mt_bson = mt._collection.find_one({'name': 'meaning_of_life'})
     self.assertEquals(mt_bson['name'], 'meaning_of_life')
     self.assertEquals(mt_bson['version'], 42)
Exemplo n.º 18
0
    def test_migrate_with_new_packages(self, mocked_apply_migration):
        """
        Adding new packages to a system that doesn't have any trackers should automatically advance
        each package to the latest available version without calling any migrate() functions.
        """
        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        manage.main()
        # No calls to apply_migration should have been made, and we should be at the latest package
        # versions for each of the packages that have valid migrations.
        self.assertFalse(mocked_apply_migration.called)
        for package in models.get_migration_packages():
            self.assertEqual(package.current_version, package.latest_available_version)

        # Calling main() again should still not call apply_migration() or change the versions
        manage.main()
        self.assertFalse(mocked_apply_migration.called)
        for package in models.get_migration_packages():
            self.assertEqual(package.current_version, package.latest_available_version)
Exemplo n.º 19
0
    def test_migrate_with_new_packages(self, start_logging_mock, logger_mock,
                                       mocked_stderr):
        """
        Adding new packages to a system that doesn't have any trackers should advance
        each package to the latest available version, applying all migrate() functions along the way.
        """
        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(),
                          0)
        # Make sure that our mock works. There are four valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        manage.main()

        for package in models.get_migration_packages():
            if 'raise_exception' in str(package):
                # The Exception raising package should get to version 1, because version 2 raises
                self.assertEqual(package.current_version, 1)
            else:
                # All other packages should reach their top versions
                self.assertEqual(package.current_version,
                                 package.latest_available_version)
Exemplo n.º 20
0
 def test_current_version_too_high(self, mocked_file_config, mocked_logger, mocked_stderr):
     """
     Set the current package version higher than latest available version, then sit back and eat
     popcorn.
     """
     # Make sure we start out with a clean slate
     self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
     # Make sure that our mock works. There are four valid packages.
     self.assertEquals(len(models.get_migration_packages()), 4)
     # Set all versions to ridiculously high values
     for package in models.get_migration_packages():
         package._migration_tracker.version = 9999999
         package._migration_tracker.save()
     error_code = manage.main()
     self.assertEqual(error_code, os.EX_DATAERR)
     # There should have been a print to stderr about the Exception
     expected_stderr_calls = [
         'The database for migration package data.test_migration_packages.platform is at ' +\
         'version 9999999, which is larger than the latest version available, 1.', '\n']
     stderr_calls = [call[1][0] for call in mocked_stderr.mock_calls]
     self.assertEquals(stderr_calls, expected_stderr_calls)
Exemplo n.º 21
0
 def test_save(self):
     # Make sure we are starting off clean
     self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
     # Instantiate a MigrationTracker
     mt = MigrationTracker('meaning_of_life', 41)
     # At this point there should not be a MigrationTracker in the database
     self.assertEquals(mt._collection.find({}).count(), 0)
     # saving the mt should add it to the DB
     mt.save()
     self.assertEquals(mt._collection.find({}).count(), 1)
     mt_bson = mt._collection.find_one({'name': 'meaning_of_life'})
     self.assertEquals(mt_bson['name'], 'meaning_of_life')
     self.assertEquals(mt_bson['version'], 41)
     # now let's update the version to 42, the correct meaning of life
     mt.version = 42
     mt.save()
     # see if the updated meaning of life made it to the DB
     self.assertEquals(mt._collection.find({}).count(), 1)
     mt_bson = mt._collection.find_one({'name': 'meaning_of_life'})
     self.assertEquals(mt_bson['name'], 'meaning_of_life')
     self.assertEquals(mt_bson['version'], 42)
Exemplo n.º 22
0
 def test_migrate_with_test_flag(self, start_logging_mock, mocked_apply_migration, mocked_stdout,
                                 mocked_stderr):
     """
     Let's set all the packages to be at version 0, and then check that the migrations get called
     in the correct order. We will also set the --test flag and ensure that the migration
     versions do not get updated.
     """
     # Make sure we start out with a clean slate
     self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
     # Make sure that our mock works. There are three valid packages.
     self.assertEquals(len(models.get_migration_packages()), 4)
     # Set all versions back to 0
     for package in models.get_migration_packages():
         package._migration_tracker.version = 0
         package._migration_tracker.save()
     manage.main()
     # There should have been a print to stderr about the Exception
     expected_stderr_calls = [
         ('Applying migration unit.server.db.migration_packages.raise_exception.0002_oh_no '
          'failed.\n\nHalting migrations due to a migration failure.'), ' ', ' See log for details.', '\n',
         'Bet you didn\'t see this coming.', '\n']
     stderr_calls = [mock_call[1][0] for mock_call in mocked_stderr.mock_calls]
     self.assertEquals(stderr_calls, expected_stderr_calls)
     migration_modules_called = [
         mock_call[1][1].name for mock_call in mocked_apply_migration.mock_calls]
     # Note that none of the migrations that don't meet our criteria show up in this list. Also,
     # Note that migration_packages.raise_exception.0003_shouldnt_run doesn't appear
     # since migration_packages.raise_exception.0002_oh_no raised an Exception. Note
     # also that even though the raise_exception package raised an Exception, we still run all
     # the z migrations because we don't want one package to break another.
     expected_migration_modules_called = [
         'unit.server.db.migration_packages.platform.0001_stuff_and_junk',
         'unit.server.db.migration_packages.raise_exception.0001_works_fine',
         'unit.server.db.migration_packages.raise_exception.0002_oh_no']
     self.assertEquals(migration_modules_called, expected_migration_modules_called)
     # Assert that our precious versions have not been updated, since we have the --test flag
     for package in models.get_migration_packages():
         self.assertEqual(package.current_version, 0)
Exemplo n.º 23
0
    def test_migrate_with_dry_run_flag(self, mock_file_config, mocked_apply_migration, getLogger):
        """
        Test that when a dry run is performed, no migrations actually occur.
        """
        logger = MagicMock()
        getLogger.return_value = logger

        # Make sure we start out with a clean slate
        self.assertEquals(MigrationTracker.get_collection().find({}).count(), 0)
        # Make sure that our mock works. There are three valid packages.
        self.assertEquals(len(models.get_migration_packages()), 4)
        # Set all versions back to 0
        for package in models.get_migration_packages():
            package._migration_tracker.version = 0
            package._migration_tracker.save()
        result = manage.main()

        # Test that none of the mock objects were actually called
        migration_modules_called = [
            mock_call[1][1].name for mock_call in mocked_apply_migration.mock_calls]
        self.assertEquals(0, len(migration_modules_called))
        self.assertEquals(1, result)
        for package in models.get_migration_packages():
            self.assertEqual(package.current_version, 0)
Exemplo n.º 24
0
class MigrationPackage(object):
    """
    A wrapper around the migration packages found in pulp.server.db.migrations. Has methods to
    retrieve information about the migrations that are found there, and to apply the migrations.
    """
    class DuplicateVersions(Exception):
        """
        This is raised when a single migration package has two MigrationModules in it that have the
        same version.
        """
        pass

    class MissingVersion(Exception):
        """
        This is raised when a migration package has a gap in the MigrationModule versions.
        """
        pass

    def __init__(self, python_package):
        """
        Initialize the MigrationPackage to represent the Python migration package passed in.

        :param python_package: The Python package this object should represent
        :type  python_package: package
        """
        self._package = python_package
        # This is an object representation of the DB object that keeps track of the migration
        # version that has been applied

        try:
            self._migration_tracker = MigrationTracker.objects().get(
                name=self.name)
        except DoesNotExist:
            self._migration_tracker = MigrationTracker(name=self.name)
            self._migration_tracker.save()

        # Calculate the latest available version
        available_versions = self.available_versions
        if available_versions:
            self.latest_available_version = available_versions[-1]
        else:
            self.latest_available_version = 0

    def apply_migration(self, migration, update_current_version=True):
        """
        Apply the migration that is passed in, and update the DB to note the new version that this
        migration represents.

        :param migration:              The migration to apply
        :type  migration:              pulp.server.db.migrate.utils.MigrationModule
        :param update_current_version: If True, update the package's current version after
                                       successful application and enforce migration version order.
                                       If False, don't enforce and don't update.
        :type  update_current_version: bool
        """
        if update_current_version and migration.version != self.current_version + 1:
            msg = _(
                'Cannot apply migration %(name)s, because the next migration version is '
                '%(version)s.')
            msg = msg % {
                'name': migration.name,
                'version': self.current_version + 1
            }
            raise Exception(msg)
        migration.migrate()
        if update_current_version:
            self._migration_tracker.version = migration.version
            self._migration_tracker.save()

    @property
    def available_versions(self):
        """
        Return a list of the migration versions that are available in this migration package.

        :rtype: list
        """
        migrations = self.migrations
        versions = [migration.version for migration in migrations]
        return versions

    @property
    def current_version(self):
        """
        An integer that represents the migration version that the database is currently at.
        None means that the migration package has never been run before.

        :rtype: int
        """
        return self._migration_tracker.version

    @property
    def migrations(self):
        """
        Finds all available migration modules for the MigrationPackage,
        and then sorts by the version. Return a list of MigrationModules.

        :rtype: list
        """
        # Generate a list of the names of the modules found inside this package
        module_names = [
            name for module_loader, name, ispkg in iter_modules(
                [os.path.dirname(self._package.__file__)])
        ]
        migration_modules = []
        for module_name in module_names:
            try:
                module_name = '%s.%s' % (self.name, module_name)
                migration_modules.append(MigrationModule(module_name))
            except MigrationModule.MissingMigrate:
                msg = _(
                    "The module %(m)s doesn't have a migrate function. It will be ignored."
                )
                msg = msg % {'m': module_name}
                _logger.debug(msg)
            except MigrationModule.MissingVersion:
                msg = _(
                    "The module %(m)s doesn't conform to the migration package naming "
                    "conventions. It will be ignored.")
                msg = msg % {'m': module_name}
                _logger.debug(msg)
        migration_modules.sort()
        # We should have migrations starting at version 1, which each module version being exactly
        # one larger than the migration preceeding it.
        last_version = 0
        for module in migration_modules:
            if module.version == 0:
                error_message = _(
                    '0 is a reserved migration version number, but the '
                    'module %(n)s has been assigned that version.')
                error_message = error_message % {'n': module.name}
                raise self.__class__.DuplicateVersions(error_message)
            if module.version == last_version:
                error_message = _(
                    'There are two migration modules that share version %(v)s in '
                    '%(n)s.')
                error_message = error_message % {
                    'v': module.version,
                    'n': self.name
                }
                raise self.__class__.DuplicateVersions(error_message)
            if module.version != last_version + 1:
                msg = _('Migration version %(v)s is missing in %(n)s.')
                msg = msg % ({'v': last_version + 1, 'n': self.name})
                raise self.__class__.MissingVersion(msg)
            last_version = module.version
        return migration_modules

    @property
    def name(self):
        """
        Returns the name of the Python package that this MigrationPackage represents.

        :rtype: str
        """
        return self._package.__name__

    @property
    def unapplied_migrations(self):
        """
        Return a list of MigrationModules in this package that have not been applied yet.

        :rtype: list
        """
        return [
            migration for migration in self.migrations
            if migration.version > self.current_version
        ]

    def __cmp__(self, other_package):
        """
        This method returns a negative value if self.name < other_package.name, 0 if they are
        equal, and a positive value if self.name > other_package.name. There is an exception to this
        sorting rule, in that if self._package is pulp.server.db.migrations, this method will always
        return -1, and if other_package is pulp.server.db.migrations, it will always return 1.

        :rtype: int
        """
        if self._package is pulp.server.db.migrations:
            return -1
        if other_package._package is pulp.server.db.migrations:
            return 1
        return cmp(self.name, other_package.name)

    def __str__(self):
        return self.name

    def __repr__(self):
        return str(self)
Exemplo n.º 25
0
Arquivo: models.py Projeto: kaos/pulp
class MigrationPackage(object):
    """
    A wrapper around the migration packages found in pulp.server.db.migrations. Has methods to
    retrieve information about the migrations that are found there, and to apply the migrations.
    """
    class DuplicateVersions(Exception):
        """
        This is raised when a single migration package has two MigrationModules in it that have the
        same version.
        """
        pass

    class MissingVersion(Exception):
        """
        This is raised when a migration package has a gap in the MigrationModule versions.
        """
        pass

    def __init__(self, python_package):
        """
        Initialize the MigrationPackage to represent the Python migration package passed in.

        :param python_package: The Python package this object should represent
        :type  python_package: package
        """
        self._package = python_package
        # This is an object representation of the DB object that keeps track of the migration
        # version that has been applied

        try:
            self._migration_tracker = MigrationTracker.objects().get(name=self.name)
        except DoesNotExist:
            self._migration_tracker = MigrationTracker(name=self.name)
            self._migration_tracker.save()

        # Calculate the latest available version
        available_versions = self.available_versions
        if available_versions:
            self.latest_available_version = available_versions[-1]
        else:
            self.latest_available_version = 0

    def apply_migration(self, migration, update_current_version=True):
        """
        Apply the migration that is passed in, and update the DB to note the new version that this
        migration represents.

        :param migration:              The migration to apply
        :type  migration:              pulp.server.db.migrate.utils.MigrationModule
        :param update_current_version: If True, update the package's current version after
                                       successful application and enforce migration version order.
                                       If False, don't enforce and don't update.
        :type  update_current_version: bool
        """
        if update_current_version and migration.version != self.current_version + 1:
            msg = _('Cannot apply migration %(name)s, because the next migration version is '
                    '%(version)s.')
            msg = msg % {'name': migration.name, 'version': self.current_version + 1}
            raise Exception(msg)
        migration.migrate()
        if update_current_version:
            self._migration_tracker.version = migration.version
            self._migration_tracker.save()

    @property
    def available_versions(self):
        """
        Return a list of the migration versions that are available in this migration package.

        :rtype: list
        """
        migrations = self.migrations
        versions = [migration.version for migration in migrations]
        return versions

    @property
    def current_version(self):
        """
        An integer that represents the migration version that the database is currently at.
        None means that the migration package has never been run before.

        :rtype: int
        """
        return self._migration_tracker.version

    @property
    def migrations(self):
        """
        Finds all available migration modules for the MigrationPackage,
        and then sorts by the version. Return a list of MigrationModules.

        :rtype: list
        """
        # Generate a list of the names of the modules found inside this package
        module_names = [name for module_loader, name, ispkg in
                        iter_modules([os.path.dirname(self._package.__file__)])]
        migration_modules = []
        for module_name in module_names:
            try:
                module_name = '%s.%s' % (self.name, module_name)
                migration_modules.append(MigrationModule(module_name))
            except MigrationModule.MissingMigrate:
                msg = _("The module %(m)s doesn't have a migrate function. It will be ignored.")
                msg = msg % {'m': module_name}
                _logger.debug(msg)
            except MigrationModule.MissingVersion:
                msg = _("The module %(m)s doesn't conform to the migration package naming "
                        "conventions. It will be ignored.")
                msg = msg % {'m': module_name}
                _logger.debug(msg)
        migration_modules.sort()
        # We should have migrations starting at version 1, which each module version being exactly
        # one larger than the migration preceeding it.
        last_version = 0
        for module in migration_modules:
            if module.version == 0:
                error_message = _('0 is a reserved migration version number, but the '
                                  'module %(n)s has been assigned that version.')
                error_message = error_message % {'n': module.name}
                raise self.__class__.DuplicateVersions(error_message)
            if module.version == last_version:
                error_message = _('There are two migration modules that share version %(v)s in '
                                  '%(n)s.')
                error_message = error_message % {'v': module.version, 'n': self.name}
                raise self.__class__.DuplicateVersions(error_message)
            if module.version != last_version + 1:
                msg = _('Migration version %(v)s is missing in %(n)s.')
                msg = msg % ({'v': last_version + 1, 'n': self.name})
                raise self.__class__.MissingVersion(msg)
            last_version = module.version
        return migration_modules

    @property
    def name(self):
        """
        Returns the name of the Python package that this MigrationPackage represents.

        :rtype: str
        """
        return self._package.__name__

    @property
    def unapplied_migrations(self):
        """
        Return a list of MigrationModules in this package that have not been applied yet.

        :rtype: list
        """
        return [migration for migration in self.migrations
                if migration.version > self.current_version]

    def __cmp__(self, other_package):
        """
        This method returns a negative value if self.name < other_package.name, 0 if they are
        equal, and a positive value if self.name > other_package.name. There is an exception to this
        sorting rule, in that if self._package is pulp.server.db.migrations, this method will always
        return -1, and if other_package is pulp.server.db.migrations, it will always return 1.

        :rtype: int
        """
        if self._package is pulp.server.db.migrations:
            return -1
        if other_package._package is pulp.server.db.migrations:
            return 1
        return cmp(self.name, other_package.name)

    def __str__(self):
        return self.name

    def __repr__(self):
        return str(self)
Exemplo n.º 26
0
 def test_presense_of_ns(self):
     mt = MigrationTracker('meaning_of_life')
     self.assertEquals(mt._ns, 'migration_trackers')
Exemplo n.º 27
0
 def test_name_version_default(self):
     mt = MigrationTracker('meaning_of_life')
     self.assertEquals(mt.name, 'meaning_of_life')
     self.assertEquals(mt.version, 0)
Exemplo n.º 28
0
 def test___init__(self):
     mt = MigrationTracker('meaning_of_life', 42)
     self.assertEquals(mt.name, 'meaning_of_life')
     self.assertEquals(mt.version, 42)
     self.assertEquals(mt._collection, MigrationTracker.get_collection())
Exemplo n.º 29
0
 def __init__(self):
     self._collection = MigrationTracker.get_collection()
Exemplo n.º 30
0
 def clean(self):
     super(MigrationTest, self).clean()
     # Make sure each test doesn't have any lingering MigrationTrackers
     MigrationTracker.get_collection().remove({})
Exemplo n.º 31
0
 def __init__(self):
     self._collection = MigrationTracker.get_collection()
Exemplo n.º 32
0
 def test___init__(self):
     self.assertEquals(self.mtm._collection,
                       MigrationTracker.get_collection())
Exemplo n.º 33
0
 def test___init__(self):
     self.assertEquals(self.mtm._collection, MigrationTracker.get_collection())
Exemplo n.º 34
0
 def test___init__(self):
     mt = MigrationTracker('meaning_of_life', 42)
     self.assertEquals(mt.name, 'meaning_of_life')
     self.assertEquals(mt.version, 42)
     self.assertEquals(mt._collection, MigrationTracker.get_collection())
Exemplo n.º 35
0
 def clean(self):
     super(MigrationTest, self).clean()
     # Make sure each test doesn't have any lingering MigrationTrackers
     MigrationTracker.get_collection().remove({})
Exemplo n.º 36
0
 def clean(self):
     super(MigrationTest, self).clean()
     # Make sure each test doesn't have any lingering MigrationTrackers
     MigrationTracker.objects().delete()