def test_migrate_command_with_django_table(django_db_setup_no_init, settings): """ This test simulate the case when a project was created to be used with django migrations table Either because it didn't use septentrion-based django-north, or a pre septentrion-base django-north version. """ connection = connections['no_init'] # We begin with an empty database assert migrations.get_current_version(connection) is None # We simulate the setup of the database in the past, # with a django_migrations table. updated_settings = septentrion_settings(connection) updated_settings.update({ "target_version": "1.0", "table": "django_migrations", }) septentrion.migrate(**updated_settings) # DB is initialized, this doesn't return None assert migrations.get_current_version(connections['no_init']) is not None # and migrate to newer version call_command('migrate', '--database', 'no_init') # check if max applied version is target version assert settings.NORTH_TARGET_VERSION != "1.0" assert (migrations.get_applied_versions( connections['no_init'])[-1] == settings.NORTH_TARGET_VERSION)
def test_get_current_version(settings, mocker): mock_table = mocker.patch( 'django_north.management.migrations' '.get_current_version_from_table', return_value='from_table') mock_comment = mocker.patch( 'django_north.management.migrations' '.get_current_version_from_comment', return_value='from_comment') # no setting if hasattr(settings, 'NORTH_CURRENT_VERSION_DETECTOR'): del settings.NORTH_CURRENT_VERSION_DETECTOR result = migrations.get_current_version() assert mock_table.called is True assert mock_comment.called is False assert result == 'from_table' # wrong setting mock_table.reset_mock() mock_comment.reset_mock() settings.NORTH_CURRENT_VERSION_DETECTOR = ( 'django_north.management.migrations' '.get_current_version_from_foo') with pytest.raises(AttributeError): migrations.get_current_version() assert mock_table.called is False assert mock_comment.called is False # good setting - table mock_table.reset_mock() mock_comment.reset_mock() settings.NORTH_CURRENT_VERSION_DETECTOR = ( 'django_north.management.migrations' '.get_current_version_from_table') result = migrations.get_current_version() assert mock_table.called is True assert mock_comment.called is False assert result == 'from_table' # good setting - comment mock_table.reset_mock() mock_comment.reset_mock() settings.NORTH_CURRENT_VERSION_DETECTOR = ( 'django_north.management.migrations' '.get_current_version_from_comment') result = migrations.get_current_version() assert mock_table.called is False assert mock_comment.called is True assert result == 'from_comment'
def test_migrate_command_for_real(django_db_setup_no_init, settings): # from scratch, septentrion will create a migrations table itself # if DB is not initialized, this return None assert migrations.get_current_version(connections['no_init']) is None call_command('migrate', '--database', 'no_init') assert migrations.get_current_version(connections['no_init']) is not None # check if max applied version is target version assert (migrations.get_applied_versions( connections['no_init'])[-1] == settings.NORTH_TARGET_VERSION)
def flush(self, **options): database = options.get('database') connection = connections[database] verbosity = options.get('verbosity') interactive = options.get('interactive') # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) allow_cascade = options.get('allow_cascade', False) inhibit_post_migrate = options.get('inhibit_post_migrate', False) self.style = no_style() # Import the 'management' module within each installed app, to register # dispatcher events. for app_config in apps.get_app_configs(): try: import_module('.management', app_config.name) except ImportError: pass # custom: only_django False # get current version before flush current_version = get_current_version(connection) sql_list = sql_flush(self.style, connection, only_django=False, reset_sequences=reset_sequences, allow_cascade=allow_cascade) if interactive: confirm = input("""You have requested a flush of the database. This will IRREVERSIBLY DESTROY all data currently in the %r database, and return each table to an empty state. Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['NAME']) else: confirm = 'yes' if confirm == 'yes': try: with transaction.atomic( using=database, savepoint=connection.features.can_rollback_ddl): with connection.cursor() as cursor: for sql in sql_list: cursor.execute(sql) except Exception as e: new_msg = ( "Database %s couldn't be flushed. Possible reasons:\n" " * The database isn't running or isn't configured " "correctly.\n" " * At least one of the expected database tables doesn't " "exist.\n" " * The SQL was invalid.\n" "Hint: Look at the output of 'django-admin sqlflush'. " "That's the SQL this command wasn't able to run.\n" "The full error: %s") % (connection.settings_dict['NAME'], e) raise CommandError(new_msg) from e if not inhibit_post_migrate: self.emit_post_migrate(verbosity, interactive, database, current_version) # Reinstall the initial_data fixture. if options.get('load_initial_data'): # Remove any option that is not handle by loaddata # We need to load loaddata command, get its parser to extract # valid options app_name = get_commands()['loaddata'] command = load_command_class(app_name, 'loaddata') parser = command.create_parser('loaddata', 'initial_data') valid_options = [ action.dest for action in parser._actions if action.option_strings ] app_options = { k: v for k, v in options.items() if k in valid_options } # Reinstall the initial_data fixture for apps without # migrations. from django.db.migrations.executor import MigrationExecutor executor = MigrationExecutor(connection) for app_label in executor.loader.unmigrated_apps: app_options['app_label'] = app_label try: call_command('loaddata', 'initial_data', **app_options) except CommandError: # fails with django 1.10 if initial_data does not exist pass else: self.stdout.write("Flush cancelled.\n")