2
0

test_creation.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import copy
  2. import unittest
  3. from contextlib import contextmanager
  4. from io import StringIO
  5. from unittest import mock
  6. from django.db import DEFAULT_DB_ALIAS, connection, connections
  7. from django.db.backends.base.creation import (
  8. TEST_DATABASE_PREFIX, BaseDatabaseCreation,
  9. )
  10. from django.db.backends.mysql.creation import (
  11. DatabaseCreation as MySQLDatabaseCreation,
  12. )
  13. from django.db.backends.oracle.creation import (
  14. DatabaseCreation as OracleDatabaseCreation,
  15. )
  16. from django.db.utils import DatabaseError
  17. from django.test import SimpleTestCase, TestCase
  18. try:
  19. import psycopg2 # NOQA
  20. except ImportError:
  21. pass
  22. else:
  23. from psycopg2 import errorcodes
  24. from django.db.backends.postgresql.creation import \
  25. DatabaseCreation as PostgreSQLDatabaseCreation
  26. class TestDbSignatureTests(SimpleTestCase):
  27. def get_connection_copy(self):
  28. # Get a copy of the default connection. (Can't use django.db.connection
  29. # because it'll modify the default connection itself.)
  30. test_connection = copy.copy(connections[DEFAULT_DB_ALIAS])
  31. test_connection.settings_dict = copy.copy(connections[DEFAULT_DB_ALIAS].settings_dict)
  32. return test_connection
  33. def test_default_name(self):
  34. # A test db name isn't set.
  35. prod_name = 'hodor'
  36. test_connection = self.get_connection_copy()
  37. test_connection.settings_dict['NAME'] = prod_name
  38. test_connection.settings_dict['TEST'] = {'NAME': None}
  39. signature = BaseDatabaseCreation(test_connection).test_db_signature()
  40. self.assertEqual(signature[3], TEST_DATABASE_PREFIX + prod_name)
  41. def test_custom_test_name(self):
  42. # A regular test db name is set.
  43. test_name = 'hodor'
  44. test_connection = self.get_connection_copy()
  45. test_connection.settings_dict['TEST'] = {'NAME': test_name}
  46. signature = BaseDatabaseCreation(test_connection).test_db_signature()
  47. self.assertEqual(signature[3], test_name)
  48. def test_custom_test_name_with_test_prefix(self):
  49. # A test db name prefixed with TEST_DATABASE_PREFIX is set.
  50. test_name = TEST_DATABASE_PREFIX + 'hodor'
  51. test_connection = self.get_connection_copy()
  52. test_connection.settings_dict['TEST'] = {'NAME': test_name}
  53. signature = BaseDatabaseCreation(test_connection).test_db_signature()
  54. self.assertEqual(signature[3], test_name)
  55. @unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL-specific tests")
  56. class PostgreSQLDatabaseCreationTests(SimpleTestCase):
  57. @contextmanager
  58. def changed_test_settings(self, **kwargs):
  59. settings = connection.settings_dict['TEST']
  60. saved_values = {}
  61. for name in kwargs:
  62. if name in settings:
  63. saved_values[name] = settings[name]
  64. for name, value in kwargs.items():
  65. settings[name] = value
  66. try:
  67. yield
  68. finally:
  69. for name, value in kwargs.items():
  70. if name in saved_values:
  71. settings[name] = saved_values[name]
  72. else:
  73. del settings[name]
  74. def check_sql_table_creation_suffix(self, settings, expected):
  75. with self.changed_test_settings(**settings):
  76. creation = PostgreSQLDatabaseCreation(connection)
  77. suffix = creation.sql_table_creation_suffix()
  78. self.assertEqual(suffix, expected)
  79. def test_sql_table_creation_suffix_with_none_settings(self):
  80. settings = {'CHARSET': None, 'TEMPLATE': None}
  81. self.check_sql_table_creation_suffix(settings, "")
  82. def test_sql_table_creation_suffix_with_encoding(self):
  83. settings = {'CHARSET': 'UTF8'}
  84. self.check_sql_table_creation_suffix(settings, "WITH ENCODING 'UTF8'")
  85. def test_sql_table_creation_suffix_with_template(self):
  86. settings = {'TEMPLATE': 'template0'}
  87. self.check_sql_table_creation_suffix(settings, 'WITH TEMPLATE "template0"')
  88. def test_sql_table_creation_suffix_with_encoding_and_template(self):
  89. settings = {'CHARSET': 'UTF8', 'TEMPLATE': 'template0'}
  90. self.check_sql_table_creation_suffix(settings, '''WITH ENCODING 'UTF8' TEMPLATE "template0"''')
  91. def _execute_raise_database_already_exists(self, cursor, parameters, keepdb=False):
  92. error = DatabaseError('database %s already exists' % parameters['dbname'])
  93. error.pgcode = errorcodes.DUPLICATE_DATABASE
  94. raise DatabaseError() from error
  95. def _execute_raise_permission_denied(self, cursor, parameters, keepdb=False):
  96. error = DatabaseError('permission denied to create database')
  97. error.pgcode = errorcodes.INSUFFICIENT_PRIVILEGE
  98. raise DatabaseError() from error
  99. def patch_test_db_creation(self, execute_create_test_db):
  100. return mock.patch.object(BaseDatabaseCreation, '_execute_create_test_db', execute_create_test_db)
  101. @mock.patch('sys.stdout', new_callable=StringIO)
  102. @mock.patch('sys.stderr', new_callable=StringIO)
  103. def test_create_test_db(self, *mocked_objects):
  104. creation = PostgreSQLDatabaseCreation(connection)
  105. # Simulate test database creation raising "database already exists"
  106. with self.patch_test_db_creation(self._execute_raise_database_already_exists):
  107. with mock.patch('builtins.input', return_value='no'):
  108. with self.assertRaises(SystemExit):
  109. # SystemExit is raised if the user answers "no" to the
  110. # prompt asking if it's okay to delete the test database.
  111. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=False)
  112. # "Database already exists" error is ignored when keepdb is on
  113. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=True)
  114. # Simulate test database creation raising unexpected error
  115. with self.patch_test_db_creation(self._execute_raise_permission_denied):
  116. with self.assertRaises(SystemExit):
  117. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=False)
  118. with self.assertRaises(SystemExit):
  119. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=True)
  120. @unittest.skipUnless(connection.vendor == 'oracle', "Oracle specific tests")
  121. @mock.patch.object(OracleDatabaseCreation, '_maindb_connection', return_value=connection)
  122. @mock.patch('sys.stdout', new_callable=StringIO)
  123. @mock.patch('sys.stderr', new_callable=StringIO)
  124. class OracleDatabaseCreationTests(TestCase):
  125. def _execute_raise_user_already_exists(self, cursor, statements, parameters, verbosity, allow_quiet_fail=False):
  126. # Raise "user already exists" only in test user creation
  127. if statements and statements[0].startswith('CREATE USER'):
  128. raise DatabaseError("ORA-01920: user name 'string' conflicts with another user or role name")
  129. def _execute_raise_tablespace_already_exists(
  130. self, cursor, statements, parameters, verbosity, allow_quiet_fail=False
  131. ):
  132. raise DatabaseError("ORA-01543: tablespace 'string' already exists")
  133. def _execute_raise_insufficient_privileges(
  134. self, cursor, statements, parameters, verbosity, allow_quiet_fail=False
  135. ):
  136. raise DatabaseError("ORA-01031: insufficient privileges")
  137. def _test_database_passwd(self):
  138. # Mocked to avoid test user password changed
  139. return connection.settings_dict['SAVED_PASSWORD']
  140. def patch_execute_statements(self, execute_statements):
  141. return mock.patch.object(OracleDatabaseCreation, '_execute_statements', execute_statements)
  142. @mock.patch.object(OracleDatabaseCreation, '_test_user_create', return_value=False)
  143. def test_create_test_db(self, *mocked_objects):
  144. creation = OracleDatabaseCreation(connection)
  145. # Simulate test database creation raising "tablespace already exists"
  146. with self.patch_execute_statements(self._execute_raise_tablespace_already_exists):
  147. with mock.patch('builtins.input', return_value='no'):
  148. with self.assertRaises(SystemExit):
  149. # SystemExit is raised if the user answers "no" to the
  150. # prompt asking if it's okay to delete the test tablespace.
  151. creation._create_test_db(verbosity=0, keepdb=False)
  152. # "Tablespace already exists" error is ignored when keepdb is on
  153. creation._create_test_db(verbosity=0, keepdb=True)
  154. # Simulate test database creation raising unexpected error
  155. with self.patch_execute_statements(self._execute_raise_insufficient_privileges):
  156. with self.assertRaises(SystemExit):
  157. creation._create_test_db(verbosity=0, keepdb=False)
  158. with self.assertRaises(SystemExit):
  159. creation._create_test_db(verbosity=0, keepdb=True)
  160. @mock.patch.object(OracleDatabaseCreation, '_test_database_create', return_value=False)
  161. def test_create_test_user(self, *mocked_objects):
  162. creation = OracleDatabaseCreation(connection)
  163. with mock.patch.object(OracleDatabaseCreation, '_test_database_passwd', self._test_database_passwd):
  164. # Simulate test user creation raising "user already exists"
  165. with self.patch_execute_statements(self._execute_raise_user_already_exists):
  166. with mock.patch('builtins.input', return_value='no'):
  167. with self.assertRaises(SystemExit):
  168. # SystemExit is raised if the user answers "no" to the
  169. # prompt asking if it's okay to delete the test user.
  170. creation._create_test_db(verbosity=0, keepdb=False)
  171. # "User already exists" error is ignored when keepdb is on
  172. creation._create_test_db(verbosity=0, keepdb=True)
  173. # Simulate test user creation raising unexpected error
  174. with self.patch_execute_statements(self._execute_raise_insufficient_privileges):
  175. with self.assertRaises(SystemExit):
  176. creation._create_test_db(verbosity=0, keepdb=False)
  177. with self.assertRaises(SystemExit):
  178. creation._create_test_db(verbosity=0, keepdb=True)
  179. @unittest.skipUnless(connection.vendor == 'mysql', "MySQL specific tests")
  180. class MySQLDatabaseCreationTests(SimpleTestCase):
  181. def _execute_raise_database_exists(self, cursor, parameters, keepdb=False):
  182. raise DatabaseError(1007, "Can't create database '%s'; database exists" % parameters['dbname'])
  183. def _execute_raise_access_denied(self, cursor, parameters, keepdb=False):
  184. raise DatabaseError(1044, "Access denied for user")
  185. def patch_test_db_creation(self, execute_create_test_db):
  186. return mock.patch.object(BaseDatabaseCreation, '_execute_create_test_db', execute_create_test_db)
  187. @mock.patch('sys.stdout', new_callable=StringIO)
  188. @mock.patch('sys.stderr', new_callable=StringIO)
  189. def test_create_test_db_database_exists(self, *mocked_objects):
  190. # Simulate test database creation raising "database exists"
  191. creation = MySQLDatabaseCreation(connection)
  192. with self.patch_test_db_creation(self._execute_raise_database_exists):
  193. with mock.patch('builtins.input', return_value='no'):
  194. with self.assertRaises(SystemExit):
  195. # SystemExit is raised if the user answers "no" to the
  196. # prompt asking if it's okay to delete the test database.
  197. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=False)
  198. # "Database exists" shouldn't appear when keepdb is on
  199. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=True)
  200. @mock.patch('sys.stdout', new_callable=StringIO)
  201. @mock.patch('sys.stderr', new_callable=StringIO)
  202. def test_create_test_db_unexpected_error(self, *mocked_objects):
  203. # Simulate test database creation raising unexpected error
  204. creation = MySQLDatabaseCreation(connection)
  205. with self.patch_test_db_creation(self._execute_raise_access_denied):
  206. with self.assertRaises(SystemExit):
  207. creation._create_test_db(verbosity=0, autoclobber=False, keepdb=False)