ibm_db 5.6.1 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/Makefile +13 -9
- data/ext/extconf.rb +176 -110
- data/ext/ibm_db.c +60 -0
- data/ext/ibm_db.o +0 -0
- data/ext/ibm_db.so +0 -0
- data/ext/mkmf.log +6 -6
- data/ext/ruby_ibm_db_cli.c +14 -10
- data/ext/ruby_ibm_db_cli.h +4 -0
- data/ext/ruby_ibm_db_cli.o +0 -0
- data/lib/IBM_DB.rb +2 -2
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
- data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
- data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
- data/test/activejob/destroy_association_async_job_test.rb +62 -0
- data/test/activejob/destroy_association_async_test.rb +147 -11
- data/test/activejob/job_runtime_test.rb +41 -0
- data/test/activejob/unloadable_base_job.rb +3 -0
- data/test/cases/active_record_schema_test.rb +196 -0
- data/test/cases/active_record_test.rb +21 -0
- data/test/cases/adapter_prevent_writes_test.rb +26 -202
- data/test/cases/adapter_test.rb +592 -82
- data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
- data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
- data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
- data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
- data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
- data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
- data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
- data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
- data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
- data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
- data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
- data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
- data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
- data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
- data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
- data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
- data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
- data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
- data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
- data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
- data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
- data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
- data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
- data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
- data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
- data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
- data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
- data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
- data/test/cases/adapters/postgresql/array_test.rb +6 -6
- data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
- data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
- data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
- data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
- data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
- data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
- data/test/cases/adapters/postgresql/citext_test.rb +7 -1
- data/test/cases/adapters/postgresql/collation_test.rb +1 -1
- data/test/cases/adapters/postgresql/composite_test.rb +1 -1
- data/test/cases/adapters/postgresql/connection_test.rb +43 -36
- data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
- data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
- data/test/cases/adapters/postgresql/date_test.rb +2 -2
- data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
- data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
- data/test/cases/adapters/postgresql/domain_test.rb +1 -1
- data/test/cases/adapters/postgresql/enum_test.rb +208 -8
- data/test/cases/adapters/postgresql/explain_test.rb +25 -6
- data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
- data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
- data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
- data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
- data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
- data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
- data/test/cases/adapters/postgresql/integer_test.rb +1 -1
- data/test/cases/adapters/postgresql/interval_test.rb +9 -17
- data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
- data/test/cases/adapters/postgresql/json_test.rb +5 -0
- data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
- data/test/cases/adapters/postgresql/money_test.rb +17 -9
- data/test/cases/adapters/postgresql/network_test.rb +13 -1
- data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
- data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
- data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
- data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
- data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
- data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
- data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
- data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
- data/test/cases/adapters/postgresql/range_test.rb +185 -21
- data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
- data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
- data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
- data/test/cases/adapters/postgresql/schema_test.rb +270 -20
- data/test/cases/adapters/postgresql/serial_test.rb +5 -5
- data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
- data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
- data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
- data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
- data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
- data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
- data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
- data/test/cases/adapters/postgresql/xml_test.rb +1 -1
- data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
- data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
- data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
- data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
- data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
- data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
- data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
- data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
- data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
- data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
- data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
- data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
- data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
- data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
- data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
- data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
- data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
- data/test/cases/aggregations_test.rb +16 -0
- data/test/cases/annotate_test.rb +14 -12
- data/test/cases/arel/attributes/attribute_test.rb +86 -47
- data/test/cases/arel/collectors/bind_test.rb +1 -1
- data/test/cases/arel/collectors/composite_test.rb +11 -1
- data/test/cases/arel/collectors/sql_string_test.rb +1 -1
- data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
- data/test/cases/arel/delete_manager_test.rb +0 -6
- data/test/cases/arel/factory_methods_test.rb +45 -0
- data/test/cases/arel/insert_manager_test.rb +1 -7
- data/test/cases/arel/nodes/as_test.rb +12 -0
- data/test/cases/arel/nodes/ascending_test.rb +1 -1
- data/test/cases/arel/nodes/bin_test.rb +1 -1
- data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
- data/test/cases/arel/nodes/cte_test.rb +46 -0
- data/test/cases/arel/nodes/descending_test.rb +1 -1
- data/test/cases/arel/nodes/equality_test.rb +3 -3
- data/test/cases/arel/nodes/filter_test.rb +37 -0
- data/test/cases/arel/nodes/fragments_test.rb +38 -0
- data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
- data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
- data/test/cases/arel/nodes/node_test.rb +1 -1
- data/test/cases/arel/nodes/or_test.rb +2 -2
- data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
- data/test/cases/arel/nodes/table_alias_test.rb +12 -0
- data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
- data/test/cases/arel/nodes/update_statement_test.rb +4 -0
- data/test/cases/arel/nodes_test.rb +3 -2
- data/test/cases/arel/select_manager_test.rb +12 -12
- data/test/cases/arel/support/fake_record.rb +22 -17
- data/test/cases/arel/table_test.rb +15 -25
- data/test/cases/arel/update_manager_test.rb +51 -6
- data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
- data/test/cases/arel/visitors/dot_test.rb +177 -2
- data/test/cases/arel/visitors/mysql_test.rb +49 -1
- data/test/cases/arel/visitors/postgres_test.rb +1 -31
- data/test/cases/arel/visitors/sqlite_test.rb +1 -1
- data/test/cases/arel/visitors/to_sql_test.rb +330 -20
- data/test/cases/assertions/query_assertions_test.rb +136 -0
- data/test/cases/associations/belongs_to_associations_test.rb +502 -41
- data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
- data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
- data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
- data/test/cases/associations/eager_singularization_test.rb +1 -1
- data/test/cases/associations/eager_test.rb +255 -93
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
- data/test/cases/associations/has_many_associations_test.rb +282 -72
- data/test/cases/associations/has_many_through_associations_test.rb +172 -45
- data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
- data/test/cases/associations/has_one_associations_test.rb +160 -29
- data/test/cases/associations/has_one_through_associations_test.rb +64 -15
- data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
- data/test/cases/associations/inner_join_association_test.rb +36 -6
- data/test/cases/associations/inverse_associations_test.rb +177 -40
- data/test/cases/associations/join_model_test.rb +17 -12
- data/test/cases/associations/left_outer_join_association_test.rb +14 -3
- data/test/cases/associations/nested_error_test.rb +116 -0
- data/test/cases/associations/nested_through_associations_test.rb +54 -19
- data/test/cases/associations/required_test.rb +1 -1
- data/test/cases/associations_test.rb +1278 -21
- data/test/cases/asynchronous_queries_test.rb +310 -0
- data/test/cases/attribute_methods/read_test.rb +6 -0
- data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
- data/test/cases/attribute_methods_test.rb +565 -46
- data/test/cases/attributes_test.rb +42 -1
- data/test/cases/autosave_association_test.rb +645 -92
- data/test/cases/base_prevent_writes_test.rb +28 -159
- data/test/cases/base_test.rb +434 -209
- data/test/cases/batches_test.rb +441 -57
- data/test/cases/binary_test.rb +31 -0
- data/test/cases/bind_parameter_test.rb +107 -16
- data/test/cases/cache_key_test.rb +7 -7
- data/test/cases/calculations_test.rb +541 -110
- data/test/cases/callbacks_test.rb +0 -1
- data/test/cases/clone_test.rb +5 -4
- data/test/cases/coders/yaml_column_test.rb +97 -2
- data/test/cases/collection_cache_key_test.rb +24 -16
- data/test/cases/column_alias_test.rb +2 -8
- data/test/cases/column_definition_test.rb +12 -3
- data/test/cases/comment_test.rb +23 -26
- data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
- data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
- data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
- data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
- data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
- data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
- data/test/cases/connection_adapters/registration_test.rb +98 -0
- data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
- data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
- data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
- data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
- data/test/cases/connection_handling_test.rb +210 -0
- data/test/cases/connection_management_test.rb +44 -7
- data/test/cases/connection_pool_test.rb +466 -99
- data/test/cases/core_test.rb +167 -9
- data/test/cases/counter_cache_test.rb +129 -2
- data/test/cases/custom_locking_test.rb +3 -3
- data/test/cases/database_configurations/hash_config_test.rb +149 -13
- data/test/cases/database_configurations/resolver_test.rb +14 -10
- data/test/cases/database_configurations/url_config_test.rb +53 -0
- data/test/cases/database_configurations_test.rb +86 -43
- data/test/cases/database_selector_test.rb +30 -8
- data/test/cases/database_statements_test.rb +10 -14
- data/test/cases/date_time_precision_test.rb +141 -11
- data/test/cases/date_time_test.rb +19 -1
- data/test/cases/defaults_test.rb +107 -41
- data/test/cases/delegated_type_test.rb +69 -9
- data/test/cases/dirty_test.rb +82 -25
- data/test/cases/disconnected_test.rb +10 -9
- data/test/cases/dup_test.rb +26 -6
- data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
- data/test/cases/encryption/cipher_test.rb +65 -0
- data/test/cases/encryption/concurrency_test.rb +27 -0
- data/test/cases/encryption/config_test.rb +21 -0
- data/test/cases/encryption/configurable_test.rb +93 -0
- data/test/cases/encryption/contexts_test.rb +105 -0
- data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
- data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
- data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
- data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
- data/test/cases/encryption/encryptable_record_test.rb +470 -0
- data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
- data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
- data/test/cases/encryption/encryption_schemes_test.rb +240 -0
- data/test/cases/encryption/encryptor_test.rb +113 -0
- data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
- data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
- data/test/cases/encryption/helper.rb +152 -0
- data/test/cases/encryption/key_generator_test.rb +55 -0
- data/test/cases/encryption/key_provider_test.rb +57 -0
- data/test/cases/encryption/key_test.rb +17 -0
- data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
- data/test/cases/encryption/message_serializer_test.rb +82 -0
- data/test/cases/encryption/message_test.rb +43 -0
- data/test/cases/encryption/null_encryptor_test.rb +21 -0
- data/test/cases/encryption/properties_test.rb +69 -0
- data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
- data/test/cases/encryption/scheme_test.rb +58 -0
- data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
- data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
- data/test/cases/enum_test.rb +374 -72
- data/test/cases/errors_test.rb +7 -4
- data/test/cases/excluding_test.rb +116 -0
- data/test/cases/explain_subscriber_test.rb +6 -1
- data/test/cases/explain_test.rb +119 -10
- data/test/cases/filter_attributes_test.rb +7 -14
- data/test/cases/finder_respond_to_test.rb +3 -3
- data/test/cases/finder_test.rb +357 -72
- data/test/cases/fixture_set/file_test.rb +9 -0
- data/test/cases/fixtures_test.rb +426 -190
- data/test/cases/helper.rb +66 -192
- data/test/cases/hot_compatibility_test.rb +10 -10
- data/test/cases/inheritance_test.rb +51 -61
- data/test/cases/inherited_test.rb +40 -0
- data/test/cases/insert_all_test.rb +419 -9
- data/test/cases/instrumentation_test.rb +202 -30
- data/test/cases/integration_test.rb +25 -7
- data/test/cases/invalid_connection_test.rb +5 -5
- data/test/cases/invertible_migration_test.rb +108 -24
- data/test/cases/json_attribute_test.rb +1 -0
- data/test/cases/json_serialization_test.rb +5 -5
- data/test/cases/json_shared_test_cases.rb +5 -9
- data/test/cases/locking_test.rb +67 -31
- data/test/cases/log_subscriber_test.rb +17 -15
- data/test/cases/marshal_serialization_test.rb +78 -5
- data/test/cases/message_pack_test.rb +91 -0
- data/test/cases/migration/change_schema_test.rb +77 -46
- data/test/cases/migration/change_table_test.rb +129 -114
- data/test/cases/migration/check_constraint_test.rb +192 -10
- data/test/cases/migration/column_attributes_test.rb +4 -9
- data/test/cases/migration/column_positioning_test.rb +2 -2
- data/test/cases/migration/columns_test.rb +118 -4
- data/test/cases/migration/command_recorder_test.rb +181 -14
- data/test/cases/migration/compatibility_test.rb +883 -196
- data/test/cases/migration/create_join_table_test.rb +8 -1
- data/test/cases/migration/exclusion_constraint_test.rb +192 -0
- data/test/cases/migration/foreign_key_test.rb +356 -14
- data/test/cases/migration/helper.rb +4 -1
- data/test/cases/migration/index_test.rb +67 -2
- data/test/cases/migration/invalid_options_test.rb +129 -0
- data/test/cases/migration/logger_test.rb +7 -4
- data/test/cases/migration/pending_migrations_test.rb +103 -60
- data/test/cases/migration/references_foreign_key_test.rb +73 -4
- data/test/cases/migration/references_index_test.rb +25 -27
- data/test/cases/migration/references_statements_test.rb +27 -3
- data/test/cases/migration/rename_table_test.rb +39 -54
- data/test/cases/migration/schema_definitions_test.rb +109 -0
- data/test/cases/migration/unique_constraint_test.rb +248 -0
- data/test/cases/migration_test.rb +677 -220
- data/test/cases/migrator_test.rb +102 -75
- data/test/cases/multi_db_migrator_test.rb +55 -34
- data/test/cases/multiparameter_attributes_test.rb +26 -29
- data/test/cases/multiple_db_test.rb +42 -19
- data/test/cases/nested_attributes_test.rb +124 -6
- data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
- data/test/cases/normalized_attribute_test.rb +117 -0
- data/test/cases/null_relation_test.rb +35 -2
- data/test/cases/persistence/reload_association_cache_test.rb +20 -0
- data/test/cases/persistence_test.rb +629 -22
- data/test/cases/pooled_connections_test.rb +57 -56
- data/test/cases/prepared_statement_status_test.rb +8 -3
- data/test/cases/primary_class_test.rb +134 -0
- data/test/cases/primary_keys_test.rb +171 -55
- data/test/cases/query_cache_test.rb +558 -263
- data/test/cases/query_logs_test.rb +293 -0
- data/test/cases/quoting_test.rb +39 -72
- data/test/cases/readonly_test.rb +50 -12
- data/test/cases/reaper_test.rb +22 -6
- data/test/cases/reflection_test.rb +207 -9
- data/test/cases/relation/and_test.rb +43 -0
- data/test/cases/relation/delegation_test.rb +32 -5
- data/test/cases/relation/delete_all_test.rb +27 -6
- data/test/cases/relation/field_ordered_values_test.rb +128 -0
- data/test/cases/relation/load_async_test.rb +650 -0
- data/test/cases/relation/merging_test.rb +80 -109
- data/test/cases/relation/mutation_test.rb +12 -7
- data/test/cases/relation/or_test.rb +11 -8
- data/test/cases/relation/order_test.rb +90 -0
- data/test/cases/relation/predicate_builder_test.rb +21 -6
- data/test/cases/relation/select_test.rb +162 -3
- data/test/cases/relation/structural_compatibility_test.rb +38 -0
- data/test/cases/relation/update_all_test.rb +81 -27
- data/test/cases/relation/where_chain_test.rb +190 -3
- data/test/cases/relation/where_clause_test.rb +43 -1
- data/test/cases/relation/where_test.rb +95 -7
- data/test/cases/relation/with_test.rb +165 -0
- data/test/cases/relation_test.rb +42 -37
- data/test/cases/relations_test.rb +436 -138
- data/test/cases/reload_models_test.rb +18 -14
- data/test/cases/reserved_word_test.rb +2 -1
- data/test/cases/result_test.rb +14 -22
- data/test/cases/sanitize_test.rb +89 -27
- data/test/cases/schema_dumper_test.rb +535 -62
- data/test/cases/scoping/default_scoping_test.rb +219 -35
- data/test/cases/scoping/named_scoping_test.rb +25 -46
- data/test/cases/scoping/relation_scoping_test.rb +112 -4
- data/test/cases/secure_password_test.rb +108 -0
- data/test/cases/secure_token_test.rb +72 -0
- data/test/cases/serialization_test.rb +1 -1
- data/test/cases/serialized_attribute_test.rb +305 -60
- data/test/cases/shard_keys_test.rb +125 -0
- data/test/cases/shard_selector_test.rb +45 -0
- data/test/cases/signed_id_test.rb +57 -5
- data/test/cases/statement_cache_test.rb +31 -30
- data/test/cases/statement_invalid_test.rb +8 -4
- data/test/cases/store_test.rb +73 -9
- data/test/cases/strict_loading_test.rb +327 -13
- data/test/cases/table_metadata_test.rb +16 -0
- data/test/cases/tasks/database_tasks_test.rb +517 -244
- data/test/cases/test_case.rb +254 -60
- data/test/cases/test_case_test.rb +69 -0
- data/test/cases/test_databases_test.rb +7 -3
- data/test/cases/test_fixtures_test.rb +19 -40
- data/test/cases/time_precision_test.rb +17 -5
- data/test/cases/timestamp_test.rb +124 -16
- data/test/cases/token_for_test.rb +165 -0
- data/test/cases/touch_later_test.rb +43 -1
- data/test/cases/transaction_callbacks_test.rb +325 -8
- data/test/cases/transaction_instrumentation_test.rb +453 -0
- data/test/cases/transaction_isolation_test.rb +12 -8
- data/test/cases/transactions_test.rb +629 -112
- data/test/cases/type/date_time_test.rb +7 -1
- data/test/cases/type/time_test.rb +9 -0
- data/test/cases/type/type_map_test.rb +108 -73
- data/test/cases/type/unsigned_integer_test.rb +12 -0
- data/test/cases/type_caster/connection_test.rb +19 -0
- data/test/cases/type_test.rb +1 -1
- data/test/cases/unconnected_test.rb +7 -7
- data/test/cases/unsafe_raw_sql_test.rb +39 -8
- data/test/cases/validations/absence_validation_test.rb +1 -1
- data/test/cases/validations/association_validation_test.rb +25 -3
- data/test/cases/validations/numericality_validation_test.rb +3 -9
- data/test/cases/validations/presence_validation_test.rb +1 -1
- data/test/cases/validations/uniqueness_validation_test.rb +280 -40
- data/test/cases/validations_test.rb +2 -2
- data/test/cases/view_test.rb +33 -22
- data/test/cases/yaml_serialization_test.rb +23 -17
- data/test/config.example.yml +58 -56
- data/test/config.rb +1 -0
- data/test/fixtures/1_need_quoting.yml +2 -0
- data/test/fixtures/accounts.yml +5 -0
- data/test/fixtures/aircrafts.yml +7 -0
- data/test/fixtures/book_identifiers.yml +11 -0
- data/test/fixtures/books.yml +5 -4
- data/test/fixtures/cake_designers.yml +5 -0
- data/test/fixtures/cars.yml +6 -0
- data/test/fixtures/chefs.yml +5 -0
- data/test/fixtures/clothing_items.yml +23 -0
- data/test/fixtures/clubs.yml +1 -1
- data/test/fixtures/comments.yml +2 -1
- data/test/fixtures/cpk_authors.yml +8 -0
- data/test/fixtures/cpk_books.yml +21 -0
- data/test/fixtures/cpk_order_agreements.yml +13 -0
- data/test/fixtures/cpk_order_tags.yml +15 -0
- data/test/fixtures/cpk_orders.yml +11 -0
- data/test/fixtures/cpk_posts.yml +12 -0
- data/test/fixtures/cpk_reviews.yml +13 -0
- data/test/fixtures/cpk_tags.yml +11 -0
- data/test/fixtures/drink_designers.yml +5 -0
- data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
- data/test/fixtures/encrypted_books.yml +4 -0
- data/test/fixtures/fk_object_to_point_to.yml +2 -0
- data/test/fixtures/memberships.yml +15 -15
- data/test/fixtures/paragraphs.yml +5 -0
- data/test/fixtures/parrots.yml +4 -0
- data/test/fixtures/people.yml +2 -0
- data/test/fixtures/pirates.yml +2 -2
- data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
- data/test/fixtures/references.yml +3 -3
- data/test/fixtures/sharded_blog_posts.yml +14 -0
- data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
- data/test/fixtures/sharded_blogs.yml +8 -0
- data/test/fixtures/sharded_comments.yml +22 -0
- data/test/fixtures/sharded_tags.yml +34 -0
- data/test/fixtures/sponsors.yml +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures/treasures.yml +4 -0
- data/test/fixtures/virtual_columns.yml +5 -0
- data/test/fixtures/warehouse_things.yml +1 -1
- data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
- data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
- data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
- data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
- data/test/migrations/scope/1_unscoped.rb +7 -0
- data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
- data/test/models/admin/user.rb +2 -0
- data/test/models/admin/user_json.rb +48 -0
- data/test/models/attachment.rb +7 -0
- data/test/models/author.rb +70 -3
- data/test/models/author_encrypted.rb +16 -0
- data/test/models/bird.rb +1 -1
- data/test/models/book.rb +18 -11
- data/test/models/book_destroy_async.rb +1 -1
- data/test/models/book_encrypted.rb +106 -0
- data/test/models/book_identifier.rb +5 -0
- data/test/models/branch.rb +11 -0
- data/test/models/bulb.rb +1 -1
- data/test/models/car.rb +8 -1
- data/test/models/cat.rb +1 -1
- data/test/models/category.rb +3 -1
- data/test/models/chat_message.rb +8 -0
- data/test/models/chef.rb +52 -0
- data/test/models/clothing_item.rb +12 -0
- data/test/models/club.rb +4 -1
- data/test/models/comment.rb +7 -4
- data/test/models/comment_overlapping_counter_cache.rb +15 -0
- data/test/models/company.rb +16 -2
- data/test/models/computer.rb +1 -0
- data/test/models/contact.rb +3 -3
- data/test/models/contract.rb +5 -1
- data/test/models/cpk/author.rb +9 -0
- data/test/models/cpk/book.rb +55 -0
- data/test/models/cpk/book_destroy_async.rb +9 -0
- data/test/models/cpk/car.rb +9 -0
- data/test/models/cpk/car_review.rb +9 -0
- data/test/models/cpk/chapter.rb +16 -0
- data/test/models/cpk/chapter_destroy_async.rb +10 -0
- data/test/models/cpk/comment.rb +9 -0
- data/test/models/cpk/order.rb +55 -0
- data/test/models/cpk/order_agreement.rb +10 -0
- data/test/models/cpk/order_tag.rb +10 -0
- data/test/models/cpk/post.rb +10 -0
- data/test/models/cpk/posts_tag.rb +10 -0
- data/test/models/cpk/review.rb +9 -0
- data/test/models/cpk/tag.rb +10 -0
- data/test/models/cpk.rb +15 -0
- data/test/models/customer.rb +3 -1
- data/test/models/destroy_async_parent.rb +1 -1
- data/test/models/developer.rb +44 -3
- data/test/models/discount.rb +4 -0
- data/test/models/drink_designer.rb +1 -0
- data/test/models/editor.rb +8 -0
- data/test/models/editorship.rb +6 -0
- data/test/models/entry.rb +5 -0
- data/test/models/essay.rb +6 -1
- data/test/models/essay_destroy_async.rb +1 -0
- data/test/models/eye.rb +87 -21
- data/test/models/face.rb +1 -1
- data/test/models/friendship.rb +3 -0
- data/test/models/hardback.rb +7 -0
- data/test/models/hotel.rb +2 -0
- data/test/models/human.rb +2 -2
- data/test/models/invoice.rb +2 -1
- data/test/models/invokes_an_undefined_method.rb +5 -0
- data/test/models/line_item.rb +6 -0
- data/test/models/member.rb +9 -4
- data/test/models/membership.rb +2 -2
- data/test/models/message.rb +2 -1
- data/test/models/need_quoting.rb +5 -0
- data/test/models/paragraph.rb +5 -0
- data/test/models/parrot.rb +6 -3
- data/test/models/person.rb +7 -4
- data/test/models/pirate.rb +4 -1
- data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
- data/test/models/post.rb +65 -2
- data/test/models/post_encrypted.rb +15 -0
- data/test/models/post_with_prefetched_pk.rb +15 -0
- data/test/models/project.rb +1 -0
- data/test/models/publication.rb +16 -0
- data/test/models/raises_argument_error.rb +5 -0
- data/test/models/raises_no_method_error.rb +5 -0
- data/test/models/recipient.rb +5 -0
- data/test/models/reference.rb +1 -1
- data/test/models/reply.rb +1 -1
- data/test/models/room.rb +3 -0
- data/test/models/sharded/blog.rb +12 -0
- data/test/models/sharded/blog_post.rb +17 -0
- data/test/models/sharded/blog_post_destroy_async.rb +14 -0
- data/test/models/sharded/blog_post_tag.rb +11 -0
- data/test/models/sharded/blog_post_with_revision.rb +11 -0
- data/test/models/sharded/comment.rb +12 -0
- data/test/models/sharded/comment_destroy_async.rb +12 -0
- data/test/models/sharded/tag.rb +11 -0
- data/test/models/sharded.rb +8 -0
- data/test/models/ship.rb +1 -1
- data/test/models/shipping_line.rb +11 -0
- data/test/models/subscriber.rb +1 -0
- data/test/models/subscription.rb +3 -1
- data/test/models/too_long_table_name.rb +5 -0
- data/test/models/topic.rb +3 -1
- data/test/models/traffic_light.rb +2 -2
- data/test/models/traffic_light_encrypted.rb +21 -0
- data/test/models/translation.rb +9 -0
- data/test/models/treasure.rb +1 -1
- data/test/models/tyre.rb +1 -1
- data/test/models/user.rb +16 -0
- data/test/models/user_with_invalid_relation.rb +28 -0
- data/test/models/uuid_comment.rb +5 -0
- data/test/models/uuid_entry.rb +5 -0
- data/test/models/uuid_message.rb +5 -0
- data/test/models/zine.rb +2 -1
- data/test/schema/mysql2_specific_schema.rb +26 -12
- data/test/schema/postgresql_specific_schema.rb +121 -13
- data/test/schema/schema.rb +361 -103
- data/test/schema/sqlite_specific_schema.rb +17 -6
- data/test/schema/trilogy_specific_schema.rb +96 -0
- data/test/support/adapter_helper.rb +104 -0
- data/test/support/async_helper.rb +15 -0
- data/test/support/config.rb +1 -1
- data/test/support/connection.rb +14 -2
- data/test/support/ddl_helper.rb +1 -1
- data/test/support/fake_adapter.rb +42 -0
- data/test/support/load_schema_helper.rb +22 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
- data/test/support/schema_dumping_helper.rb +15 -9
- data/test/support/tools.rb +37 -0
- data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
- metadata +247 -15
|
@@ -5,15 +5,28 @@ require "concurrent/atomic/count_down_latch"
|
|
|
5
5
|
|
|
6
6
|
module ActiveRecord
|
|
7
7
|
module ConnectionAdapters
|
|
8
|
-
|
|
8
|
+
module ConnectionPoolTests
|
|
9
|
+
def self.included(test)
|
|
10
|
+
super
|
|
11
|
+
test.use_transactional_tests = false
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
attr_reader :pool
|
|
10
15
|
|
|
11
16
|
def setup
|
|
12
|
-
|
|
17
|
+
@previous_isolation_level = ActiveSupport::IsolatedExecutionState.isolation_level
|
|
13
18
|
|
|
14
19
|
# Keep a duplicate pool so we do not bother others
|
|
15
|
-
|
|
16
|
-
@
|
|
20
|
+
config = ActiveRecord::Base.connection_pool.db_config
|
|
21
|
+
@db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(
|
|
22
|
+
config.env_name,
|
|
23
|
+
config.name,
|
|
24
|
+
config.configuration_hash.merge(
|
|
25
|
+
checkout_timeout: 0.2, # Reduce checkout_timeout to speedup tests
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, @db_config, :writing, :default)
|
|
17
30
|
@pool = ConnectionPool.new(@pool_config)
|
|
18
31
|
|
|
19
32
|
if in_memory_db?
|
|
@@ -27,28 +40,26 @@ module ActiveRecord
|
|
|
27
40
|
end
|
|
28
41
|
end
|
|
29
42
|
|
|
30
|
-
teardown
|
|
43
|
+
def teardown
|
|
44
|
+
super
|
|
31
45
|
@pool.disconnect!
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def active_connections(pool)
|
|
35
|
-
pool.connections.find_all(&:in_use?)
|
|
46
|
+
ActiveSupport::IsolatedExecutionState.isolation_level = @previous_isolation_level
|
|
36
47
|
end
|
|
37
48
|
|
|
38
49
|
def test_checkout_after_close
|
|
39
|
-
connection = pool.
|
|
50
|
+
connection = pool.lease_connection
|
|
40
51
|
assert_predicate connection, :in_use?
|
|
41
52
|
|
|
42
53
|
connection.close
|
|
43
54
|
assert_not_predicate connection, :in_use?
|
|
44
55
|
|
|
45
|
-
assert_predicate pool.
|
|
56
|
+
assert_predicate pool.lease_connection, :in_use?
|
|
46
57
|
end
|
|
47
58
|
|
|
48
59
|
def test_released_connection_moves_between_threads
|
|
49
60
|
thread_conn = nil
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
new_thread {
|
|
52
63
|
pool.with_connection do |conn|
|
|
53
64
|
thread_conn = conn
|
|
54
65
|
end
|
|
@@ -56,7 +67,7 @@ module ActiveRecord
|
|
|
56
67
|
|
|
57
68
|
assert thread_conn
|
|
58
69
|
|
|
59
|
-
|
|
70
|
+
new_thread {
|
|
60
71
|
pool.with_connection do |conn|
|
|
61
72
|
assert_equal thread_conn, conn
|
|
62
73
|
end
|
|
@@ -66,14 +77,24 @@ module ActiveRecord
|
|
|
66
77
|
def test_with_connection
|
|
67
78
|
assert_equal 0, active_connections(pool).size
|
|
68
79
|
|
|
69
|
-
main_thread = pool.
|
|
80
|
+
main_thread = pool.lease_connection
|
|
70
81
|
assert_equal 1, active_connections(pool).size
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
new_thread {
|
|
84
|
+
pool.with_connection do |conn|
|
|
85
|
+
assert conn
|
|
86
|
+
assert_equal 2, active_connections(pool).size
|
|
87
|
+
end
|
|
88
|
+
assert_equal 1, active_connections(pool).size
|
|
89
|
+
|
|
73
90
|
pool.with_connection do |conn|
|
|
74
91
|
assert conn
|
|
75
92
|
assert_equal 2, active_connections(pool).size
|
|
93
|
+
pool.lease_connection
|
|
76
94
|
end
|
|
95
|
+
|
|
96
|
+
assert_equal 2, active_connections(pool).size
|
|
97
|
+
pool.release_connection
|
|
77
98
|
assert_equal 1, active_connections(pool).size
|
|
78
99
|
}.join
|
|
79
100
|
|
|
@@ -81,9 +102,21 @@ module ActiveRecord
|
|
|
81
102
|
assert_equal 0, active_connections(pool).size
|
|
82
103
|
end
|
|
83
104
|
|
|
105
|
+
def test_new_connection_no_query
|
|
106
|
+
skip("Can't test with in-memory dbs") if in_memory_db?
|
|
107
|
+
assert_equal 0, pool.connections.size
|
|
108
|
+
pool.with_connection { |_conn| } # warm the schema cache
|
|
109
|
+
pool.flush(0)
|
|
110
|
+
assert_equal 0, pool.connections.size
|
|
111
|
+
|
|
112
|
+
assert_no_queries do
|
|
113
|
+
pool.with_connection { |_conn| }
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
84
117
|
def test_active_connection_in_use
|
|
85
118
|
assert_not_predicate pool, :active_connection?
|
|
86
|
-
main_thread = pool.
|
|
119
|
+
main_thread = pool.lease_connection
|
|
87
120
|
|
|
88
121
|
assert_predicate pool, :active_connection?
|
|
89
122
|
|
|
@@ -96,17 +129,19 @@ module ActiveRecord
|
|
|
96
129
|
@pool.checkout_timeout = 0.001 # no need to delay test suite by waiting the whole full default timeout
|
|
97
130
|
@pool.size.times { assert @pool.checkout }
|
|
98
131
|
|
|
99
|
-
assert_raises(ConnectionTimeoutError) do
|
|
132
|
+
error = assert_raises(ConnectionTimeoutError) do
|
|
100
133
|
@pool.checkout
|
|
101
134
|
end
|
|
135
|
+
assert_equal @pool, error.connection_pool
|
|
102
136
|
end
|
|
103
137
|
|
|
104
138
|
def test_full_pool_blocks
|
|
139
|
+
skip_fiber_testing
|
|
105
140
|
cs = @pool.size.times.map { @pool.checkout }
|
|
106
|
-
t =
|
|
141
|
+
t = new_thread { @pool.checkout }
|
|
107
142
|
|
|
108
143
|
# make sure our thread is in the timeout section
|
|
109
|
-
|
|
144
|
+
pass_to(t) until @pool.num_waiting_in_queue == 1
|
|
110
145
|
|
|
111
146
|
connection = cs.first
|
|
112
147
|
connection.close
|
|
@@ -114,6 +149,7 @@ module ActiveRecord
|
|
|
114
149
|
end
|
|
115
150
|
|
|
116
151
|
def test_full_pool_blocking_shares_load_interlock
|
|
152
|
+
skip_fiber_testing
|
|
117
153
|
@pool.instance_variable_set(:@size, 1)
|
|
118
154
|
|
|
119
155
|
load_interlock_latch = Concurrent::CountDownLatch.new
|
|
@@ -122,7 +158,7 @@ module ActiveRecord
|
|
|
122
158
|
able_to_get_connection = false
|
|
123
159
|
able_to_load = false
|
|
124
160
|
|
|
125
|
-
thread_with_load_interlock =
|
|
161
|
+
thread_with_load_interlock = new_thread do
|
|
126
162
|
ActiveSupport::Dependencies.interlock.running do
|
|
127
163
|
load_interlock_latch.count_down
|
|
128
164
|
connection_latch.wait
|
|
@@ -133,7 +169,7 @@ module ActiveRecord
|
|
|
133
169
|
end
|
|
134
170
|
end
|
|
135
171
|
|
|
136
|
-
thread_with_last_connection =
|
|
172
|
+
thread_with_last_connection = new_thread do
|
|
137
173
|
@pool.with_connection do
|
|
138
174
|
connection_latch.count_down
|
|
139
175
|
load_interlock_latch.wait
|
|
@@ -152,11 +188,12 @@ module ActiveRecord
|
|
|
152
188
|
end
|
|
153
189
|
|
|
154
190
|
def test_removing_releases_latch
|
|
191
|
+
skip_fiber_testing
|
|
155
192
|
cs = @pool.size.times.map { @pool.checkout }
|
|
156
|
-
t =
|
|
193
|
+
t = new_thread { @pool.checkout }
|
|
157
194
|
|
|
158
195
|
# make sure our thread is in the timeout section
|
|
159
|
-
|
|
196
|
+
pass_to(t) until @pool.num_waiting_in_queue == 1
|
|
160
197
|
|
|
161
198
|
connection = cs.first
|
|
162
199
|
@pool.remove connection
|
|
@@ -179,13 +216,13 @@ module ActiveRecord
|
|
|
179
216
|
def test_reap_inactive
|
|
180
217
|
ready = Concurrent::CountDownLatch.new
|
|
181
218
|
@pool.checkout
|
|
182
|
-
child =
|
|
219
|
+
child = new_thread do
|
|
183
220
|
@pool.checkout
|
|
184
221
|
@pool.checkout
|
|
185
222
|
ready.count_down
|
|
186
|
-
|
|
223
|
+
stop_thread
|
|
187
224
|
end
|
|
188
|
-
ready.wait
|
|
225
|
+
pass_to(child) until ready.wait(0)
|
|
189
226
|
|
|
190
227
|
assert_equal 3, active_connections(@pool).size
|
|
191
228
|
|
|
@@ -198,20 +235,44 @@ module ActiveRecord
|
|
|
198
235
|
@pool.connections.each { |conn| conn.close if conn.in_use? }
|
|
199
236
|
end
|
|
200
237
|
|
|
238
|
+
def test_inactive_are_returned_from_dead_thread
|
|
239
|
+
ready = Concurrent::CountDownLatch.new
|
|
240
|
+
@pool.instance_variable_set(:@size, 1)
|
|
241
|
+
|
|
242
|
+
child = new_thread do
|
|
243
|
+
@pool.checkout
|
|
244
|
+
ready.count_down
|
|
245
|
+
stop_thread
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
pass_to(child) until ready.wait(0)
|
|
249
|
+
|
|
250
|
+
assert_equal 1, active_connections(@pool).size
|
|
251
|
+
|
|
252
|
+
child.terminate
|
|
253
|
+
child.join
|
|
254
|
+
|
|
255
|
+
@pool.checkout
|
|
256
|
+
|
|
257
|
+
assert_equal 1, active_connections(@pool).size
|
|
258
|
+
ensure
|
|
259
|
+
@pool.connections.each { |conn| conn.close if conn.in_use? }
|
|
260
|
+
end
|
|
261
|
+
|
|
201
262
|
def test_idle_timeout_configuration
|
|
202
263
|
@pool.disconnect!
|
|
203
264
|
|
|
204
265
|
config = @db_config.configuration_hash.merge(idle_timeout: "0.02")
|
|
205
266
|
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(@db_config.env_name, @db_config.name, config)
|
|
206
267
|
|
|
207
|
-
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config)
|
|
268
|
+
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config, :writing, :default)
|
|
208
269
|
@pool = ConnectionPool.new(pool_config)
|
|
209
270
|
idle_conn = @pool.checkout
|
|
210
271
|
@pool.checkin(idle_conn)
|
|
211
272
|
|
|
212
273
|
idle_conn.instance_variable_set(
|
|
213
274
|
:@idle_since,
|
|
214
|
-
|
|
275
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - 0.01
|
|
215
276
|
)
|
|
216
277
|
|
|
217
278
|
@pool.flush
|
|
@@ -219,7 +280,7 @@ module ActiveRecord
|
|
|
219
280
|
|
|
220
281
|
idle_conn.instance_variable_set(
|
|
221
282
|
:@idle_since,
|
|
222
|
-
|
|
283
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - 0.03
|
|
223
284
|
)
|
|
224
285
|
|
|
225
286
|
@pool.flush
|
|
@@ -231,14 +292,14 @@ module ActiveRecord
|
|
|
231
292
|
|
|
232
293
|
config = @db_config.configuration_hash.merge(idle_timeout: -5)
|
|
233
294
|
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(@db_config.env_name, @db_config.name, config)
|
|
234
|
-
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config)
|
|
295
|
+
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config, :writing, :default)
|
|
235
296
|
@pool = ConnectionPool.new(pool_config)
|
|
236
297
|
idle_conn = @pool.checkout
|
|
237
298
|
@pool.checkin(idle_conn)
|
|
238
299
|
|
|
239
300
|
idle_conn.instance_variable_set(
|
|
240
301
|
:@idle_since,
|
|
241
|
-
|
|
302
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - 1
|
|
242
303
|
)
|
|
243
304
|
|
|
244
305
|
@pool.flush
|
|
@@ -257,7 +318,7 @@ module ActiveRecord
|
|
|
257
318
|
|
|
258
319
|
idle_conn.instance_variable_set(
|
|
259
320
|
:@idle_since,
|
|
260
|
-
|
|
321
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - 1000
|
|
261
322
|
)
|
|
262
323
|
|
|
263
324
|
@pool.flush(30)
|
|
@@ -273,7 +334,7 @@ module ActiveRecord
|
|
|
273
334
|
idle_conn = @pool.checkout
|
|
274
335
|
recent_conn = @pool.checkout
|
|
275
336
|
active_conn = @pool.checkout
|
|
276
|
-
_dead_conn =
|
|
337
|
+
_dead_conn = new_thread { @pool.checkout }.join
|
|
277
338
|
|
|
278
339
|
@pool.checkin idle_conn
|
|
279
340
|
@pool.checkin recent_conn
|
|
@@ -306,29 +367,29 @@ module ActiveRecord
|
|
|
306
367
|
end
|
|
307
368
|
|
|
308
369
|
def test_remove_connection_for_thread
|
|
309
|
-
conn = @pool.
|
|
370
|
+
conn = @pool.lease_connection
|
|
310
371
|
@pool.remove conn
|
|
311
|
-
assert_not_equal(conn, @pool.
|
|
372
|
+
assert_not_equal(conn, @pool.lease_connection)
|
|
312
373
|
ensure
|
|
313
374
|
conn.close if conn
|
|
314
375
|
end
|
|
315
376
|
|
|
316
377
|
def test_active_connection?
|
|
317
378
|
assert_not_predicate @pool, :active_connection?
|
|
318
|
-
assert @pool.
|
|
379
|
+
assert @pool.lease_connection
|
|
319
380
|
assert_predicate @pool, :active_connection?
|
|
320
381
|
@pool.release_connection
|
|
321
382
|
assert_not_predicate @pool, :active_connection?
|
|
322
383
|
end
|
|
323
384
|
|
|
324
|
-
def
|
|
385
|
+
def test_checkout_behavior
|
|
325
386
|
pool = ConnectionPool.new(@pool_config)
|
|
326
|
-
main_connection = pool.
|
|
387
|
+
main_connection = pool.lease_connection
|
|
327
388
|
assert_not_nil main_connection
|
|
328
389
|
threads = []
|
|
329
390
|
4.times do |i|
|
|
330
|
-
threads <<
|
|
331
|
-
thread_connection = pool.
|
|
391
|
+
threads << new_thread(i) do
|
|
392
|
+
thread_connection = pool.lease_connection
|
|
332
393
|
assert_not_nil thread_connection
|
|
333
394
|
thread_connection.close
|
|
334
395
|
end
|
|
@@ -336,9 +397,9 @@ module ActiveRecord
|
|
|
336
397
|
|
|
337
398
|
threads.each(&:join)
|
|
338
399
|
|
|
339
|
-
|
|
340
|
-
assert pool.
|
|
341
|
-
pool.
|
|
400
|
+
new_thread do
|
|
401
|
+
assert pool.lease_connection
|
|
402
|
+
pool.lease_connection.close
|
|
342
403
|
end.join
|
|
343
404
|
end
|
|
344
405
|
|
|
@@ -364,6 +425,8 @@ module ActiveRecord
|
|
|
364
425
|
# available connections slowly, ensuring the wakeup order is
|
|
365
426
|
# correct in this case.
|
|
366
427
|
def test_checkout_fairness
|
|
428
|
+
skip_fiber_testing
|
|
429
|
+
|
|
367
430
|
@pool.instance_variable_set(:@size, 10)
|
|
368
431
|
expected = (1..@pool.size).to_a.freeze
|
|
369
432
|
# check out all connections so our threads start out waiting
|
|
@@ -371,23 +434,30 @@ module ActiveRecord
|
|
|
371
434
|
mutex = Mutex.new
|
|
372
435
|
order = []
|
|
373
436
|
errors = []
|
|
437
|
+
dispose_held_connections = Concurrent::Event.new
|
|
374
438
|
|
|
375
439
|
threads = expected.map do |i|
|
|
376
|
-
t =
|
|
440
|
+
t = new_thread {
|
|
377
441
|
begin
|
|
378
442
|
@pool.checkout # never checked back in
|
|
379
443
|
mutex.synchronize { order << i }
|
|
444
|
+
|
|
445
|
+
# if the thread terminates, its connection may be
|
|
446
|
+
# reclaimed by the pool, so we need to hold on to it
|
|
447
|
+
# until we're done trickling in connections
|
|
448
|
+
dispose_held_connections.wait
|
|
380
449
|
rescue => e
|
|
381
450
|
mutex.synchronize { errors << e }
|
|
382
451
|
end
|
|
383
452
|
}
|
|
384
|
-
|
|
453
|
+
pass_to(t) until @pool.num_waiting_in_queue == i
|
|
385
454
|
t
|
|
386
455
|
end
|
|
387
456
|
|
|
388
457
|
# this should wake up the waiting threads one by one in order
|
|
389
|
-
conns.each { |conn| @pool.checkin(conn); sleep 0.
|
|
458
|
+
conns.each { |conn| @pool.checkin(conn); sleep 0.01 }
|
|
390
459
|
|
|
460
|
+
dispose_held_connections.set
|
|
391
461
|
threads.each(&:join)
|
|
392
462
|
|
|
393
463
|
raise errors.first if errors.any?
|
|
@@ -402,23 +472,28 @@ module ActiveRecord
|
|
|
402
472
|
# group1 threads, and the fact that only group1 and no group2
|
|
403
473
|
# threads acquired a connection is enforced.
|
|
404
474
|
def test_checkout_fairness_by_group
|
|
475
|
+
skip_fiber_testing
|
|
476
|
+
|
|
405
477
|
@pool.instance_variable_set(:@size, 10)
|
|
406
478
|
# take all the connections
|
|
407
479
|
conns = (1..10).map { @pool.checkout }
|
|
408
480
|
mutex = Mutex.new
|
|
409
481
|
successes = [] # threads that successfully got a connection
|
|
410
482
|
errors = []
|
|
483
|
+
dispose_held_connections = Concurrent::Event.new
|
|
411
484
|
|
|
412
485
|
make_thread = proc do |i|
|
|
413
|
-
t =
|
|
486
|
+
t = new_thread {
|
|
414
487
|
begin
|
|
415
488
|
@pool.checkout # never checked back in
|
|
416
489
|
mutex.synchronize { successes << i }
|
|
490
|
+
|
|
491
|
+
dispose_held_connections.wait
|
|
417
492
|
rescue => e
|
|
418
493
|
mutex.synchronize { errors << e }
|
|
419
494
|
end
|
|
420
495
|
}
|
|
421
|
-
|
|
496
|
+
pass_to(t) until @pool.num_waiting_in_queue == i
|
|
422
497
|
t
|
|
423
498
|
end
|
|
424
499
|
|
|
@@ -444,6 +519,7 @@ module ActiveRecord
|
|
|
444
519
|
winners = mutex.synchronize { successes.dup }
|
|
445
520
|
checkin.call(group2.size) # should wake up everyone remaining
|
|
446
521
|
|
|
522
|
+
dispose_held_connections.set
|
|
447
523
|
group1.each(&:join)
|
|
448
524
|
group2.each(&:join)
|
|
449
525
|
|
|
@@ -457,10 +533,10 @@ module ActiveRecord
|
|
|
457
533
|
def test_automatic_reconnect_restores_after_disconnect
|
|
458
534
|
pool = ConnectionPool.new(@pool_config)
|
|
459
535
|
assert pool.automatic_reconnect
|
|
460
|
-
assert pool.
|
|
536
|
+
assert pool.lease_connection
|
|
461
537
|
|
|
462
538
|
pool.disconnect!
|
|
463
|
-
assert pool.
|
|
539
|
+
assert pool.lease_connection
|
|
464
540
|
end
|
|
465
541
|
|
|
466
542
|
def test_automatic_reconnect_can_be_disabled
|
|
@@ -469,7 +545,7 @@ module ActiveRecord
|
|
|
469
545
|
pool.automatic_reconnect = false
|
|
470
546
|
|
|
471
547
|
assert_raises(ConnectionNotEstablished) do
|
|
472
|
-
pool.
|
|
548
|
+
pool.lease_connection
|
|
473
549
|
end
|
|
474
550
|
|
|
475
551
|
assert_raises(ConnectionNotEstablished) do
|
|
@@ -478,7 +554,7 @@ module ActiveRecord
|
|
|
478
554
|
end
|
|
479
555
|
|
|
480
556
|
def test_pool_sets_connection_visitor
|
|
481
|
-
assert @pool.
|
|
557
|
+
assert @pool.lease_connection.visitor.is_a?(Arel::Visitors::ToSql)
|
|
482
558
|
end
|
|
483
559
|
|
|
484
560
|
# make sure exceptions are thrown when establish_connection
|
|
@@ -491,21 +567,20 @@ module ActiveRecord
|
|
|
491
567
|
end
|
|
492
568
|
end
|
|
493
569
|
|
|
494
|
-
class ConnectionTestModel < ActiveRecord::Base
|
|
495
|
-
self.abstract_class = true
|
|
496
|
-
end
|
|
497
|
-
|
|
498
570
|
def test_connection_notification_is_called
|
|
499
571
|
payloads = []
|
|
500
572
|
subscription = ActiveSupport::Notifications.subscribe("!connection.active_record") do |name, started, finished, unique_id, payload|
|
|
501
573
|
payloads << payload
|
|
502
574
|
end
|
|
503
|
-
ConnectionTestModel.establish_connection :arunit
|
|
504
575
|
|
|
505
|
-
|
|
506
|
-
|
|
576
|
+
@connection_test_model_class.establish_connection :arunit
|
|
577
|
+
|
|
578
|
+
assert_equal [:config, :connection_name, :role, :shard], payloads[0].keys.sort
|
|
579
|
+
assert_equal @connection_test_model_class.name, payloads[0][:connection_name]
|
|
507
580
|
assert_equal ActiveRecord::Base.default_shard, payloads[0][:shard]
|
|
581
|
+
assert_equal :writing, payloads[0][:role]
|
|
508
582
|
ensure
|
|
583
|
+
@connection_test_model_class.remove_connection
|
|
509
584
|
ActiveSupport::Notifications.unsubscribe(subscription) if subscription
|
|
510
585
|
end
|
|
511
586
|
|
|
@@ -514,30 +589,47 @@ module ActiveRecord
|
|
|
514
589
|
subscription = ActiveSupport::Notifications.subscribe("!connection.active_record") do |name, started, finished, unique_id, payload|
|
|
515
590
|
payloads << payload
|
|
516
591
|
end
|
|
517
|
-
|
|
592
|
+
@connection_test_model_class.connects_to shards: { default: { writing: :arunit } }
|
|
518
593
|
|
|
519
|
-
assert_equal [:config, :
|
|
520
|
-
assert_equal
|
|
521
|
-
assert_equal :
|
|
594
|
+
assert_equal [:config, :connection_name, :role, :shard], payloads[0].keys.sort
|
|
595
|
+
assert_equal @connection_test_model_class.name, payloads[0][:connection_name]
|
|
596
|
+
assert_equal :default, payloads[0][:shard]
|
|
597
|
+
assert_equal :writing, payloads[0][:role]
|
|
522
598
|
ensure
|
|
599
|
+
@connection_test_model_class.remove_connection
|
|
523
600
|
ActiveSupport::Notifications.unsubscribe(subscription) if subscription
|
|
524
601
|
end
|
|
525
602
|
|
|
603
|
+
def test_sets_pool_schema_reflection
|
|
604
|
+
pool.schema_cache.add(:posts)
|
|
605
|
+
assert pool.schema_cache.cached?(:posts)
|
|
606
|
+
|
|
607
|
+
pool.schema_reflection = SchemaReflection.new("does-not-exist")
|
|
608
|
+
assert_not pool.schema_cache.cached?(:posts)
|
|
609
|
+
|
|
610
|
+
pool.schema_cache.add(:posts)
|
|
611
|
+
assert pool.schema_cache.cached?(:posts)
|
|
612
|
+
end
|
|
613
|
+
|
|
526
614
|
def test_pool_sets_connection_schema_cache
|
|
615
|
+
pool.schema_cache.add(:posts)
|
|
527
616
|
connection = pool.checkout
|
|
528
|
-
schema_cache = SchemaCache.new connection
|
|
529
|
-
schema_cache.add(:posts)
|
|
530
|
-
pool.schema_cache = schema_cache
|
|
531
617
|
|
|
532
618
|
pool.with_connection do |conn|
|
|
533
|
-
|
|
534
|
-
|
|
619
|
+
# We've retrieved a second, distinct, connection from the pool
|
|
620
|
+
assert_not_same connection, conn
|
|
621
|
+
|
|
622
|
+
# But the new connection can already see the schema cache
|
|
623
|
+
# entry we added above
|
|
624
|
+
assert_equal connection.schema_cache.size, conn.schema_cache.size
|
|
625
|
+
assert_same connection.schema_cache.columns(:posts), conn.schema_cache.columns(:posts)
|
|
535
626
|
end
|
|
536
627
|
|
|
537
628
|
pool.checkin connection
|
|
538
629
|
end
|
|
539
630
|
|
|
540
631
|
def test_concurrent_connection_establishment
|
|
632
|
+
skip_fiber_testing
|
|
541
633
|
assert_operator @pool.connections.size, :<=, 1
|
|
542
634
|
|
|
543
635
|
all_threads_in_new_connection = Concurrent::CountDownLatch.new(@pool.size - @pool.connections.size)
|
|
@@ -553,7 +645,7 @@ module ActiveRecord
|
|
|
553
645
|
|
|
554
646
|
connecting_threads = []
|
|
555
647
|
@pool.size.times do
|
|
556
|
-
connecting_threads <<
|
|
648
|
+
connecting_threads << new_thread { @pool.checkout }
|
|
557
649
|
end
|
|
558
650
|
|
|
559
651
|
begin
|
|
@@ -578,9 +670,10 @@ module ActiveRecord
|
|
|
578
670
|
@pool.checkout_timeout = 0.001 # no need to delay test suite by waiting the whole full default timeout
|
|
579
671
|
[:disconnect, :clear_reloadable_connections].each do |group_action_method|
|
|
580
672
|
@pool.with_connection do |connection|
|
|
581
|
-
assert_raises(ExclusiveConnectionTimeoutError) do
|
|
582
|
-
|
|
673
|
+
error = assert_raises(ExclusiveConnectionTimeoutError) do
|
|
674
|
+
new_thread { @pool.public_send(group_action_method) }.join
|
|
583
675
|
end
|
|
676
|
+
assert_equal @pool, error.connection_pool
|
|
584
677
|
end
|
|
585
678
|
end
|
|
586
679
|
ensure
|
|
@@ -588,10 +681,11 @@ module ActiveRecord
|
|
|
588
681
|
end
|
|
589
682
|
|
|
590
683
|
def test_disconnect_and_clear_reloadable_connections_attempt_to_wait_for_threads_to_return_their_conns
|
|
684
|
+
skip_fiber_testing
|
|
591
685
|
[:disconnect, :disconnect!, :clear_reloadable_connections, :clear_reloadable_connections!].each do |group_action_method|
|
|
592
686
|
thread = timed_join_result = nil
|
|
593
687
|
@pool.with_connection do |connection|
|
|
594
|
-
thread =
|
|
688
|
+
thread = new_thread { @pool.send(group_action_method) }
|
|
595
689
|
|
|
596
690
|
# give the other `thread` some time to get stuck in `group_action_method`
|
|
597
691
|
timed_join_result = thread.join(0.3)
|
|
@@ -609,43 +703,53 @@ module ActiveRecord
|
|
|
609
703
|
|
|
610
704
|
def test_bang_versions_of_disconnect_and_clear_reloadable_connections_if_unable_to_acquire_all_connections_proceed_anyway
|
|
611
705
|
@pool.checkout_timeout = 0.001 # no need to delay test suite by waiting the whole full default timeout
|
|
612
|
-
[:disconnect!, :clear_reloadable_connections!].each do |group_action_method|
|
|
613
|
-
@pool.with_connection do |connection|
|
|
614
|
-
Thread.new { @pool.send(group_action_method) }.join
|
|
615
|
-
# assert connection has been forcefully taken away from us
|
|
616
|
-
assert_not_predicate @pool, :active_connection?
|
|
617
706
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
707
|
+
@pool.with_connection do |connection|
|
|
708
|
+
new_thread { @pool.disconnect! }.join
|
|
709
|
+
# assert connection has been forcefully taken away from us
|
|
710
|
+
assert_not_predicate @pool, :active_connection?
|
|
711
|
+
|
|
712
|
+
# make a new connection for with_connection to clean up
|
|
713
|
+
@pool.lease_connection
|
|
714
|
+
end
|
|
715
|
+
@pool.release_connection
|
|
716
|
+
|
|
717
|
+
@pool.with_connection do |connection|
|
|
718
|
+
new_thread { @pool.clear_reloadable_connections! }.join
|
|
719
|
+
# assert connection has been forcefully taken away from us
|
|
720
|
+
assert_not_predicate @pool, :active_connection?
|
|
721
|
+
|
|
722
|
+
# make a new connection for with_connection to clean up
|
|
723
|
+
@pool.lease_connection
|
|
621
724
|
end
|
|
622
725
|
end
|
|
623
726
|
|
|
624
727
|
def test_disconnect_and_clear_reloadable_connections_are_able_to_preempt_other_waiting_threads
|
|
728
|
+
skip_fiber_testing
|
|
625
729
|
with_single_connection_pool do |pool|
|
|
626
730
|
[:disconnect, :disconnect!, :clear_reloadable_connections, :clear_reloadable_connections!].each do |group_action_method|
|
|
627
|
-
conn = pool.
|
|
731
|
+
conn = pool.lease_connection # drain the only available connection
|
|
628
732
|
second_thread_done = Concurrent::Event.new
|
|
629
733
|
|
|
630
734
|
begin
|
|
631
735
|
# create a first_thread and let it get into the FIFO queue first
|
|
632
|
-
first_thread =
|
|
736
|
+
first_thread = new_thread do
|
|
633
737
|
pool.with_connection { second_thread_done.wait }
|
|
634
738
|
end
|
|
635
739
|
|
|
636
740
|
# wait for first_thread to get in queue
|
|
637
|
-
|
|
741
|
+
pass_to(first_thread) until pool.num_waiting_in_queue == 1
|
|
638
742
|
|
|
639
743
|
# create a different, later thread, that will attempt to do a "group action",
|
|
640
744
|
# but because of the group action semantics it should be able to preempt the
|
|
641
745
|
# first_thread when a connection is made available
|
|
642
|
-
second_thread =
|
|
746
|
+
second_thread = new_thread do
|
|
643
747
|
pool.send(group_action_method)
|
|
644
748
|
second_thread_done.set
|
|
645
749
|
end
|
|
646
750
|
|
|
647
751
|
# wait for second_thread to get in queue
|
|
648
|
-
|
|
752
|
+
pass_to(second_thread) until pool.num_waiting_in_queue == 2
|
|
649
753
|
|
|
650
754
|
# return the only available connection
|
|
651
755
|
pool.checkin(conn)
|
|
@@ -662,8 +766,8 @@ module ActiveRecord
|
|
|
662
766
|
if failed
|
|
663
767
|
second_thread_done.set
|
|
664
768
|
|
|
665
|
-
first_thread
|
|
666
|
-
second_thread
|
|
769
|
+
first_thread&.join(2)
|
|
770
|
+
second_thread&.join(2)
|
|
667
771
|
end
|
|
668
772
|
|
|
669
773
|
first_thread.join(10) || raise("first_thread got stuck")
|
|
@@ -674,18 +778,19 @@ module ActiveRecord
|
|
|
674
778
|
end
|
|
675
779
|
|
|
676
780
|
def test_clear_reloadable_connections_creates_new_connections_for_waiting_threads_if_necessary
|
|
781
|
+
skip_fiber_testing
|
|
677
782
|
with_single_connection_pool do |pool|
|
|
678
|
-
conn = pool.
|
|
783
|
+
conn = pool.lease_connection # drain the only available connection
|
|
679
784
|
def conn.requires_reloading? # make sure it gets removed from the pool by clear_reloadable_connections
|
|
680
785
|
true
|
|
681
786
|
end
|
|
682
787
|
|
|
683
|
-
stuck_thread =
|
|
788
|
+
stuck_thread = new_thread do
|
|
684
789
|
pool.with_connection { }
|
|
685
790
|
end
|
|
686
791
|
|
|
687
792
|
# wait for stuck_thread to get in queue
|
|
688
|
-
|
|
793
|
+
pass_to(stuck_thread) until pool.num_waiting_in_queue == 1
|
|
689
794
|
|
|
690
795
|
pool.clear_reloadable_connections
|
|
691
796
|
|
|
@@ -698,22 +803,27 @@ module ActiveRecord
|
|
|
698
803
|
end
|
|
699
804
|
|
|
700
805
|
def test_connection_pool_stat
|
|
806
|
+
Thread.report_on_exception, original_report_on_exception = false, Thread.report_on_exception
|
|
701
807
|
with_single_connection_pool do |pool|
|
|
702
808
|
pool.with_connection do |connection|
|
|
703
809
|
stats = pool.stat
|
|
704
|
-
assert_equal({ size: 1, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout:
|
|
810
|
+
assert_equal({ size: 1, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 0.2 }, stats)
|
|
705
811
|
end
|
|
706
812
|
|
|
707
813
|
stats = pool.stat
|
|
708
|
-
assert_equal({ size: 1, connections: 1, busy: 0, dead: 0, idle: 1, waiting: 0, checkout_timeout:
|
|
814
|
+
assert_equal({ size: 1, connections: 1, busy: 0, dead: 0, idle: 1, waiting: 0, checkout_timeout: 0.2 }, stats)
|
|
709
815
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
816
|
+
assert_raise(ThreadError) do
|
|
817
|
+
new_thread do
|
|
818
|
+
pool.checkout
|
|
819
|
+
raise ThreadError
|
|
820
|
+
end.join
|
|
821
|
+
end
|
|
714
822
|
|
|
715
823
|
stats = pool.stat
|
|
716
|
-
assert_equal({ size: 1, connections: 1, busy: 0, dead: 1, idle: 0, waiting: 0, checkout_timeout:
|
|
824
|
+
assert_equal({ size: 1, connections: 1, busy: 0, dead: 1, idle: 0, waiting: 0, checkout_timeout: 0.2 }, stats)
|
|
825
|
+
ensure
|
|
826
|
+
Thread.report_on_exception = original_report_on_exception
|
|
717
827
|
end
|
|
718
828
|
end
|
|
719
829
|
|
|
@@ -729,7 +839,7 @@ module ActiveRecord
|
|
|
729
839
|
# the pool is thread-safe.
|
|
730
840
|
connections.each_index do |idx|
|
|
731
841
|
if connections[idx] == conn2
|
|
732
|
-
|
|
842
|
+
new_thread do
|
|
733
843
|
@pool.remove(conn2)
|
|
734
844
|
end.join
|
|
735
845
|
end
|
|
@@ -739,16 +849,273 @@ module ActiveRecord
|
|
|
739
849
|
assert_not_nil found_conn
|
|
740
850
|
end
|
|
741
851
|
|
|
852
|
+
def test_role_and_shard_is_returned
|
|
853
|
+
assert_equal :writing, @pool_config.role
|
|
854
|
+
assert_equal :writing, @pool.role
|
|
855
|
+
assert_equal :writing, @pool.lease_connection.role
|
|
856
|
+
|
|
857
|
+
assert_equal :default, @pool_config.shard
|
|
858
|
+
assert_equal :default, @pool.shard
|
|
859
|
+
assert_equal :default, @pool.lease_connection.shard
|
|
860
|
+
|
|
861
|
+
db_config = ActiveRecord::Base.connection_pool.db_config
|
|
862
|
+
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config, :reading, :shard_one)
|
|
863
|
+
pool = ConnectionPool.new(pool_config)
|
|
864
|
+
|
|
865
|
+
assert_equal :reading, pool_config.role
|
|
866
|
+
assert_equal :reading, pool.role
|
|
867
|
+
assert_equal :reading, pool.lease_connection.role
|
|
868
|
+
|
|
869
|
+
assert_equal :shard_one, pool_config.shard
|
|
870
|
+
assert_equal :shard_one, pool.shard
|
|
871
|
+
assert_equal :shard_one, pool.lease_connection.shard
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
def test_pin_connection_always_returns_the_same_connection
|
|
875
|
+
assert_not_predicate @pool, :active_connection?
|
|
876
|
+
@pool.pin_connection!(true)
|
|
877
|
+
pinned_connection = @pool.checkout
|
|
878
|
+
|
|
879
|
+
assert_not_predicate @pool, :active_connection?
|
|
880
|
+
assert_same pinned_connection, @pool.lease_connection
|
|
881
|
+
assert_predicate @pool, :active_connection?
|
|
882
|
+
|
|
883
|
+
assert_same pinned_connection, @pool.checkout
|
|
884
|
+
|
|
885
|
+
@pool.release_connection
|
|
886
|
+
assert_not_predicate @pool, :active_connection?
|
|
887
|
+
assert_same pinned_connection, @pool.checkout
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
def test_pin_connection_connected?
|
|
891
|
+
skip("Can't test with in-memory dbs") if in_memory_db?
|
|
892
|
+
|
|
893
|
+
assert_not_predicate @pool, :connected?
|
|
894
|
+
@pool.pin_connection!(true)
|
|
895
|
+
assert_predicate @pool, :connected?
|
|
896
|
+
|
|
897
|
+
pin_connection = @pool.checkout
|
|
898
|
+
|
|
899
|
+
@pool.disconnect
|
|
900
|
+
assert_not_predicate @pool, :connected?
|
|
901
|
+
assert_same pin_connection, @pool.checkout
|
|
902
|
+
assert_predicate @pool, :connected?
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
def test_pin_connection_synchronize_the_connection
|
|
906
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
907
|
+
@pool.pin_connection!(true)
|
|
908
|
+
assert_not_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
909
|
+
@pool.unpin_connection!
|
|
910
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
911
|
+
|
|
912
|
+
@pool.pin_connection!(false)
|
|
913
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def test_pin_connection_opens_a_transaction
|
|
917
|
+
assert_instance_of NullTransaction, @pool.lease_connection.current_transaction
|
|
918
|
+
@pool.pin_connection!(true)
|
|
919
|
+
assert_instance_of RealTransaction, @pool.lease_connection.current_transaction
|
|
920
|
+
@pool.unpin_connection!
|
|
921
|
+
assert_instance_of NullTransaction, @pool.lease_connection.current_transaction
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
def test_unpin_connection_returns_whether_transaction_has_been_rolledback
|
|
925
|
+
@pool.pin_connection!(true)
|
|
926
|
+
assert_equal true, @pool.unpin_connection!
|
|
927
|
+
|
|
928
|
+
@pool.pin_connection!(true)
|
|
929
|
+
@pool.lease_connection.commit_transaction
|
|
930
|
+
assert_equal false, @pool.unpin_connection!
|
|
931
|
+
|
|
932
|
+
@pool.pin_connection!(true)
|
|
933
|
+
@pool.lease_connection.rollback_transaction
|
|
934
|
+
assert_equal false, @pool.unpin_connection!
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
def test_pin_connection_nesting
|
|
938
|
+
assert_instance_of NullTransaction, @pool.lease_connection.current_transaction
|
|
939
|
+
@pool.pin_connection!(true)
|
|
940
|
+
assert_instance_of RealTransaction, @pool.lease_connection.current_transaction
|
|
941
|
+
@pool.pin_connection!(true)
|
|
942
|
+
assert_instance_of SavepointTransaction, @pool.lease_connection.current_transaction
|
|
943
|
+
@pool.unpin_connection!
|
|
944
|
+
assert_instance_of RealTransaction, @pool.lease_connection.current_transaction
|
|
945
|
+
@pool.unpin_connection!
|
|
946
|
+
assert_instance_of NullTransaction, @pool.lease_connection.current_transaction
|
|
947
|
+
|
|
948
|
+
assert_raises(RuntimeError, match: /There isn't a pinned connection/) do
|
|
949
|
+
@pool.unpin_connection!
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
def test_pin_connection_nesting_lock
|
|
954
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
955
|
+
|
|
956
|
+
@pool.pin_connection!(true)
|
|
957
|
+
actual_lock = @pool.lease_connection.lock
|
|
958
|
+
assert_not_equal ActiveSupport::Concurrency::NullLock, actual_lock
|
|
959
|
+
|
|
960
|
+
@pool.pin_connection!(false)
|
|
961
|
+
assert_same actual_lock, @pool.lease_connection.lock
|
|
962
|
+
|
|
963
|
+
@pool.unpin_connection!
|
|
964
|
+
assert_same actual_lock, @pool.lease_connection.lock
|
|
965
|
+
|
|
966
|
+
@pool.unpin_connection!
|
|
967
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
def test_pin_connection_nesting_lock_inverse
|
|
971
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
972
|
+
|
|
973
|
+
@pool.pin_connection!(false)
|
|
974
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
975
|
+
|
|
976
|
+
@pool.pin_connection!(true)
|
|
977
|
+
actual_lock = @pool.lease_connection.lock
|
|
978
|
+
assert_not_equal ActiveSupport::Concurrency::NullLock, actual_lock
|
|
979
|
+
|
|
980
|
+
@pool.unpin_connection!
|
|
981
|
+
assert_same actual_lock, @pool.lease_connection.lock # The lock persist until full unpin
|
|
982
|
+
|
|
983
|
+
@pool.unpin_connection!
|
|
984
|
+
assert_equal ActiveSupport::Concurrency::NullLock, @pool.lease_connection.lock
|
|
985
|
+
end
|
|
986
|
+
|
|
987
|
+
def test_inspect_does_not_show_secrets
|
|
988
|
+
assert_match(/#<ActiveRecord::ConnectionAdapters::ConnectionPool env_name="\w+" role=:writing>/, @pool.inspect)
|
|
989
|
+
|
|
990
|
+
db_config = ActiveRecord::Base.connection_pool.db_config
|
|
991
|
+
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config, :reading, :shard_one)
|
|
992
|
+
pool = ConnectionPool.new(pool_config)
|
|
993
|
+
|
|
994
|
+
assert_match(/#<ActiveRecord::ConnectionAdapters::ConnectionPool env_name="\w+" role=:reading shard=:shard_one>/, pool.inspect)
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
def test_checkout_callback_error_does_not_affect_permanent_lease_and_active_connection_state
|
|
998
|
+
checkout_error = StandardError.new("error during checkout")
|
|
999
|
+
proc_to_raise = -> { raise checkout_error }
|
|
1000
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.set_callback(:checkout, :after, proc_to_raise)
|
|
1001
|
+
|
|
1002
|
+
assert_predicate @pool, :permanent_lease?
|
|
1003
|
+
assert_not_predicate @pool, :active_connection?
|
|
1004
|
+
|
|
1005
|
+
error = assert_raises StandardError do
|
|
1006
|
+
@pool.lease_connection
|
|
1007
|
+
end
|
|
1008
|
+
assert_same checkout_error, error
|
|
1009
|
+
|
|
1010
|
+
assert_predicate @pool, :permanent_lease?
|
|
1011
|
+
assert_not_predicate @pool, :active_connection?
|
|
1012
|
+
ensure
|
|
1013
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.skip_callback(:checkout, :after, proc_to_raise)
|
|
1014
|
+
end
|
|
1015
|
+
|
|
742
1016
|
private
|
|
1017
|
+
def active_connections(pool)
|
|
1018
|
+
pool.connections.find_all(&:in_use?)
|
|
1019
|
+
end
|
|
1020
|
+
|
|
743
1021
|
def with_single_connection_pool
|
|
744
1022
|
config = @db_config.configuration_hash.merge(pool: 1)
|
|
745
1023
|
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", config)
|
|
746
|
-
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config)
|
|
1024
|
+
pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new(ActiveRecord::Base, db_config, :writing, :default)
|
|
747
1025
|
|
|
748
1026
|
yield(pool = ConnectionPool.new(pool_config))
|
|
749
1027
|
ensure
|
|
750
1028
|
pool.disconnect! if pool
|
|
751
1029
|
end
|
|
752
1030
|
end
|
|
1031
|
+
|
|
1032
|
+
class ConnectionPoolThreadTest < ActiveRecord::TestCase
|
|
1033
|
+
include ConnectionPoolTests
|
|
1034
|
+
|
|
1035
|
+
class ThreadConnectionTestModel < ActiveRecord::Base
|
|
1036
|
+
self.abstract_class = true
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
def setup
|
|
1040
|
+
super
|
|
1041
|
+
ActiveSupport::IsolatedExecutionState.isolation_level = :thread
|
|
1042
|
+
@connection_test_model_class = ThreadConnectionTestModel
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
def test_lock_thread_allow_fiber_reentrency
|
|
1046
|
+
connection = @pool.checkout
|
|
1047
|
+
connection.lock_thread = ActiveSupport::IsolatedExecutionState.context
|
|
1048
|
+
connection.transaction do
|
|
1049
|
+
enumerator = Enumerator.new do |yielder|
|
|
1050
|
+
connection.transaction do
|
|
1051
|
+
yielder.yield 1
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
assert_equal 1, enumerator.next
|
|
1055
|
+
end
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
private
|
|
1059
|
+
def new_thread(...)
|
|
1060
|
+
Thread.new(...)
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
def stop_thread
|
|
1064
|
+
Thread.stop
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
def pass_to(_thread)
|
|
1068
|
+
Thread.pass
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
def skip_fiber_testing; end
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
class ConnectionPoolFiberTest < ActiveRecord::TestCase
|
|
1075
|
+
include ConnectionPoolTests
|
|
1076
|
+
|
|
1077
|
+
class FiberConnectionTestModel < ActiveRecord::Base
|
|
1078
|
+
self.abstract_class = true
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
class ThreadlikeFiber < Fiber
|
|
1082
|
+
def join(timeout = nil)
|
|
1083
|
+
now = Time.now
|
|
1084
|
+
resume while alive? && (!timeout || Time.now - now < timeout)
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
def terminate
|
|
1088
|
+
nil
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
unless method_defined?(:kill) # RUBY_VERSION <= "3.3"
|
|
1092
|
+
def kill
|
|
1093
|
+
end
|
|
1094
|
+
end
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
def setup
|
|
1098
|
+
super
|
|
1099
|
+
ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
|
|
1100
|
+
@connection_test_model_class = FiberConnectionTestModel
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
private
|
|
1104
|
+
def new_thread(*args, &block)
|
|
1105
|
+
ThreadlikeFiber.new(*args, &block)
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
def stop_thread
|
|
1109
|
+
Fiber.yield
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
def pass_to(fiber)
|
|
1113
|
+
fiber.resume
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
def skip_fiber_testing
|
|
1117
|
+
skip "Can't test isolation_level=fiber without a Ruby 3.1+ Fiber Scheduler"
|
|
1118
|
+
end
|
|
1119
|
+
end
|
|
753
1120
|
end
|
|
754
1121
|
end
|