Repository: googleapis/python-spanner-django

Issue:
ci: audit Django test apps
I'm auditing the list of Django test apps in `.travis.yml`. CI is running many which are unnecessary (no database interaction). Also, some folders in django/tests don't include any tests.

- [x] absolute_url_overrides (no database interaction)
- [x] admin_autodiscover (no database interaction)
- [x] admin_changelist
- [x] admin_checks (no database interaction)
- [x] admin_custom_urls (no database interaction)
- [x] admin_default_site (no database interaction)
- [x] admin_docs
- [x] admin_filters
- [x] admin_inlines
- [x] admin_ordering
- [x] admin_registration (no database interaction)
- [x] admin_scripts (no database interaction)
- [X] admin_utils (https://github.com/orijtech/django-spanner/issues/150)
- [x] admin_views
- [x] admin_widgets (unlikely to add test coverage)
- [x] aggregation
- [x] aggregation_regress
- [x] annotations
- [x] app_loading (no database interaction)
- [x] apps (no database interaction)
- [x] auth_tests
- [x] backends (https://github.com/orijtech/django-spanner/issues/318)
- [x] base (no tests)
- [x] bash_completion (no database interaction)
- [x] basic
- [x] builtin_server (no database interaction)
- [x] bulk_create
- [x] cache
- [x] check_framework (no database interaction)
- [x] choices
- [x] conditional_processing (no database interaction)
- [x] constraints
- [x] contenttypes_tests (#396)
- [x] context_processors (no database interaction)
- [x] csrf_tests (no database interaction)
- [x] custom_columns
- [x] custom_lookups
- [x] custom_managers
- [x] custom_methods
- [x] custom_migration_operations (no tests)
- [x] custom_pk
- [x] datatypes
- [x] dates
- [x] datetimes
- [x] db_functions
- [x] dbshell (no database interaction)
- [x] db_typecasts (no database interaction)
- [x] db_utils (no database interaction)
- [x] decorators (no database interaction)
- [x] defer
- [x] defer_regress
- [x] delete
- [x] delete_regress
- [x] deprecation (no database interaction)
- [x] dispatch (no database interaction)
- [x] distinct_on_fields
- [x] empty
- [x] expressions
- [x] expressions_case (https://github.com/orijtech/django-spanner/issues/353)
- [x] expressions_window
- [x] extra_regress
- [x] field_deconstruction (no database interaction)
- [x] field_defaults
- [x] field_subclassing (no database interaction)
- [x] files (no database interaction)
- [x] file_storage
- [x] file_uploads
- [x] filtered_relation
- [x] fixtures
- [x] fixtures_model_package
- [x] fixtures_regress
- [x] flatpages_tests
- [x] force_insert_update (https://github.com/googleapis/python-spanner-django/issues/420)
- [x] foreign_object (https://github.com/googleapis/python-spanner-django/issues/421)
- [x] forms_tests
- [x] from_db_value
- [x] generic_inline_admin
- [x] generic_relations
- [x] generic_relations_regress
- [x] generic_views
- [x] get_earliest_or_latest
- [x] get_object_or_404
- [X] get_or_create (#270)
- [x] gis_tests (not applicable)
- [x] handlers (no database interaction)
- [x] httpwrappers (no database interaction)
- [x] humanize_tests (no database interaction)
- [x] i18n
- [x] import_error_package (no tests)
- [x] indexes
- [x] inline_formsets
- [x] inspectdb
- [x] introspection
- [x] invalid_models_tests
- [x] known_related_objects
- [x] logging_tests (no database interaction)
- [x] lookup
- [x] m2m_and_m2o
- [x] m2m_intermediary
- [x] m2m_multiple
- [x] m2m_recursive
- [x] m2m_regress
- [x] m2m_signals
- [x] m2m_through
- [x] m2m_through_regress
- [x] m2o_recursive
- [x] mail  (no database interaction)
- [x] managers_regress
- [x] many_to_many
- [x] many_to_one
- [x] many_to_one_null
- [x] max_lengths
- [x] messages_tests (no database interaction)
- [x] middleware (no database interaction)
- [x] middleware_exceptions (no database interaction)
- [x] migrate_signals
- [x] migrations
- [x] migrations2 (no tests)
- [x] migration_test_data_persistence
- [x] modeladmin
- [x] model_fields
- [x] model_forms
- [x] model_formsets
- [x] model_formsets_regress
- [x] model_indexes
- [x] model_inheritance
- [x] model_inheritance_regress
- [x] model_meta (no database interaction)
- [x] model_options
- [x] model_package
- [x] model_regress
- [x] multiple_database
- [x] mutually_referential
- [x] nested_foreign_keys
- [x] no_models (no database interaction)
- [x] null_fk
- [x] null_fk_ordering
- [x] null_queries
- [x] one_to_one
- [x] ordering
- [x] order_with_respect_to (#396)
- [x] or_lookups
- [x] pagination (all tests assume ordering by a serial pk)
- [x] postgres_tests (not applicable)
- [x] prefetch_related
- [x] project_template (no database interaction)
- [x] properties (no database interaction)
- [x] proxy_model_inheritance
- [x] proxy_models
- [x] queries
- [x] queryset_pickle
- [x] raw_query
- [x] redirects_tests
- [x] requests_ (no database interaction)
- [x] requirements (no tests)
- [x] reserved_names
- [x] resolve_url (no database interaction)
- [x] responses (no database interaction)
- [x] reverse_lookup
- [x] save_delete_hooks
- [x] schema
- [x] select_for_update
- [x] select_related
- [x] select_related_onetoone
- [x] select_related_regress
- [x] serializers
- [x] servers
- [X] sessions_tests (https://github.com/orijtech/django-spanner/pull/395)
- [x] settings_tests (no database interaction)
- [x] shell (no database interaction)
- [x] shortcuts (no database interaction)
- [x] signals
- [x] signed_cookies_tests (no database interaction)
- [x] signing (no database interaction)
- [x] sitemaps_tests
- [x] sites_framework
- [x] sites_tests
- [x] staticfiles_tests (no database interaction)
- [x] str (no database interaction)
- [x] string_lookup
- [x] swappable_models (no database interaction)
- [x] syndication_tests
- [x] template_backends (no database interaction)
- [x] template_loader (no database interaction)
- [x] templates (no tests)
- [x] template_tests (no database interaction)
- [x] test_client
- [x] test_client_regress
- [x] test_exceptions (no database interaction)
- [x] test_runner
- [x] test_runner_apps (no tests)
- [x] test_utils
- [x] timezones
- [x] transaction_hooks
- [x] transactions
- [x] unmanaged_models
- [x] update
- [x] update_only_fields
- [x] urlpatterns (no database interaction)
- [x] urlpatterns_reverse (no database interaction)
- [x] user_commands (no database interaction)
- [x] utils_tests (no database interaction)
- [x] validation
- [x] validators (no database interaction)
- [x] version (no database interaction)
- [x] view_tests
- [x] wsgi (no database interaction)


Discussion:

Resolving patch:
diff --git a/django_spanner/features.py b/django_spanner/features.py
--- a/django_spanner/features.py
+++ b/django_spanner/features.py
@@ -13,6 +13,10 @@
 class DatabaseFeatures(BaseDatabaseFeatures):
     can_introspect_big_integer_field = False
     can_introspect_duration_field = False
+    can_introspect_foreign_keys = False
+    # TimeField is introspected as DateTimeField because they both use
+    # TIMESTAMP.
+    can_introspect_time_field = False
     closed_cursor_error_class = InterfaceError
     # Spanner uses REGEXP_CONTAINS which is case-sensitive.
     has_case_insensitive_like = False
@@ -22,6 +26,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     supports_ignore_conflicts = False
     supports_partial_indexes = False
     supports_regex_backreferencing = False
+    supports_select_for_update_with_limit = False
+    supports_sequence_reset = False
     supports_timezones = False
     supports_transactions = False
     supports_column_check_constraints = False
@@ -37,6 +43,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'basic.tests.SelectOnSaveTests.test_select_on_save_lying_update',
         # django_spanner monkey patches AutoField to have a default value.
         'basic.tests.ModelTest.test_hash',
+        'generic_relations.test_forms.GenericInlineFormsetTests.test_options',
+        'generic_relations.tests.GenericRelationsTests.test_unsaved_instance_on_generic_foreign_key',
+        'generic_relations_regress.tests.GenericRelationTests.test_target_model_is_unsaved',
         'm2m_through_regress.tests.ToFieldThroughTests.test_m2m_relations_unusable_on_null_pk_obj',
         'many_to_many.tests.ManyToManyTests.test_add',
         'many_to_one.tests.ManyToOneTests.test_fk_assignment_and_related_object_cache',
@@ -44,14 +53,18 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'model_fields.test_durationfield.TestSerialization.test_dumping',
         'model_fields.test_uuid.TestSerialization.test_dumping',
         'model_fields.test_booleanfield.ValidationTest.test_nullbooleanfield_blank',
+        'model_inheritance.tests.ModelInheritanceTests.test_create_child_no_update',
+        'model_regress.tests.ModelTests.test_get_next_prev_by_field_unsaved',
         'one_to_one.tests.OneToOneTests.test_get_reverse_on_unsaved_object',
         'one_to_one.tests.OneToOneTests.test_set_reverse_on_unsaved_object',
         'one_to_one.tests.OneToOneTests.test_unsaved_object',
         'queries.test_bulk_update.BulkUpdateNoteTests.test_unsaved_models',
         'serializers.test_json.JsonSerializerTestCase.test_pkless_serialized_strings',
         'serializers.test_json.JsonSerializerTestCase.test_serialize_with_null_pk',
-        'serializers.test_json.JsonSerializerTestCase.test_json_serializer_natural_keys',
-        'serializers.test_json.JsonSerializerTestCase.test_python_serializer_natural_keys',
+        'serializers.test_xml.XmlSerializerTestCase.test_pkless_serialized_strings',
+        'serializers.test_xml.XmlSerializerTestCase.test_serialize_with_null_pk',
+        'serializers.test_yaml.YamlSerializerTestCase.test_pkless_serialized_strings',
+        'serializers.test_yaml.YamlSerializerTestCase.test_serialize_with_null_pk',
         'timezones.tests.LegacyDatabaseTests.test_cursor_execute_accepts_naive_datetime',
         'timezones.tests.NewDatabaseTests.test_cursor_execute_accepts_naive_datetime',
         'validation.test_custom_messages.CustomMessagesTests.test_custom_null_message',
@@ -88,6 +101,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'aggregation_regress.tests.AggregationTests.test_ticket_11293',
         'defer_regress.tests.DeferRegressionTest.test_ticket_23270',
         'distinct_on_fields.tests.DistinctOnTests.test_basic_distinct_on',
+        'extra_regress.tests.ExtraRegressTests.test_regression_7314_7372',
         'generic_relations_regress.tests.GenericRelationTests.test_annotate',
         'get_earliest_or_latest.tests.TestFirstLast',
         'known_related_objects.tests.ExistingRelatedInstancesTests.test_reverse_one_to_one_multi_prefetch_related',
@@ -96,12 +110,19 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'lookup.tests.LookupTests.test_values_list',
         'migrations.test_operations.OperationTests.test_alter_order_with_respect_to',
         'model_fields.tests.GetChoicesOrderingTests.test_get_choices_reverse_related_field',
+        'model_formsets.tests.ModelFormsetTest.test_custom_pk',
         'model_formsets_regress.tests.FormfieldShouldDeleteFormTests.test_custom_delete',
         'multiple_database.tests.RouterTestCase.test_generic_key_cross_database_protection',
         'ordering.tests.OrderingTests.test_default_ordering_by_f_expression',
         'ordering.tests.OrderingTests.test_order_by_fk_attname',
         'ordering.tests.OrderingTests.test_order_by_override',
         'ordering.tests.OrderingTests.test_order_by_pk',
+        'prefetch_related.test_prefetch_related_objects.PrefetchRelatedObjectsTests.test_m2m_then_m2m',
+        'prefetch_related.tests.CustomPrefetchTests.test_custom_qs',
+        'prefetch_related.tests.CustomPrefetchTests.test_nested_prefetch_related_are_not_overwritten',
+        'prefetch_related.tests.DirectPrefechedObjectCacheReuseTests.test_detect_is_fetched',
+        'prefetch_related.tests.DirectPrefechedObjectCacheReuseTests.test_detect_is_fetched_with_to_attr',
+        'prefetch_related.tests.ForeignKeyToFieldTest.test_m2m',
         'queries.test_bulk_update.BulkUpdateNoteTests.test_multiple_fields',
         'queries.test_bulk_update.BulkUpdateTests.test_inherited_fields',
         'queries.tests.Queries1Tests.test_ticket9411',
@@ -136,6 +157,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'model_fields.test_decimalfield.DecimalFieldTests.test_roundtrip_with_trailing_zeros',
         # No CHECK constraints in Spanner.
         'model_fields.test_integerfield.PositiveIntegerFieldTests.test_negative_values',
+        # contains lookup crashes with bilateral transform:
+        # https://github.com/googleapis/python-spanner-django/issues/419
+        'custom_lookups.tests.BilateralTransformTests.test_bilateral_upper',
         # Spanner doesn't support the variance the standard deviation database
         # functions:
         'aggregation.test_filter_argument.FilteredAggregateTests.test_filtered_numerical_aggregates',
@@ -156,6 +180,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'expressions.tests.FTimeDeltaTests.test_delta_add',
         'expressions.tests.FTimeDeltaTests.test_duration_with_datetime',
         'expressions.tests.FTimeDeltaTests.test_mixed_comparisons2',
+        # This test doesn't raise NotSupportedError because Spanner doesn't
+        # support select for update either (besides the "with limit"
+        # restriction).
+        'select_for_update.tests.SelectForUpdateTests.test_unsupported_select_for_update_with_limit',
         # integer division produces a float result, which can't be assigned to
         # an integer column:
         # https://github.com/orijtech/django-spanner/issues/331
@@ -186,19 +214,32 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         # casting DateField to DateTimeField adds an unexpected hour:
         # https://github.com/orijtech/spanner-orm/issues/260
         'db_functions.comparison.test_cast.CastTests.test_cast_from_db_date_to_datetime',
-        # Obscure error with auth_tests:
-        # https://github.com/orijtech/spanner-orm/issues/271
+        # Tests that fail during tear down on databases that don't support
+        # transactions: https://github.com/orijtech/spanner-orm/issues/271
+        'admin_views.test_multidb.MultiDatabaseTests.test_add_view',
+        'admin_views.test_multidb.MultiDatabaseTests.test_change_view',
+        'admin_views.test_multidb.MultiDatabaseTests.test_delete_view',
         'auth_tests.test_admin_multidb.MultiDatabaseTests.test_add_view',
+        'contenttypes_tests.test_models.ContentTypesMultidbTests.test_multidb',
         # Tests that by-pass using django_spanner and generate
         # invalid DDL: https://github.com/orijtech/django-spanner/issues/298
         'cache.tests.CreateCacheTableForDBCacheTests',
         'cache.tests.DBCacheTests',
         'cache.tests.DBCacheWithTimeZoneTests',
+        # Tests that require transactions.
+        'transaction_hooks.tests.TestConnectionOnCommit.test_does_not_execute_if_transaction_rolled_back',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_hooks_cleared_after_rollback',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_hooks_cleared_on_reconnect',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_no_hooks_run_from_failed_transaction',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_no_savepoints_atomic_merged_with_outer',
         # Tests that require savepoints.
         'get_or_create.tests.UpdateOrCreateTests.test_integrity',
         'get_or_create.tests.UpdateOrCreateTests.test_manual_primary_key_test',
         'get_or_create.tests.UpdateOrCreateTestsWithManualPKs.test_create_with_duplicate_primary_key',
         'test_utils.tests.TestBadSetUpTestData.test_failure_in_setUpTestData_should_rollback_transaction',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_discards_hooks_from_rolled_back_savepoint',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_rolled_back_with_outer',
+        'transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_does_not_affect_outer',
         # Spanner doesn't support views.
         'inspectdb.tests.InspectDBTransactionalTests.test_include_views',
         'introspection.tests.IntrospectionTests.test_table_names_with_views',
@@ -228,6 +269,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'schema.tests.SchemaTests.test_alter_text_field_to_datetime_field',
         'schema.tests.SchemaTests.test_alter_text_field_to_time_field',
         # Spanner limitation: Cannot rename tables and columns.
+        'contenttypes_tests.test_operations.ContentTypeOperationsTests',
         'migrations.test_operations.OperationTests.test_alter_fk_non_fk',
         'migrations.test_operations.OperationTests.test_alter_model_table',
         'migrations.test_operations.OperationTests.test_alter_model_table_m2m',
@@ -278,6 +320,14 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         # This test isn't isolated on databases like Spanner that don't
         # support transactions: https://code.djangoproject.com/ticket/31413
         'migrations.test_loader.LoaderTests.test_loading_squashed',
+        # Probably due to django-spanner setting a default on AutoField:
+        # https://github.com/googleapis/python-spanner-django/issues/422
+        'model_inheritance_regress.tests.ModelInheritanceTest.test_issue_6755',
+        # Probably due to django-spanner setting a default on AutoField:
+        # https://github.com/googleapis/python-spanner-django/issues/424
+        'model_formsets.tests.ModelFormsetTest.test_prevent_change_outer_model_and_create_invalid_data',
+        'model_formsets_regress.tests.FormfieldShouldDeleteFormTests.test_no_delete',
+        'model_formsets_regress.tests.FormsetTests.test_extraneous_query_is_not_run',
     )
     # Kokoro-specific skips.
     if os.environ.get('KOKORO_JOB_NAME'):
@@ -285,7 +335,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
             # os.chmod() doesn't work on Kokoro?
             'file_uploads.tests.DirectoryCreationTests.test_readonly_root',
             # Tests that sometimes fail on Kokoro for unknown reasons.
+            'contenttypes_tests.test_models.ContentTypesTests.test_cache_not_shared_between_managers',
             'migration_test_data_persistence.tests.MigrationDataNormalPersistenceTestCase.test_persistence',
+            'servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections',
         )
 
     if os.environ.get('SPANNER_EMULATOR_HOST', None):


Test patch:
diff --git a/django_test_apps.txt b/django_test_apps.txt
--- a/django_test_apps.txt
+++ b/django_test_apps.txt
@@ -1,8 +1,10 @@
 admin_changelist
-admin_custom_urls
 admin_docs
+admin_filters
 admin_inlines
 admin_ordering
+admin_utils
+admin_views
 aggregation
 aggregation_regress
 annotations
@@ -10,37 +12,52 @@ auth_tests
 backends
 basic
 bulk_create
+cache
 choices
+constraints
+contenttypes_tests
 custom_columns
-cache
+custom_lookups
+custom_managers
 custom_methods
 custom_pk
 datatypes
 dates
 datetimes
+db_functions
 defer
 defer_regress
+delete
 delete_regress
-db_functions
-db_utils
 distinct_on_fields
 empty
 expressions
+expressions_case
 expressions_window
+extra_regress
 field_defaults
-field_subclassing
 file_storage
 file_uploads
+filtered_relation
 fixtures
 fixtures_model_package
+fixtures_regress
+flatpages_tests
+force_insert_update
 foreign_object
+forms_tests
 from_db_value
+generic_inline_admin
+generic_relations
+generic_relations_regress
+generic_views
 get_earliest_or_latest
 get_object_or_404
 get_or_create
 i18n
 indexes
 inline_formsets
+inspectdb
 introspection
 invalid_models_tests
 known_related_objects
@@ -48,7 +65,6 @@ lookup
 m2m_and_m2o
 m2m_intermediary
 m2m_multiple
-max_lengths
 m2m_recursive
 m2m_regress
 m2m_signals
@@ -63,60 +79,60 @@ max_lengths
 migrate_signals
 migrations
 migration_test_data_persistence
-model_fields.test_binaryfield
-model_fields.test_booleanfield
-model_fields.test_charfield
-model_fields.test_datetimefield
-model_fields.test_decimalfield
-model_fields.test_durationfield
-model_fields.test_field_flags
-model_fields.test_filefield
-model_fields.test_floatfield
-model_fields.test_foreignkey
-model_fields.test_genericipaddressfield
-model_fields.test_imagefield
-model_fields.test_integerfield
-model_fields.test_manytomanyfield
-model_fields.test_promises
-model_fields.test_slugfield
-model_fields.test_textfield
-model_fields.test_uuid
 modeladmin
+model_fields
+model_forms
+model_formsets
+model_formsets_regress
+model_indexes
+model_inheritance
+model_inheritance_regress
+model_options
+model_package
+model_regress
 multiple_database
+mutually_referential
+nested_foreign_keys
 null_fk
 null_fk_ordering
 null_queries
 one_to_one
-or_lookups
 ordering
-queries.test_bulk_update
-queries.test_explain
-queries.test_iterator
-queries.test_q
-queries.test_qs_combinators
-queries.test_query
-queries.tests
-queries.tests.Queries5Tests.test_extra_select_literal_percent_s
+order_with_respect_to
+or_lookups
+prefetch_related
+proxy_model_inheritance
+proxy_models
+queries
+queryset_pickle
 raw_query
 redirects_tests
 reserved_names
 reverse_lookup
 save_delete_hooks
 schema
+select_for_update
 select_related
 select_related_onetoone
-signing
-sitemaps_tests
+select_related_regress
+serializers
+servers
 sessions_tests
 signals
+sitemaps_tests
+sites_framework
+sites_tests
 string_lookup
-test_utils
+syndication_tests
 test_client
 test_client_regress
+test_runner
+test_utils
 timezones
+transaction_hooks
 transactions
 unmanaged_models
-update_only_fields
 update
+update_only_fields
 validation
 view_tests