示例#1
0
    def test_signature_save(self):
        """Testing Version.signature field serializes JSON-encoded v2
        signatures
        """
        project_sig = ProjectSignature()
        project_sig.add_app_sig(AppSignature('app1'))
        project_sig.add_app_sig(AppSignature('app2'))

        version = Version.objects.create(signature=project_sig)

        raw_signature = (Version.objects.filter(
            pk=version.pk).values_list('signature'))[0][0]

        self.assertTrue(raw_signature.startswith('json!'))
        sig_data = json.loads(raw_signature[len('json!'):])

        self.assertEqual(
            sig_data, {
                '__version__': 2,
                'apps': {
                    'app1': {
                        'legacy_app_label': 'app1',
                        'models': {},
                    },
                    'app2': {
                        'legacy_app_label': 'app2',
                        'models': {},
                    },
                },
            })
示例#2
0
    def test_current_version_with_dup_timestamps(self):
        """Testing Version.current_version() with two entries with same timestamps"""
        # Remove anything that may already exist.
        Version.objects.all().delete()

        timestamp = datetime(year=2015,
                             month=12,
                             day=10,
                             hour=12,
                             minute=13,
                             second=14)

        Version.objects.create(signature=ProjectSignature(), when=timestamp)
        version = Version.objects.create(signature=ProjectSignature(),
                                         when=timestamp)

        latest_version = Version.objects.current_version()
        self.assertEqual(latest_version, version)
示例#3
0
    def test_with_bad_app(self):
        """Testing AddField with application not in signature"""
        mutation = AddField('TestModel', 'char_field1', models.CharField)

        message = (
            'Cannot add the field "char_field1" to model "badapp.TestModel". '
            'The application could not be found in the signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='badapp',
                                    project_sig=ProjectSignature(),
                                    database_state=None)
    def test_add_fields_bad_update_func_signature(self):
        """Testing SQLMutation and bad update_func signature"""
        mutation = SQLMutation('test', '', update_func=lambda a, b, c: None)

        message = ('SQLMutations must provide an update_func(simulation) or '
                   'legacy update_func(app_label, project_sig) parameter in '
                   'order to be simulated.')

        with self.assertRaisesMessage(CannotSimulate, message):
            mutation.run_simulation(app_label='tests',
                                    project_sig=ProjectSignature(),
                                    database_state=None)
    def test_with_bad_app(self):
        """Testing DeleteApplication with application not in signature"""
        mutation = DeleteApplication()

        message = (
            'Cannot delete the application "badapp". The application could '
            'not be found in the signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='badapp',
                                    project_sig=ProjectSignature(),
                                    database_state=None)
    def test_with_bad_app(self):
        """Testing RenameField with application not in signature"""
        mutation = RenameField('TestModel', 'char_field1', 'char_field2')

        message = (
            'Cannot rename the field "char_field1" on model '
            '"badapp.TestModel". The application could not be found in the '
            'signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='badapp',
                                    project_sig=ProjectSignature(),
                                    database_state=None)
    def test_with_bad_app(self):
        """Testing RenameModel with application not in signature"""
        mutation = RenameModel('TestModel', 'DestModel',
                               db_table='tests_destmodel')

        message = (
            'Cannot rename the model "badapp.TestModel". The application '
            'could not be found in the signature.'
        )

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='badapp',
                                    project_sig=ProjectSignature(),
                                    database_state=None)
示例#8
0
    def test_with_bad_model(self):
        """Testing ChangeField with model not in signature"""
        mutation = ChangeField('TestModel', 'char_field1')

        project_sig = ProjectSignature()
        project_sig.add_app_sig(AppSignature(app_id='tests'))

        message = ('Cannot change the field "char_field1" on model '
                   '"tests.TestModel". The model could not be found in the '
                   'signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='tests',
                                    project_sig=project_sig,
                                    database_state=None)
    def test_with_bad_model(self):
        """Testing DeleteModel with model not in signature"""
        mutation = DeleteModel('TestModel')

        project_sig = ProjectSignature()
        project_sig.add_app_sig(AppSignature(app_id='tests'))

        message = (
            'Cannot delete the model "tests.TestModel". The model could '
            'not be found in the signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='tests',
                                    project_sig=project_sig,
                                    database_state=None)
    def test_with_bad_field(self):
        """Testing RenameField with field not in signature"""
        mutation = RenameField('TestModel', 'char_field1', 'char_field2')

        model_sig = ModelSignature(model_name='TestModel',
                                   table_name='tests_testmodel')

        app_sig = AppSignature(app_id='tests')
        app_sig.add_model_sig(model_sig)

        project_sig = ProjectSignature()
        project_sig.add_app_sig(app_sig)

        message = ('Cannot rename the field "char_field1" on model '
                   '"tests.TestModel". The field could not be found in the '
                   'signature.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='tests',
                                    project_sig=project_sig,
                                    database_state=None)
示例#11
0
def create_test_project_sig(models, app_label='tests', version=1):
    """Return a dummy project signature for the given models.

    Args:
        models (list of django.db.models.Model):
            The list of models for the project signature.

        app_label (unicode, optional):
            The application label that will contain the models.

        version (int, optional):
            The signature version to use for the project signature.

    Returns:
        dict:
        The new project signature.
    """
    app_sig = AppSignature(app_id=app_label)

    project_sig = ProjectSignature()
    project_sig.add_app_sig(app_sig)

    for full_name, model in models:
        parts = full_name.split('.')

        if len(parts) == 1:
            app_sig.add_model_sig(ModelSignature.from_model(model))
        else:
            model_app_label, model_name = parts
            model_app_sig = project_sig.get_app_sig(model_app_label)

            if model_app_sig is None:
                model_app_sig = AppSignature(app_id=model_app_label)
                project_sig.add_app_sig(model_app_sig)

            model_app_sig.add_model_sig(ModelSignature.from_model(model))

    return project_sig
示例#12
0
    def to_python(self, value):
        """Return a ProjectSignature value from the field contents.

        Args:
            value (object):
                The current value assigned to the field. This might be
                serialized string content or a
                :py:class:`~django_evolution.signatures.ProjectSignature`
                instance.

        Returns:
            django_evolution.signatures.ProjectSignature:
            The project signature stored in the field.

        Raises:
            django.core.exceptions.ValidationError:
                The field contents are of an unexpected type.
        """
        if not value:
            return ProjectSignature()
        elif isinstance(value, six.string_types):
            if value.startswith('json!'):
                loaded_value = json.loads(value[len('json!'):],
                                          object_pairs_hook=OrderedDict)
            else:
                loaded_value = pickle_loads(value)

            return ProjectSignature.deserialize(loaded_value)
        elif isinstance(value, ProjectSignature):
            return value
        else:
            raise ValidationError('Unsupported serialized signature type %s' %
                                  type(value),
                                  code='invalid',
                                  params={
                                      'value': value,
                                  })
示例#13
0
    def test_with_bad_field(self):
        """Testing AddField with field already in signature"""
        mutation = AddField('TestModel', 'char_field1', models.CharField)

        model_sig = ModelSignature(model_name='TestModel',
                                   table_name='tests_testmodel')
        model_sig.add_field_sig(
            FieldSignature(field_name='char_field1',
                           field_type=models.CharField))

        app_sig = AppSignature(app_id='tests')
        app_sig.add_model_sig(model_sig)

        project_sig = ProjectSignature()
        project_sig.add_app_sig(app_sig)

        message = (
            'Cannot add the field "char_field1" to model "tests.TestModel". '
            'A field with this name already exists.')

        with self.assertRaisesMessage(SimulationFailure, message):
            mutation.run_simulation(app_label='tests',
                                    project_sig=project_sig,
                                    database_state=None)
示例#14
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)