Fixed #29040 -- Made test database creation messages use a consistent output stream.

This commit is contained in:
Claude Paroz 2018-07-20 00:05:33 +02:00 committed by Tim Graham
parent 1e9b02a4c2
commit 65503ca097
5 changed files with 59 additions and 55 deletions

View File

@ -1,3 +1,4 @@
import os
import sys import sys
from io import StringIO from io import StringIO
@ -26,6 +27,9 @@ class BaseDatabaseCreation:
""" """
return self.connection._nodb_connection return self.connection._nodb_connection
def log(self, msg):
sys.stderr.write(msg + os.linesep)
def create_test_db(self, verbosity=1, autoclobber=False, serialize=True, keepdb=False): def create_test_db(self, verbosity=1, autoclobber=False, serialize=True, keepdb=False):
""" """
Create a test database, prompting the user for confirmation if the Create a test database, prompting the user for confirmation if the
@ -41,7 +45,7 @@ class BaseDatabaseCreation:
if keepdb: if keepdb:
action = "Using existing" action = "Using existing"
print("%s test database for alias %s..." % ( self.log('%s test database for alias %s...' % (
action, action,
self._get_database_display_str(verbosity, test_database_name), self._get_database_display_str(verbosity, test_database_name),
)) ))
@ -170,8 +174,7 @@ class BaseDatabaseCreation:
if keepdb: if keepdb:
return test_database_name return test_database_name
sys.stderr.write( self.log('Got an error creating the test database: %s' % e)
"Got an error creating the test database: %s\n" % e)
if not autoclobber: if not autoclobber:
confirm = input( confirm = input(
"Type 'yes' if you would like to try deleting the test " "Type 'yes' if you would like to try deleting the test "
@ -179,17 +182,16 @@ class BaseDatabaseCreation:
if autoclobber or confirm == 'yes': if autoclobber or confirm == 'yes':
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias %s..." % ( self.log('Destroying old test database for alias %s...' % (
self._get_database_display_str(verbosity, test_database_name), self._get_database_display_str(verbosity, test_database_name),
)) ))
cursor.execute('DROP DATABASE %(dbname)s' % test_db_params) cursor.execute('DROP DATABASE %(dbname)s' % test_db_params)
self._execute_create_test_db(cursor, test_db_params, keepdb) self._execute_create_test_db(cursor, test_db_params, keepdb)
except Exception as e: except Exception as e:
sys.stderr.write( self.log('Got an error recreating the test database: %s' % e)
"Got an error recreating the test database: %s\n" % e)
sys.exit(2) sys.exit(2)
else: else:
print("Tests cancelled.") self.log('Tests cancelled.')
sys.exit(1) sys.exit(1)
return test_database_name return test_database_name
@ -204,7 +206,7 @@ class BaseDatabaseCreation:
action = 'Cloning test database' action = 'Cloning test database'
if keepdb: if keepdb:
action = 'Using existing clone' action = 'Using existing clone'
print("%s for alias %s..." % ( self.log('%s for alias %s...' % (
action, action,
self._get_database_display_str(verbosity, source_database_name), self._get_database_display_str(verbosity, source_database_name),
)) ))
@ -246,7 +248,7 @@ class BaseDatabaseCreation:
action = 'Destroying' action = 'Destroying'
if keepdb: if keepdb:
action = 'Preserving' action = 'Preserving'
print("%s test database for alias %s..." % ( self.log('%s test database for alias %s...' % (
action, action,
self._get_database_display_str(verbosity, test_database_name), self._get_database_display_str(verbosity, test_database_name),
)) ))

View File

@ -33,7 +33,7 @@ class DatabaseCreation(BaseDatabaseCreation):
except Exception as e: except Exception as e:
if len(e.args) < 1 or e.args[0] != 1007: if len(e.args) < 1 or e.args[0] != 1007:
# All errors except "database exists" (1007) cancel tests. # All errors except "database exists" (1007) cancel tests.
sys.stderr.write('Got an error creating the test database: %s\n' % e) self.log('Got an error creating the test database: %s' % e)
sys.exit(2) sys.exit(2)
else: else:
raise e raise e
@ -51,13 +51,13 @@ class DatabaseCreation(BaseDatabaseCreation):
except Exception: except Exception:
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias %s..." % ( self.log('Destroying old test database for alias %s...' % (
self._get_database_display_str(verbosity, target_database_name), self._get_database_display_str(verbosity, target_database_name),
)) ))
cursor.execute('DROP DATABASE %(dbname)s' % test_db_params) cursor.execute('DROP DATABASE %(dbname)s' % test_db_params)
self._execute_create_test_db(cursor, test_db_params, keepdb) self._execute_create_test_db(cursor, test_db_params, keepdb)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e) self.log('Got an error recreating the test database: %s' % e)
sys.exit(2) sys.exit(2)
dump_cmd = DatabaseClient.settings_to_cmd_args(self.connection.settings_dict) dump_cmd = DatabaseClient.settings_to_cmd_args(self.connection.settings_dict)

View File

@ -36,7 +36,7 @@ class DatabaseCreation(BaseDatabaseCreation):
except Exception as e: except Exception as e:
if 'ORA-01543' not in str(e): if 'ORA-01543' not in str(e):
# All errors except "tablespace already exists" cancel tests # All errors except "tablespace already exists" cancel tests
sys.stderr.write("Got an error creating the test database: %s\n" % e) self.log('Got an error creating the test database: %s' % e)
sys.exit(2) sys.exit(2)
if not autoclobber: if not autoclobber:
confirm = input( confirm = input(
@ -44,7 +44,7 @@ class DatabaseCreation(BaseDatabaseCreation):
"Type 'yes' to delete it, or 'no' to cancel: " % parameters['user']) "Type 'yes' to delete it, or 'no' to cancel: " % parameters['user'])
if autoclobber or confirm == 'yes': if autoclobber or confirm == 'yes':
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias '%s'..." % self.connection.alias) self.log("Destroying old test database for alias '%s'..." % self.connection.alias)
try: try:
self._execute_test_db_destruction(cursor, parameters, verbosity) self._execute_test_db_destruction(cursor, parameters, verbosity)
except DatabaseError as e: except DatabaseError as e:
@ -53,29 +53,29 @@ class DatabaseCreation(BaseDatabaseCreation):
verbosity, autoclobber) verbosity, autoclobber)
else: else:
# Ran into a database error that isn't about leftover objects in the tablespace # Ran into a database error that isn't about leftover objects in the tablespace
sys.stderr.write("Got an error destroying the old test database: %s\n" % e) self.log('Got an error destroying the old test database: %s' % e)
sys.exit(2) sys.exit(2)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error destroying the old test database: %s\n" % e) self.log('Got an error destroying the old test database: %s' % e)
sys.exit(2) sys.exit(2)
try: try:
self._execute_test_db_creation(cursor, parameters, verbosity, keepdb) self._execute_test_db_creation(cursor, parameters, verbosity, keepdb)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e) self.log('Got an error recreating the test database: %s' % e)
sys.exit(2) sys.exit(2)
else: else:
print("Tests cancelled.") self.log('Tests cancelled.')
sys.exit(1) sys.exit(1)
if self._test_user_create(): if self._test_user_create():
if verbosity >= 1: if verbosity >= 1:
print("Creating test user...") self.log('Creating test user...')
try: try:
self._create_test_user(cursor, parameters, verbosity, keepdb) self._create_test_user(cursor, parameters, verbosity, keepdb)
except Exception as e: except Exception as e:
if 'ORA-01920' not in str(e): if 'ORA-01920' not in str(e):
# All errors except "user already exists" cancel tests # All errors except "user already exists" cancel tests
sys.stderr.write("Got an error creating the test user: %s\n" % e) self.log('Got an error creating the test user: %s' % e)
sys.exit(2) sys.exit(2)
if not autoclobber: if not autoclobber:
confirm = input( confirm = input(
@ -84,16 +84,16 @@ class DatabaseCreation(BaseDatabaseCreation):
if autoclobber or confirm == 'yes': if autoclobber or confirm == 'yes':
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test user...") self.log('Destroying old test user...')
self._destroy_test_user(cursor, parameters, verbosity) self._destroy_test_user(cursor, parameters, verbosity)
if verbosity >= 1: if verbosity >= 1:
print("Creating test user...") self.log('Creating test user...')
self._create_test_user(cursor, parameters, verbosity, keepdb) self._create_test_user(cursor, parameters, verbosity, keepdb)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error recreating the test user: %s\n" % e) self.log('Got an error recreating the test user: %s' % e)
sys.exit(2) sys.exit(2)
else: else:
print("Tests cancelled.") self.log('Tests cancelled.')
sys.exit(1) sys.exit(1)
self._maindb_connection.close() # done with main user -- test user and tablespaces created self._maindb_connection.close() # done with main user -- test user and tablespaces created
self._switch_to_test_user(parameters) self._switch_to_test_user(parameters)
@ -130,36 +130,38 @@ class DatabaseCreation(BaseDatabaseCreation):
def _handle_objects_preventing_db_destruction(self, cursor, parameters, verbosity, autoclobber): def _handle_objects_preventing_db_destruction(self, cursor, parameters, verbosity, autoclobber):
# There are objects in the test tablespace which prevent dropping it # There are objects in the test tablespace which prevent dropping it
# The easy fix is to drop the test user -- but are we allowed to do so? # The easy fix is to drop the test user -- but are we allowed to do so?
print("There are objects in the old test database which prevent its destruction.") self.log(
print("If they belong to the test user, deleting the user will allow the test " 'There are objects in the old test database which prevent its destruction.\n'
"database to be recreated.") 'If they belong to the test user, deleting the user will allow the test '
print("Otherwise, you will need to find and remove each of these objects, " 'database to be recreated.\n'
"or use a different tablespace.\n") 'Otherwise, you will need to find and remove each of these objects, '
'or use a different tablespace.\n'
)
if self._test_user_create(): if self._test_user_create():
if not autoclobber: if not autoclobber:
confirm = input("Type 'yes' to delete user %s: " % parameters['user']) confirm = input("Type 'yes' to delete user %s: " % parameters['user'])
if autoclobber or confirm == 'yes': if autoclobber or confirm == 'yes':
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test user...") self.log('Destroying old test user...')
self._destroy_test_user(cursor, parameters, verbosity) self._destroy_test_user(cursor, parameters, verbosity)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error destroying the test user: %s\n" % e) self.log('Got an error destroying the test user: %s' % e)
sys.exit(2) sys.exit(2)
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias '%s'..." % self.connection.alias) self.log("Destroying old test database for alias '%s'..." % self.connection.alias)
self._execute_test_db_destruction(cursor, parameters, verbosity) self._execute_test_db_destruction(cursor, parameters, verbosity)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error destroying the test database: %s\n" % e) self.log('Got an error destroying the test database: %s' % e)
sys.exit(2) sys.exit(2)
else: else:
print("Tests cancelled -- test database cannot be recreated.") self.log('Tests cancelled -- test database cannot be recreated.')
sys.exit(1) sys.exit(1)
else: else:
print("Django is configured to use pre-existing test user '%s'," self.log("Django is configured to use pre-existing test user '%s',"
" and will not attempt to delete it.\n" % parameters['user']) " and will not attempt to delete it." % parameters['user'])
print("Tests cancelled -- test database cannot be recreated.") self.log('Tests cancelled -- test database cannot be recreated.')
sys.exit(1) sys.exit(1)
def _destroy_test_db(self, test_database_name, verbosity=1): def _destroy_test_db(self, test_database_name, verbosity=1):
@ -174,17 +176,17 @@ class DatabaseCreation(BaseDatabaseCreation):
with self._maindb_connection.cursor() as cursor: with self._maindb_connection.cursor() as cursor:
if self._test_user_create(): if self._test_user_create():
if verbosity >= 1: if verbosity >= 1:
print('Destroying test user...') self.log('Destroying test user...')
self._destroy_test_user(cursor, parameters, verbosity) self._destroy_test_user(cursor, parameters, verbosity)
if self._test_database_create(): if self._test_database_create():
if verbosity >= 1: if verbosity >= 1:
print('Destroying test database tables...') self.log('Destroying test database tables...')
self._execute_test_db_destruction(cursor, parameters, verbosity) self._execute_test_db_destruction(cursor, parameters, verbosity)
self._maindb_connection.close() self._maindb_connection.close()
def _execute_test_db_creation(self, cursor, parameters, verbosity, keepdb=False): def _execute_test_db_creation(self, cursor, parameters, verbosity, keepdb=False):
if verbosity >= 2: if verbosity >= 2:
print("_create_test_db(): dbname = %s" % parameters['user']) self.log('_create_test_db(): dbname = %s' % parameters['user'])
statements = [ statements = [
"""CREATE TABLESPACE %(tblspace)s """CREATE TABLESPACE %(tblspace)s
DATAFILE '%(datafile)s' SIZE %(size)s DATAFILE '%(datafile)s' SIZE %(size)s
@ -201,7 +203,7 @@ class DatabaseCreation(BaseDatabaseCreation):
def _create_test_user(self, cursor, parameters, verbosity, keepdb=False): def _create_test_user(self, cursor, parameters, verbosity, keepdb=False):
if verbosity >= 2: if verbosity >= 2:
print("_create_test_user(): username = %s" % parameters['user']) self.log('_create_test_user(): username = %s' % parameters['user'])
statements = [ statements = [
"""CREATE USER %(user)s """CREATE USER %(user)s
IDENTIFIED BY "%(password)s" IDENTIFIED BY "%(password)s"
@ -227,11 +229,11 @@ class DatabaseCreation(BaseDatabaseCreation):
extra = "GRANT CREATE VIEW TO %(user)s" extra = "GRANT CREATE VIEW TO %(user)s"
success = self._execute_allow_fail_statements(cursor, [extra], parameters, verbosity, 'ORA-01031') success = self._execute_allow_fail_statements(cursor, [extra], parameters, verbosity, 'ORA-01031')
if not success and verbosity >= 2: if not success and verbosity >= 2:
print("Failed to grant CREATE VIEW permission to test user. This may be ok.") self.log('Failed to grant CREATE VIEW permission to test user. This may be ok.')
def _execute_test_db_destruction(self, cursor, parameters, verbosity): def _execute_test_db_destruction(self, cursor, parameters, verbosity):
if verbosity >= 2: if verbosity >= 2:
print("_execute_test_db_destruction(): dbname=%s" % parameters['user']) self.log('_execute_test_db_destruction(): dbname=%s' % parameters['user'])
statements = [ statements = [
'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
@ -240,8 +242,8 @@ class DatabaseCreation(BaseDatabaseCreation):
def _destroy_test_user(self, cursor, parameters, verbosity): def _destroy_test_user(self, cursor, parameters, verbosity):
if verbosity >= 2: if verbosity >= 2:
print("_destroy_test_user(): user=%s" % parameters['user']) self.log('_destroy_test_user(): user=%s' % parameters['user'])
print("Be patient. This can take some time...") self.log('Be patient. This can take some time...')
statements = [ statements = [
'DROP USER %(user)s CASCADE', 'DROP USER %(user)s CASCADE',
] ]
@ -256,7 +258,7 @@ class DatabaseCreation(BaseDatabaseCreation):
cursor.execute(stmt) cursor.execute(stmt)
except Exception as err: except Exception as err:
if (not allow_quiet_fail) or verbosity >= 2: if (not allow_quiet_fail) or verbosity >= 2:
sys.stderr.write("Failed (%s)\n" % (err)) self.log('Failed (%s)' % (err))
raise raise
def _execute_allow_fail_statements(self, cursor, statements, parameters, verbosity, acceptable_ora_err): def _execute_allow_fail_statements(self, cursor, statements, parameters, verbosity, acceptable_ora_err):

View File

@ -34,7 +34,7 @@ class DatabaseCreation(BaseDatabaseCreation):
except Exception as e: except Exception as e:
if getattr(e.__cause__, 'pgcode', '') != errorcodes.DUPLICATE_DATABASE: if getattr(e.__cause__, 'pgcode', '') != errorcodes.DUPLICATE_DATABASE:
# All errors except "database already exists" cancel tests. # All errors except "database already exists" cancel tests.
sys.stderr.write('Got an error creating the test database: %s\n' % e) self.log('Got an error creating the test database: %s' % e)
sys.exit(2) sys.exit(2)
elif not keepdb: elif not keepdb:
# If the database should be kept, ignore "database already # If the database should be kept, ignore "database already
@ -58,11 +58,11 @@ class DatabaseCreation(BaseDatabaseCreation):
except Exception as e: except Exception as e:
try: try:
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias %s..." % ( self.log('Destroying old test database for alias %s...' % (
self._get_database_display_str(verbosity, target_database_name), self._get_database_display_str(verbosity, target_database_name),
)) ))
cursor.execute('DROP DATABASE %(dbname)s' % test_db_params) cursor.execute('DROP DATABASE %(dbname)s' % test_db_params)
self._execute_create_test_db(cursor, test_db_params, keepdb) self._execute_create_test_db(cursor, test_db_params, keepdb)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error cloning the test database: %s\n" % e) self.log('Got an error cloning the test database: %s' % e)
sys.exit(2) sys.exit(2)

View File

@ -25,7 +25,7 @@ class DatabaseCreation(BaseDatabaseCreation):
if not self.is_in_memory_db(test_database_name): if not self.is_in_memory_db(test_database_name):
# Erase the old test database # Erase the old test database
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias %s..." % ( self.log('Destroying old test database for alias %s...' % (
self._get_database_display_str(verbosity, test_database_name), self._get_database_display_str(verbosity, test_database_name),
)) ))
if os.access(test_database_name, os.F_OK): if os.access(test_database_name, os.F_OK):
@ -38,10 +38,10 @@ class DatabaseCreation(BaseDatabaseCreation):
try: try:
os.remove(test_database_name) os.remove(test_database_name)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error deleting the old test database: %s\n" % e) self.log('Got an error deleting the old test database: %s' % e)
sys.exit(2) sys.exit(2)
else: else:
print("Tests cancelled.") self.log('Tests cancelled.')
sys.exit(1) sys.exit(1)
return test_database_name return test_database_name
@ -64,18 +64,18 @@ class DatabaseCreation(BaseDatabaseCreation):
if keepdb: if keepdb:
return return
if verbosity >= 1: if verbosity >= 1:
print("Destroying old test database for alias %s..." % ( self.log('Destroying old test database for alias %s...' % (
self._get_database_display_str(verbosity, target_database_name), self._get_database_display_str(verbosity, target_database_name),
)) ))
try: try:
os.remove(target_database_name) os.remove(target_database_name)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error deleting the old test database: %s\n" % e) self.log('Got an error deleting the old test database: %s' % e)
sys.exit(2) sys.exit(2)
try: try:
shutil.copy(source_database_name, target_database_name) shutil.copy(source_database_name, target_database_name)
except Exception as e: except Exception as e:
sys.stderr.write("Got an error cloning the test database: %s\n" % e) self.log('Got an error cloning the test database: %s' % e)
sys.exit(2) sys.exit(2)
def _destroy_test_db(self, test_database_name, verbosity): def _destroy_test_db(self, test_database_name, verbosity):