예제 #1
0
    def test_has_table(self):
        """Testing DatabaseState.has_table"""
        database_state = DatabaseState(db_name='default', scan=False)
        self.assertFalse(database_state.has_table('my_test_table'))

        database_state.add_table('my_test_table')
        self.assertTrue(database_state.has_table('my_test_table'))
예제 #2
0
    def test_clone(self):
        """Testing DatabaseState.clone"""
        database_state = DatabaseState(db_name='default')
        cloned_state = database_state.clone()

        self.assertEqual(cloned_state.db_name, database_state.db_name)
        self.assertEqual(cloned_state._tables, database_state._tables)
예제 #3
0
    def __init__(self, db_name, database_state=None):
        """Initialize the instance.

        Args:
            db_name (unicode):
                The name of the database.

            database_state (django_evolution.db.state.DatabaseState):
                The database state to track information through.
        """
        if database_state is None:
            from django_evolution.db.state import DatabaseState
            database_state = DatabaseState(db_name, scan=False)

        try:
            from django.db import connections
            engine = settings.DATABASES[db_name]['ENGINE'].split('.')[-1]
            connection = connections[db_name]
            module_name = ['django_evolution.db', engine]
            module = __import__('.'.join(module_name), {}, {}, [''])
            self.evolver = module.EvolutionOperations(database_state,
                                                      connection)
        except ImportError:
            if hasattr(settings, 'DATABASE_ENGINE'):
                module_name = ['django_evolution.db', settings.DATABASE_ENGINE]
                module = __import__('.'.join(module_name), {}, {}, [''])
                self.evolver = module.EvolutionOperations(database_state)
            else:
                raise
예제 #4
0
    def test_has_model(self):
        """Testing DatabaseState.has_model"""
        database_state = DatabaseState(db_name='default', scan=False)
        self.assertFalse(database_state.has_model(Evolution))

        database_state.rescan_tables()
        self.assertTrue(database_state.has_model(Evolution))
    def test_add_table(self):
        """Testing DatabaseState.add_table"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')

        self.assertEqual(database_state._tables['my_test_table'], {
            'indexes': {},
        })
예제 #6
0
    def test_get_index_with_invalid_name(self):
        """Testing DatabaseState.get_index with invalid name"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')

        self.assertIsNone(
            database_state.get_index(table_name='my_test_table',
                                     index_name='my_index'), )
예제 #7
0
    def test_find_index_with_not_found(self):
        """Testing DatabaseState.find_index with index no found"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')

        index = database_state.find_index(table_name='my_test_table',
                                          columns=['col1', 'col2'],
                                          unique=True)
        self.assertIsNone(index)
예제 #8
0
    def setUp(self):
        super(BaseRelationFieldsTestCase, self).setUp()

        register_models(database_state=DatabaseState(DEFAULT_DB_ALIAS),
                        models=[
                            ('CompatModelsTestModel', CompatModelsTestModel),
                            ('CompatModelsAnchor', CompatModelsAnchor),
                        ],
                        new_app_label='tests')
예제 #9
0
    def test_has_model_with_auto_created(self):
        """Testing DatabaseState.has_model with auto-created model"""
        model = get_remote_field(User._meta.get_field('groups')).through
        self.assertTrue(model._meta.auto_created)

        database_state = DatabaseState(db_name='default', scan=False)
        self.assertFalse(database_state.has_model(model))

        database_state.rescan_tables()
        self.assertTrue(database_state.has_model(model))
예제 #10
0
    def test_remove_index_with_untracked_table(self):
        """Testing DatabaseState.remove_index with untracked table"""
        database_state = DatabaseState(db_name='default', scan=False)

        expected_message = (
            'Unable to remove index "my_index" from table "my_test_table". '
            'The table is not being tracked in the database state.')

        with self.assertRaisesMessage(DatabaseStateError, expected_message):
            database_state.remove_index(table_name='my_test_table',
                                        index_name='my_index')
    def clear_indexes(self):
        """Testing DatabaseState.clear_indexes"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        self.assertEqual(database_state._tables['my_test_table']['indexes'],
                         {})
예제 #12
0
    def test_find_index(self):
        """Testing DatabaseState.find_index"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'])

        index = database_state.find_index(table_name='my_test_table',
                                          columns=['col1', 'col2'])
        self.assertEqual(index,
                         IndexState(name='my_index', columns=['col1', 'col2']))
예제 #13
0
    def set_base_model(self,
                       base_model,
                       name=None,
                       extra_models=[],
                       pre_extra_models=[],
                       db_name=None):
        """Set the base model(s) that will be mutated in a test.

        These models will be registered in Django's model registry and
        queued up to be written to the database. Starting signatures based
        on these models will be provided, which the test is expected to
        mutate.

        Args:
            base_model (type):
                The base :py:class:`~django.db.models.Model` to register and
                write to the database that the test will then mutate.

            name (unicode, optional):
                The name to register for the model. This defaults to
                :py:attr:`default_model_name`.

            extra_models (list of type, optional):
                The list of extra models to register and write to the
                database after writing ``base_model``. These may form
                relations to ``base_model``.

            pre_extra_models (list of type, optional):
                The list of extra models to write to the database before
                writing ``base_model``. ``base_model`` may form relations to
                these models.

            db_name (unicode, optional):
                The name of the database to write the models to. This
                defaults to :py:attr:`default_database_name`.
        """
        name = name or self.default_model_name
        db_name = db_name or self.default_database_name

        if self.base_model:
            unregister_app('tests')

        self.base_model = base_model
        self.pre_extra_models = pre_extra_models
        self.extra_models = extra_models
        self.database_state = DatabaseState(db_name)

        self.start = self.register_model(model=base_model,
                                         name=name,
                                         register_indexes=True,
                                         db_name=db_name)
        self.start_sig = self.create_test_proj_sig(model=base_model, name=name)
    def test_get_index(self):
        """Testing DatabaseState.get_index"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        self.assertEqual(
            database_state.get_index(table_name='my_test_table',
                                     index_name='my_index'),
            IndexState(name='my_index', columns=['col1', 'col2'], unique=True))
예제 #15
0
    def test_remove_index_with_invalid_index_name(self):
        """Testing DatabaseState.remove_index with invalid index name"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')

        expected_message = (
            'Unable to remove index "my_index" from table "my_test_table". '
            'The index could not be found.')

        with self.assertRaisesMessage(DatabaseStateError, expected_message):
            database_state.remove_index(table_name='my_test_table',
                                        index_name='my_index',
                                        unique=True)
예제 #16
0
    def test_add_index_with_untracked_table(self):
        """Testing DatabaseState.add_index with untracked table"""
        database_state = DatabaseState(db_name='default', scan=False)

        expected_message = (
            'Unable to add index "my_index" to table "my_test_table". The '
            'table is not being tracked in the database state.')

        with self.assertRaisesMessage(DatabaseStateError, expected_message):
            database_state.add_index(table_name='my_test_table',
                                     index_name='my_index',
                                     columns=['col1', 'col2'],
                                     unique=True)
예제 #17
0
    def test_find_index_with_unique_true(self):
        """Testing DatabaseState.find_index with unique=True"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        index = database_state.find_index(table_name='my_test_table',
                                          columns=['col1', 'col2'],
                                          unique=True)
        self.assertEqual(
            index,
            IndexState(name='my_index', columns=['col1', 'col2'], unique=True))
예제 #18
0
    def test_remove_index(self):
        """Testing DatabaseState.remove_index"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'])

        database_state.remove_index(table_name='my_test_table',
                                    index_name='my_index')

        self.assertEqual(database_state._tables['my_test_table'], {
            'indexes': {},
            'unique_indexes': {},
        })
예제 #19
0
    def test_rescan_indexes(self):
        """Testing DatabaseState.rescan_indexes"""
        database_state = DatabaseState(db_name='default')

        # Check that a few known tables are in the list, to make sure
        # the scan worked.
        for table_name in ('django_content_type', 'django_evolution',
                           'django_project_version'):
            self.assertTrue(database_state.has_table(table_name))

        # Check the Evolution model.
        indexes = [
            (index_state.columns, index_state.unique)
            for index_state in database_state.iter_indexes('django_evolution')
        ]

        self.assertIn((['version_id'], False), indexes)
    def test_remove_index_with_invalid_index_type(self):
        """Testing DatabaseState.remove_index with invalid index type"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        expected_message = (
            'Unable to remove index "my_index" from table "my_test_table". '
            'The specified index type (unique=False) does not match the '
            'existing type (unique=True).')

        with self.assertRaisesMessage(DatabaseStateError, expected_message):
            database_state.remove_index(table_name='my_test_table',
                                        index_name='my_index',
                                        unique=False)
예제 #21
0
    def test_add_index_with_unique_true(self):
        """Testing DatabaseState.add_index with unique=True"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        self.assertEqual(
            database_state._tables['my_test_table'], {
                'indexes': {},
                'unique_indexes': {
                    'my_index':
                    IndexState(name='my_index',
                               columns=['col1', 'col2'],
                               unique=True),
                },
            })
    def test_iter_indexes(self):
        """Testing DatabaseState.iter_indexes"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index1',
                                 columns=['col1', 'col2'],
                                 unique=True)
        database_state.add_index(table_name='my_test_table',
                                 index_name='my_index2',
                                 columns=['col3'])

        indexes = list(database_state.iter_indexes('my_test_table'))

        self.assertEqual(indexes, [
            IndexState(name='my_index1', columns=['col1', 'col2'],
                       unique=True),
            IndexState(name='my_index2', columns=['col3'], unique=False),
        ])
예제 #23
0
    def test_apply_migrations(self):
        """Testing apply_migrations"""
        database_state = DatabaseState(db_name=DEFAULT_DB_ALIAS)
        register_models(database_state=database_state,
                        models=[('MigrationTestModel', MigrationTestModel)])

        app_migrations = [
            InitialMigration('0001_initial', 'tests'),
            AddFieldMigration('0002_add_field', 'tests'),
        ]

        targets = [
            ('tests', '0001_initial'),
            ('tests', '0002_add_field'),
        ]

        custom_migrations = MigrationList()
        custom_migrations.add_migration(app_migrations[0])
        custom_migrations.add_migration(app_migrations[1])

        connection = connections[DEFAULT_DB_ALIAS]
        executor = MigrationExecutor(connection,
                                     custom_migrations=custom_migrations)

        migrate_state = apply_migrations(
            executor=executor,
            targets=targets,
            plan=[
                (app_migrations[0], False),
                (app_migrations[1], False),
            ],
            pre_migrate_state=create_pre_migrate_state(executor))
        finalize_migrations(migrate_state)

        # Make sure this is in the database now.
        MigrationTestModel.objects.create(field1=123,
                                          field2='abc',
                                          field3=True)
예제 #24
0
    def test_add_index_with_existing_index(self):
        """Testing DatabaseState.add_index with existing index"""
        database_state = DatabaseState(db_name='default', scan=False)
        database_state.add_table('my_test_table')
        database_state.add_index(table_name='my_test_table',
                                 index_name='existing_index',
                                 columns=['col1', 'col2'],
                                 unique=True)

        expected_message = (
            'Unable to add index "existing_index" to table "my_test_table". '
            'This index already exists.')

        with self.assertRaisesMessage(DatabaseStateError, expected_message):
            database_state.add_index(table_name='my_test_table',
                                     index_name='existing_index',
                                     columns=['col1', 'col2'],
                                     unique=True)

        # It's fine if it has a new name.
        database_state.add_index(table_name='my_test_table',
                                 index_name='new_index',
                                 columns=['col1', 'col2'],
                                 unique=True)
예제 #25
0
    def __init__(self,
                 hinted=False,
                 verbosity=0,
                 interactive=False,
                 database_name=DEFAULT_DB_ALIAS):
        """Initialize the evolver.

        Args:
            hinted (bool, optional):
                Whether to operate against hinted evolutions. This may
                result in changes to the database without there being any
                accompanying evolution files backing those changes.

            verbosity (int, optional):
                The verbosity level for any output. This is passed along to
                signal emissions.

            interactive (bool, optional):
                Whether the evolution operations are being performed in a
                way that allows interactivity on the command line. This is
                passed along to signal emissions.

            database_name (unicode, optional):
                The name of the database to evolve.

        Raises:
            django_evolution.errors.EvolutionBaselineMissingError:
                An initial baseline for the project was not yet installed.
                This is due to ``syncdb``/``migrate`` not having been run.
        """
        self.database_name = database_name
        self.hinted = hinted
        self.verbosity = verbosity
        self.interactive = interactive

        self.evolved = False
        self.initial_diff = None
        self.project_sig = None
        self.version = None
        self.installed_new_database = False

        self.connection = connections[database_name]

        if hasattr(self.connection, 'prepare_database'):
            # Django >= 1.8
            self.connection.prepare_database()

        self.database_state = DatabaseState(self.database_name)
        self.target_project_sig = \
            ProjectSignature.from_database(database_name)

        self._tasks_by_class = OrderedDict()
        self._tasks_by_id = OrderedDict()
        self._tasks_prepared = False

        latest_version = None

        if self.database_state.has_model(Version):
            try:
                latest_version = \
                    Version.objects.current_version(using=database_name)
            except Version.DoesNotExist:
                # We'll populate this next.
                pass

        if latest_version is None:
            # Either the models aren't yet synced to the database, or we
            # don't have a saved project signature, so let's set these up.
            self.installed_new_database = True

            self.project_sig = ProjectSignature()
            app = get_app('django_evolution')

            task = EvolveAppTask(evolver=self, app=app)
            task.prepare(hinted=False)

            with self.sql_executor() as sql_executor:
                task.execute(sql_executor=sql_executor, create_models_now=True)

            self.database_state.rescan_tables()

            app_sig = AppSignature.from_app(app=app, database=database_name)
            self.project_sig.add_app_sig(app_sig)

            # Let's make completely sure that we've only found the models
            # we expect. This is mostly for the benefit of unit tests.
            model_names = set(model_sig.model_name
                              for model_sig in app_sig.model_sigs)
            expected_model_names = set(['Evolution', 'Version'])

            assert model_names == expected_model_names, (
                'Unexpected models found for django_evolution app: %s' %
                ', '.join(model_names - expected_model_names))

            self._save_project_sig(new_evolutions=task.new_evolutions)
            latest_version = self.version

        self.project_sig = latest_version.signature
        self.initial_diff = Diff(self.project_sig, self.target_project_sig)