You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

108 lines
4.7 KiB

  1. import os
  2. import shutil
  3. import sys
  4. from django.core.exceptions import ImproperlyConfigured
  5. from django.db.backends.base.creation import BaseDatabaseCreation
  6. from django.utils.six.moves import input
  7. class DatabaseCreation(BaseDatabaseCreation):
  8. def _get_test_db_name(self):
  9. test_database_name = self.connection.settings_dict['TEST']['NAME']
  10. can_share_in_memory_db = self.connection.features.can_share_in_memory_db
  11. if test_database_name and test_database_name != ':memory:':
  12. if 'mode=memory' in test_database_name and not can_share_in_memory_db:
  13. raise ImproperlyConfigured(
  14. "Using a shared memory database with `mode=memory` in the "
  15. "database name is not supported in your environment, "
  16. "use `:memory:` instead."
  17. )
  18. return test_database_name
  19. if can_share_in_memory_db:
  20. return 'file:memorydb_%s?mode=memory&cache=shared' % self.connection.alias
  21. return ':memory:'
  22. def _create_test_db(self, verbosity, autoclobber, keepdb=False):
  23. test_database_name = self._get_test_db_name()
  24. if keepdb:
  25. return test_database_name
  26. if not self.connection.is_in_memory_db(test_database_name):
  27. # Erase the old test database
  28. if verbosity >= 1:
  29. print("Destroying old test database for alias %s..." % (
  30. self._get_database_display_str(verbosity, test_database_name),
  31. ))
  32. if os.access(test_database_name, os.F_OK):
  33. if not autoclobber:
  34. confirm = input(
  35. "Type 'yes' if you would like to try deleting the test "
  36. "database '%s', or 'no' to cancel: " % test_database_name
  37. )
  38. if autoclobber or confirm == 'yes':
  39. try:
  40. os.remove(test_database_name)
  41. except Exception as e:
  42. sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
  43. sys.exit(2)
  44. else:
  45. print("Tests cancelled.")
  46. sys.exit(1)
  47. return test_database_name
  48. def get_test_db_clone_settings(self, number):
  49. orig_settings_dict = self.connection.settings_dict
  50. source_database_name = orig_settings_dict['NAME']
  51. if self.connection.is_in_memory_db(source_database_name):
  52. return orig_settings_dict
  53. else:
  54. new_settings_dict = orig_settings_dict.copy()
  55. root, ext = os.path.splitext(orig_settings_dict['NAME'])
  56. new_settings_dict['NAME'] = '{}_{}.{}'.format(root, number, ext)
  57. return new_settings_dict
  58. def _clone_test_db(self, number, verbosity, keepdb=False):
  59. source_database_name = self.connection.settings_dict['NAME']
  60. target_database_name = self.get_test_db_clone_settings(number)['NAME']
  61. # Forking automatically makes a copy of an in-memory database.
  62. if not self.connection.is_in_memory_db(source_database_name):
  63. # Erase the old test database
  64. if os.access(target_database_name, os.F_OK):
  65. if keepdb:
  66. return
  67. if verbosity >= 1:
  68. print("Destroying old test database for alias %s..." % (
  69. self._get_database_display_str(verbosity, target_database_name),
  70. ))
  71. try:
  72. os.remove(target_database_name)
  73. except Exception as e:
  74. sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
  75. sys.exit(2)
  76. try:
  77. shutil.copy(source_database_name, target_database_name)
  78. except Exception as e:
  79. sys.stderr.write("Got an error cloning the test database: %s\n" % e)
  80. sys.exit(2)
  81. def _destroy_test_db(self, test_database_name, verbosity):
  82. if test_database_name and not self.connection.is_in_memory_db(test_database_name):
  83. # Remove the SQLite database file
  84. os.remove(test_database_name)
  85. def test_db_signature(self):
  86. """
  87. Returns a tuple that uniquely identifies a test database.
  88. This takes into account the special cases of ":memory:" and "" for
  89. SQLite since the databases will be distinct despite having the same
  90. TEST NAME. See http://www.sqlite.org/inmemorydb.html
  91. """
  92. test_database_name = self._get_test_db_name()
  93. sig = [self.connection.settings_dict['NAME']]
  94. if self.connection.is_in_memory_db(test_database_name):
  95. sig.append(self.connection.alias)
  96. return tuple(sig)