diff options
Diffstat (limited to 'lib/python2.7/site-packages/south/tests/db.py')
-rw-r--r-- | lib/python2.7/site-packages/south/tests/db.py | 1060 |
1 files changed, 0 insertions, 1060 deletions
diff --git a/lib/python2.7/site-packages/south/tests/db.py b/lib/python2.7/site-packages/south/tests/db.py deleted file mode 100644 index e63c563..0000000 --- a/lib/python2.7/site-packages/south/tests/db.py +++ /dev/null @@ -1,1060 +0,0 @@ -import datetime -from warnings import filterwarnings - -from south.db import db, generic -from django.db import connection, models, IntegrityError as DjangoIntegrityError - -from south.tests import unittest, skipIf, skipUnless -from south.utils.py3 import text_type, with_metaclass - -# Create a list of error classes from the various database libraries -errors = [] -try: - from psycopg2 import ProgrammingError - errors.append(ProgrammingError) -except ImportError: - pass -errors = tuple(errors) - -# On SQL Server, the backend's IntegrityError is not (a subclass of) Django's. -try: - from sql_server.pyodbc.base import IntegrityError as SQLServerIntegrityError - IntegrityError = (DjangoIntegrityError, SQLServerIntegrityError) -except ImportError: - IntegrityError = DjangoIntegrityError - -try: - from south.db import mysql -except ImportError: - mysql = None - - -class TestOperations(unittest.TestCase): - - """ - Tests if the various DB abstraction calls work. - Can only test a limited amount due to DB differences. - """ - - def setUp(self): - db.debug = False - try: - import MySQLdb - except ImportError: - pass - else: - filterwarnings('ignore', category=MySQLdb.Warning) - db.clear_deferred_sql() - db.start_transaction() - - def tearDown(self): - db.rollback_transaction() - - def test_create(self): - """ - Test creation of tables. - """ - cursor = connection.cursor() - # It needs to take at least 2 args - self.assertRaises(TypeError, db.create_table) - self.assertRaises(TypeError, db.create_table, "test1") - # Empty tables (i.e. no columns) are not fine, so make at least 1 - db.create_table("test1", [('email_confirmed', models.BooleanField(default=False))]) - # And should exist - cursor.execute("SELECT * FROM test1") - # Make sure we can't do the same query on an empty table - try: - cursor.execute("SELECT * FROM nottheretest1") - except: - pass - else: - self.fail("Non-existent table could be selected!") - - @skipUnless(db.raises_default_errors, 'This database does not raise errors on missing defaults.') - def test_create_default(self): - """ - Test creation of tables, make sure defaults are not left in the database - """ - db.create_table("test_create_default", [('a', models.IntegerField()), - ('b', models.IntegerField(default=17))]) - cursor = connection.cursor() - self.assertRaises(IntegrityError, cursor.execute, "INSERT INTO test_create_default(a) VALUES (17)") - - def test_delete(self): - """ - Test deletion of tables. - """ - cursor = connection.cursor() - db.create_table("test_deltable", [('email_confirmed', models.BooleanField(default=False))]) - db.delete_table("test_deltable") - # Make sure it went - try: - cursor.execute("SELECT * FROM test_deltable") - except: - pass - else: - self.fail("Just-deleted table could be selected!") - - def test_nonexistent_delete(self): - """ - Test deletion of nonexistent tables. - """ - try: - db.delete_table("test_nonexistdeltable") - except: - pass - else: - self.fail("Non-existent table could be deleted!") - - def test_foreign_keys(self): - """ - Tests foreign key creation, especially uppercase (see #61) - """ - Test = db.mock_model(model_name='Test', db_table='test5a', - db_tablespace='', pk_field_name='ID', - pk_field_type=models.AutoField, pk_field_args=[]) - db.create_table("test5a", [('ID', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True))]) - db.create_table("test5b", [ - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('UNIQUE', models.ForeignKey(Test)), - ]) - db.execute_deferred_sql() - - @skipUnless(db.supports_foreign_keys, 'Foreign keys can only be deleted on ' - 'engines that support them.') - def test_recursive_foreign_key_delete(self): - """ - Test that recursive foreign keys are deleted correctly (see #1065) - """ - Test = db.mock_model(model_name='Test', db_table='test_rec_fk_del', - db_tablespace='', pk_field_name='id', - pk_field_type=models.AutoField, pk_field_args=[]) - db.create_table('test_rec_fk_del', [ - ('id', models.AutoField(primary_key=True, auto_created=True)), - ('fk', models.ForeignKey(Test)), - ]) - db.execute_deferred_sql() - db.delete_foreign_key('test_rec_fk_del', 'fk_id') - - def test_rename(self): - """ - Test column renaming - """ - cursor = connection.cursor() - db.create_table("test_rn", [('spam', models.BooleanField(default=False))]) - # Make sure we can select the column - cursor.execute("SELECT spam FROM test_rn") - # Rename it - db.rename_column("test_rn", "spam", "eggs") - cursor.execute("SELECT eggs FROM test_rn") - db.commit_transaction() - db.start_transaction() - try: - cursor.execute("SELECT spam FROM test_rn") - except: - pass - else: - self.fail("Just-renamed column could be selected!") - db.rollback_transaction() - db.delete_table("test_rn") - db.start_transaction() - - def test_dry_rename(self): - """ - Test column renaming while --dry-run is turned on (should do nothing) - See ticket #65 - """ - cursor = connection.cursor() - db.create_table("test_drn", [('spam', models.BooleanField(default=False))]) - # Make sure we can select the column - cursor.execute("SELECT spam FROM test_drn") - # Rename it - db.dry_run = True - db.rename_column("test_drn", "spam", "eggs") - db.dry_run = False - cursor.execute("SELECT spam FROM test_drn") - db.commit_transaction() - db.start_transaction() - try: - cursor.execute("SELECT eggs FROM test_drn") - except: - pass - else: - self.fail("Dry-renamed new column could be selected!") - db.rollback_transaction() - db.delete_table("test_drn") - db.start_transaction() - - def test_table_rename(self): - """ - Test column renaming - """ - cursor = connection.cursor() - db.create_table("testtr", [('spam', models.BooleanField(default=False))]) - # Make sure we can select the column - cursor.execute("SELECT spam FROM testtr") - # Rename it - db.rename_table("testtr", "testtr2") - cursor.execute("SELECT spam FROM testtr2") - db.commit_transaction() - db.start_transaction() - try: - cursor.execute("SELECT spam FROM testtr") - except: - pass - else: - self.fail("Just-renamed column could be selected!") - db.rollback_transaction() - db.delete_table("testtr2") - db.start_transaction() - - def test_percents_in_defaults(self): - """ - Test that % in a default gets escaped to %%. - """ - try: - db.create_table("testpind", [('cf', models.CharField(max_length=255, default="It should be 2%!"))]) - except IndexError: - self.fail("% was not properly escaped in column SQL.") - db.delete_table("testpind") - - def test_index(self): - """ - Test the index operations - """ - db.create_table("test3", [ - ('SELECT', models.BooleanField(default=False)), - ('eggs', models.IntegerField(unique=True)), - ]) - db.execute_deferred_sql() - # Add an index on that column - db.create_index("test3", ["SELECT"]) - # Add another index on two columns - db.create_index("test3", ["SELECT", "eggs"]) - # Delete them both - db.delete_index("test3", ["SELECT"]) - db.delete_index("test3", ["SELECT", "eggs"]) - # Delete the unique index/constraint - if db.backend_name != "sqlite3": - db.delete_unique("test3", ["eggs"]) - db.delete_table("test3") - - def test_primary_key(self): - """ - Test the primary key operations - """ - - db.create_table("test_pk", [ - ('id', models.IntegerField(primary_key=True)), - ('new_pkey', models.IntegerField()), - ('eggs', models.IntegerField(unique=True)), - ]) - db.execute_deferred_sql() - # Remove the default primary key, and make eggs it - db.delete_primary_key("test_pk") - db.create_primary_key("test_pk", "new_pkey") - # Try inserting a now-valid row pair - db.execute("INSERT INTO test_pk (id, new_pkey, eggs) VALUES (1, 2, 3)") - db.execute("INSERT INTO test_pk (id, new_pkey, eggs) VALUES (1, 3, 4)") - db.delete_table("test_pk") - - def test_primary_key_implicit(self): - """ - Tests that changing primary key implicitly fails. - """ - db.create_table("test_pki", [ - ('id', models.IntegerField(primary_key=True)), - ('new_pkey', models.IntegerField()), - ('eggs', models.IntegerField(unique=True)), - ]) - db.execute_deferred_sql() - # Fiddle with alter_column to attempt to make it remove the primary key - db.alter_column("test_pki", "id", models.IntegerField()) - db.alter_column("test_pki", "new_pkey", models.IntegerField(primary_key=True)) - # Try inserting a should-be-valid row pair - db.execute("INSERT INTO test_pki (id, new_pkey, eggs) VALUES (1, 2, 3)") - db.execute("INSERT INTO test_pki (id, new_pkey, eggs) VALUES (2, 2, 4)") - db.delete_table("test_pki") - - def test_add_columns(self): - """ - Test adding columns - """ - db.create_table("test_addc", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.IntegerField()), - ]) - # Add a column - db.add_column("test_addc", "add1", models.IntegerField(default=3)) - User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - # insert some data so we can test the default value of the added fkey - db.execute("INSERT INTO test_addc (spam, eggs, add1) VALUES (%s, 1, 2)", [False]) - db.add_column("test_addc", "user", models.ForeignKey(User, null=True)) - db.execute_deferred_sql() - # try selecting from the user_id column to make sure it was actually created - val = db.execute("SELECT user_id FROM test_addc")[0][0] - self.assertEquals(val, None) - db.delete_column("test_addc", "add1") - # make sure adding an indexed field works - db.add_column("test_addc", "add2", models.CharField(max_length=15, db_index=True, default='pi')) - db.execute_deferred_sql() - db.delete_table("test_addc") - - def test_delete_columns(self): - """ - Test deleting columns - """ - db.create_table("test_delc", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.IntegerField(db_index=True, unique=True)), - ]) - db.delete_column("test_delc", "eggs") - - def test_add_nullbool_column(self): - """ - Test adding NullBoolean columns - """ - db.create_table("test_addnbc", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.IntegerField()), - ]) - # Add a column - db.add_column("test_addnbc", "add1", models.NullBooleanField()) - # Add a column with a default - db.add_column("test_addnbc", "add2", models.NullBooleanField(default=True)) - # insert some data so we can test the default values of the added column - db.execute("INSERT INTO test_addnbc (spam, eggs) VALUES (%s, 1)", [False]) - # try selecting from the new columns to make sure they were properly created - false, null1, null2 = db.execute("SELECT spam,add1,add2 FROM test_addnbc")[0][0:3] - self.assertIsNone(null1, "Null boolean field with no value inserted returns non-null") - self.assertIsNone(null2, "Null boolean field (added with default) with no value inserted returns non-null") - self.assertEquals(false, False) - db.delete_table("test_addnbc") - - def test_alter_columns(self): - """ - Test altering columns - """ - db.create_table("test_alterc", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.IntegerField()), - ]) - db.execute_deferred_sql() - # Change eggs to be a FloatField - db.alter_column("test_alterc", "eggs", models.FloatField()) - db.execute_deferred_sql() - db.delete_table("test_alterc") - db.execute_deferred_sql() - - def test_alter_char_default(self): - """ - Test altering column defaults with char fields - """ - db.create_table("test_altercd", [ - ('spam', models.CharField(max_length=30)), - ('eggs', models.IntegerField()), - ]) - # Change spam default - db.alter_column("test_altercd", "spam", models.CharField(max_length=30, default="loof", null=True)) - # Assert the default is not in the database - db.execute("INSERT INTO test_altercd (eggs) values (12)") - null = db.execute("SELECT spam FROM test_altercd")[0][0] - self.assertFalse(null, "Default for char field was installed into database") - - # Change again to a column with default and not null - db.alter_column("test_altercd", "spam", models.CharField(max_length=30, default="loof", null=False)) - # Assert the default is not in the database - if 'oracle' in db.backend_name: - # Oracle special treatment -- nulls are always allowed in char columns, so - # inserting doesn't raise an integrity error; so we check again as above - db.execute("DELETE FROM test_altercd") - db.execute("INSERT INTO test_altercd (eggs) values (12)") - null = db.execute("SELECT spam FROM test_altercd")[0][0] - self.assertFalse(null, "Default for char field was installed into database") - else: - # For other backends, insert should now just fail - self.assertRaises(IntegrityError, - db.execute, "INSERT INTO test_altercd (eggs) values (12)") - - @skipIf('oracle' in db.backend_name, "Oracle does not differentiate empty trings from null") - def test_default_empty_string(self): - """ - Test altering column defaults with char fields - """ - db.create_table("test_cd_empty", [ - ('spam', models.CharField(max_length=30, default='')), - ('eggs', models.CharField(max_length=30)), - ]) - # Create a record - db.execute("INSERT INTO test_cd_empty (spam, eggs) values ('1','2')") - # Add a column - db.add_column("test_cd_empty", "ham", models.CharField(max_length=30, default='')) - - empty = db.execute("SELECT ham FROM test_cd_empty")[0][0] - self.assertEquals(empty, "", "Empty Default for char field isn't empty string") - - @skipUnless('oracle' in db.backend_name, "Oracle does not differentiate empty trings from null") - def test_oracle_strings_null(self): - """ - Test that under Oracle, CherFields are created as null even when specified not-null, - because otherwise they would not be able to hold empty strings (which Oracle equates - with nulls). - Verify fix of #1269. - """ - db.create_table("test_ora_char_nulls", [ - ('spam', models.CharField(max_length=30, null=True)), - ('eggs', models.CharField(max_length=30)), - ]) - db.add_column("test_ora_char_nulls", "ham", models.CharField(max_length=30)) - db.alter_column("test_ora_char_nulls", "spam", models.CharField(max_length=30, null=False)) - # So, by the look of it, we should now have three not-null columns - db.execute("INSERT INTO test_ora_char_nulls VALUES (NULL, NULL, NULL)") - - - def test_mysql_defaults(self): - """ - Test MySQL default handling for BLOB and TEXT. - """ - db.create_table("test_altermyd", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.TextField()), - ]) - # Change eggs to be a FloatField - db.alter_column("test_altermyd", "eggs", models.TextField(null=True)) - db.delete_table("test_altermyd") - - def test_alter_column_postgres_multiword(self): - """ - Tests altering columns with multiple words in Postgres types (issue #125) - e.g. 'datetime with time zone', look at django/db/backends/postgresql/creation.py - """ - db.create_table("test_multiword", [ - ('col_datetime', models.DateTimeField(null=True)), - ('col_integer', models.PositiveIntegerField(null=True)), - ('col_smallint', models.PositiveSmallIntegerField(null=True)), - ('col_float', models.FloatField(null=True)), - ]) - - # test if 'double precision' is preserved - db.alter_column('test_multiword', 'col_float', models.FloatField('float', null=True)) - - # test if 'CHECK ("%(column)s" >= 0)' is stripped - db.alter_column('test_multiword', 'col_integer', models.PositiveIntegerField(null=True)) - db.alter_column('test_multiword', 'col_smallint', models.PositiveSmallIntegerField(null=True)) - - # test if 'with timezone' is preserved - if db.backend_name == "postgres": - db.execute("INSERT INTO test_multiword (col_datetime) VALUES ('2009-04-24 14:20:55+02')") - db.alter_column('test_multiword', 'col_datetime', models.DateTimeField(auto_now=True)) - assert db.execute("SELECT col_datetime = '2009-04-24 14:20:55+02' FROM test_multiword")[0][0] - - db.delete_table("test_multiword") - - @skipUnless(db.has_check_constraints, 'Only applies to databases that ' - 'support CHECK constraints.') - def test_alter_constraints(self): - """ - Tests that going from a PostiveIntegerField to an IntegerField drops - the constraint on the database. - """ - # Make the test table - db.create_table("test_alterc", [ - ('num', models.PositiveIntegerField()), - ]) - db.execute_deferred_sql() - # Add in some test values - db.execute("INSERT INTO test_alterc (num) VALUES (1)") - db.execute("INSERT INTO test_alterc (num) VALUES (2)") - # Ensure that adding a negative number is bad - db.commit_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alterc (num) VALUES (-3)") - except: - db.rollback_transaction() - else: - self.fail("Could insert a negative integer into a PositiveIntegerField.") - # Alter it to a normal IntegerField - db.alter_column("test_alterc", "num", models.IntegerField()) - db.execute_deferred_sql() - # It should now work - db.execute("INSERT INTO test_alterc (num) VALUES (-3)") - db.delete_table("test_alterc") - # We need to match up for tearDown - db.start_transaction() - - @skipIf(db.backend_name == "sqlite3", "SQLite backend doesn't support this " - "yet.") - def test_unique(self): - """ - Tests creating/deleting unique constraints. - """ - db.create_table("test_unique2", [ - ('id', models.AutoField(primary_key=True)), - ]) - db.create_table("test_unique", [ - ('spam', models.BooleanField(default=False)), - ('eggs', models.IntegerField()), - ('ham', models.ForeignKey(db.mock_model('Unique2', 'test_unique2'))), - ]) - db.execute_deferred_sql() - # Add a constraint - db.create_unique("test_unique", ["spam"]) - db.execute_deferred_sql() - # Shouldn't do anything during dry-run - db.dry_run = True - db.delete_unique("test_unique", ["spam"]) - db.dry_run = False - db.delete_unique("test_unique", ["spam"]) - db.create_unique("test_unique", ["spam"]) - # Special preparations for Sql Server - if db.backend_name == "pyodbc": - db.execute("SET IDENTITY_INSERT test_unique2 ON;") - db.execute("INSERT INTO test_unique2 (id) VALUES (1)") - db.execute("INSERT INTO test_unique2 (id) VALUES (2)") - db.commit_transaction() - db.start_transaction() - - - # Test it works - TRUE = (True,) - FALSE = (False,) - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 0, 1)", TRUE) - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 1, 2)", FALSE) - try: - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 2, 1)", FALSE) - except: - db.rollback_transaction() - else: - self.fail("Could insert non-unique item.") - - # Drop that, add one only on eggs - db.delete_unique("test_unique", ["spam"]) - db.execute("DELETE FROM test_unique") - db.create_unique("test_unique", ["eggs"]) - db.start_transaction() - - # Test similarly - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 0, 1)", TRUE) - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 1, 2)", FALSE) - try: - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 1, 1)", TRUE) - except: - db.rollback_transaction() - else: - self.fail("Could insert non-unique item.") - - # Drop those, test combined constraints - db.delete_unique("test_unique", ["eggs"]) - db.execute("DELETE FROM test_unique") - db.create_unique("test_unique", ["spam", "eggs", "ham_id"]) - db.start_transaction() - # Test similarly - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 0, 1)", TRUE) - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 1, 1)", FALSE) - try: - db.execute("INSERT INTO test_unique (spam, eggs, ham_id) VALUES (%s, 0, 1)", TRUE) - except: - db.rollback_transaction() - else: - self.fail("Could insert non-unique pair.") - db.delete_unique("test_unique", ["spam", "eggs", "ham_id"]) - db.start_transaction() - - def test_alter_unique(self): - """ - Tests that unique constraints are not affected when - altering columns (that's handled by create_/delete_unique) - """ - db.create_table("test_alter_unique", [ - ('spam', models.IntegerField()), - ('eggs', models.IntegerField(unique=True)), - ]) - db.execute_deferred_sql() - - # Make sure the unique constraint is created - db.execute('INSERT INTO test_alter_unique (spam, eggs) VALUES (0, 42)') - db.commit_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique (spam, eggs) VALUES (1, 42)") - except: - pass - else: - self.fail("Could insert the same integer twice into a unique field.") - db.rollback_transaction() - - # Alter without unique=True (should not affect anything) - db.alter_column("test_alter_unique", "eggs", models.IntegerField()) - - # Insertion should still fail - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique (spam, eggs) VALUES (1, 42)") - except: - pass - else: - self.fail("Could insert the same integer twice into a unique field after alter_column with unique=False.") - db.rollback_transaction() - - # Delete the unique index/constraint - if db.backend_name != "sqlite3": - db.delete_unique("test_alter_unique", ["eggs"]) - db.delete_table("test_alter_unique") - db.start_transaction() - - # Test multi-field constraint - db.create_table("test_alter_unique2", [ - ('spam', models.IntegerField()), - ('eggs', models.IntegerField()), - ]) - db.create_unique('test_alter_unique2', ('spam', 'eggs')) - db.execute_deferred_sql() - db.execute('INSERT INTO test_alter_unique2 (spam, eggs) VALUES (0, 42)') - db.commit_transaction() - # Verify that constraint works - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (1, 42)") - except: - self.fail("Looks like multi-field unique constraint applied to only one field.") - db.rollback_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (0, 43)") - except: - self.fail("Looks like multi-field unique constraint applied to only one field.") - db.rollback_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (0, 42)") - except: - pass - else: - self.fail("Could insert the same pair twice into unique-together fields.") - db.rollback_transaction() - # Altering one column should not drop or modify multi-column constraint - db.alter_column("test_alter_unique2", "eggs", models.PositiveIntegerField()) - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (1, 42)") - except: - self.fail("Altering one column broken multi-column unique constraint.") - db.rollback_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (0, 43)") - except: - self.fail("Altering one column broken multi-column unique constraint.") - db.rollback_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_alter_unique2 (spam, eggs) VALUES (0, 42)") - except: - pass - else: - self.fail("Could insert the same pair twice into unique-together fields after alter_column with unique=False.") - db.rollback_transaction() - db.delete_table("test_alter_unique2") - db.start_transaction() - - def test_capitalised_constraints(self): - """ - Under PostgreSQL at least, capitalised constraints must be quoted. - """ - db.create_table("test_capconst", [ - ('SOMECOL', models.PositiveIntegerField(primary_key=True)), - ]) - # Alter it so it's not got the check constraint - db.alter_column("test_capconst", "SOMECOL", models.IntegerField()) - - def test_text_default(self): - """ - MySQL cannot have blank defaults on TEXT columns. - """ - db.create_table("test_textdef", [ - ('textcol', models.TextField(blank=True)), - ]) - - def test_text_to_char(self): - """ - On Oracle, you can't simply ALTER TABLE MODIFY a textfield to a charfield - """ - value = "kawabanga" - db.create_table("test_text_to_char", [ - ('textcol', models.TextField()), - ]) - db.execute_deferred_sql() - db.execute("INSERT INTO test_text_to_char VALUES (%s)", [value]) - db.alter_column("test_text_to_char", "textcol", models.CharField(max_length=100)) - db.execute_deferred_sql() - after = db.execute("select * from test_text_to_char")[0][0] - self.assertEqual(value, after, "Change from text to char altered value [ %r != %r ]" % (value, after)) - - def test_char_to_text(self): - """ - On Oracle, you can't simply ALTER TABLE MODIFY a charfield to a textfield either - """ - value = "agnabawak" - db.create_table("test_char_to_text", [ - ('textcol', models.CharField(max_length=100)), - ]) - db.execute_deferred_sql() - db.execute("INSERT INTO test_char_to_text VALUES (%s)", [value]) - db.alter_column("test_char_to_text", "textcol", models.TextField()) - db.execute_deferred_sql() - after = db.execute("select * from test_char_to_text")[0][0] - after = text_type(after) # Oracle text fields return a sort of lazy string -- force evaluation - self.assertEqual(value, after, "Change from char to text altered value [ %r != %r ]" % (value, after)) - - @skipUnless(db.raises_default_errors, 'This database does not raise errors on missing defaults.') - def test_datetime_default(self): - """ - Test that defaults are correctly not created for datetime columns - """ - end_of_world = datetime.datetime(2012, 12, 21, 0, 0, 1) - - try: - from django.utils import timezone - except ImportError: - pass - else: - from django.conf import settings - if getattr(settings, 'USE_TZ', False): - end_of_world = end_of_world.replace(tzinfo=timezone.utc) - - db.create_table("test_datetime_def", [ - ('col0', models.IntegerField(null=True)), - ('col1', models.DateTimeField(default=end_of_world)), - ('col2', models.DateTimeField(null=True)), - ]) - db.execute_deferred_sql() - # insert a row - db.execute("INSERT INTO test_datetime_def (col0, col1, col2) values (null,%s,null)", [end_of_world]) - db.alter_column("test_datetime_def", "col2", models.DateTimeField(default=end_of_world)) - db.add_column("test_datetime_def", "col3", models.DateTimeField(default=end_of_world)) - db.execute_deferred_sql() - db.commit_transaction() - # In the single existing row, we now expect col1=col2=col3=end_of_world... - db.start_transaction() - ends = db.execute("select col1,col2,col3 from test_datetime_def")[0] - self.failUnlessEqual(len(ends), 3) - for e in ends: - self.failUnlessEqual(e, end_of_world) - db.commit_transaction() - # ...but there should not be a default in the database for col1 or col3 - for cols in ["col1,col2", "col2,col3"]: - db.start_transaction() - statement = "insert into test_datetime_def (col0,%s) values (null,%%s,%%s)" % cols - self.assertRaises( - IntegrityError, - db.execute, statement, [end_of_world, end_of_world] - ) - db.rollback_transaction() - - db.start_transaction() # To preserve the sanity and semantics of this test class - - def test_add_unique_fk(self): - """ - Test adding a ForeignKey with unique=True or a OneToOneField - """ - db.create_table("test_add_unique_fk", [ - ('spam', models.BooleanField(default=False)) - ]) - - db.add_column("test_add_unique_fk", "mock1", models.ForeignKey(db.mock_model('User', 'auth_user'), null=True, unique=True)) - db.add_column("test_add_unique_fk", "mock2", models.OneToOneField(db.mock_model('User', 'auth_user'), null=True)) - db.execute_deferred_sql() - - db.delete_table("test_add_unique_fk") - - @skipUnless(db.has_check_constraints, 'Only applies to databases that ' - 'support CHECK constraints.') - def test_column_constraint(self): - """ - Tests that the value constraint of PositiveIntegerField is enforced on - the database level. - """ - db.create_table("test_column_constraint", [ - ('spam', models.PositiveIntegerField()), - ]) - db.execute_deferred_sql() - - # Make sure we can't insert negative values - db.commit_transaction() - db.start_transaction() - try: - db.execute("INSERT INTO test_column_constraint VALUES (-42)") - except: - pass - else: - self.fail("Could insert a negative value into a PositiveIntegerField.") - db.rollback_transaction() - - # remove constraint - db.alter_column("test_column_constraint", "spam", models.IntegerField()) - db.execute_deferred_sql() - # make sure the insertion works now - db.execute('INSERT INTO test_column_constraint VALUES (-42)') - db.execute('DELETE FROM test_column_constraint') - - # add it back again - db.alter_column("test_column_constraint", "spam", models.PositiveIntegerField()) - db.execute_deferred_sql() - # it should fail again - db.start_transaction() - try: - db.execute("INSERT INTO test_column_constraint VALUES (-42)") - except: - pass - else: - self.fail("Could insert a negative value after changing an IntegerField to a PositiveIntegerField.") - db.rollback_transaction() - - db.delete_table("test_column_constraint") - db.start_transaction() - - def test_sql_defaults(self): - """ - Test that sql default value is correct for non-string field types. - Datetimes are handled in test_datetime_default. - """ - - class CustomField(with_metaclass(models.SubfieldBase, models.CharField)): - description = 'CustomField' - def get_default(self): - if self.has_default(): - if callable(self.default): - return self.default() - return self.default - return super(CustomField, self).get_default() - def get_prep_value(self, value): - if not value: - return value - return ','.join(map(str, value)) - def to_python(self, value): - if not value or isinstance(value, list): - return value - return list(map(int, value.split(','))) - - false_value = db.has_booleans and 'False' or '0' - defaults = ( - (models.CharField(default='sukasuka'), 'DEFAULT \'sukasuka'), - (models.BooleanField(default=False), 'DEFAULT %s' % false_value), - (models.IntegerField(default=42), 'DEFAULT 42'), - (CustomField(default=[2012, 2018, 2021, 2036]), 'DEFAULT \'2012,2018,2021,2036') - ) - for field, sql_test_str in defaults: - sql = db.column_sql('fish', 'YAAAAAAZ', field) - if sql_test_str not in sql: - self.fail("default sql value was not properly generated for field %r.\nSql was %s" % (field, sql)) - - def test_make_added_foreign_key_not_null(self): - # Table for FK to target - User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - # Table with no foreign key - db.create_table("test_fk", [ - ('eggs', models.IntegerField()), - ]) - db.execute_deferred_sql() - - # Add foreign key - db.add_column("test_fk", 'foreik', models.ForeignKey(User, null=True)) - db.execute_deferred_sql() - - # Make the FK not null - db.alter_column("test_fk", "foreik_id", models.ForeignKey(User)) - db.execute_deferred_sql() - - def test_make_foreign_key_null(self): - # Table for FK to target - User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - # Table with no foreign key - db.create_table("test_make_fk_null", [ - ('eggs', models.IntegerField()), - ('foreik', models.ForeignKey(User)) - ]) - db.execute_deferred_sql() - - # Make the FK null - db.alter_column("test_make_fk_null", "foreik_id", models.ForeignKey(User, null=True)) - db.execute_deferred_sql() - - def test_change_foreign_key_target(self): - # Tables for FK to target - User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - db.create_table("test_fk_changed_target", [ - ('eggs', models.IntegerField(primary_key=True)), - ]) - Egg = db.mock_model(model_name='Egg', db_table='test_fk_changed_target', db_tablespace='', pk_field_name='eggs', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - # Table with a foreign key to the wrong table - db.create_table("test_fk_changing", [ - ('egg', models.ForeignKey(User, null=True)), - ]) - db.execute_deferred_sql() - - # Change foreign key pointing - db.alter_column("test_fk_changing", "egg_id", models.ForeignKey(Egg, null=True)) - db.execute_deferred_sql() - - # Test that it is pointing at the right table now - try: - non_user_id = db.execute("SELECT MAX(id) FROM auth_user")[0][0] + 1 - except (TypeError, IndexError): - # Got a "None" or no records, treat as 0 - non_user_id = 17 - db.execute("INSERT INTO test_fk_changed_target (eggs) VALUES (%s)", [non_user_id]) - db.execute("INSERT INTO test_fk_changing (egg_id) VALUES (%s)", [non_user_id]) - db.commit_transaction() - db.start_transaction() # The test framework expects tests to end in transaction - - def test_alter_double_indexed_column(self): - # Table for FK to target - User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={}) - # Table with no foreign key - db.create_table("test_2indexed", [ - ('eggs', models.IntegerField()), - ('foreik', models.ForeignKey(User)) - ]) - db.create_unique("test_2indexed", ["eggs", "foreik_id"]) - db.execute_deferred_sql() - - # Make the FK null - db.alter_column("test_2indexed", "foreik_id", models.ForeignKey(User, null=True)) - db.execute_deferred_sql() - -class TestCacheGeneric(unittest.TestCase): - base_ops_cls = generic.DatabaseOperations - def setUp(self): - class CacheOps(self.base_ops_cls): - def __init__(self): - self._constraint_cache = {} - self.cache_filled = 0 - self.settings = {'NAME': 'db'} - - def _fill_constraint_cache(self, db, table): - self.cache_filled += 1 - self._constraint_cache.setdefault(db, {}) - self._constraint_cache[db].setdefault(table, {}) - - @generic.invalidate_table_constraints - def clear_con(self, table): - pass - - @generic.copy_column_constraints - def cp_column(self, table, column_old, column_new): - pass - - @generic.delete_column_constraints - def rm_column(self, table, column): - pass - - @generic.copy_column_constraints - @generic.delete_column_constraints - def mv_column(self, table, column_old, column_new): - pass - - def _get_setting(self, attr): - return self.settings[attr] - self.CacheOps = CacheOps - - def test_cache(self): - ops = self.CacheOps() - self.assertEqual(0, ops.cache_filled) - self.assertFalse(ops.lookup_constraint('db', 'table')) - self.assertEqual(1, ops.cache_filled) - self.assertFalse(ops.lookup_constraint('db', 'table')) - self.assertEqual(1, ops.cache_filled) - ops.clear_con('table') - self.assertEqual(1, ops.cache_filled) - self.assertFalse(ops.lookup_constraint('db', 'table')) - self.assertEqual(2, ops.cache_filled) - self.assertFalse(ops.lookup_constraint('db', 'table', 'column')) - self.assertEqual(2, ops.cache_filled) - - cache = ops._constraint_cache - cache['db']['table']['column'] = 'constraint' - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - self.assertEqual([('column', 'constraint')], ops.lookup_constraint('db', 'table')) - self.assertEqual(2, ops.cache_filled) - - # invalidate_table_constraints - ops.clear_con('new_table') - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - self.assertEqual(2, ops.cache_filled) - - self.assertFalse(ops.lookup_constraint('db', 'new_table')) - self.assertEqual(3, ops.cache_filled) - - # delete_column_constraints - cache['db']['table']['column'] = 'constraint' - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - ops.rm_column('table', 'column') - self.assertEqual([], ops.lookup_constraint('db', 'table', 'column')) - self.assertEqual([], ops.lookup_constraint('db', 'table', 'noexist_column')) - - # copy_column_constraints - cache['db']['table']['column'] = 'constraint' - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - ops.cp_column('table', 'column', 'column_new') - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column_new')) - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - - # copy + delete - cache['db']['table']['column'] = 'constraint' - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column')) - ops.mv_column('table', 'column', 'column_new') - self.assertEqual('constraint', ops.lookup_constraint('db', 'table', 'column_new')) - self.assertEqual([], ops.lookup_constraint('db', 'table', 'column')) - - def test_valid(self): - ops = self.CacheOps() - # none of these should vivify a table into a valid state - self.assertFalse(ops._is_valid_cache('db', 'table')) - self.assertFalse(ops._is_valid_cache('db', 'table')) - ops.clear_con('table') - self.assertFalse(ops._is_valid_cache('db', 'table')) - ops.rm_column('table', 'column') - self.assertFalse(ops._is_valid_cache('db', 'table')) - - # these should change the cache state - ops.lookup_constraint('db', 'table') - self.assertTrue(ops._is_valid_cache('db', 'table')) - ops.lookup_constraint('db', 'table', 'column') - self.assertTrue(ops._is_valid_cache('db', 'table')) - ops.clear_con('table') - self.assertFalse(ops._is_valid_cache('db', 'table')) - - def test_valid_implementation(self): - # generic fills the cache on a per-table basis - ops = self.CacheOps() - self.assertFalse(ops._is_valid_cache('db', 'table')) - self.assertFalse(ops._is_valid_cache('db', 'other_table')) - ops.lookup_constraint('db', 'table') - self.assertTrue(ops._is_valid_cache('db', 'table')) - self.assertFalse(ops._is_valid_cache('db', 'other_table')) - ops.lookup_constraint('db', 'other_table') - self.assertTrue(ops._is_valid_cache('db', 'table')) - self.assertTrue(ops._is_valid_cache('db', 'other_table')) - ops.clear_con('table') - self.assertFalse(ops._is_valid_cache('db', 'table')) - self.assertTrue(ops._is_valid_cache('db', 'other_table')) - -if mysql: - class TestCacheMysql(TestCacheGeneric): - base_ops_cls = mysql.DatabaseOperations - - def test_valid_implementation(self): - # mysql fills the cache on a per-db basis - ops = self.CacheOps() - self.assertFalse(ops._is_valid_cache('db', 'table')) - self.assertFalse(ops._is_valid_cache('db', 'other_table')) - ops.lookup_constraint('db', 'table') - self.assertTrue(ops._is_valid_cache('db', 'table')) - self.assertTrue(ops._is_valid_cache('db', 'other_table')) - ops.lookup_constraint('db', 'other_table') - self.assertTrue(ops._is_valid_cache('db', 'table')) - self.assertTrue(ops._is_valid_cache('db', 'other_table')) - ops.clear_con('table') - self.assertFalse(ops._is_valid_cache('db', 'table')) - self.assertTrue(ops._is_valid_cache('db', 'other_table')) |