PageRenderTime 29ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb

http://github.com/rails/rails
Ruby | 424 lines | 338 code | 85 blank | 1 comment | 0 complexity | 3ed7ac82e32505ca8c459fd35dc590e8 MD5 | raw file
  1. # frozen_string_literal: true
  2. require "cases/helper"
  3. module ActiveRecord
  4. module ConnectionAdapters
  5. class MergeAndResolveDefaultUrlConfigTest < ActiveRecord::TestCase
  6. def setup
  7. @previous_database_url = ENV.delete("DATABASE_URL")
  8. @previous_rack_env = ENV.delete("RACK_ENV")
  9. @previous_rails_env = ENV.delete("RAILS_ENV")
  10. end
  11. teardown do
  12. ENV["DATABASE_URL"] = @previous_database_url
  13. ENV["RACK_ENV"] = @previous_rack_env
  14. ENV["RAILS_ENV"] = @previous_rails_env
  15. end
  16. def resolve_config(config, env_name = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call)
  17. configs = ActiveRecord::DatabaseConfigurations.new(config)
  18. configs.configs_for(env_name: env_name, name: "primary")&.configuration_hash
  19. end
  20. def resolve_db_config(spec, config)
  21. configs = ActiveRecord::DatabaseConfigurations.new(config)
  22. configs.resolve(spec)
  23. end
  24. def test_invalid_string_config
  25. config = { "foo" => "bar" }
  26. assert_raises ActiveRecord::DatabaseConfigurations::InvalidConfigurationError do
  27. resolve_config(config)
  28. end
  29. end
  30. def test_invalid_symbol_config
  31. config = { "foo" => :bar }
  32. assert_raises ActiveRecord::DatabaseConfigurations::InvalidConfigurationError do
  33. resolve_config(config)
  34. end
  35. end
  36. def test_resolver_with_database_uri_and_current_env_symbol_key
  37. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  38. config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
  39. actual = resolve_db_config(:default_env, config)
  40. expected = { adapter: "postgresql", database: "foo", host: "localhost" }
  41. assert_equal expected, actual.configuration_hash
  42. end
  43. def test_resolver_with_database_uri_and_current_env_symbol_key_and_rails_env
  44. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  45. ENV["RAILS_ENV"] = "foo"
  46. config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
  47. actual = resolve_db_config(:foo, config)
  48. expected = { adapter: "postgresql", database: "foo", host: "localhost" }
  49. assert_equal expected, actual.configuration_hash
  50. end
  51. def test_resolver_with_nil_database_url_and_current_env
  52. ENV["RAILS_ENV"] = "foo"
  53. config = { "foo" => { "adapter" => "postgres", "url" => ENV["DATABASE_URL"] } }
  54. actual = resolve_db_config(:foo, config)
  55. expected_config = { adapter: "postgres", url: nil }
  56. assert_equal expected_config, actual.configuration_hash
  57. end
  58. def test_resolver_with_database_uri_and_current_env_symbol_key_and_rack_env
  59. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  60. ENV["RACK_ENV"] = "foo"
  61. config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
  62. actual = resolve_db_config(:foo, config)
  63. expected = { adapter: "postgresql", database: "foo", host: "localhost" }
  64. assert_equal expected, actual.configuration_hash
  65. end
  66. def test_resolver_with_database_uri_and_known_key
  67. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  68. config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } }
  69. actual = resolve_db_config(:production, config)
  70. expected = { adapter: "not_postgres", database: "not_foo", host: "localhost" }
  71. assert_equal expected, actual.configuration_hash
  72. end
  73. def test_resolver_with_database_uri_and_multiple_envs
  74. ENV["DATABASE_URL"] = "postgres://localhost"
  75. ENV["RAILS_ENV"] = "test"
  76. config = { "production" => { "adapter" => "postgresql", "database" => "foo_prod" }, "test" => { "adapter" => "postgresql", "database" => "foo_test" } }
  77. actual = resolve_db_config(:test, config)
  78. expected = { adapter: "postgresql", database: "foo_test", host: "localhost" }
  79. assert_equal expected, actual.configuration_hash
  80. end
  81. def test_resolver_with_database_uri_and_unknown_symbol_key
  82. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  83. config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
  84. assert_raises AdapterNotSpecified do
  85. resolve_db_config(:production, config)
  86. end
  87. end
  88. def test_resolver_with_database_uri_and_supplied_url
  89. ENV["DATABASE_URL"] = "not-postgres://not-localhost/not_foo"
  90. config = { "production" => { "adapter" => "also_not_postgres", "database" => "also_not_foo" } }
  91. actual = resolve_db_config("postgres://localhost/foo", config)
  92. expected = { adapter: "postgresql", database: "foo", host: "localhost" }
  93. assert_equal expected, actual.configuration_hash
  94. end
  95. def test_jdbc_url
  96. config = { "production" => { "url" => "jdbc:postgres://localhost/foo" } }
  97. actual = resolve_config(config, "production")
  98. assert_equal config["production"].symbolize_keys, actual
  99. end
  100. def test_environment_does_not_exist_in_config_url_does_exist
  101. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  102. config = { "not_default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } }
  103. actual = resolve_config(config, "default_env")
  104. expect_prod = {
  105. adapter: "postgresql",
  106. database: "foo",
  107. host: "localhost"
  108. }
  109. assert_equal expect_prod, actual
  110. end
  111. def test_url_with_hyphenated_scheme
  112. ENV["DATABASE_URL"] = "ibm-db://localhost/foo"
  113. config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } }
  114. actual = resolve_db_config(:default_env, config)
  115. expected = { adapter: "ibm_db", database: "foo", host: "localhost" }
  116. assert_equal expected, actual.configuration_hash
  117. end
  118. def test_string_connection
  119. config = { "default_env" => "postgres://localhost/foo" }
  120. actual = resolve_config(config, "default_env")
  121. expected = {
  122. adapter: "postgresql",
  123. database: "foo",
  124. host: "localhost"
  125. }
  126. assert_equal expected, actual
  127. end
  128. def test_url_sub_key
  129. config = { "default_env" => { "url" => "postgres://localhost/foo" } }
  130. actual = resolve_config(config)
  131. expected = {
  132. adapter: "postgresql",
  133. database: "foo",
  134. host: "localhost"
  135. }
  136. assert_equal expected, actual
  137. end
  138. def test_url_removed_from_hash
  139. config = { "default_env" => { "url" => "postgres://localhost/foo" } }
  140. actual = resolve_db_config(:default_env, config)
  141. assert_not_includes actual.configuration_hash, :url
  142. end
  143. def test_url_with_equals_in_query_value
  144. config = { "default_env" => { "url" => "postgresql://localhost/foo?options=-cmyoption=on" } }
  145. actual = resolve_config(config)
  146. expected = { options: "-cmyoption=on", adapter: "postgresql", database: "foo", host: "localhost" }
  147. assert_equal expected, actual
  148. end
  149. def test_hash
  150. config = { "production" => { "adapter" => "postgres", "database" => "foo" } }
  151. actual = resolve_config(config, "production")
  152. assert_equal config["production"].symbolize_keys, actual
  153. end
  154. def test_blank
  155. config = {}
  156. actual = resolve_config(config, "default_env")
  157. assert_nil actual
  158. end
  159. def test_blank_with_database_url
  160. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  161. config = {}
  162. actual = resolve_config(config)
  163. expected = {
  164. adapter: "postgresql",
  165. database: "foo",
  166. host: "localhost"
  167. }
  168. assert_equal expected, actual
  169. end
  170. def test_blank_with_database_url_with_rails_env
  171. ENV["RAILS_ENV"] = "not_production"
  172. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  173. config = {}
  174. actual = resolve_config(config)
  175. expected = {
  176. adapter: "postgresql",
  177. database: "foo",
  178. host: "localhost"
  179. }
  180. assert_equal expected, actual
  181. end
  182. def test_blank_with_database_url_with_rack_env
  183. ENV["RACK_ENV"] = "not_production"
  184. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  185. config = {}
  186. actual = resolve_config(config)
  187. expected = {
  188. adapter: "postgresql",
  189. database: "foo",
  190. host: "localhost"
  191. }
  192. assert_equal expected, actual
  193. end
  194. def test_database_url_with_ipv6_host_and_port
  195. ENV["DATABASE_URL"] = "postgres://[::1]:5454/foo"
  196. config = {}
  197. actual = resolve_config(config)
  198. expected = {
  199. adapter: "postgresql",
  200. database: "foo",
  201. host: "::1",
  202. port: 5454
  203. }
  204. assert_equal expected, actual
  205. end
  206. def test_url_sub_key_with_database_url
  207. ENV["DATABASE_URL"] = "NOT-POSTGRES://localhost/NOT_FOO"
  208. config = { "default_env" => { "url" => "postgres://localhost/foo" } }
  209. actual = resolve_config(config)
  210. expected = {
  211. adapter: "postgresql",
  212. database: "foo",
  213. host: "localhost"
  214. }
  215. assert_equal expected, actual
  216. end
  217. def test_no_url_sub_key_with_database_url_doesnt_trample_other_envs
  218. ENV["DATABASE_URL"] = "postgres://localhost/baz"
  219. config = { "default_env" => { "database" => "foo" }, "other_env" => { "url" => "postgres://foohost/bardb" } }
  220. expected = {
  221. default_env: {
  222. database: "baz",
  223. adapter: "postgresql",
  224. host: "localhost"
  225. },
  226. other_env: {
  227. adapter: "postgresql",
  228. database: "bardb",
  229. host: "foohost"
  230. }
  231. }
  232. assert_equal expected[:default_env], resolve_config(config, "default_env")
  233. assert_equal expected[:other_env], resolve_config(config, "other_env")
  234. end
  235. def test_merge_no_conflicts_with_database_url
  236. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  237. config = { "default_env" => { "pool" => "5" } }
  238. actual = resolve_config(config)
  239. expected = {
  240. adapter: "postgresql",
  241. database: "foo",
  242. host: "localhost",
  243. pool: "5"
  244. }
  245. assert_equal expected, actual
  246. end
  247. def test_merge_conflicts_with_database_url
  248. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  249. config = { "default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } }
  250. actual = resolve_config(config)
  251. expected = {
  252. adapter: "postgresql",
  253. database: "foo",
  254. host: "localhost",
  255. pool: "5"
  256. }
  257. assert_equal expected, actual
  258. end
  259. def test_merge_no_conflicts_with_database_url_and_adapter
  260. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  261. config = { "default_env" => { "adapter" => "postgresql", "pool" => "5" } }
  262. actual = resolve_config(config)
  263. expected = {
  264. adapter: "postgresql",
  265. database: "foo",
  266. host: "localhost",
  267. pool: "5"
  268. }
  269. assert_equal expected, actual
  270. end
  271. def test_merge_no_conflicts_with_database_url_and_numeric_pool
  272. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  273. config = { "default_env" => { "pool" => 5 } }
  274. actual = resolve_config(config)
  275. expected = {
  276. adapter: "postgresql",
  277. database: "foo",
  278. host: "localhost",
  279. pool: 5
  280. }
  281. assert_equal expected, actual
  282. end
  283. def test_tiered_configs_with_database_url
  284. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  285. config = {
  286. "default_env" => {
  287. "primary" => { "pool" => 5 },
  288. "animals" => { "pool" => 5 }
  289. }
  290. }
  291. configs = ActiveRecord::DatabaseConfigurations.new(config)
  292. actual = configs.configs_for(env_name: "default_env", name: "primary").configuration_hash
  293. expected = {
  294. adapter: "postgresql",
  295. database: "foo",
  296. host: "localhost",
  297. pool: 5
  298. }
  299. assert_equal expected, actual
  300. configs = ActiveRecord::DatabaseConfigurations.new(config)
  301. actual = configs.configs_for(env_name: "default_env", name: "animals").configuration_hash
  302. expected = { pool: 5 }
  303. assert_equal expected, actual
  304. end
  305. def test_separate_database_env_vars
  306. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  307. ENV["PRIMARY_DATABASE_URL"] = "postgres://localhost/primary"
  308. ENV["ANIMALS_DATABASE_URL"] = "postgres://localhost/animals"
  309. config = {
  310. "default_env" => {
  311. "primary" => { "pool" => 5 },
  312. "animals" => { "pool" => 5 }
  313. }
  314. }
  315. configs = ActiveRecord::DatabaseConfigurations.new(config)
  316. actual = configs.configs_for(env_name: "default_env", name: "primary").configuration_hash
  317. assert_equal "primary", actual[:database]
  318. configs = ActiveRecord::DatabaseConfigurations.new(config)
  319. actual = configs.configs_for(env_name: "default_env", name: "animals").configuration_hash
  320. assert_equal "animals", actual[:database]
  321. ensure
  322. ENV.delete("PRIMARY_DATABASE_URL")
  323. ENV.delete("ANIMALS_DATABASE_URL")
  324. end
  325. def test_does_not_change_other_environments
  326. ENV["DATABASE_URL"] = "postgres://localhost/foo"
  327. config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" }, "default_env" => {} }
  328. actual = resolve_db_config(:production, config)
  329. assert_equal config["production"].symbolize_keys, actual.configuration_hash
  330. actual = resolve_db_config(:default_env, config)
  331. assert_equal({
  332. host: "localhost",
  333. database: "foo",
  334. adapter: "postgresql",
  335. }, actual.configuration_hash)
  336. end
  337. end
  338. end
  339. end