sequel 5.28.0 → 5.33.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.
Files changed (380) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +64 -1922
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/doc/advanced_associations.rdoc +4 -4
  6. data/doc/association_basics.rdoc +3 -3
  7. data/doc/code_order.rdoc +12 -2
  8. data/doc/model_dataset_method_design.rdoc +1 -1
  9. data/doc/postgresql.rdoc +71 -0
  10. data/doc/release_notes/5.29.0.txt +22 -0
  11. data/doc/release_notes/5.30.0.txt +20 -0
  12. data/doc/release_notes/5.31.0.txt +148 -0
  13. data/doc/release_notes/5.32.0.txt +46 -0
  14. data/doc/release_notes/5.33.0.txt +24 -0
  15. data/doc/testing.rdoc +1 -1
  16. data/lib/sequel/adapters/postgres.rb +5 -1
  17. data/lib/sequel/adapters/shared/access.rb +6 -6
  18. data/lib/sequel/adapters/shared/mssql.rb +5 -5
  19. data/lib/sequel/adapters/shared/mysql.rb +10 -10
  20. data/lib/sequel/adapters/shared/oracle.rb +16 -16
  21. data/lib/sequel/adapters/shared/postgres.rb +169 -14
  22. data/lib/sequel/adapters/shared/sqlanywhere.rb +9 -9
  23. data/lib/sequel/adapters/shared/sqlite.rb +32 -5
  24. data/lib/sequel/adapters/tinytds.rb +1 -1
  25. data/lib/sequel/connection_pool/sharded_threaded.rb +2 -2
  26. data/lib/sequel/connection_pool/threaded.rb +1 -1
  27. data/lib/sequel/core.rb +318 -314
  28. data/lib/sequel/database/query.rb +1 -1
  29. data/lib/sequel/database/schema_generator.rb +1 -1
  30. data/lib/sequel/database/transactions.rb +8 -12
  31. data/lib/sequel/dataset/misc.rb +2 -2
  32. data/lib/sequel/extensions/connection_expiration.rb +2 -2
  33. data/lib/sequel/extensions/connection_validator.rb +2 -2
  34. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  35. data/lib/sequel/extensions/index_caching.rb +9 -7
  36. data/lib/sequel/extensions/integer64.rb +2 -0
  37. data/lib/sequel/extensions/migration.rb +1 -1
  38. data/lib/sequel/extensions/pg_enum.rb +5 -2
  39. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  40. data/lib/sequel/extensions/pg_inet.rb +13 -5
  41. data/lib/sequel/extensions/pg_interval.rb +2 -0
  42. data/lib/sequel/extensions/pg_range.rb +2 -0
  43. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  44. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  45. data/lib/sequel/extensions/schema_dumper.rb +10 -4
  46. data/lib/sequel/extensions/server_block.rb +3 -3
  47. data/lib/sequel/model/associations.rb +18 -5
  48. data/lib/sequel/model/base.rb +60 -53
  49. data/lib/sequel/model/plugins.rb +1 -0
  50. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  51. data/lib/sequel/plugins/association_multi_add_remove.rb +2 -0
  52. data/lib/sequel/plugins/association_proxies.rb +2 -0
  53. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  54. data/lib/sequel/plugins/class_table_inheritance.rb +26 -26
  55. data/lib/sequel/plugins/dirty.rb +13 -13
  56. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  57. data/lib/sequel/plugins/forbid_lazy_load.rb +214 -0
  58. data/lib/sequel/plugins/json_serializer.rb +18 -11
  59. data/lib/sequel/plugins/single_table_inheritance.rb +15 -15
  60. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  61. data/lib/sequel/plugins/subclasses.rb +2 -0
  62. data/lib/sequel/plugins/throw_failures.rb +1 -1
  63. data/lib/sequel/timezones.rb +6 -4
  64. data/lib/sequel/version.rb +1 -1
  65. metadata +18 -367
  66. data/Rakefile +0 -151
  67. data/doc/release_notes/4.0.0.txt +0 -262
  68. data/doc/release_notes/4.1.0.txt +0 -85
  69. data/doc/release_notes/4.10.0.txt +0 -226
  70. data/doc/release_notes/4.11.0.txt +0 -147
  71. data/doc/release_notes/4.12.0.txt +0 -105
  72. data/doc/release_notes/4.13.0.txt +0 -169
  73. data/doc/release_notes/4.14.0.txt +0 -68
  74. data/doc/release_notes/4.15.0.txt +0 -56
  75. data/doc/release_notes/4.16.0.txt +0 -36
  76. data/doc/release_notes/4.17.0.txt +0 -38
  77. data/doc/release_notes/4.18.0.txt +0 -36
  78. data/doc/release_notes/4.19.0.txt +0 -45
  79. data/doc/release_notes/4.2.0.txt +0 -129
  80. data/doc/release_notes/4.20.0.txt +0 -79
  81. data/doc/release_notes/4.21.0.txt +0 -94
  82. data/doc/release_notes/4.22.0.txt +0 -72
  83. data/doc/release_notes/4.23.0.txt +0 -65
  84. data/doc/release_notes/4.24.0.txt +0 -99
  85. data/doc/release_notes/4.25.0.txt +0 -181
  86. data/doc/release_notes/4.26.0.txt +0 -44
  87. data/doc/release_notes/4.27.0.txt +0 -78
  88. data/doc/release_notes/4.28.0.txt +0 -57
  89. data/doc/release_notes/4.29.0.txt +0 -41
  90. data/doc/release_notes/4.3.0.txt +0 -40
  91. data/doc/release_notes/4.30.0.txt +0 -37
  92. data/doc/release_notes/4.31.0.txt +0 -57
  93. data/doc/release_notes/4.32.0.txt +0 -132
  94. data/doc/release_notes/4.33.0.txt +0 -88
  95. data/doc/release_notes/4.34.0.txt +0 -86
  96. data/doc/release_notes/4.35.0.txt +0 -130
  97. data/doc/release_notes/4.36.0.txt +0 -116
  98. data/doc/release_notes/4.37.0.txt +0 -50
  99. data/doc/release_notes/4.38.0.txt +0 -67
  100. data/doc/release_notes/4.39.0.txt +0 -127
  101. data/doc/release_notes/4.4.0.txt +0 -92
  102. data/doc/release_notes/4.40.0.txt +0 -179
  103. data/doc/release_notes/4.41.0.txt +0 -77
  104. data/doc/release_notes/4.42.0.txt +0 -221
  105. data/doc/release_notes/4.43.0.txt +0 -87
  106. data/doc/release_notes/4.44.0.txt +0 -125
  107. data/doc/release_notes/4.45.0.txt +0 -370
  108. data/doc/release_notes/4.46.0.txt +0 -404
  109. data/doc/release_notes/4.47.0.txt +0 -56
  110. data/doc/release_notes/4.48.0.txt +0 -293
  111. data/doc/release_notes/4.49.0.txt +0 -222
  112. data/doc/release_notes/4.5.0.txt +0 -34
  113. data/doc/release_notes/4.6.0.txt +0 -30
  114. data/doc/release_notes/4.7.0.txt +0 -103
  115. data/doc/release_notes/4.8.0.txt +0 -175
  116. data/doc/release_notes/4.9.0.txt +0 -190
  117. data/spec/adapter_spec.rb +0 -4
  118. data/spec/adapters/db2_spec.rb +0 -170
  119. data/spec/adapters/mssql_spec.rb +0 -828
  120. data/spec/adapters/mysql_spec.rb +0 -1060
  121. data/spec/adapters/oracle_spec.rb +0 -371
  122. data/spec/adapters/postgres_spec.rb +0 -4476
  123. data/spec/adapters/spec_helper.rb +0 -44
  124. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  125. data/spec/adapters/sqlite_spec.rb +0 -652
  126. data/spec/bin_spec.rb +0 -278
  127. data/spec/core/connection_pool_spec.rb +0 -1250
  128. data/spec/core/database_spec.rb +0 -2915
  129. data/spec/core/dataset_spec.rb +0 -5547
  130. data/spec/core/deprecated_spec.rb +0 -70
  131. data/spec/core/expression_filters_spec.rb +0 -1498
  132. data/spec/core/mock_adapter_spec.rb +0 -722
  133. data/spec/core/object_graph_spec.rb +0 -336
  134. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  135. data/spec/core/schema_generator_spec.rb +0 -214
  136. data/spec/core/schema_spec.rb +0 -1844
  137. data/spec/core/spec_helper.rb +0 -24
  138. data/spec/core/version_spec.rb +0 -14
  139. data/spec/core_extensions_spec.rb +0 -763
  140. data/spec/core_model_spec.rb +0 -2
  141. data/spec/core_spec.rb +0 -1
  142. data/spec/deprecation_helper.rb +0 -30
  143. data/spec/extensions/accessed_columns_spec.rb +0 -51
  144. data/spec/extensions/active_model_spec.rb +0 -99
  145. data/spec/extensions/after_initialize_spec.rb +0 -28
  146. data/spec/extensions/any_not_empty_spec.rb +0 -23
  147. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  148. data/spec/extensions/association_dependencies_spec.rb +0 -125
  149. data/spec/extensions/association_multi_add_remove_spec.rb +0 -1041
  150. data/spec/extensions/association_pks_spec.rb +0 -423
  151. data/spec/extensions/association_proxies_spec.rb +0 -100
  152. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  153. data/spec/extensions/auto_validations_spec.rb +0 -229
  154. data/spec/extensions/blacklist_security_spec.rb +0 -95
  155. data/spec/extensions/blank_spec.rb +0 -69
  156. data/spec/extensions/boolean_readers_spec.rb +0 -93
  157. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  158. data/spec/extensions/caching_spec.rb +0 -273
  159. data/spec/extensions/caller_logging_spec.rb +0 -52
  160. data/spec/extensions/class_table_inheritance_spec.rb +0 -750
  161. data/spec/extensions/column_conflicts_spec.rb +0 -75
  162. data/spec/extensions/column_select_spec.rb +0 -129
  163. data/spec/extensions/columns_introspection_spec.rb +0 -90
  164. data/spec/extensions/columns_updated_spec.rb +0 -35
  165. data/spec/extensions/composition_spec.rb +0 -248
  166. data/spec/extensions/connection_expiration_spec.rb +0 -151
  167. data/spec/extensions/connection_validator_spec.rb +0 -144
  168. data/spec/extensions/constant_sql_override_spec.rb +0 -24
  169. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  170. data/spec/extensions/constraint_validations_spec.rb +0 -439
  171. data/spec/extensions/core_refinements_spec.rb +0 -528
  172. data/spec/extensions/csv_serializer_spec.rb +0 -183
  173. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  174. data/spec/extensions/dataset_associations_spec.rb +0 -365
  175. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  176. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  177. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  178. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  179. data/spec/extensions/defaults_setter_spec.rb +0 -150
  180. data/spec/extensions/delay_add_association_spec.rb +0 -73
  181. data/spec/extensions/dirty_spec.rb +0 -222
  182. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  183. data/spec/extensions/eager_each_spec.rb +0 -62
  184. data/spec/extensions/eager_graph_eager_spec.rb +0 -100
  185. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  186. data/spec/extensions/error_splitter_spec.rb +0 -18
  187. data/spec/extensions/error_sql_spec.rb +0 -20
  188. data/spec/extensions/escaped_like_spec.rb +0 -40
  189. data/spec/extensions/eval_inspect_spec.rb +0 -81
  190. data/spec/extensions/exclude_or_null_spec.rb +0 -15
  191. data/spec/extensions/finder_spec.rb +0 -260
  192. data/spec/extensions/force_encoding_spec.rb +0 -126
  193. data/spec/extensions/freeze_datasets_spec.rb +0 -31
  194. data/spec/extensions/graph_each_spec.rb +0 -113
  195. data/spec/extensions/hook_class_methods_spec.rb +0 -402
  196. data/spec/extensions/identifier_mangling_spec.rb +0 -201
  197. data/spec/extensions/implicit_subquery_spec.rb +0 -58
  198. data/spec/extensions/index_caching_spec.rb +0 -66
  199. data/spec/extensions/inflector_spec.rb +0 -183
  200. data/spec/extensions/input_transformer_spec.rb +0 -69
  201. data/spec/extensions/insert_conflict_spec.rb +0 -103
  202. data/spec/extensions/insert_returning_select_spec.rb +0 -72
  203. data/spec/extensions/instance_filters_spec.rb +0 -79
  204. data/spec/extensions/instance_hooks_spec.rb +0 -246
  205. data/spec/extensions/integer64_spec.rb +0 -22
  206. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  207. data/spec/extensions/json_serializer_spec.rb +0 -336
  208. data/spec/extensions/lazy_attributes_spec.rb +0 -183
  209. data/spec/extensions/list_spec.rb +0 -291
  210. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  211. data/spec/extensions/many_through_many_spec.rb +0 -2177
  212. data/spec/extensions/migration_spec.rb +0 -864
  213. data/spec/extensions/modification_detection_spec.rb +0 -93
  214. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
  215. data/spec/extensions/named_timezones_spec.rb +0 -218
  216. data/spec/extensions/nested_attributes_spec.rb +0 -815
  217. data/spec/extensions/null_dataset_spec.rb +0 -85
  218. data/spec/extensions/optimistic_locking_spec.rb +0 -127
  219. data/spec/extensions/pagination_spec.rb +0 -116
  220. data/spec/extensions/pg_array_associations_spec.rb +0 -802
  221. data/spec/extensions/pg_array_ops_spec.rb +0 -144
  222. data/spec/extensions/pg_array_spec.rb +0 -398
  223. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -209
  224. data/spec/extensions/pg_enum_spec.rb +0 -118
  225. data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
  226. data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
  227. data/spec/extensions/pg_hstore_spec.rb +0 -219
  228. data/spec/extensions/pg_inet_ops_spec.rb +0 -102
  229. data/spec/extensions/pg_inet_spec.rb +0 -72
  230. data/spec/extensions/pg_interval_spec.rb +0 -103
  231. data/spec/extensions/pg_json_ops_spec.rb +0 -356
  232. data/spec/extensions/pg_json_spec.rb +0 -451
  233. data/spec/extensions/pg_loose_count_spec.rb +0 -23
  234. data/spec/extensions/pg_range_ops_spec.rb +0 -60
  235. data/spec/extensions/pg_range_spec.rb +0 -600
  236. data/spec/extensions/pg_row_ops_spec.rb +0 -61
  237. data/spec/extensions/pg_row_plugin_spec.rb +0 -60
  238. data/spec/extensions/pg_row_spec.rb +0 -363
  239. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
  240. data/spec/extensions/pg_timestamptz_spec.rb +0 -17
  241. data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
  242. data/spec/extensions/prepared_statements_spec.rb +0 -177
  243. data/spec/extensions/pretty_table_spec.rb +0 -123
  244. data/spec/extensions/query_spec.rb +0 -94
  245. data/spec/extensions/rcte_tree_spec.rb +0 -387
  246. data/spec/extensions/round_timestamps_spec.rb +0 -39
  247. data/spec/extensions/s_spec.rb +0 -60
  248. data/spec/extensions/schema_caching_spec.rb +0 -64
  249. data/spec/extensions/schema_dumper_spec.rb +0 -870
  250. data/spec/extensions/select_remove_spec.rb +0 -38
  251. data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
  252. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  253. data/spec/extensions/serialization_spec.rb +0 -365
  254. data/spec/extensions/server_block_spec.rb +0 -135
  255. data/spec/extensions/server_logging_spec.rb +0 -45
  256. data/spec/extensions/sharding_spec.rb +0 -197
  257. data/spec/extensions/shared_caching_spec.rb +0 -151
  258. data/spec/extensions/single_table_inheritance_spec.rb +0 -347
  259. data/spec/extensions/singular_table_names_spec.rb +0 -22
  260. data/spec/extensions/skip_create_refresh_spec.rb +0 -18
  261. data/spec/extensions/spec_helper.rb +0 -70
  262. data/spec/extensions/split_array_nil_spec.rb +0 -24
  263. data/spec/extensions/split_values_spec.rb +0 -57
  264. data/spec/extensions/sql_comments_spec.rb +0 -33
  265. data/spec/extensions/sql_expr_spec.rb +0 -59
  266. data/spec/extensions/static_cache_cache_spec.rb +0 -35
  267. data/spec/extensions/static_cache_spec.rb +0 -471
  268. data/spec/extensions/string_agg_spec.rb +0 -90
  269. data/spec/extensions/string_date_time_spec.rb +0 -95
  270. data/spec/extensions/string_stripper_spec.rb +0 -68
  271. data/spec/extensions/subclasses_spec.rb +0 -79
  272. data/spec/extensions/subset_conditions_spec.rb +0 -38
  273. data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
  274. data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
  275. data/spec/extensions/synchronize_sql_spec.rb +0 -124
  276. data/spec/extensions/table_select_spec.rb +0 -83
  277. data/spec/extensions/tactical_eager_loading_spec.rb +0 -402
  278. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  279. data/spec/extensions/throw_failures_spec.rb +0 -74
  280. data/spec/extensions/timestamps_spec.rb +0 -209
  281. data/spec/extensions/to_dot_spec.rb +0 -153
  282. data/spec/extensions/touch_spec.rb +0 -226
  283. data/spec/extensions/tree_spec.rb +0 -334
  284. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  285. data/spec/extensions/unlimited_update_spec.rb +0 -21
  286. data/spec/extensions/update_or_create_spec.rb +0 -83
  287. data/spec/extensions/update_primary_key_spec.rb +0 -105
  288. data/spec/extensions/update_refresh_spec.rb +0 -59
  289. data/spec/extensions/uuid_spec.rb +0 -101
  290. data/spec/extensions/validate_associated_spec.rb +0 -52
  291. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  292. data/spec/extensions/validation_contexts_spec.rb +0 -31
  293. data/spec/extensions/validation_helpers_spec.rb +0 -525
  294. data/spec/extensions/whitelist_security_spec.rb +0 -157
  295. data/spec/extensions/xml_serializer_spec.rb +0 -213
  296. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  297. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  298. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  299. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  300. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  301. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  302. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  303. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  304. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  305. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  306. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  307. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  308. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  309. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  310. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  311. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  312. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  313. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  314. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  315. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  316. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  317. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  318. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  319. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  320. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  321. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  322. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  323. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  324. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  325. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  326. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  327. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  328. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  329. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  330. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  331. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  332. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  333. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  334. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  335. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  336. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  337. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  338. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  339. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  340. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  341. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  342. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  343. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  344. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  345. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  346. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  347. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  348. data/spec/guards_helper.rb +0 -59
  349. data/spec/integration/associations_test.rb +0 -2597
  350. data/spec/integration/database_test.rb +0 -113
  351. data/spec/integration/dataset_test.rb +0 -2037
  352. data/spec/integration/eager_loader_test.rb +0 -687
  353. data/spec/integration/migrator_test.rb +0 -262
  354. data/spec/integration/model_test.rb +0 -203
  355. data/spec/integration/plugin_test.rb +0 -2423
  356. data/spec/integration/prepared_statement_test.rb +0 -405
  357. data/spec/integration/schema_test.rb +0 -903
  358. data/spec/integration/spec_helper.rb +0 -71
  359. data/spec/integration/timezone_test.rb +0 -86
  360. data/spec/integration/transaction_test.rb +0 -603
  361. data/spec/integration/type_test.rb +0 -127
  362. data/spec/model/association_reflection_spec.rb +0 -803
  363. data/spec/model/associations_spec.rb +0 -4738
  364. data/spec/model/base_spec.rb +0 -875
  365. data/spec/model/class_dataset_methods_spec.rb +0 -146
  366. data/spec/model/dataset_methods_spec.rb +0 -198
  367. data/spec/model/eager_loading_spec.rb +0 -2377
  368. data/spec/model/hooks_spec.rb +0 -370
  369. data/spec/model/inflector_spec.rb +0 -26
  370. data/spec/model/model_spec.rb +0 -956
  371. data/spec/model/plugins_spec.rb +0 -429
  372. data/spec/model/record_spec.rb +0 -2118
  373. data/spec/model/spec_helper.rb +0 -46
  374. data/spec/model/validations_spec.rb +0 -220
  375. data/spec/model_no_assoc_spec.rb +0 -1
  376. data/spec/model_spec.rb +0 -1
  377. data/spec/plugin_spec.rb +0 -1
  378. data/spec/sequel_coverage.rb +0 -15
  379. data/spec/sequel_warning.rb +0 -4
  380. data/spec/spec_config.rb +0 -12
@@ -1,278 +0,0 @@
1
- require 'rbconfig'
2
- require 'yaml'
3
-
4
- RUBY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['RUBY_INSTALL_NAME'])
5
- OUTPUT = "spec/bin-sequel-spec-output-#{$$}.log"
6
- TMP_FILE = "spec/bin-sequel-tmp-#{$$}.rb"
7
- BIN_SPEC_DB = "spec/bin-sequel-spec-db-#{$$}.sqlite3"
8
- BIN_SPEC_DB2 = "spec/bin-sequel-spec-db2-#{$$}.sqlite3"
9
-
10
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
11
- CONN_PREFIX = 'jdbc:sqlite:'
12
- CONN_HASH = {:adapter=>'jdbc', :uri=>"#{CONN_PREFIX}#{BIN_SPEC_DB}"}
13
- else
14
- CONN_PREFIX = 'sqlite://'
15
- CONN_HASH = {:adapter=>'sqlite', :database=>BIN_SPEC_DB}
16
- end
17
-
18
- require_relative '../lib/sequel'
19
-
20
- Sequel::DB = nil
21
- File.delete(BIN_SPEC_DB) if File.file?(BIN_SPEC_DB)
22
- File.delete(BIN_SPEC_DB2) if File.file?(BIN_SPEC_DB2)
23
- DB = Sequel.connect("#{CONN_PREFIX}#{BIN_SPEC_DB}", :test=>false)
24
- DB2 = Sequel.connect("#{CONN_PREFIX}#{BIN_SPEC_DB2}", :test=>false)
25
-
26
- ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
27
- gem 'minitest'
28
- require 'minitest/global_expectations/autorun'
29
-
30
- describe "bin/sequel" do
31
- def bin(opts={})
32
- cmd = "#{opts[:pre]}\"#{RUBY}\" -I lib bin/sequel #{opts[:args]} #{"#{CONN_PREFIX}#{BIN_SPEC_DB}" unless opts[:no_conn]} #{opts[:post]}> #{OUTPUT}#{" 2>&1" if opts[:stderr]}"
33
- system(cmd)
34
- File.read(OUTPUT)
35
- end
36
-
37
- after do
38
- DB.disconnect
39
- DB2.disconnect
40
- [BIN_SPEC_DB, BIN_SPEC_DB2, TMP_FILE, OUTPUT].each do |file|
41
- if File.file?(file)
42
- begin
43
- File.delete(file)
44
- rescue Errno::ENOENT
45
- nil
46
- end
47
- end
48
- end
49
- end
50
-
51
- it "-h should print the help" do
52
- help = bin(:args=>"-h", :no_conn=>true)
53
- help.must_match(/\ASequel: The Database Toolkit for Ruby/)
54
- help.must_match(/^Usage: sequel /)
55
- end
56
-
57
- it "-c should run code" do
58
- bin(:args=>'-c "print DB.tables.inspect"').must_equal '[]'
59
- DB.create_table(:a){Integer :a}
60
- bin(:args=>'-c "print DB.tables.inspect"').must_equal '[:a]'
61
- bin(:args=>'-v -c "print DB.tables.inspect"').strip.must_equal "sequel #{Sequel.version}\n[:a]"
62
- end
63
-
64
- it "-C should copy databases" do
65
- DB.create_table(:a) do
66
- primary_key :a
67
- String :name
68
- end
69
- DB.create_table(:b) do
70
- foreign_key :a, :a
71
- index :a
72
- end
73
- DB[:a].insert(1, 'foo')
74
- DB[:b].insert(1)
75
- bin(:args=>'-C', :post=>"#{CONN_PREFIX}#{BIN_SPEC_DB2}").must_match Regexp.new(<<END)
76
- Databases connections successful
77
- Migrations dumped successfully
78
- Tables created
79
- Begin copying data
80
- Begin copying records for table: a
81
- Finished copying 1 records for table: a
82
- Begin copying records for table: b
83
- Finished copying 1 records for table: b
84
- Finished copying data
85
- Begin creating indexes
86
- Finished creating indexes
87
- Begin adding foreign key constraints
88
- Finished adding foreign key constraints
89
- Database copy finished in \\d+\\.\\d+ seconds
90
- END
91
- DB2.tables.sort_by{|t| t.to_s}.must_equal [:a, :b]
92
- DB[:a].all.must_equal [{:a=>1, :name=>'foo'}]
93
- DB[:b].all.must_equal [{:a=>1}]
94
- DB2.schema(:a).map{|col, sch| [col, *sch.values_at(:allow_null, :default, :primary_key, :db_type, :type, :ruby_default)]}.must_equal [[:a, false, nil, true, "integer", :integer, nil], [:name, true, nil, false, "varchar(255)", :string, nil]]
95
- DB2.schema(:b).map{|col, sch| [col, *sch.values_at(:allow_null, :default, :primary_key, :db_type, :type, :ruby_default)]}.must_equal [[:a, true, nil, false, "integer", :integer, nil]]
96
- DB2.indexes(:a).must_equal({})
97
- DB2.indexes(:b).must_equal(:b_a_index=>{:unique=>false, :columns=>[:a]})
98
- DB2.foreign_key_list(:a).must_equal []
99
- DB2.foreign_key_list(:b).must_equal [{:columns=>[:a], :table=>:a, :key=>nil, :on_update=>:no_action, :on_delete=>:no_action}]
100
- end
101
-
102
- it "-C should convert integer to bigint when copying from SQLite to other databases" do
103
- DB.create_table(:a) do
104
- Integer :id
105
- end
106
- bin(:args=>'-EC', :post=>"mock://postgres").must_include 'CREATE TABLE "a" ("id" bigint)'
107
- end
108
-
109
- it "-d and -D should dump generic and specific migrations" do
110
- DB.create_table(:a) do
111
- primary_key :a
112
- String :name
113
- end
114
- DB.create_table(:b) do
115
- foreign_key :a, :a
116
- index :a
117
- end
118
- bin(:args=>'-d').must_equal <<END
119
- Sequel.migration do
120
- change do
121
- create_table(:a) do
122
- primary_key :a
123
- String :name, :size=>255
124
- end
125
-
126
- create_table(:b, :ignore_index_errors=>true) do
127
- foreign_key :a, :a
128
-
129
- index [:a]
130
- end
131
- end
132
- end
133
- END
134
- bin(:args=>'-D').must_equal <<END
135
- Sequel.migration do
136
- change do
137
- create_table(:a) do
138
- primary_key :a
139
- column :name, "varchar(255)"
140
- end
141
-
142
- create_table(:b) do
143
- foreign_key :a, :a
144
-
145
- index [:a]
146
- end
147
- end
148
- end
149
- END
150
- end
151
-
152
- it "-E should echo SQL statements to stdout" do
153
- bin(:args=>'-E -c DB.tables').must_include "SELECT * FROM `sqlite_master` WHERE ((`name` != 'sqlite_sequence') AND (`type` = 'table'))"
154
- end
155
-
156
- it "-I should include directory in load path" do
157
- bin(:args=>'-Ifoo -c "p 1 if $:.include?(\'foo\')"').must_equal "1\n"
158
- end
159
-
160
- it "-l should log SQL statements to file" do
161
- bin(:args=>"-l #{TMP_FILE} -c DB.tables").must_equal ''
162
- File.read(TMP_FILE).must_include "SELECT * FROM `sqlite_master` WHERE ((`name` != 'sqlite_sequence') AND (`type` = 'table'))"
163
- end
164
-
165
- it "-L should load all *.rb files in given directory" do
166
- bin(:args=>'-r ./lib/sequel/extensions/migration -L ./spec/files/integer_migrations -c "p Sequel::Migration.descendants.length"').must_equal "3\n"
167
- end
168
-
169
- it "-m should migrate database up" do
170
- bin(:args=>"-m spec/files/integer_migrations").must_equal ''
171
- DB.tables.sort_by{|t| t.to_s}.must_equal [:schema_info, :sm1111, :sm2222, :sm3333]
172
- end
173
-
174
- it "-M should specify version to migrate to" do
175
- bin(:args=>"-m spec/files/integer_migrations -M 2").must_equal ''
176
- DB.tables.sort_by{|t| t.to_s}.must_equal [:schema_info, :sm1111, :sm2222]
177
- end
178
-
179
- it "-N should not test for a valid connection" do
180
- bin(:no_conn=>true, :args=>"-c '' -N #{CONN_PREFIX}spec/nonexistent/foo").must_equal ''
181
- bin(:no_conn=>true, :args=>"-c '' #{CONN_PREFIX}spec/nonexistent/foo", :stderr=>true).must_match(/\AError: Sequel::DatabaseConnectionError: /)
182
- end
183
-
184
- it "-r should require a given library" do
185
- bin(:args=>'-rsequel/extensions/sql_expr -c "print DB.literal(1.sql_expr)"').must_equal "1"
186
- end
187
-
188
- it "-S should dump the schema cache" do
189
- bin(:args=>"-S #{TMP_FILE}").must_equal ''
190
- Marshal.load(File.read(TMP_FILE)).must_equal({})
191
- DB.create_table(:a){Integer :a}
192
- bin(:args=>"-S #{TMP_FILE}").must_equal ''
193
- Marshal.load(File.read(TMP_FILE)).must_equal("`a`"=>[[:a, {:type=>:integer, :db_type=>"integer", :ruby_default=>nil, :allow_null=>true, :default=>nil, :primary_key=>false}]])
194
- end
195
-
196
- it "-X should dump the index cache" do
197
- bin(:args=>"-X #{TMP_FILE}").must_equal ''
198
- Marshal.load(File.read(TMP_FILE)).must_equal({})
199
- DB.create_table(:a){Integer :id}
200
- DB.create_table(:b){Integer :b, index: {name: "idx_test", unique: true}}
201
- bin(:args=>"-X #{TMP_FILE}").must_equal ''
202
- Marshal.load(File.read(TMP_FILE)).must_equal("`a`"=>{}, "`b`"=>{:idx_test=>{:unique=>true, :columns=>[:b]}})
203
- end
204
-
205
- it "-t should output full backtraces on error" do
206
- bin(:args=>'-c "lambda{lambda{lambda{raise \'foo\'}.call}.call}.call"', :stderr=>true).count("\n").must_be :<, 3
207
- bin(:args=>'-t -c "lambda{lambda{lambda{raise \'foo\'}.call}.call}.call"', :stderr=>true).count("\n").must_be :>, 3
208
- end
209
-
210
- it "-v should output the Sequel version and exit if database is not given" do
211
- bin(:args=>"-v", :no_conn=>true).strip.must_equal "sequel #{Sequel.version}"
212
- end
213
-
214
- it "should error if using -M without -m" do
215
- bin(:args=>'-M 2', :stderr=>true).must_equal "Error: Must specify -m if using -M\n"
216
- end
217
-
218
- it "should error if using mutually exclusive options together" do
219
- bin(:args=>'-c foo -d', :stderr=>true).must_equal "Error: Cannot specify -c and -d together\n"
220
- bin(:args=>'-D -d', :stderr=>true).must_equal "Error: Cannot specify -D and -d together\n"
221
- bin(:args=>'-m foo -d', :stderr=>true).must_equal "Error: Cannot specify -m and -d together\n"
222
- bin(:args=>'-S foo -d', :stderr=>true).must_equal "Error: Cannot specify -S and -d together\n"
223
- bin(:args=>'-S foo -C', :stderr=>true).must_equal "Error: Cannot specify -S and -C together\n"
224
- end
225
-
226
- it "should warn if providing too many arguments" do
227
- bin(:args=>'-c "" "" 1 2 3 4', :stderr=>true).must_equal "Warning: last 5 arguments ignored\n"
228
- end
229
-
230
- it "should use a mock database if no database is given" do
231
- bin(:args=>'-c "print DB.adapter_scheme"', :no_conn=>true).must_equal "mock"
232
- end
233
-
234
- it "should work with a yaml config file" do
235
- File.open(TMP_FILE, 'wb'){|f| f.write(YAML.dump(CONN_HASH))}
236
- bin(:args=>"-c \"print DB.tables.inspect\" #{TMP_FILE}", :no_conn=>true).must_equal "[]"
237
- DB.create_table(:a){Integer :a}
238
- bin(:args=>"-c \"print DB.tables.inspect\" #{TMP_FILE}", :no_conn=>true).must_equal "[:a]"
239
- end
240
-
241
- it "should work with a yaml config file with string keys" do
242
- h = {}
243
- CONN_HASH.each{|k,v| h[k.to_s] = v}
244
- File.open(TMP_FILE, 'wb'){|f| f.write(YAML.dump(h))}
245
- DB.create_table(:a){Integer :a}
246
- bin(:args=>"-c \"print DB.tables.inspect\" #{TMP_FILE}", :no_conn=>true).must_equal "[:a]"
247
- end
248
-
249
- it "should work with a yaml config file with environments" do
250
- File.open(TMP_FILE, 'wb'){|f| f.write(YAML.dump(:development=>CONN_HASH))}
251
- bin(:args=>"-c \"print DB.tables.inspect\" #{TMP_FILE}", :no_conn=>true).must_equal "[]"
252
- DB.create_table(:a){Integer :a}
253
- bin(:args=>"-c \"print DB.tables.inspect\" #{TMP_FILE}", :no_conn=>true).must_equal "[:a]"
254
- end
255
-
256
- it "-e should set environment for yaml config file" do
257
- File.open(TMP_FILE, 'wb'){|f| f.write(YAML.dump(:foo=>CONN_HASH))}
258
- bin(:args=>"-c \"print DB.tables.inspect\" -e foo #{TMP_FILE}", :no_conn=>true).must_equal "[]"
259
- DB.create_table(:a){Integer :a}
260
- bin(:args=>"-c \"print DB.tables.inspect\" -e foo #{TMP_FILE}", :no_conn=>true).must_equal "[:a]"
261
- File.open(TMP_FILE, 'wb'){|f| f.write(YAML.dump('foo'=>CONN_HASH))}
262
- bin(:args=>"-c \"print DB.tables.inspect\" -e foo #{TMP_FILE}", :no_conn=>true).must_equal "[:a]"
263
- end
264
-
265
- it "should run code in given filenames" do
266
- File.open(TMP_FILE, 'wb'){|f| f.write('print DB.tables.inspect')}
267
- bin(:post=>TMP_FILE).must_equal '[]'
268
- DB.create_table(:a){Integer :a}
269
- bin(:post=>TMP_FILE).must_equal '[:a]'
270
- bin(:post=>TMP_FILE, :args=>'-v').strip.must_equal "sequel #{Sequel.version}\n[:a]"
271
- end
272
-
273
- it "should run code provided on stdin" do
274
- bin(:pre=>'echo print DB.tables.inspect | ').must_equal '[]'
275
- DB.create_table(:a){Integer :a}
276
- bin(:pre=>'echo print DB.tables.inspect | ').must_equal '[:a]'
277
- end
278
- end
@@ -1,1250 +0,0 @@
1
- require_relative "spec_helper"
2
- require_relative '../../lib/sequel/connection_pool/sharded_threaded'
3
-
4
- connection_pool_defaults = {:pool_timeout=>5, :max_connections=>4}
5
- st_connection_pool_defaults = connection_pool_defaults.merge(:single_threaded=>true)
6
-
7
- mock_db = lambda do |*a, &b|
8
- db = Sequel.mock
9
- db.define_singleton_method(:connect){|c| b.arity == 1 ? b.call(c) : b.call} if b
10
- if b2 = a.shift
11
- db.define_singleton_method(:disconnect_connection){|c| b2.arity == 1 ? b2.call(c) : b2.call}
12
- end
13
- # Work around JRuby Issue #3854
14
- db.singleton_class.send(:public, :connect, :disconnect_connection)
15
- db
16
- end
17
-
18
- describe "An empty ConnectionPool" do
19
- before do
20
- @cpool = Sequel::ConnectionPool.get_pool(mock_db.call, connection_pool_defaults)
21
- end
22
-
23
- it "should have no available connections" do
24
- @cpool.available_connections.must_equal []
25
- end
26
-
27
- it "should have no allocated connections" do
28
- @cpool.allocated.must_equal({})
29
- end
30
-
31
- it "should have a size of zero" do
32
- @cpool.size.must_equal 0
33
- end
34
-
35
- it "should raise Error for bad pool class" do
36
- proc{Sequel::ConnectionPool.get_pool(mock_db.call, :pool_class=>:foo)}.must_raise Sequel::Error
37
- end
38
- end
39
-
40
- describe "ConnectionPool options" do
41
- it "should support string option values" do
42
- cpool = Sequel::ConnectionPool.get_pool(mock_db.call, {:max_connections=>'5', :pool_timeout=>'3'})
43
- cpool.max_size.must_equal 5
44
- cpool.instance_variable_get(:@timeout).must_equal 3
45
- end
46
-
47
- it "should raise an error unless size is positive" do
48
- lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>0)}.must_raise(Sequel::Error)
49
- lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>-10)}.must_raise(Sequel::Error)
50
- lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>'-10')}.must_raise(Sequel::Error)
51
- lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>'0')}.must_raise(Sequel::Error)
52
- end
53
- end
54
-
55
- describe "A connection pool handling connections" do
56
- before do
57
- @max_size = 2
58
- msp = proc{@max_size=3}
59
- @cpool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){:got_connection}, connection_pool_defaults.merge(:max_connections=>@max_size))
60
- end
61
-
62
- it "#hold should increment #size" do
63
- @cpool.hold do
64
- @cpool.size.must_equal 1
65
- @cpool.hold {@cpool.hold {@cpool.size.must_equal 1}}
66
- Thread.new{@cpool.hold {_(@cpool.size).must_equal 2}}.join
67
- end
68
- end
69
-
70
- it "#hold should add the connection to the #allocated array" do
71
- @cpool.hold do
72
- @cpool.allocated.size.must_equal 1
73
-
74
- @cpool.allocated.must_equal(Thread.current=>:got_connection)
75
- end
76
- end
77
-
78
- it "#hold should yield a new connection" do
79
- @cpool.hold {|conn| conn.must_equal :got_connection}
80
- end
81
-
82
- it "a connection should be de-allocated after it has been used in #hold" do
83
- @cpool.hold {}
84
- @cpool.allocated.size.must_equal 0
85
- end
86
-
87
- it "#hold should return the value of its block" do
88
- @cpool.hold {:block_return}.must_equal :block_return
89
- end
90
-
91
- it "#make_new should not make more than max_size connections" do
92
- q = Queue.new
93
- 50.times{Thread.new{@cpool.hold{q.pop}}}
94
- 50.times{q.push nil}
95
- @cpool.size.must_be :<=, @max_size
96
- end
97
-
98
- it "database's disconnect connection method should be called when a disconnect is detected" do
99
- @max_size.must_equal 2
100
- proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
101
- @max_size.must_equal 3
102
- end
103
-
104
- it "#hold should remove the connection if a DatabaseDisconnectError is raised" do
105
- @cpool.size.must_equal 0
106
- q, q1 = Queue.new, Queue.new
107
- @cpool.hold{Thread.new{@cpool.hold{q1.pop; q.push nil}; q1.pop; q.push nil}; q1.push nil; q.pop; q1.push nil; q.pop}
108
- @cpool.size.must_equal 2
109
- proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
110
- @cpool.size.must_equal 1
111
- proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
112
- @cpool.size.must_equal 0
113
- proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
114
- @cpool.size.must_equal 0
115
- end
116
- end
117
-
118
- describe "A connection pool handling connection errors" do
119
- it "#hold should raise a Sequel::DatabaseConnectionError if an exception is raised by the connection_proc" do
120
- cpool = Sequel::ConnectionPool.get_pool(mock_db.call{raise Interrupt}, connection_pool_defaults)
121
- proc{cpool.hold{:block_return}}.must_raise(Sequel::DatabaseConnectionError)
122
- cpool.size.must_equal 0
123
- end
124
-
125
- it "#hold should raise a Sequel::DatabaseConnectionError if nil is returned by the connection_proc" do
126
- cpool = Sequel::ConnectionPool.get_pool(mock_db.call{nil}, connection_pool_defaults)
127
- proc{cpool.hold{:block_return}}.must_raise(Sequel::DatabaseConnectionError)
128
- cpool.size.must_equal 0
129
- end
130
- end
131
-
132
- describe "ConnectionPool#hold" do
133
- before do
134
- value = 0
135
- c = @c = Class.new do
136
- define_method(:initialize){value += 1}
137
- define_method(:value){value}
138
- end
139
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{c.new}, connection_pool_defaults)
140
- end
141
-
142
- it "shoulda use the database's connect method to get new connections" do
143
- res = nil
144
- @pool.hold {|c| res = c}
145
- res.must_be_kind_of(@c)
146
- res.value.must_equal 1
147
- @pool.hold {|c| res = c}
148
- res.must_be_kind_of(@c)
149
- res.value.must_equal 1 # the connection maker is invoked only once
150
- end
151
-
152
- it "should be re-entrant by the same thread" do
153
- cc = nil
154
- @pool.hold {|c| @pool.hold {|c1| @pool.hold {|c2| cc = c2}}}
155
- cc.must_be_kind_of(@c)
156
- end
157
-
158
- it "should catch exceptions and reraise them" do
159
- proc {@pool.hold {|c| c.foobar}}.must_raise(NoMethodError)
160
- end
161
- end
162
-
163
- describe "A connection pool with a max size of 1" do
164
- before do
165
- @invoked_count = 0
166
- icp = proc{@invoked_count += 1}
167
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{icp.call; 'herro'.dup}, connection_pool_defaults.merge(:max_connections=>1))
168
- end
169
-
170
- it "should let only one thread access the connection at any time" do
171
- cc,c1, c2 = nil
172
- q, q1 = Queue.new, Queue.new
173
-
174
- t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; q1.push nil; q.pop}}
175
- q1.pop
176
- cc.must_equal 'herro'
177
- c1.must_equal 'herro'
178
-
179
- t2 = Thread.new {@pool.hold {|c| c2 = c.dup; q1.push nil; q.pop;}}
180
-
181
- # connection held by t1
182
- t1.must_be :alive?
183
- t2.must_be :alive?
184
-
185
- cc.must_equal 'herro'
186
- c1.must_equal 'herro'
187
- c2.must_be_nil
188
-
189
- @pool.available_connections.must_be :empty?
190
- @pool.allocated.must_equal(t1=>cc)
191
-
192
- cc.gsub!('rr', 'll')
193
- q.push nil
194
- q1.pop
195
-
196
- t1.join
197
- t2.must_be :alive?
198
-
199
- c2.must_equal 'hello'
200
-
201
- @pool.available_connections.must_be :empty?
202
- @pool.allocated.must_equal(t2=>cc)
203
-
204
- #connection released
205
- q.push nil
206
- t2.join
207
-
208
- @invoked_count.must_equal 1
209
- @pool.size.must_equal 1
210
- @pool.available_connections.must_equal [cc]
211
- @pool.allocated.must_be :empty?
212
- end
213
-
214
- it "should let the same thread reenter #hold" do
215
- c1, c2, c3 = nil
216
- @pool.hold do |c|
217
- c1 = c
218
- @pool.hold do |cc2|
219
- c2 = cc2
220
- @pool.hold do |cc3|
221
- c3 = cc3
222
- end
223
- end
224
- end
225
- c1.must_equal 'herro'
226
- c2.must_equal 'herro'
227
- c3.must_equal 'herro'
228
-
229
- @invoked_count.must_equal 1
230
- @pool.size.must_equal 1
231
- @pool.available_connections.size.must_equal 1
232
- @pool.allocated.must_be :empty?
233
- end
234
- end
235
-
236
- ThreadedConnectionPoolSpecs = shared_description do
237
- it "should not have all_connections yield connections allocated to other threads" do
238
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
239
- q, q1 = Queue.new, Queue.new
240
- t = Thread.new do
241
- pool.hold do |c1|
242
- q1.push nil
243
- q.pop
244
- end
245
- end
246
- pool.hold do |c1|
247
- q1.pop
248
- pool.all_connections{|c| c.must_equal c1}
249
- q.push nil
250
- end
251
- t.join
252
- end
253
-
254
- it "should work when acquire fails and then succeeds" do
255
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
256
- def pool._acquire(*)
257
- if @called
258
- super
259
- else
260
- @called = true
261
- nil
262
- end
263
- end
264
- c = nil
265
- pool.hold do |c1|
266
- c = c1
267
- end
268
- c.wont_be_nil
269
- end
270
-
271
- it "should wait until a connection is available if all are checked out" do
272
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>1, :pool_timeout=>0.1))
273
- q, q1 = Queue.new, Queue.new
274
- t = Thread.new do
275
- pool.hold do |c|
276
- q1.push nil
277
- 3.times{Thread.pass}
278
- q.pop
279
- end
280
- end
281
- q1.pop
282
- proc{pool.hold{}}.must_raise(Sequel::PoolTimeout)
283
- q.push nil
284
- t.join
285
- end
286
-
287
- it "should not have all_connections yield all available connections" do
288
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
289
- q, q1 = Queue.new, Queue.new
290
- b = []
291
- t = Thread.new do
292
- pool.hold do |c1|
293
- @m.synchronize{b << c1}
294
- q1.push nil
295
- q.pop
296
- end
297
- end
298
- pool.hold do |c1|
299
- q1.pop
300
- @m.synchronize{b << c1}
301
- q.push nil
302
- end
303
- t.join
304
- a = []
305
- pool.all_connections{|c| a << c}
306
- a.sort.must_equal b.sort
307
- end
308
-
309
- it "should raise a PoolTimeout error if a connection couldn't be acquired before timeout" do
310
- q, q1 = Queue.new, Queue.new
311
- db = mock_db.call(&@icpp)
312
- db.opts[:name] = 'testing'
313
- pool = Sequel::ConnectionPool.get_pool(db, @cp_opts.merge(:max_connections=>1, :pool_timeout=>0))
314
- t = Thread.new{pool.hold{|c| q1.push nil; q.pop}}
315
- q1.pop
316
- e = proc{pool.hold{|c|}}.must_raise(Sequel::PoolTimeout)
317
- e.message.must_include "name: testing"
318
- e.message.must_include "server: default" if pool.is_a?(Sequel::ShardedThreadedConnectionPool)
319
- q.push nil
320
- t.join
321
- end
322
-
323
- it "should not add a disconnected connection back to the pool if the disconnection_proc raises an error" do
324
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| raise Sequel::Error}, &@icpp), @cp_opts.merge(:max_connections=>1, :pool_timeout=>0))
325
- proc{pool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::Error)
326
- pool.available_connections.length.must_equal 0
327
- end
328
-
329
- it "should let five threads simultaneously access separate connections" do
330
- cc = {}
331
- threads = []
332
- q, q1, q2 = Queue.new, Queue.new, Queue.new
333
-
334
- 5.times{|i| threads << Thread.new{@pool.hold{|c| q.pop; @m.synchronize{cc[i] = c}; q1.push nil; q2.pop}}; q.push nil; q1.pop}
335
- threads.each {|t| t.must_be :alive?}
336
- cc.size.must_equal 5
337
- @invoked_count.must_equal 5
338
- @pool.size.must_equal 5
339
- @pool.available_connections.must_be :empty?
340
-
341
- h = {}
342
- i = 0
343
- threads.each{|t| h[t] = (i+=1)}
344
- @pool.allocated.must_equal h
345
- @pool.available_connections.must_equal []
346
- 5.times{q2.push nil}
347
- threads.each{|t| t.join}
348
-
349
- @pool.available_connections.size.must_equal 5
350
- @pool.allocated.must_be :empty?
351
- end
352
-
353
- it "should allow simultaneous connections without preconnecting" do
354
- @pool.disconnect
355
- b = @icpp
356
-
357
- time = Time.now
358
- cc = {}
359
- threads = []
360
- results = []
361
- j = 0
362
- q, q1, q2, q3, q4 = Queue.new, Queue.new, Queue.new, Queue.new, Queue.new
363
- m = @m
364
- @pool.db.define_singleton_method(:connect) do |server|
365
- q1.pop
366
- m.synchronize{q3.push(j += 1)}
367
- q4.pop
368
- b.call
369
- end
370
- 5.times{|i| threads << Thread.new{@pool.hold{|c| m.synchronize{i -= 1; cc[i] = c}; q2.pop; q.push nil}}}
371
- 5.times{|i| q1.push nil}
372
- 5.times{|i| results << q3.pop}
373
- 5.times{|i| q4.push nil}
374
- 5.times{|i| q2.push nil}
375
- 5.times{|i| q.pop}
376
- results.sort.must_equal (1..5).to_a
377
- threads.each(&:join)
378
- (Time.now - time).must_be :<, 0.75
379
-
380
- threads.each{|t| t.wont_be :alive?}
381
- cc.size.must_equal 5
382
- @invoked_count.must_equal 5
383
- @pool.size.must_equal 5
384
- @pool.available_connections.sort.must_equal (1..5).to_a
385
- end
386
-
387
- it "should block threads until a connection becomes available" do
388
- cc = {}
389
- threads = []
390
- q, q1 = Queue.new, Queue.new
391
-
392
- 5.times{|i| threads << Thread.new{@pool.hold{|c| @m.synchronize{cc[i] = c}; q1.push nil; q.pop}}}
393
- 5.times{q1.pop}
394
- threads.each {|t| t.must_be :alive?}
395
- @pool.available_connections.must_be :empty?
396
-
397
- 3.times {|i| threads << Thread.new {@pool.hold {|c| @m.synchronize{cc[i + 5] = c}; q1.push nil}}}
398
-
399
- threads[5].must_be :alive?
400
- threads[6].must_be :alive?
401
- threads[7].must_be :alive?
402
- cc.size.must_equal 5
403
- cc[5].must_be_nil
404
- cc[6].must_be_nil
405
- cc[7].must_be_nil
406
-
407
- 5.times{q.push nil}
408
- 5.times{|i| threads[i].join}
409
- 3.times{q1.pop}
410
- 3.times{|i| threads[i+5].join}
411
-
412
- threads.each {|t| t.wont_be :alive?}
413
- cc.values.uniq.length.must_equal 5
414
-
415
- @pool.size.must_equal 5
416
- @invoked_count.must_equal 5
417
- @pool.available_connections.size.must_equal 5
418
- @pool.allocated.must_be :empty?
419
- end
420
-
421
- it "should block threads until a connection becomes available, when assign connection returns nil" do
422
- # Shorten pool timeout, as making assign_connection return nil when there are
423
- # connections in the pool can make the pool later block until the timeout expires,
424
- # since then the pool will not be signalled correctly.
425
- # This spec is only added for coverage purposes, to ensure that fallback code is tested.
426
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:pool_timeout=>0.25))
427
-
428
- cc = {}
429
- threads = []
430
- q, q1 = Queue.new, Queue.new
431
-
432
- 5.times{|i| threads << Thread.new{@pool.hold{|c| @m.synchronize{cc[i] = c}; q1.push nil; q.pop}}}
433
- 5.times{q1.pop}
434
- threads.each {|t| t.must_be :alive?}
435
- @pool.available_connections.must_be :empty?
436
-
437
- def @pool.assign_connection(*) nil end
438
- 3.times {|i| threads << Thread.new {@pool.hold {|c| @m.synchronize{cc[i + 5] = c}; q1.push nil}}}
439
-
440
- threads[5].must_be :alive?
441
- threads[6].must_be :alive?
442
- threads[7].must_be :alive?
443
- cc.size.must_equal 5
444
- cc[5].must_be_nil
445
- cc[6].must_be_nil
446
- cc[7].must_be_nil
447
-
448
- 5.times{q.push nil}
449
- 5.times{|i| threads[i].join}
450
- 3.times{q1.pop}
451
- 3.times{|i| threads[i+5].join}
452
-
453
- threads.each {|t| t.wont_be :alive?}
454
- cc.values.uniq.length.must_equal 5
455
-
456
- @pool.size.must_equal 5
457
- @invoked_count.must_equal 5
458
- @pool.available_connections.size.must_equal 5
459
- @pool.allocated.must_be :empty?
460
- end
461
-
462
- it "should block threads until a connection becomes available, and reconnect on disconnection" do
463
- cc = {}
464
- threads = []
465
- exceptions = []
466
- q, q1, q2, q3 = Queue.new, Queue.new, Queue.new, Queue.new
467
- b = @icpp
468
- @pool.db.define_singleton_method(:connect) do |server|
469
- b.call
470
- Object.new
471
- end
472
- 5.times{|i| threads << Thread.new{@pool.hold{|c| @m.synchronize{cc[i] = c}; q1.push nil; q.pop; raise Sequel::DatabaseDisconnectError} rescue q2.push($!)}}
473
- 5.times{q1.pop}
474
- threads.each {|t| t.must_be :alive?}
475
- @pool.available_connections.must_be :empty?
476
-
477
- 3.times {|i| threads << Thread.new {@pool.hold {|c| @m.synchronize{cc[i + 5] = c}; q1.push nil; q3.pop}}}
478
-
479
- threads[5].must_be :alive?
480
- threads[6].must_be :alive?
481
- threads[7].must_be :alive?
482
- cc.size.must_equal 5
483
- cc[5].must_be_nil
484
- cc[6].must_be_nil
485
- cc[7].must_be_nil
486
-
487
- 5.times{q.push nil}
488
- 5.times{|i| threads[i].join}
489
- 5.times{exceptions << q2.pop}
490
- 3.times{q1.pop}
491
- 3.times{q3.push nil}
492
- 3.times{|i| threads[i+5].join}
493
-
494
- threads.each {|t| t.wont_be :alive?}
495
- exceptions.length.must_equal 5
496
- cc.values.uniq.length.must_equal 8
497
-
498
- @pool.size.must_equal 3
499
- @invoked_count.must_equal 8
500
- @pool.available_connections.size.must_equal 3
501
- @pool.allocated.must_be :empty?
502
- end
503
-
504
- it "should store connections in a stack if :connection_handling=>:stack" do
505
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:connection_handling=>:stack))
506
- c2 = nil
507
- c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
508
- @pool.size.must_equal 2
509
- @pool.hold{|cc| cc.must_equal c}
510
- @pool.hold{|cc| cc.must_equal c}
511
- @pool.hold do |cc|
512
- cc.must_equal c
513
- Thread.new{@pool.hold{|cc2| _(cc2).must_equal c2}}.join
514
- end
515
- end
516
-
517
- it "should store connections in a queue if :connection_handling=>:queue" do
518
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:connection_handling=>:queue))
519
- c2 = nil
520
- c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
521
- @pool.size.must_equal 2
522
- @pool.hold{|cc| cc.must_equal c2}
523
- @pool.hold{|cc| cc.must_equal c}
524
- @pool.hold do |cc|
525
- cc.must_equal c2
526
- Thread.new{@pool.hold{|cc2| _(cc2).must_equal c}}.join
527
- end
528
- end
529
-
530
- it "should not store connections if :connection_handling=>:disconnect" do
531
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:connection_handling=>:disconnect))
532
- d = []
533
- m = @m
534
- @pool.db.define_singleton_method(:disconnect_connection){|c| m.synchronize{d << c}}
535
- @pool.hold do |cc|
536
- cc.must_equal 1
537
- Thread.new{@pool.hold{|cc2| _(cc2).must_equal 2}}.join
538
- d.must_equal [2]
539
- @pool.hold{|cc3| cc3.must_equal 1}
540
- end
541
- @pool.size.must_equal 0
542
- d.must_equal [2, 1]
543
-
544
- @pool.hold{|cc| cc.must_equal 3}
545
- @pool.size.must_equal 0
546
- d.must_equal [2, 1, 3]
547
-
548
- @pool.hold{|cc| cc.must_equal 4}
549
- @pool.size.must_equal 0
550
- d.must_equal [2, 1, 3, 4]
551
- end
552
-
553
-
554
- it "should handle dead threads with checked out connections" do
555
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>1))
556
-
557
- skip = true
558
- # Leave allocated connection to emulate dead thread with checked out connection
559
- pool.define_singleton_method(:release){|*a| return if skip; super(*a)}
560
- Thread.new{pool.hold{Thread.current.kill}}.join
561
- skip = false
562
-
563
- pool.allocated.wont_be :empty?
564
- pool.available_connections.must_be :empty?
565
-
566
- pool.hold{|c1| c1}
567
- pool.allocated.must_be :empty?
568
- pool.available_connections.wont_be :empty?
569
-
570
- pool.disconnect
571
- pool.allocated.must_be :empty?
572
- pool.available_connections.must_be :empty?
573
- end
574
- end
575
-
576
- describe "Threaded Unsharded Connection Pool" do
577
- before do
578
- @m = Mutex.new
579
- @invoked_count = 0
580
- @icpp = proc{@m.synchronize{@invoked_count += 1}}
581
- @cp_opts = connection_pool_defaults.merge(:max_connections=>5)
582
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts)
583
- end
584
-
585
- include ThreadedConnectionPoolSpecs
586
- end
587
-
588
- describe "Threaded Sharded Connection Pool" do
589
- before do
590
- @m = Mutex.new
591
- @invoked_count = 0
592
- @icpp = proc{@m.synchronize{@invoked_count += 1}}
593
- @cp_opts = connection_pool_defaults.merge(:max_connections=>5, :servers=>{})
594
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts)
595
- end
596
-
597
- include ThreadedConnectionPoolSpecs
598
- end
599
-
600
- describe "ConnectionPool#disconnect" do
601
- before do
602
- @count = 0
603
- cp = proc{@count += 1}
604
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{{:id => cp.call}}, connection_pool_defaults.merge(:max_connections=>5, :servers=>{}))
605
- threads = []
606
- q, q1 = Queue.new, Queue.new
607
- 5.times {|i| threads << Thread.new {@pool.hold {|c| q1.push nil; q.pop}}}
608
- 5.times{q1.pop}
609
- 5.times{q.push nil}
610
- threads.each {|t| t.join}
611
- end
612
-
613
- it "should invoke the given block for each available connection" do
614
- @pool.size.must_equal 5
615
- @pool.available_connections.size.must_equal 5
616
- @pool.available_connections.each {|c| c[:id].wont_equal nil}
617
- conns = []
618
- @pool.db.define_singleton_method(:disconnect_connection){|c| conns << c}
619
- @pool.disconnect
620
- conns.size.must_equal 5
621
- end
622
-
623
- it "should remove all available connections" do
624
- @pool.size.must_equal 5
625
- @pool.disconnect
626
- @pool.size.must_equal 0
627
- end
628
-
629
- it "should disconnect connections in use as soon as they are no longer in use" do
630
- @pool.size.must_equal 5
631
- @pool.hold do |conn|
632
- @pool.available_connections.size.must_equal 4
633
- @pool.available_connections.each {|c| c.wont_be_same_as(conn)}
634
- conns = []
635
- @pool.db.define_singleton_method(:disconnect_connection){|c| conns << c}
636
- @pool.disconnect
637
- conns.size.must_equal 4
638
- @pool.size.must_equal 1
639
- end
640
- @pool.size.must_equal 0
641
- end
642
- end
643
-
644
- describe "A connection pool with multiple servers" do
645
- before do
646
- ic = @invoked_counts = Hash.new(0)
647
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, connection_pool_defaults.merge(:servers=>{:read_only=>{}}))
648
- end
649
-
650
- it "should support preconnect method that immediately creates the maximum number of connections" do
651
- @pool.send(:preconnect)
652
- i = 0
653
- @pool.all_connections{|c1| i+=1}
654
- i.must_equal(@pool.max_size * 2)
655
- end
656
-
657
- it "should support preconnect method that immediately creates the maximum number of connections concurrently" do
658
- @pool.send(:preconnect, true)
659
- i = 0
660
- @pool.all_connections{|c1| i+=1}
661
- i.must_equal(@pool.max_size * 2)
662
- end
663
-
664
- it "#all_connections should return connections for all servers" do
665
- @pool.hold{}
666
- @pool.all_connections{|c1| c1.must_equal "default1"}
667
- a = []
668
- @pool.hold(:read_only) do |c|
669
- @pool.all_connections{|c1| a << c1}
670
- end
671
- a.sort_by{|c| c.to_s}.must_equal ["default1", "read_only1"]
672
- end
673
-
674
- it "#servers should return symbols for all servers" do
675
- @pool.servers.sort_by{|s| s.to_s}.must_equal [:default, :read_only]
676
- end
677
-
678
- it "should use the :default server by default" do
679
- @pool.size.must_equal 0
680
- @pool.hold do |c|
681
- c.must_equal "default1"
682
- @pool.allocated.must_equal(Thread.current=>"default1")
683
- end
684
- @pool.available_connections.must_equal ["default1"]
685
- @pool.size.must_equal 1
686
- @invoked_counts.must_equal(:default=>1)
687
- end
688
-
689
- it "should use the :default server an invalid server is used" do
690
- @pool.hold do |c1|
691
- c1.must_equal "default1"
692
- @pool.hold(:blah) do |c2|
693
- c2.must_equal c1
694
- @pool.hold(:blah2) do |c3|
695
- c2.must_equal c3
696
- end
697
- end
698
- end
699
- end
700
-
701
- it "should support a :servers_hash option used for converting the server argument" do
702
- ic = @invoked_counts
703
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, connection_pool_defaults.merge(:servers_hash=>Hash.new(:read_only), :servers=>{:read_only=>{}}))
704
- @pool.hold(:blah) do |c1|
705
- c1.must_equal "read_only1"
706
- @pool.hold(:blah) do |c2|
707
- c2.must_equal c1
708
- @pool.hold(:blah2) do |c3|
709
- c2.must_equal c3
710
- end
711
- end
712
- end
713
-
714
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, connection_pool_defaults.merge(:servers_hash=>Hash.new{|h,k| raise Sequel::Error}, :servers=>{:read_only=>{}}))
715
- proc{@pool.hold(:blah){|c1|}}.must_raise(Sequel::Error)
716
- end
717
-
718
- it "should use the requested server if server is given" do
719
- @pool.size(:read_only).must_equal 0
720
- @pool.hold(:read_only) do |c|
721
- c.must_equal "read_only1"
722
- @pool.allocated(:read_only).must_equal(Thread.current=>"read_only1")
723
- end
724
- @pool.available_connections(:read_only).must_equal ["read_only1"]
725
- @pool.size(:read_only).must_equal 1
726
- @invoked_counts.must_equal(:read_only=>1)
727
- end
728
-
729
- it "#hold should only yield connections for the server requested" do
730
- @pool.hold(:read_only) do |c|
731
- c.must_equal "read_only1"
732
- @pool.allocated(:read_only).must_equal(Thread.current=>"read_only1")
733
- @pool.hold do |d|
734
- d.must_equal "default1"
735
- @pool.hold do |e|
736
- e.must_equal d
737
- @pool.hold(:read_only){|b| b.must_equal c}
738
- end
739
- @pool.allocated.must_equal(Thread.current=>"default1")
740
- end
741
- end
742
- @invoked_counts.must_equal(:read_only=>1, :default=>1)
743
- end
744
-
745
- it "#disconnect should disconnect from all servers" do
746
- @pool.hold(:read_only){}
747
- @pool.hold{}
748
- conns = []
749
- @pool.size.must_equal 1
750
- @pool.size(:read_only).must_equal 1
751
- @pool.db.define_singleton_method(:disconnect_connection){|c| conns << c}
752
- @pool.disconnect
753
- conns.sort.must_equal %w'default1 read_only1'
754
- @pool.size.must_equal 0
755
- @pool.size(:read_only).must_equal 0
756
- @pool.hold(:read_only){|c| c.must_equal 'read_only2'}
757
- @pool.hold{|c| c.must_equal 'default2'}
758
- end
759
-
760
- it "#add_servers should add new servers to the pool" do
761
- pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
762
-
763
- pool.hold{}
764
- pool.hold(:server2){}
765
- pool.hold(:server3){}
766
- pool.hold(:server1) do
767
- pool.allocated.length.must_equal 0
768
- pool.allocated(:server1).length.must_equal 1
769
- pool.allocated(:server2).must_be_nil
770
- pool.allocated(:server3).must_be_nil
771
- pool.available_connections.length.must_equal 1
772
- pool.available_connections(:server1).length.must_equal 0
773
- pool.available_connections(:server2).must_be_nil
774
- pool.available_connections(:server3).must_be_nil
775
-
776
- pool.add_servers([:server2, :server3])
777
- pool.hold(:server2){}
778
- pool.hold(:server3) do
779
- pool.allocated.length.must_equal 0
780
- pool.allocated(:server1).length.must_equal 1
781
- pool.allocated(:server2).length.must_equal 0
782
- pool.allocated(:server3).length.must_equal 1
783
- pool.available_connections.length.must_equal 1
784
- pool.available_connections(:server1).length.must_equal 0
785
- pool.available_connections(:server2).length.must_equal 1
786
- pool.available_connections(:server3).length.must_equal 0
787
- end
788
- end
789
- end
790
-
791
- it "#add_servers should ignore existing keys" do
792
- pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
793
-
794
- pool.allocated.length.must_equal 0
795
- pool.allocated(:server1).length.must_equal 0
796
- pool.available_connections.length.must_equal 0
797
- pool.available_connections(:server1).length.must_equal 0
798
- pool.hold do |c1|
799
- c1.must_equal :default
800
- pool.allocated.length.must_equal 1
801
- pool.allocated(:server1).length.must_equal 0
802
- pool.available_connections.length.must_equal 0
803
- pool.available_connections(:server1).length.must_equal 0
804
- pool.hold(:server1) do |c2|
805
- c2.must_equal :server1
806
- pool.allocated.length.must_equal 1
807
- pool.allocated(:server1).length.must_equal 1
808
- pool.available_connections.length.must_equal 0
809
- pool.available_connections(:server1).length.must_equal 0
810
- pool.add_servers([:default, :server1])
811
- pool.allocated.length.must_equal 1
812
- pool.allocated(:server1).length.must_equal 1
813
- pool.available_connections.length.must_equal 0
814
- pool.available_connections(:server1).length.must_equal 0
815
- end
816
- pool.allocated.length.must_equal 1
817
- pool.allocated(:server1).length.must_equal 0
818
- pool.available_connections.length.must_equal 0
819
- pool.available_connections(:server1).length.must_equal 1
820
- pool.add_servers([:default, :server1])
821
- pool.allocated.length.must_equal 1
822
- pool.allocated(:server1).length.must_equal 0
823
- pool.available_connections.length.must_equal 0
824
- pool.available_connections(:server1).length.must_equal 1
825
- end
826
- pool.allocated.length.must_equal 0
827
- pool.allocated(:server1).length.must_equal 0
828
- pool.available_connections.length.must_equal 1
829
- pool.available_connections(:server1).length.must_equal 1
830
- pool.add_servers([:default, :server1])
831
- pool.allocated.length.must_equal 0
832
- pool.allocated(:server1).length.must_equal 0
833
- pool.available_connections.length.must_equal 1
834
- pool.available_connections(:server1).length.must_equal 1
835
- end
836
-
837
- it "#remove_servers should disconnect available connections immediately" do
838
- pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :max_connections=>5, :servers=>{:server1=>{}})
839
- threads = []
840
- q, q1 = Queue.new, Queue.new
841
- 5.times {|i| threads << Thread.new {pool.hold(:server1){|c| q1.push nil; q.pop}}}
842
- 5.times{q1.pop}
843
- 5.times{q.push nil}
844
- threads.each {|t| t.join}
845
-
846
- pool.size(:server1).must_equal 5
847
- pool.remove_servers([:server1])
848
- pool.size(:server1).must_equal 0
849
- end
850
-
851
- it "#remove_servers should disconnect connections in use as soon as they are returned to the pool" do
852
- dc = []
853
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| dc << c}){|c| c}, :servers=>{:server1=>{}})
854
- c1 = nil
855
- pool.hold(:server1) do |c|
856
- pool.size(:server1).must_equal 1
857
- dc.must_equal []
858
- pool.remove_servers([:server1])
859
- pool.size(:server1).must_equal 0
860
- dc.must_equal []
861
- c1 = c
862
- end
863
- pool.size(:server1).must_equal 0
864
- dc.must_equal [c1]
865
- end
866
-
867
- it "#remove_servers should remove server related data structures immediately" do
868
- pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
869
- pool.available_connections(:server1).must_equal []
870
- pool.allocated(:server1).must_equal({})
871
- pool.remove_servers([:server1])
872
- pool.available_connections(:server1).must_be_nil
873
- pool.allocated(:server1).must_be_nil
874
- end
875
-
876
- it "#remove_servers should not allow the removal of the default server" do
877
- pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
878
- pool.remove_servers([:server1])
879
- proc{pool.remove_servers([:default])}.must_raise(Sequel::Error)
880
- end
881
-
882
- it "#remove_servers should ignore servers that have already been removed" do
883
- dc = []
884
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| dc << c}){|c| c}, :servers=>{:server1=>{}})
885
- c1 = nil
886
- pool.hold(:server1) do |c|
887
- pool.size(:server1).must_equal 1
888
- dc.must_equal []
889
- pool.remove_servers([:server1])
890
- pool.remove_servers([:server1])
891
- pool.size(:server1).must_equal 0
892
- dc.must_equal []
893
- c1 = c
894
- end
895
- pool.size(:server1).must_equal 0
896
- dc.must_equal [c1]
897
- end
898
- end
899
-
900
- describe "SingleConnectionPool" do
901
- before do
902
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call{1234}, st_connection_pool_defaults)
903
- end
904
-
905
- it "should provide a #hold method" do
906
- conn = nil
907
- @pool.hold{|c| conn = c}
908
- conn.must_equal 1234
909
- end
910
-
911
- it "should provide a #disconnect method" do
912
- conn = nil
913
- x = nil
914
- pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c; c.must_be_kind_of(Integer)}){1234}, st_connection_pool_defaults)
915
- pool.hold{|c| x = c}
916
- x.must_equal 1234
917
- pool.disconnect
918
- conn.must_equal 1234
919
- pool.disconnect
920
- end
921
- end
922
-
923
- describe "A single threaded pool with multiple servers" do
924
- before do
925
- @max_size=2
926
- msp = proc{@max_size += 1}
927
- @pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){|c| c}, st_connection_pool_defaults.merge(:servers=>{:read_only=>{}}))
928
- end
929
-
930
- it "should support preconnect method that immediately creates the maximum number of connections" do
931
- @pool.send(:preconnect)
932
- i = 0
933
- @pool.all_connections{|c1| i+=1}
934
- i.must_equal 2
935
- end
936
-
937
- it "should support preconnect method that immediately creates the maximum number of connections, ignoring concurrent param" do
938
- @pool.send(:preconnect, true)
939
- i = 0
940
- @pool.all_connections{|c1| i+=1}
941
- i.must_equal 2
942
- end
943
-
944
- it "#all_connections should return connections for all servers" do
945
- @pool.hold{}
946
- @pool.all_connections{|c1| c1.must_equal :default}
947
- a = []
948
- @pool.hold(:read_only) do
949
- @pool.all_connections{|c1| a << c1}
950
- end
951
- a.sort_by{|c| c.to_s}.must_equal [:default, :read_only]
952
- end
953
-
954
- it "#servers should return symbols for all servers" do
955
- @pool.servers.sort_by{|s| s.to_s}.must_equal [:default, :read_only]
956
- end
957
-
958
- it "#add_servers should add new servers to the pool" do
959
- @pool.hold(:blah){|c| c.must_equal :default}
960
- @pool.add_servers([:blah])
961
- @pool.hold(:blah){|c| c.must_equal :blah}
962
- end
963
-
964
- it "#add_servers should ignore keys already existing" do
965
- @pool.hold{|c| c.must_equal :default}
966
- @pool.hold(:read_only){|c| c.must_equal :read_only}
967
- @pool.add_servers([:default, :read_only])
968
- @pool.conn.must_equal :default
969
- @pool.conn(:read_only).must_equal :read_only
970
- end
971
-
972
- it "#remove_servers should remove servers from the pool" do
973
- @pool.hold(:read_only){|c| c.must_equal :read_only}
974
- @pool.remove_servers([:read_only])
975
- @pool.hold(:read_only){|c| c.must_equal :default}
976
- end
977
-
978
- it "#remove_servers should not allow the removal of the default server" do
979
- proc{@pool.remove_servers([:default])}.must_raise(Sequel::Error)
980
- end
981
-
982
- it "#remove_servers should disconnect connection immediately" do
983
- @pool.hold(:read_only){|c| c.must_equal :read_only}
984
- @pool.conn(:read_only).must_equal :read_only
985
- @pool.remove_servers([:read_only])
986
- @pool.conn(:read_only).must_be_nil
987
- @pool.hold{}
988
- @pool.conn(:read_only).must_equal :default
989
- end
990
-
991
- it "#remove_servers should ignore keys that do not exist" do
992
- @pool.remove_servers([:blah])
993
- end
994
-
995
- it "should use the :default server by default" do
996
- @pool.hold{|c| c.must_equal :default}
997
- @pool.conn.must_equal :default
998
- end
999
-
1000
- it "should use the :default server an invalid server is used" do
1001
- @pool.hold do |c1|
1002
- c1.must_equal :default
1003
- @pool.hold(:blah) do |c2|
1004
- c2.must_equal c1
1005
- @pool.hold(:blah2) do |c3|
1006
- c2.must_equal c3
1007
- end
1008
- end
1009
- end
1010
- end
1011
-
1012
- it "should use the requested server if server is given" do
1013
- @pool.hold(:read_only){|c| c.must_equal :read_only}
1014
- @pool.conn(:read_only).must_equal :read_only
1015
- end
1016
-
1017
- it "#hold should only yield connections for the server requested" do
1018
- @pool.hold(:read_only) do |c|
1019
- c.must_equal :read_only
1020
- @pool.hold do |d|
1021
- d.must_equal :default
1022
- @pool.hold do |e|
1023
- e.must_equal d
1024
- @pool.hold(:read_only){|b| b.must_equal c}
1025
- end
1026
- end
1027
- end
1028
- @pool.conn.must_equal :default
1029
- @pool.conn(:read_only).must_equal :read_only
1030
- end
1031
-
1032
- it "#disconnect should disconnect from all servers" do
1033
- @pool.hold(:read_only){}
1034
- @pool.hold{}
1035
- @pool.conn.must_equal :default
1036
- @pool.conn(:read_only).must_equal :read_only
1037
- @pool.disconnect
1038
- @max_size.must_equal 4
1039
- @pool.conn.must_be_nil
1040
- @pool.conn(:read_only).must_be_nil
1041
- end
1042
-
1043
- it ":disconnection_proc option should set the disconnection proc to use" do
1044
- @max_size.must_equal 2
1045
- proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
1046
- @max_size.must_equal 3
1047
- end
1048
-
1049
- it "#hold should remove the connection if a DatabaseDisconnectError is raised" do
1050
- @pool.instance_variable_get(:@conns).length.must_equal 0
1051
- @pool.hold{}
1052
- @pool.instance_variable_get(:@conns).length.must_equal 1
1053
- proc{@pool.hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
1054
- @pool.instance_variable_get(:@conns).length.must_equal 0
1055
- end
1056
- end
1057
-
1058
- AllConnectionPoolClassesSpecs = shared_description do
1059
- it "should work correctly after being frozen" do
1060
- o = Object.new
1061
- db = mock_db.call{o}
1062
- cp = @class.new(db, {})
1063
- db.instance_variable_set(:@pool, cp)
1064
- db.freeze
1065
- cp.frozen?.must_equal true
1066
- db.synchronize{|c| c.must_be_same_as o}
1067
- end
1068
-
1069
- it "should have pool correctly handle disconnect errors not raised as DatabaseDisconnectError" do
1070
- db = mock_db.call{Object.new}
1071
- def db.dec; @dec ||= Class.new(StandardError) end
1072
- def db.database_error_classes; super + [dec] end
1073
- def db.disconnect_error?(e, opts); e.message =~ /foo/ end
1074
- cp = @class.new(db, {})
1075
-
1076
- conn = nil
1077
- cp.hold do |c|
1078
- conn = c
1079
- end
1080
-
1081
- proc do
1082
- cp.hold do |c|
1083
- c.must_equal conn
1084
- raise db.dec, "bar"
1085
- end
1086
- end.must_raise db.dec
1087
-
1088
- proc do
1089
- cp.hold do |c|
1090
- c.must_equal conn
1091
- raise StandardError
1092
- end
1093
- end.must_raise StandardError
1094
-
1095
- cp.hold do |c|
1096
- c.must_equal conn
1097
- end
1098
-
1099
- proc do
1100
- cp.hold do |c|
1101
- c.must_equal conn
1102
- raise db.dec, "foo"
1103
- end
1104
- end.must_raise db.dec
1105
-
1106
- cp.hold do |c|
1107
- c.wont_equal conn
1108
- end
1109
- end
1110
-
1111
- it "should have pool_type return a symbol" do
1112
- @class.new(mock_db.call{123}, {}).pool_type.must_be_kind_of(Symbol)
1113
- end
1114
-
1115
- it "should have all_connections yield current and available connections" do
1116
- p = @class.new(mock_db.call{123}, {})
1117
- p.hold{|c| p.all_connections{|c1| c.must_equal c1}}
1118
- end
1119
-
1120
- it "should have a size method that gives the current size of the pool" do
1121
- p = @class.new(mock_db.call{123}, {})
1122
- p.size.must_equal 0
1123
- p.hold{}
1124
- p.size.must_equal 1
1125
- end
1126
-
1127
- it "should have a max_size method that gives the maximum size of the pool" do
1128
- @class.new(mock_db.call{123}, {}).max_size.must_be :>=, 1
1129
- end
1130
-
1131
- it "should support preconnect method that immediately creates the maximum number of connections" do
1132
- p = @class.new(mock_db.call{123}, {})
1133
- p.send(:preconnect)
1134
- i = 0
1135
- p.all_connections{|c1| i+=1}
1136
- i.must_equal p.max_size
1137
- end
1138
-
1139
- it "should support preconnect method that immediately creates the maximum number of connections concurrently" do
1140
- p = @class.new(mock_db.call{123}, {})
1141
- p.send(:preconnect, true)
1142
- i = 0
1143
- p.all_connections{|c1| i+=1}
1144
- i.must_equal p.max_size
1145
- end
1146
-
1147
- it "should be able to modify after_connect proc after the pool is created" do
1148
- a = []
1149
- p = @class.new(mock_db.call{123}, {})
1150
- p.after_connect = pr = proc{|c| a << c}
1151
- p.after_connect.must_equal pr
1152
- a.must_equal []
1153
- p.hold{}
1154
- a.must_equal [123]
1155
- end
1156
-
1157
- it "should not raise an error when disconnecting twice" do
1158
- c = @class.new(mock_db.call{123}, {})
1159
- c.disconnect
1160
- c.disconnect
1161
- end
1162
-
1163
- it "should yield a connection created by the initialize block to hold" do
1164
- x = nil
1165
- @class.new(mock_db.call{123}, {}).hold{|c| x = c}
1166
- x.must_equal 123
1167
- end
1168
-
1169
- it "should have the initialize block accept a shard/server argument" do
1170
- x = nil
1171
- @class.new(mock_db.call{|c| [c, c]}, {}).hold{|c| x = c}
1172
- x.must_equal [:default, :default]
1173
- end
1174
-
1175
- it "should have respect an :after_connect proc that is called with each newly created connection" do
1176
- x = nil
1177
- @class.new(mock_db.call{123}, :after_connect=>proc{|c| x = [c, c]}).hold{}
1178
- x.must_equal [123, 123]
1179
- @class.new(mock_db.call{123}, :after_connect=>lambda{|c| x = [c, c]}).hold{}
1180
- x.must_equal [123, 123]
1181
- @class.new(mock_db.call{123}, :after_connect=>proc{|c, s| x = [c, s]}).hold{}
1182
- x.must_equal [123, :default]
1183
- @class.new(mock_db.call{123}, :after_connect=>lambda{|c, s| x = [c, s]}).hold{}
1184
- x.must_equal [123, :default]
1185
- end
1186
-
1187
- it "should raise a DatabaseConnectionError if the connection raises an exception" do
1188
- proc{@class.new(mock_db.call{|c| raise Exception}, {}).hold{}}.must_raise(Sequel::DatabaseConnectionError)
1189
- end
1190
-
1191
- it "should raise a DatabaseConnectionError if the initialize block returns nil" do
1192
- proc{@class.new(mock_db.call{}, {}).hold{}}.must_raise(Sequel::DatabaseConnectionError)
1193
- end
1194
-
1195
- it "should call the disconnection_proc option if the hold block raises a DatabaseDisconnectError" do
1196
- x = nil
1197
- proc{@class.new(mock_db.call(proc{|c| x = c}){123}).hold{raise Sequel::DatabaseDisconnectError}}.must_raise(Sequel::DatabaseDisconnectError)
1198
- x.must_equal 123
1199
- end
1200
-
1201
- it "should have a disconnect method that disconnects the connection" do
1202
- x = nil
1203
- c = @class.new(mock_db.call(proc{|c1| x = c1}){123})
1204
- c.hold{}
1205
- x.must_be_nil
1206
- c.disconnect
1207
- x.must_equal 123
1208
- end
1209
-
1210
- it "should have a reentrent hold method" do
1211
- o = Object.new
1212
- c = @class.new(mock_db.call{o}, {})
1213
- c.hold do |x|
1214
- x.must_equal o
1215
- c.hold do |x1|
1216
- x1.must_equal o
1217
- c.hold do |x2|
1218
- x2.must_equal o
1219
- end
1220
- end
1221
- end
1222
- end
1223
-
1224
- it "should have a servers method that returns an array of shard/server symbols" do
1225
- @class.new(mock_db.call{123}, {}).servers.must_equal [:default]
1226
- end
1227
-
1228
- it "should have a servers method that returns an array of shard/server symbols" do
1229
- c = @class.new(mock_db.call{123}, {})
1230
- c.size.must_equal 0
1231
- c.hold{}
1232
- c.size.must_equal 1
1233
- end
1234
- end
1235
-
1236
- [true, false].each do |k|
1237
- [true, false].each do |v|
1238
- opts = {:single_threaded=>k, :servers=>(v ? {} : nil)}
1239
- describe "Connection pool with #{opts.inspect}" do
1240
- before(:all) do
1241
- Sequel::ConnectionPool.send(:get_pool, mock_db.call, opts)
1242
- end
1243
- before do
1244
- @class = Sequel::ConnectionPool.send(:connection_pool_class, opts)
1245
- end
1246
-
1247
- include AllConnectionPoolClassesSpecs
1248
- end
1249
- end
1250
- end