/tests/regressiontests/backends/tests.py

https://code.google.com/p/mango-py/ · Python · 288 lines · 202 code · 34 blank · 52 comment · 9 complexity · 9e99731ea2eb98bcf985ebb057cd8323 MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. # Unit and doctests for specific database backends.
  3. import datetime
  4. from django.core.management.color import no_style
  5. from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError
  6. from django.db.backends.signals import connection_created
  7. from django.db.backends.postgresql import version as pg_version
  8. from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
  9. from django.utils import unittest
  10. from regressiontests.backends import models
  11. class OracleChecks(unittest.TestCase):
  12. @unittest.skipUnless(connection.vendor == 'oracle',
  13. "No need to check Oracle cursor semantics")
  14. def test_dbms_session(self):
  15. # If the backend is Oracle, test that we can call a standard
  16. # stored procedure through our cursor wrapper.
  17. convert_unicode = backend.convert_unicode
  18. cursor = connection.cursor()
  19. cursor.callproc(convert_unicode('DBMS_SESSION.SET_IDENTIFIER'),
  20. [convert_unicode('_django_testing!'),])
  21. @unittest.skipUnless(connection.vendor == 'oracle',
  22. "No need to check Oracle cursor semantics")
  23. def test_cursor_var(self):
  24. # If the backend is Oracle, test that we can pass cursor variables
  25. # as query parameters.
  26. cursor = connection.cursor()
  27. var = cursor.var(backend.Database.STRING)
  28. cursor.execute("BEGIN %s := 'X'; END; ", [var])
  29. self.assertEqual(var.getvalue(), 'X')
  30. @unittest.skipUnless(connection.vendor == 'oracle',
  31. "No need to check Oracle cursor semantics")
  32. def test_long_string(self):
  33. # If the backend is Oracle, test that we can save a text longer
  34. # than 4000 chars and read it properly
  35. c = connection.cursor()
  36. c.execute('CREATE TABLE ltext ("TEXT" NCLOB)')
  37. long_str = ''.join([unicode(x) for x in xrange(4000)])
  38. c.execute('INSERT INTO ltext VALUES (%s)',[long_str])
  39. c.execute('SELECT text FROM ltext')
  40. row = c.fetchone()
  41. self.assertEqual(long_str, row[0].read())
  42. c.execute('DROP TABLE ltext')
  43. @unittest.skipUnless(connection.vendor == 'oracle',
  44. "No need to check Oracle connection semantics")
  45. def test_client_encoding(self):
  46. # If the backend is Oracle, test that the client encoding is set
  47. # correctly. This was broken under Cygwin prior to r14781.
  48. c = connection.cursor() # Ensure the connection is initialized.
  49. self.assertEqual(connection.connection.encoding, "UTF-8")
  50. self.assertEqual(connection.connection.nencoding, "UTF-8")
  51. class DateQuotingTest(TestCase):
  52. def test_django_date_trunc(self):
  53. """
  54. Test the custom ``django_date_trunc method``, in particular against
  55. fields which clash with strings passed to it (e.g. 'year') - see
  56. #12818__.
  57. __: http://code.djangoproject.com/ticket/12818
  58. """
  59. updated = datetime.datetime(2010, 2, 20)
  60. models.SchoolClass.objects.create(year=2009, last_updated=updated)
  61. years = models.SchoolClass.objects.dates('last_updated', 'year')
  62. self.assertEqual(list(years), [datetime.datetime(2010, 1, 1, 0, 0)])
  63. def test_django_extract(self):
  64. """
  65. Test the custom ``django_extract method``, in particular against fields
  66. which clash with strings passed to it (e.g. 'day') - see #12818__.
  67. __: http://code.djangoproject.com/ticket/12818
  68. """
  69. updated = datetime.datetime(2010, 2, 20)
  70. models.SchoolClass.objects.create(year=2009, last_updated=updated)
  71. classes = models.SchoolClass.objects.filter(last_updated__day=20)
  72. self.assertEqual(len(classes), 1)
  73. class ParameterHandlingTest(TestCase):
  74. def test_bad_parameter_count(self):
  75. "An executemany call with too many/not enough parameters will raise an exception (Refs #12612)"
  76. cursor = connection.cursor()
  77. query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % (
  78. connection.introspection.table_name_converter('backends_square'),
  79. connection.ops.quote_name('root'),
  80. connection.ops.quote_name('square')
  81. ))
  82. self.assertRaises(Exception, cursor.executemany, query, [(1,2,3),])
  83. self.assertRaises(Exception, cursor.executemany, query, [(1,),])
  84. # Unfortunately, the following tests would be a good test to run on all
  85. # backends, but it breaks MySQL hard. Until #13711 is fixed, it can't be run
  86. # everywhere (although it would be an effective test of #13711).
  87. class LongNameTest(TestCase):
  88. """Long primary keys and model names can result in a sequence name
  89. that exceeds the database limits, which will result in truncation
  90. on certain databases (e.g., Postgres). The backend needs to use
  91. the correct sequence name in last_insert_id and other places, so
  92. check it is. Refs #8901.
  93. """
  94. @skipUnlessDBFeature('supports_long_model_names')
  95. def test_sequence_name_length_limits_create(self):
  96. """Test creation of model with long name and long pk name doesn't error. Ref #8901"""
  97. models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
  98. @skipUnlessDBFeature('supports_long_model_names')
  99. def test_sequence_name_length_limits_m2m(self):
  100. """Test an m2m save of a model with a long name and a long m2m field name doesn't error as on Django >=1.2 this now uses object saves. Ref #8901"""
  101. obj = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
  102. rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt')
  103. obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj)
  104. @skipUnlessDBFeature('supports_long_model_names')
  105. def test_sequence_name_length_limits_flush(self):
  106. """Test that sequence resetting as part of a flush with model with long name and long pk name doesn't error. Ref #8901"""
  107. # A full flush is expensive to the full test, so we dig into the
  108. # internals to generate the likely offending SQL and run it manually
  109. # Some convenience aliases
  110. VLM = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  111. VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through
  112. tables = [
  113. VLM._meta.db_table,
  114. VLM_m2m._meta.db_table,
  115. ]
  116. sequences = [
  117. {
  118. 'column': VLM._meta.pk.column,
  119. 'table': VLM._meta.db_table
  120. },
  121. ]
  122. cursor = connection.cursor()
  123. for statement in connection.ops.sql_flush(no_style(), tables, sequences):
  124. cursor.execute(statement)
  125. class SequenceResetTest(TestCase):
  126. def test_generic_relation(self):
  127. "Sequence names are correct when resetting generic relations (Ref #13941)"
  128. # Create an object with a manually specified PK
  129. models.Post.objects.create(id=10, name='1st post', text='hello world')
  130. # Reset the sequences for the database
  131. cursor = connection.cursor()
  132. commands = connections[DEFAULT_DB_ALIAS].ops.sequence_reset_sql(no_style(), [models.Post])
  133. for sql in commands:
  134. cursor.execute(sql)
  135. # If we create a new object now, it should have a PK greater
  136. # than the PK we specified manually.
  137. obj = models.Post.objects.create(name='New post', text='goodbye world')
  138. self.assertTrue(obj.pk > 10)
  139. class PostgresVersionTest(TestCase):
  140. def assert_parses(self, version_string, version):
  141. self.assertEqual(pg_version._parse_version(version_string), version)
  142. def test_parsing(self):
  143. self.assert_parses("PostgreSQL 8.3 beta4", (8, 3, None))
  144. self.assert_parses("PostgreSQL 8.3", (8, 3, None))
  145. self.assert_parses("EnterpriseDB 8.3", (8, 3, None))
  146. self.assert_parses("PostgreSQL 8.3.6", (8, 3, 6))
  147. self.assert_parses("PostgreSQL 8.4beta1", (8, 4, None))
  148. self.assert_parses("PostgreSQL 8.3.1 on i386-apple-darwin9.2.2, compiled by GCC i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)", (8, 3, 1))
  149. # Unfortunately with sqlite3 the in-memory test database cannot be
  150. # closed, and so it cannot be re-opened during testing, and so we
  151. # sadly disable this test for now.
  152. class ConnectionCreatedSignalTest(TestCase):
  153. @skipUnlessDBFeature('test_db_allows_multiple_connections')
  154. def test_signal(self):
  155. data = {}
  156. def receiver(sender, connection, **kwargs):
  157. data["connection"] = connection
  158. connection_created.connect(receiver)
  159. connection.close()
  160. cursor = connection.cursor()
  161. self.assertTrue(data["connection"] is connection)
  162. connection_created.disconnect(receiver)
  163. data.clear()
  164. cursor = connection.cursor()
  165. self.assertTrue(data == {})
  166. class EscapingChecks(TestCase):
  167. @unittest.skipUnless(connection.vendor == 'sqlite',
  168. "This is a sqlite-specific issue")
  169. def test_parameter_escaping(self):
  170. #13648: '%s' escaping support for sqlite3
  171. cursor = connection.cursor()
  172. response = cursor.execute(
  173. "select strftime('%%s', date('now'))").fetchall()[0][0]
  174. self.assertNotEqual(response, None)
  175. # response should be an non-zero integer
  176. self.assertTrue(int(response))
  177. class BackendTestCase(TestCase):
  178. def test_cursor_executemany(self):
  179. #4896: Test cursor.executemany
  180. cursor = connection.cursor()
  181. qn = connection.ops.quote_name
  182. opts = models.Square._meta
  183. f1, f2 = opts.get_field('root'), opts.get_field('square')
  184. query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)'
  185. % (connection.introspection.table_name_converter(opts.db_table), qn(f1.column), qn(f2.column)))
  186. cursor.executemany(query, [(i, i**2) for i in range(-5, 6)])
  187. self.assertEqual(models.Square.objects.count(), 11)
  188. for i in range(-5, 6):
  189. square = models.Square.objects.get(root=i)
  190. self.assertEqual(square.square, i**2)
  191. #4765: executemany with params=[] does nothing
  192. cursor.executemany(query, [])
  193. self.assertEqual(models.Square.objects.count(), 11)
  194. def test_unicode_fetches(self):
  195. #6254: fetchone, fetchmany, fetchall return strings as unicode objects
  196. qn = connection.ops.quote_name
  197. models.Person(first_name="John", last_name="Doe").save()
  198. models.Person(first_name="Jane", last_name="Doe").save()
  199. models.Person(first_name="Mary", last_name="Agnelline").save()
  200. models.Person(first_name="Peter", last_name="Parker").save()
  201. models.Person(first_name="Clark", last_name="Kent").save()
  202. opts2 = models.Person._meta
  203. f3, f4 = opts2.get_field('first_name'), opts2.get_field('last_name')
  204. query2 = ('SELECT %s, %s FROM %s ORDER BY %s'
  205. % (qn(f3.column), qn(f4.column), connection.introspection.table_name_converter(opts2.db_table),
  206. qn(f3.column)))
  207. cursor = connection.cursor()
  208. cursor.execute(query2)
  209. self.assertEqual(cursor.fetchone(), (u'Clark', u'Kent'))
  210. self.assertEqual(list(cursor.fetchmany(2)), [(u'Jane', u'Doe'), (u'John', u'Doe')])
  211. self.assertEqual(list(cursor.fetchall()), [(u'Mary', u'Agnelline'), (u'Peter', u'Parker')])
  212. # We don't make these tests conditional because that means we would need to
  213. # check and differentiate between:
  214. # * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
  215. # * if sqlite3 (if/once we get #14204 fixed) has referential integrity turned
  216. # on or not, something that would be controlled by runtime support and user
  217. # preference.
  218. # verify if its type is django.database.db.IntegrityError.
  219. class FkConstraintsTests(TransactionTestCase):
  220. def setUp(self):
  221. # Create a Reporter.
  222. self.r = models.Reporter.objects.create(first_name='John', last_name='Smith')
  223. def test_integrity_checks_on_creation(self):
  224. """
  225. Try to create a model instance that violates a FK constraint. If it
  226. fails it should fail with IntegrityError.
  227. """
  228. a = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
  229. try:
  230. a.save()
  231. except IntegrityError:
  232. pass
  233. def test_integrity_checks_on_update(self):
  234. """
  235. Try to update a model instance introducing a FK constraint violation.
  236. If it fails it should fail with IntegrityError.
  237. """
  238. # Create an Article.
  239. models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
  240. # Retrive it from the DB
  241. a = models.Article.objects.get(headline="Test article")
  242. a.reporter_id = 30
  243. try:
  244. a.save()
  245. except IntegrityError:
  246. pass