authentik.lib.tests.test_config
Test config loader
1"""Test config loader""" 2 3import base64 4from json import dumps 5from os import chmod, environ, unlink, write 6from tempfile import mkstemp 7from unittest import mock 8 9from django.conf import ImproperlyConfigured 10from django.test import TestCase 11 12from authentik.lib.config import ( 13 ENV_PREFIX, 14 UNSET, 15 Attr, 16 AttrEncoder, 17 ConfigLoader, 18 django_db_config, 19) 20 21 22class TestConfig(TestCase): 23 """Test config loader""" 24 25 check_deprecations_env_vars = { 26 ENV_PREFIX + "_WORKER__CONCURRENCY": "2", 27 } 28 29 @mock.patch.dict(environ, {ENV_PREFIX + "_test__test": "bar"}) 30 def test_env(self): 31 """Test simple instance""" 32 config = ConfigLoader() 33 config.update_from_env() 34 self.assertEqual(config.get("test.test"), "bar") 35 36 def test_patch(self): 37 """Test patch decorator""" 38 config = ConfigLoader() 39 config.set("foo.bar", "bar") 40 self.assertEqual(config.get("foo.bar"), "bar") 41 with config.patch("foo.bar", "baz"): 42 self.assertEqual(config.get("foo.bar"), "baz") 43 self.assertEqual(config.get("foo.bar"), "bar") 44 45 @mock.patch.dict(environ, {"foo": "bar"}) 46 def test_uri_env(self): 47 """Test URI parsing (environment)""" 48 config = ConfigLoader() 49 foo_uri = "env://foo" 50 foo_parsed = config.parse_uri(foo_uri) 51 self.assertEqual(foo_parsed.value, "bar") 52 self.assertEqual(foo_parsed.source_type, Attr.Source.URI) 53 self.assertEqual(foo_parsed.source, foo_uri) 54 foo_bar_uri = "env://foo?bar" 55 foo_bar_parsed = config.parse_uri(foo_bar_uri) 56 self.assertEqual(foo_bar_parsed.value, "bar") 57 self.assertEqual(foo_bar_parsed.source_type, Attr.Source.URI) 58 self.assertEqual(foo_bar_parsed.source, foo_bar_uri) 59 60 def test_uri_file(self): 61 """Test URI parsing (file load)""" 62 config = ConfigLoader() 63 file, file_name = mkstemp() 64 write(file, b"foo") 65 _, file2_name = mkstemp() 66 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 67 self.assertEqual(config.parse_uri(f"file://{file_name}").value, "foo") 68 self.assertEqual(config.parse_uri(f"file://{file2_name}?def").value, "def") 69 unlink(file_name) 70 unlink(file2_name) 71 72 def test_uri_file_update(self): 73 """Test URI parsing (file load and update)""" 74 file, file_name = mkstemp() 75 write(file, b"foo") 76 config = ConfigLoader(file_test=f"file://{file_name}") 77 self.assertEqual(config.get("file_test"), "foo") 78 79 # Update config file 80 write(file, b"bar") 81 config.refresh("file_test") 82 self.assertEqual(config.get("file_test"), "foobar") 83 84 unlink(file_name) 85 86 def test_uri_env_full(self): 87 """Test URI set as env variable""" 88 environ["AUTHENTIK_TEST_VAR"] = "file:///foo?bar" 89 config = ConfigLoader() 90 self.assertEqual(config.get("test_var"), "bar") 91 92 def test_file_update(self): 93 """Test update_from_file""" 94 config = ConfigLoader() 95 file, file_name = mkstemp() 96 write(file, b"{") 97 file2, file2_name = mkstemp() 98 write(file2, b"{") 99 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 100 with self.assertRaises(ImproperlyConfigured): 101 config.update_from_file(file_name) 102 config.update_from_file(file2_name) 103 unlink(file_name) 104 unlink(file2_name) 105 106 def test_get_int(self): 107 """Test get_int""" 108 config = ConfigLoader() 109 config.set("foo", 1234) 110 self.assertEqual(config.get_int("foo"), 1234) 111 112 def test_get_int_invalid(self): 113 """Test get_int""" 114 config = ConfigLoader() 115 config.set("foo", "bar") 116 self.assertEqual(config.get_int("foo", 1234), 1234) 117 118 def test_get_dict_from_b64_json(self): 119 """Test get_dict_from_b64_json""" 120 config = ConfigLoader() 121 test_value = b' { "foo": "bar" } ' 122 b64_value = base64.b64encode(test_value) 123 config.set("foo", b64_value) 124 self.assertEqual(config.get_dict_from_b64_json("foo"), {"foo": "bar"}) 125 126 def test_get_dict_from_b64_json_missing_brackets(self): 127 """Test get_dict_from_b64_json with missing brackets""" 128 config = ConfigLoader() 129 test_value = b' "foo": "bar" ' 130 b64_value = base64.b64encode(test_value) 131 config.set("foo", b64_value) 132 self.assertEqual(config.get_dict_from_b64_json("foo"), {}) 133 134 def test_get_dict_from_b64_json_invalid(self): 135 """Test get_dict_from_b64_json with invalid value""" 136 config = ConfigLoader() 137 config.set("foo", "bar") 138 self.assertEqual(config.get_dict_from_b64_json("foo"), {}) 139 140 def test_attr_json_encoder(self): 141 """Test AttrEncoder""" 142 test_attr = Attr("foo", Attr.Source.ENV, "AUTHENTIK_POSTGRESQL__USERNAME") 143 json_attr = dumps(test_attr, indent=4, cls=AttrEncoder) 144 self.assertEqual(json_attr, '"foo"') 145 146 def test_attr_json_encoder_no_attr(self): 147 """Test AttrEncoder if no Attr is passed""" 148 149 class Test: 150 """Non Attr class""" 151 152 with self.assertRaises(TypeError): 153 test_obj = Test() 154 dumps(test_obj, indent=4, cls=AttrEncoder) 155 156 def test_get_optional_int(self): 157 config = ConfigLoader() 158 self.assertEqual(config.get_optional_int("foo", 21), 21) 159 self.assertEqual(config.get_optional_int("foo"), None) 160 config.set("foo", "21") 161 self.assertEqual(config.get_optional_int("foo"), 21) 162 self.assertEqual(config.get_optional_int("foo", 0), 21) 163 self.assertEqual(config.get_optional_int("foo", "null"), 21) 164 config.set("foo", "null") 165 self.assertEqual(config.get_optional_int("foo"), None) 166 self.assertEqual(config.get_optional_int("foo", 21), None) 167 168 @mock.patch.dict(environ, check_deprecations_env_vars) 169 def test_check_deprecations(self): 170 """Test config key re-write for deprecated env vars""" 171 config = ConfigLoader() 172 config.update_from_env() 173 config.check_deprecations() 174 self.assertEqual(config.get("worker.concurrency", UNSET), UNSET) 175 self.assertEqual(config.get("worker.threads"), 2) 176 177 def test_get_keys(self): 178 """Test get_keys""" 179 config = ConfigLoader() 180 config.set("foo.bar", "baz") 181 self.assertEqual(list(config.get_keys("foo")), ["bar"]) 182 183 def test_db_default(self): 184 """Test default DB Config""" 185 config = ConfigLoader() 186 config.set("postgresql.host", "foo") 187 config.set("postgresql.name", "foo") 188 config.set("postgresql.user", "foo") 189 config.set("postgresql.password", "foo") 190 config.set("postgresql.port", "foo") 191 config.set("postgresql.sslmode", "foo") 192 config.set("postgresql.sslrootcert", "foo") 193 config.set("postgresql.sslcert", "foo") 194 config.set("postgresql.sslkey", "foo") 195 config.set("postgresql.test.name", "foo") 196 conf = django_db_config(config) 197 self.assertEqual( 198 conf, 199 { 200 "default": { 201 "ENGINE": "psqlextra.backend", 202 "HOST": "foo", 203 "NAME": "foo", 204 "OPTIONS": { 205 "pool": False, 206 "sslcert": "foo", 207 "sslkey": "foo", 208 "sslmode": "foo", 209 "sslrootcert": "foo", 210 }, 211 "PASSWORD": "foo", 212 "PORT": "foo", 213 "TEST": {"NAME": "foo"}, 214 "USER": "foo", 215 "CONN_MAX_AGE": 0, 216 "CONN_HEALTH_CHECKS": False, 217 "DISABLE_SERVER_SIDE_CURSORS": False, 218 } 219 }, 220 ) 221 222 def test_db_conn_max_age(self): 223 """Test DB conn_max_age Config""" 224 config = ConfigLoader() 225 config.set("postgresql.conn_max_age", "null") 226 conf = django_db_config(config) 227 self.assertEqual( 228 conf["default"]["CONN_MAX_AGE"], 229 None, 230 ) 231 232 def test_db_read_replicas(self): 233 """Test read replicas""" 234 config = ConfigLoader() 235 config.set("postgresql.host", "foo") 236 config.set("postgresql.name", "foo") 237 config.set("postgresql.user", "foo") 238 config.set("postgresql.password", "foo") 239 config.set("postgresql.port", "foo") 240 config.set("postgresql.sslmode", "foo") 241 config.set("postgresql.sslrootcert", "foo") 242 config.set("postgresql.sslcert", "foo") 243 config.set("postgresql.sslkey", "foo") 244 config.set("postgresql.test.name", "foo") 245 # Read replica 246 config.set("postgresql.read_replicas.0.host", "bar") 247 conf = django_db_config(config) 248 self.assertEqual( 249 conf, 250 { 251 "default": { 252 "ENGINE": "psqlextra.backend", 253 "HOST": "foo", 254 "NAME": "foo", 255 "OPTIONS": { 256 "pool": False, 257 "sslcert": "foo", 258 "sslkey": "foo", 259 "sslmode": "foo", 260 "sslrootcert": "foo", 261 }, 262 "PASSWORD": "foo", 263 "PORT": "foo", 264 "TEST": {"NAME": "foo"}, 265 "USER": "foo", 266 "CONN_MAX_AGE": 0, 267 "CONN_HEALTH_CHECKS": False, 268 "DISABLE_SERVER_SIDE_CURSORS": False, 269 }, 270 "replica_0": { 271 "ENGINE": "psqlextra.backend", 272 "HOST": "bar", 273 "NAME": "foo", 274 "OPTIONS": { 275 "pool": False, 276 "sslcert": "foo", 277 "sslkey": "foo", 278 "sslmode": "foo", 279 "sslrootcert": "foo", 280 }, 281 "PASSWORD": "foo", 282 "PORT": "foo", 283 "TEST": {"NAME": "foo"}, 284 "USER": "foo", 285 "CONN_MAX_AGE": 0, 286 "CONN_HEALTH_CHECKS": False, 287 "DISABLE_SERVER_SIDE_CURSORS": False, 288 }, 289 }, 290 ) 291 292 def test_db_read_replicas_pgbouncer(self): 293 """Test read replicas""" 294 config = ConfigLoader() 295 config.set("postgresql.host", "foo") 296 config.set("postgresql.name", "foo") 297 config.set("postgresql.user", "foo") 298 config.set("postgresql.password", "foo") 299 config.set("postgresql.port", "foo") 300 config.set("postgresql.sslmode", "foo") 301 config.set("postgresql.sslrootcert", "foo") 302 config.set("postgresql.sslcert", "foo") 303 config.set("postgresql.sslkey", "foo") 304 config.set("postgresql.test.name", "foo") 305 config.set("postgresql.use_pgbouncer", True) 306 # Read replica 307 config.set("postgresql.read_replicas.0.host", "bar") 308 # Override conn_max_age 309 config.set("postgresql.read_replicas.0.conn_max_age", 10) 310 # This isn't supported 311 config.set("postgresql.read_replicas.0.use_pgbouncer", False) 312 conf = django_db_config(config) 313 self.assertEqual( 314 conf, 315 { 316 "default": { 317 "DISABLE_SERVER_SIDE_CURSORS": True, 318 "CONN_MAX_AGE": None, 319 "CONN_HEALTH_CHECKS": False, 320 "ENGINE": "psqlextra.backend", 321 "HOST": "foo", 322 "NAME": "foo", 323 "OPTIONS": { 324 "pool": False, 325 "sslcert": "foo", 326 "sslkey": "foo", 327 "sslmode": "foo", 328 "sslrootcert": "foo", 329 }, 330 "PASSWORD": "foo", 331 "PORT": "foo", 332 "TEST": {"NAME": "foo"}, 333 "USER": "foo", 334 }, 335 "replica_0": { 336 "DISABLE_SERVER_SIDE_CURSORS": True, 337 "CONN_MAX_AGE": 10, 338 "CONN_HEALTH_CHECKS": False, 339 "ENGINE": "psqlextra.backend", 340 "HOST": "bar", 341 "NAME": "foo", 342 "OPTIONS": { 343 "pool": False, 344 "sslcert": "foo", 345 "sslkey": "foo", 346 "sslmode": "foo", 347 "sslrootcert": "foo", 348 }, 349 "PASSWORD": "foo", 350 "PORT": "foo", 351 "TEST": {"NAME": "foo"}, 352 "USER": "foo", 353 }, 354 }, 355 ) 356 357 def test_db_read_replicas_pgpool(self): 358 """Test read replicas""" 359 config = ConfigLoader() 360 config.set("postgresql.host", "foo") 361 config.set("postgresql.name", "foo") 362 config.set("postgresql.user", "foo") 363 config.set("postgresql.password", "foo") 364 config.set("postgresql.port", "foo") 365 config.set("postgresql.sslmode", "foo") 366 config.set("postgresql.sslrootcert", "foo") 367 config.set("postgresql.sslcert", "foo") 368 config.set("postgresql.sslkey", "foo") 369 config.set("postgresql.test.name", "foo") 370 config.set("postgresql.use_pgpool", True) 371 # Read replica 372 config.set("postgresql.read_replicas.0.host", "bar") 373 # This isn't supported 374 config.set("postgresql.read_replicas.0.use_pgpool", False) 375 conf = django_db_config(config) 376 self.assertEqual( 377 conf, 378 { 379 "default": { 380 "DISABLE_SERVER_SIDE_CURSORS": True, 381 "CONN_MAX_AGE": 0, 382 "CONN_HEALTH_CHECKS": False, 383 "ENGINE": "psqlextra.backend", 384 "HOST": "foo", 385 "NAME": "foo", 386 "OPTIONS": { 387 "pool": False, 388 "sslcert": "foo", 389 "sslkey": "foo", 390 "sslmode": "foo", 391 "sslrootcert": "foo", 392 }, 393 "PASSWORD": "foo", 394 "PORT": "foo", 395 "TEST": {"NAME": "foo"}, 396 "USER": "foo", 397 }, 398 "replica_0": { 399 "DISABLE_SERVER_SIDE_CURSORS": True, 400 "CONN_MAX_AGE": 0, 401 "CONN_HEALTH_CHECKS": False, 402 "ENGINE": "psqlextra.backend", 403 "HOST": "bar", 404 "NAME": "foo", 405 "OPTIONS": { 406 "pool": False, 407 "sslcert": "foo", 408 "sslkey": "foo", 409 "sslmode": "foo", 410 "sslrootcert": "foo", 411 }, 412 "PASSWORD": "foo", 413 "PORT": "foo", 414 "TEST": {"NAME": "foo"}, 415 "USER": "foo", 416 }, 417 }, 418 ) 419 420 def test_db_read_replicas_diff_ssl(self): 421 """Test read replicas (with different SSL Settings)""" 422 """Test read replicas""" 423 config = ConfigLoader() 424 config.set("postgresql.host", "foo") 425 config.set("postgresql.name", "foo") 426 config.set("postgresql.user", "foo") 427 config.set("postgresql.password", "foo") 428 config.set("postgresql.port", "foo") 429 config.set("postgresql.sslmode", "foo") 430 config.set("postgresql.sslrootcert", "foo") 431 config.set("postgresql.sslcert", "foo") 432 config.set("postgresql.sslkey", "foo") 433 config.set("postgresql.test.name", "foo") 434 # Read replica 435 config.set("postgresql.read_replicas.0.host", "bar") 436 config.set("postgresql.read_replicas.0.sslcert", "bar") 437 conf = django_db_config(config) 438 self.assertEqual( 439 conf, 440 { 441 "default": { 442 "ENGINE": "psqlextra.backend", 443 "HOST": "foo", 444 "NAME": "foo", 445 "OPTIONS": { 446 "pool": False, 447 "sslcert": "foo", 448 "sslkey": "foo", 449 "sslmode": "foo", 450 "sslrootcert": "foo", 451 }, 452 "PASSWORD": "foo", 453 "PORT": "foo", 454 "TEST": {"NAME": "foo"}, 455 "USER": "foo", 456 "DISABLE_SERVER_SIDE_CURSORS": False, 457 "CONN_MAX_AGE": 0, 458 "CONN_HEALTH_CHECKS": False, 459 }, 460 "replica_0": { 461 "ENGINE": "psqlextra.backend", 462 "HOST": "bar", 463 "NAME": "foo", 464 "OPTIONS": { 465 "pool": False, 466 "sslcert": "bar", 467 "sslkey": "foo", 468 "sslmode": "foo", 469 "sslrootcert": "foo", 470 }, 471 "PASSWORD": "foo", 472 "PORT": "foo", 473 "TEST": {"NAME": "foo"}, 474 "USER": "foo", 475 "DISABLE_SERVER_SIDE_CURSORS": False, 476 "CONN_MAX_AGE": 0, 477 "CONN_HEALTH_CHECKS": False, 478 }, 479 }, 480 ) 481 482 def test_db_conn_options(self): 483 config = ConfigLoader() 484 config.set( 485 "postgresql.conn_options", 486 base64.b64encode( 487 dumps( 488 { 489 "connect_timeout": "10", 490 } 491 ).encode() 492 ).decode(), 493 ) 494 config.set("postgresql.read_replicas.0.host", "bar") 495 496 conf = django_db_config(config) 497 498 self.assertEqual( 499 conf["default"]["OPTIONS"]["connect_timeout"], 500 "10", 501 ) 502 self.assertNotIn("connect_timeout", conf["replica_0"]["OPTIONS"]) 503 504 def test_db_conn_options_read_replicas(self): 505 config = ConfigLoader() 506 config.set( 507 "postgresql.replica_conn_options", 508 base64.b64encode( 509 dumps( 510 { 511 "connect_timeout": "10", 512 } 513 ).encode() 514 ).decode(), 515 ) 516 config.set("postgresql.read_replicas.0.host", "bar") 517 config.set("postgresql.read_replicas.1.host", "bar") 518 config.set( 519 "postgresql.read_replicas.1.conn_options", 520 base64.b64encode( 521 dumps( 522 { 523 "connect_timeout": "20", 524 } 525 ).encode() 526 ).decode(), 527 ) 528 529 conf = django_db_config(config) 530 531 self.assertNotIn("connect_timeout", conf["default"]["OPTIONS"]) 532 self.assertEqual( 533 conf["replica_0"]["OPTIONS"]["connect_timeout"], 534 "10", 535 ) 536 self.assertEqual( 537 conf["replica_1"]["OPTIONS"]["connect_timeout"], 538 "20", 539 ) 540 541 # FIXME: Temporarily force pool to be deactivated. 542 # See https://github.com/goauthentik/authentik/issues/14320 543 # def test_db_pool(self): 544 # """Test DB Config with pool""" 545 # config = ConfigLoader() 546 # config.set("postgresql.host", "foo") 547 # config.set("postgresql.name", "foo") 548 # config.set("postgresql.user", "foo") 549 # config.set("postgresql.password", "foo") 550 # config.set("postgresql.port", "foo") 551 # config.set("postgresql.test.name", "foo") 552 # config.set("postgresql.use_pool", True) 553 # conf = django_db_config(config) 554 # self.assertEqual( 555 # conf, 556 # { 557 # "default": { 558 # "ENGINE": "psqlextra.backend", 559 # "HOST": "foo", 560 # "NAME": "foo", 561 # "OPTIONS": { 562 # "pool": True, 563 # "sslcert": None, 564 # "sslkey": None, 565 # "sslmode": None, 566 # "sslrootcert": None, 567 # }, 568 # "PASSWORD": "foo", 569 # "PORT": "foo", 570 # "TEST": {"NAME": "foo"}, 571 # "USER": "foo", 572 # "CONN_MAX_AGE": 0, 573 # "CONN_HEALTH_CHECKS": False, 574 # "DISABLE_SERVER_SIDE_CURSORS": False, 575 # } 576 # }, 577 # ) 578 579 # def test_db_pool_options(self): 580 # """Test DB Config with pool""" 581 # config = ConfigLoader() 582 # config.set("postgresql.host", "foo") 583 # config.set("postgresql.name", "foo") 584 # config.set("postgresql.user", "foo") 585 # config.set("postgresql.password", "foo") 586 # config.set("postgresql.port", "foo") 587 # config.set("postgresql.test.name", "foo") 588 # config.set("postgresql.use_pool", True) 589 # config.set( 590 # "postgresql.pool_options", 591 # base64.b64encode( 592 # dumps( 593 # { 594 # "max_size": 15, 595 # } 596 # ).encode() 597 # ).decode(), 598 # ) 599 # conf = django_db_config(config) 600 # self.assertEqual( 601 # conf, 602 # { 603 # "default": { 604 # "ENGINE": "psqlextra.backend", 605 # "HOST": "foo", 606 # "NAME": "foo", 607 # "OPTIONS": { 608 # "pool": { 609 # "max_size": 15, 610 # }, 611 # "sslcert": None, 612 # "sslkey": None, 613 # "sslmode": None, 614 # "sslrootcert": None, 615 # }, 616 # "PASSWORD": "foo", 617 # "PORT": "foo", 618 # "TEST": {"NAME": "foo"}, 619 # "USER": "foo", 620 # "CONN_MAX_AGE": 0, 621 # "CONN_HEALTH_CHECKS": False, 622 # "DISABLE_SERVER_SIDE_CURSORS": False, 623 # } 624 # }, 625 # )
class
TestConfig(django.test.testcases.TestCase):
23class TestConfig(TestCase): 24 """Test config loader""" 25 26 check_deprecations_env_vars = { 27 ENV_PREFIX + "_WORKER__CONCURRENCY": "2", 28 } 29 30 @mock.patch.dict(environ, {ENV_PREFIX + "_test__test": "bar"}) 31 def test_env(self): 32 """Test simple instance""" 33 config = ConfigLoader() 34 config.update_from_env() 35 self.assertEqual(config.get("test.test"), "bar") 36 37 def test_patch(self): 38 """Test patch decorator""" 39 config = ConfigLoader() 40 config.set("foo.bar", "bar") 41 self.assertEqual(config.get("foo.bar"), "bar") 42 with config.patch("foo.bar", "baz"): 43 self.assertEqual(config.get("foo.bar"), "baz") 44 self.assertEqual(config.get("foo.bar"), "bar") 45 46 @mock.patch.dict(environ, {"foo": "bar"}) 47 def test_uri_env(self): 48 """Test URI parsing (environment)""" 49 config = ConfigLoader() 50 foo_uri = "env://foo" 51 foo_parsed = config.parse_uri(foo_uri) 52 self.assertEqual(foo_parsed.value, "bar") 53 self.assertEqual(foo_parsed.source_type, Attr.Source.URI) 54 self.assertEqual(foo_parsed.source, foo_uri) 55 foo_bar_uri = "env://foo?bar" 56 foo_bar_parsed = config.parse_uri(foo_bar_uri) 57 self.assertEqual(foo_bar_parsed.value, "bar") 58 self.assertEqual(foo_bar_parsed.source_type, Attr.Source.URI) 59 self.assertEqual(foo_bar_parsed.source, foo_bar_uri) 60 61 def test_uri_file(self): 62 """Test URI parsing (file load)""" 63 config = ConfigLoader() 64 file, file_name = mkstemp() 65 write(file, b"foo") 66 _, file2_name = mkstemp() 67 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 68 self.assertEqual(config.parse_uri(f"file://{file_name}").value, "foo") 69 self.assertEqual(config.parse_uri(f"file://{file2_name}?def").value, "def") 70 unlink(file_name) 71 unlink(file2_name) 72 73 def test_uri_file_update(self): 74 """Test URI parsing (file load and update)""" 75 file, file_name = mkstemp() 76 write(file, b"foo") 77 config = ConfigLoader(file_test=f"file://{file_name}") 78 self.assertEqual(config.get("file_test"), "foo") 79 80 # Update config file 81 write(file, b"bar") 82 config.refresh("file_test") 83 self.assertEqual(config.get("file_test"), "foobar") 84 85 unlink(file_name) 86 87 def test_uri_env_full(self): 88 """Test URI set as env variable""" 89 environ["AUTHENTIK_TEST_VAR"] = "file:///foo?bar" 90 config = ConfigLoader() 91 self.assertEqual(config.get("test_var"), "bar") 92 93 def test_file_update(self): 94 """Test update_from_file""" 95 config = ConfigLoader() 96 file, file_name = mkstemp() 97 write(file, b"{") 98 file2, file2_name = mkstemp() 99 write(file2, b"{") 100 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 101 with self.assertRaises(ImproperlyConfigured): 102 config.update_from_file(file_name) 103 config.update_from_file(file2_name) 104 unlink(file_name) 105 unlink(file2_name) 106 107 def test_get_int(self): 108 """Test get_int""" 109 config = ConfigLoader() 110 config.set("foo", 1234) 111 self.assertEqual(config.get_int("foo"), 1234) 112 113 def test_get_int_invalid(self): 114 """Test get_int""" 115 config = ConfigLoader() 116 config.set("foo", "bar") 117 self.assertEqual(config.get_int("foo", 1234), 1234) 118 119 def test_get_dict_from_b64_json(self): 120 """Test get_dict_from_b64_json""" 121 config = ConfigLoader() 122 test_value = b' { "foo": "bar" } ' 123 b64_value = base64.b64encode(test_value) 124 config.set("foo", b64_value) 125 self.assertEqual(config.get_dict_from_b64_json("foo"), {"foo": "bar"}) 126 127 def test_get_dict_from_b64_json_missing_brackets(self): 128 """Test get_dict_from_b64_json with missing brackets""" 129 config = ConfigLoader() 130 test_value = b' "foo": "bar" ' 131 b64_value = base64.b64encode(test_value) 132 config.set("foo", b64_value) 133 self.assertEqual(config.get_dict_from_b64_json("foo"), {}) 134 135 def test_get_dict_from_b64_json_invalid(self): 136 """Test get_dict_from_b64_json with invalid value""" 137 config = ConfigLoader() 138 config.set("foo", "bar") 139 self.assertEqual(config.get_dict_from_b64_json("foo"), {}) 140 141 def test_attr_json_encoder(self): 142 """Test AttrEncoder""" 143 test_attr = Attr("foo", Attr.Source.ENV, "AUTHENTIK_POSTGRESQL__USERNAME") 144 json_attr = dumps(test_attr, indent=4, cls=AttrEncoder) 145 self.assertEqual(json_attr, '"foo"') 146 147 def test_attr_json_encoder_no_attr(self): 148 """Test AttrEncoder if no Attr is passed""" 149 150 class Test: 151 """Non Attr class""" 152 153 with self.assertRaises(TypeError): 154 test_obj = Test() 155 dumps(test_obj, indent=4, cls=AttrEncoder) 156 157 def test_get_optional_int(self): 158 config = ConfigLoader() 159 self.assertEqual(config.get_optional_int("foo", 21), 21) 160 self.assertEqual(config.get_optional_int("foo"), None) 161 config.set("foo", "21") 162 self.assertEqual(config.get_optional_int("foo"), 21) 163 self.assertEqual(config.get_optional_int("foo", 0), 21) 164 self.assertEqual(config.get_optional_int("foo", "null"), 21) 165 config.set("foo", "null") 166 self.assertEqual(config.get_optional_int("foo"), None) 167 self.assertEqual(config.get_optional_int("foo", 21), None) 168 169 @mock.patch.dict(environ, check_deprecations_env_vars) 170 def test_check_deprecations(self): 171 """Test config key re-write for deprecated env vars""" 172 config = ConfigLoader() 173 config.update_from_env() 174 config.check_deprecations() 175 self.assertEqual(config.get("worker.concurrency", UNSET), UNSET) 176 self.assertEqual(config.get("worker.threads"), 2) 177 178 def test_get_keys(self): 179 """Test get_keys""" 180 config = ConfigLoader() 181 config.set("foo.bar", "baz") 182 self.assertEqual(list(config.get_keys("foo")), ["bar"]) 183 184 def test_db_default(self): 185 """Test default DB Config""" 186 config = ConfigLoader() 187 config.set("postgresql.host", "foo") 188 config.set("postgresql.name", "foo") 189 config.set("postgresql.user", "foo") 190 config.set("postgresql.password", "foo") 191 config.set("postgresql.port", "foo") 192 config.set("postgresql.sslmode", "foo") 193 config.set("postgresql.sslrootcert", "foo") 194 config.set("postgresql.sslcert", "foo") 195 config.set("postgresql.sslkey", "foo") 196 config.set("postgresql.test.name", "foo") 197 conf = django_db_config(config) 198 self.assertEqual( 199 conf, 200 { 201 "default": { 202 "ENGINE": "psqlextra.backend", 203 "HOST": "foo", 204 "NAME": "foo", 205 "OPTIONS": { 206 "pool": False, 207 "sslcert": "foo", 208 "sslkey": "foo", 209 "sslmode": "foo", 210 "sslrootcert": "foo", 211 }, 212 "PASSWORD": "foo", 213 "PORT": "foo", 214 "TEST": {"NAME": "foo"}, 215 "USER": "foo", 216 "CONN_MAX_AGE": 0, 217 "CONN_HEALTH_CHECKS": False, 218 "DISABLE_SERVER_SIDE_CURSORS": False, 219 } 220 }, 221 ) 222 223 def test_db_conn_max_age(self): 224 """Test DB conn_max_age Config""" 225 config = ConfigLoader() 226 config.set("postgresql.conn_max_age", "null") 227 conf = django_db_config(config) 228 self.assertEqual( 229 conf["default"]["CONN_MAX_AGE"], 230 None, 231 ) 232 233 def test_db_read_replicas(self): 234 """Test read replicas""" 235 config = ConfigLoader() 236 config.set("postgresql.host", "foo") 237 config.set("postgresql.name", "foo") 238 config.set("postgresql.user", "foo") 239 config.set("postgresql.password", "foo") 240 config.set("postgresql.port", "foo") 241 config.set("postgresql.sslmode", "foo") 242 config.set("postgresql.sslrootcert", "foo") 243 config.set("postgresql.sslcert", "foo") 244 config.set("postgresql.sslkey", "foo") 245 config.set("postgresql.test.name", "foo") 246 # Read replica 247 config.set("postgresql.read_replicas.0.host", "bar") 248 conf = django_db_config(config) 249 self.assertEqual( 250 conf, 251 { 252 "default": { 253 "ENGINE": "psqlextra.backend", 254 "HOST": "foo", 255 "NAME": "foo", 256 "OPTIONS": { 257 "pool": False, 258 "sslcert": "foo", 259 "sslkey": "foo", 260 "sslmode": "foo", 261 "sslrootcert": "foo", 262 }, 263 "PASSWORD": "foo", 264 "PORT": "foo", 265 "TEST": {"NAME": "foo"}, 266 "USER": "foo", 267 "CONN_MAX_AGE": 0, 268 "CONN_HEALTH_CHECKS": False, 269 "DISABLE_SERVER_SIDE_CURSORS": False, 270 }, 271 "replica_0": { 272 "ENGINE": "psqlextra.backend", 273 "HOST": "bar", 274 "NAME": "foo", 275 "OPTIONS": { 276 "pool": False, 277 "sslcert": "foo", 278 "sslkey": "foo", 279 "sslmode": "foo", 280 "sslrootcert": "foo", 281 }, 282 "PASSWORD": "foo", 283 "PORT": "foo", 284 "TEST": {"NAME": "foo"}, 285 "USER": "foo", 286 "CONN_MAX_AGE": 0, 287 "CONN_HEALTH_CHECKS": False, 288 "DISABLE_SERVER_SIDE_CURSORS": False, 289 }, 290 }, 291 ) 292 293 def test_db_read_replicas_pgbouncer(self): 294 """Test read replicas""" 295 config = ConfigLoader() 296 config.set("postgresql.host", "foo") 297 config.set("postgresql.name", "foo") 298 config.set("postgresql.user", "foo") 299 config.set("postgresql.password", "foo") 300 config.set("postgresql.port", "foo") 301 config.set("postgresql.sslmode", "foo") 302 config.set("postgresql.sslrootcert", "foo") 303 config.set("postgresql.sslcert", "foo") 304 config.set("postgresql.sslkey", "foo") 305 config.set("postgresql.test.name", "foo") 306 config.set("postgresql.use_pgbouncer", True) 307 # Read replica 308 config.set("postgresql.read_replicas.0.host", "bar") 309 # Override conn_max_age 310 config.set("postgresql.read_replicas.0.conn_max_age", 10) 311 # This isn't supported 312 config.set("postgresql.read_replicas.0.use_pgbouncer", False) 313 conf = django_db_config(config) 314 self.assertEqual( 315 conf, 316 { 317 "default": { 318 "DISABLE_SERVER_SIDE_CURSORS": True, 319 "CONN_MAX_AGE": None, 320 "CONN_HEALTH_CHECKS": False, 321 "ENGINE": "psqlextra.backend", 322 "HOST": "foo", 323 "NAME": "foo", 324 "OPTIONS": { 325 "pool": False, 326 "sslcert": "foo", 327 "sslkey": "foo", 328 "sslmode": "foo", 329 "sslrootcert": "foo", 330 }, 331 "PASSWORD": "foo", 332 "PORT": "foo", 333 "TEST": {"NAME": "foo"}, 334 "USER": "foo", 335 }, 336 "replica_0": { 337 "DISABLE_SERVER_SIDE_CURSORS": True, 338 "CONN_MAX_AGE": 10, 339 "CONN_HEALTH_CHECKS": False, 340 "ENGINE": "psqlextra.backend", 341 "HOST": "bar", 342 "NAME": "foo", 343 "OPTIONS": { 344 "pool": False, 345 "sslcert": "foo", 346 "sslkey": "foo", 347 "sslmode": "foo", 348 "sslrootcert": "foo", 349 }, 350 "PASSWORD": "foo", 351 "PORT": "foo", 352 "TEST": {"NAME": "foo"}, 353 "USER": "foo", 354 }, 355 }, 356 ) 357 358 def test_db_read_replicas_pgpool(self): 359 """Test read replicas""" 360 config = ConfigLoader() 361 config.set("postgresql.host", "foo") 362 config.set("postgresql.name", "foo") 363 config.set("postgresql.user", "foo") 364 config.set("postgresql.password", "foo") 365 config.set("postgresql.port", "foo") 366 config.set("postgresql.sslmode", "foo") 367 config.set("postgresql.sslrootcert", "foo") 368 config.set("postgresql.sslcert", "foo") 369 config.set("postgresql.sslkey", "foo") 370 config.set("postgresql.test.name", "foo") 371 config.set("postgresql.use_pgpool", True) 372 # Read replica 373 config.set("postgresql.read_replicas.0.host", "bar") 374 # This isn't supported 375 config.set("postgresql.read_replicas.0.use_pgpool", False) 376 conf = django_db_config(config) 377 self.assertEqual( 378 conf, 379 { 380 "default": { 381 "DISABLE_SERVER_SIDE_CURSORS": True, 382 "CONN_MAX_AGE": 0, 383 "CONN_HEALTH_CHECKS": False, 384 "ENGINE": "psqlextra.backend", 385 "HOST": "foo", 386 "NAME": "foo", 387 "OPTIONS": { 388 "pool": False, 389 "sslcert": "foo", 390 "sslkey": "foo", 391 "sslmode": "foo", 392 "sslrootcert": "foo", 393 }, 394 "PASSWORD": "foo", 395 "PORT": "foo", 396 "TEST": {"NAME": "foo"}, 397 "USER": "foo", 398 }, 399 "replica_0": { 400 "DISABLE_SERVER_SIDE_CURSORS": True, 401 "CONN_MAX_AGE": 0, 402 "CONN_HEALTH_CHECKS": False, 403 "ENGINE": "psqlextra.backend", 404 "HOST": "bar", 405 "NAME": "foo", 406 "OPTIONS": { 407 "pool": False, 408 "sslcert": "foo", 409 "sslkey": "foo", 410 "sslmode": "foo", 411 "sslrootcert": "foo", 412 }, 413 "PASSWORD": "foo", 414 "PORT": "foo", 415 "TEST": {"NAME": "foo"}, 416 "USER": "foo", 417 }, 418 }, 419 ) 420 421 def test_db_read_replicas_diff_ssl(self): 422 """Test read replicas (with different SSL Settings)""" 423 """Test read replicas""" 424 config = ConfigLoader() 425 config.set("postgresql.host", "foo") 426 config.set("postgresql.name", "foo") 427 config.set("postgresql.user", "foo") 428 config.set("postgresql.password", "foo") 429 config.set("postgresql.port", "foo") 430 config.set("postgresql.sslmode", "foo") 431 config.set("postgresql.sslrootcert", "foo") 432 config.set("postgresql.sslcert", "foo") 433 config.set("postgresql.sslkey", "foo") 434 config.set("postgresql.test.name", "foo") 435 # Read replica 436 config.set("postgresql.read_replicas.0.host", "bar") 437 config.set("postgresql.read_replicas.0.sslcert", "bar") 438 conf = django_db_config(config) 439 self.assertEqual( 440 conf, 441 { 442 "default": { 443 "ENGINE": "psqlextra.backend", 444 "HOST": "foo", 445 "NAME": "foo", 446 "OPTIONS": { 447 "pool": False, 448 "sslcert": "foo", 449 "sslkey": "foo", 450 "sslmode": "foo", 451 "sslrootcert": "foo", 452 }, 453 "PASSWORD": "foo", 454 "PORT": "foo", 455 "TEST": {"NAME": "foo"}, 456 "USER": "foo", 457 "DISABLE_SERVER_SIDE_CURSORS": False, 458 "CONN_MAX_AGE": 0, 459 "CONN_HEALTH_CHECKS": False, 460 }, 461 "replica_0": { 462 "ENGINE": "psqlextra.backend", 463 "HOST": "bar", 464 "NAME": "foo", 465 "OPTIONS": { 466 "pool": False, 467 "sslcert": "bar", 468 "sslkey": "foo", 469 "sslmode": "foo", 470 "sslrootcert": "foo", 471 }, 472 "PASSWORD": "foo", 473 "PORT": "foo", 474 "TEST": {"NAME": "foo"}, 475 "USER": "foo", 476 "DISABLE_SERVER_SIDE_CURSORS": False, 477 "CONN_MAX_AGE": 0, 478 "CONN_HEALTH_CHECKS": False, 479 }, 480 }, 481 ) 482 483 def test_db_conn_options(self): 484 config = ConfigLoader() 485 config.set( 486 "postgresql.conn_options", 487 base64.b64encode( 488 dumps( 489 { 490 "connect_timeout": "10", 491 } 492 ).encode() 493 ).decode(), 494 ) 495 config.set("postgresql.read_replicas.0.host", "bar") 496 497 conf = django_db_config(config) 498 499 self.assertEqual( 500 conf["default"]["OPTIONS"]["connect_timeout"], 501 "10", 502 ) 503 self.assertNotIn("connect_timeout", conf["replica_0"]["OPTIONS"]) 504 505 def test_db_conn_options_read_replicas(self): 506 config = ConfigLoader() 507 config.set( 508 "postgresql.replica_conn_options", 509 base64.b64encode( 510 dumps( 511 { 512 "connect_timeout": "10", 513 } 514 ).encode() 515 ).decode(), 516 ) 517 config.set("postgresql.read_replicas.0.host", "bar") 518 config.set("postgresql.read_replicas.1.host", "bar") 519 config.set( 520 "postgresql.read_replicas.1.conn_options", 521 base64.b64encode( 522 dumps( 523 { 524 "connect_timeout": "20", 525 } 526 ).encode() 527 ).decode(), 528 ) 529 530 conf = django_db_config(config) 531 532 self.assertNotIn("connect_timeout", conf["default"]["OPTIONS"]) 533 self.assertEqual( 534 conf["replica_0"]["OPTIONS"]["connect_timeout"], 535 "10", 536 ) 537 self.assertEqual( 538 conf["replica_1"]["OPTIONS"]["connect_timeout"], 539 "20", 540 ) 541 542 # FIXME: Temporarily force pool to be deactivated. 543 # See https://github.com/goauthentik/authentik/issues/14320 544 # def test_db_pool(self): 545 # """Test DB Config with pool""" 546 # config = ConfigLoader() 547 # config.set("postgresql.host", "foo") 548 # config.set("postgresql.name", "foo") 549 # config.set("postgresql.user", "foo") 550 # config.set("postgresql.password", "foo") 551 # config.set("postgresql.port", "foo") 552 # config.set("postgresql.test.name", "foo") 553 # config.set("postgresql.use_pool", True) 554 # conf = django_db_config(config) 555 # self.assertEqual( 556 # conf, 557 # { 558 # "default": { 559 # "ENGINE": "psqlextra.backend", 560 # "HOST": "foo", 561 # "NAME": "foo", 562 # "OPTIONS": { 563 # "pool": True, 564 # "sslcert": None, 565 # "sslkey": None, 566 # "sslmode": None, 567 # "sslrootcert": None, 568 # }, 569 # "PASSWORD": "foo", 570 # "PORT": "foo", 571 # "TEST": {"NAME": "foo"}, 572 # "USER": "foo", 573 # "CONN_MAX_AGE": 0, 574 # "CONN_HEALTH_CHECKS": False, 575 # "DISABLE_SERVER_SIDE_CURSORS": False, 576 # } 577 # }, 578 # ) 579 580 # def test_db_pool_options(self): 581 # """Test DB Config with pool""" 582 # config = ConfigLoader() 583 # config.set("postgresql.host", "foo") 584 # config.set("postgresql.name", "foo") 585 # config.set("postgresql.user", "foo") 586 # config.set("postgresql.password", "foo") 587 # config.set("postgresql.port", "foo") 588 # config.set("postgresql.test.name", "foo") 589 # config.set("postgresql.use_pool", True) 590 # config.set( 591 # "postgresql.pool_options", 592 # base64.b64encode( 593 # dumps( 594 # { 595 # "max_size": 15, 596 # } 597 # ).encode() 598 # ).decode(), 599 # ) 600 # conf = django_db_config(config) 601 # self.assertEqual( 602 # conf, 603 # { 604 # "default": { 605 # "ENGINE": "psqlextra.backend", 606 # "HOST": "foo", 607 # "NAME": "foo", 608 # "OPTIONS": { 609 # "pool": { 610 # "max_size": 15, 611 # }, 612 # "sslcert": None, 613 # "sslkey": None, 614 # "sslmode": None, 615 # "sslrootcert": None, 616 # }, 617 # "PASSWORD": "foo", 618 # "PORT": "foo", 619 # "TEST": {"NAME": "foo"}, 620 # "USER": "foo", 621 # "CONN_MAX_AGE": 0, 622 # "CONN_HEALTH_CHECKS": False, 623 # "DISABLE_SERVER_SIDE_CURSORS": False, 624 # } 625 # }, 626 # )
Test config loader
@mock.patch.dict(environ, {ENV_PREFIX + '_test__test': 'bar'})
def
test_env(self):
30 @mock.patch.dict(environ, {ENV_PREFIX + "_test__test": "bar"}) 31 def test_env(self): 32 """Test simple instance""" 33 config = ConfigLoader() 34 config.update_from_env() 35 self.assertEqual(config.get("test.test"), "bar")
Test simple instance
def
test_patch(self):
37 def test_patch(self): 38 """Test patch decorator""" 39 config = ConfigLoader() 40 config.set("foo.bar", "bar") 41 self.assertEqual(config.get("foo.bar"), "bar") 42 with config.patch("foo.bar", "baz"): 43 self.assertEqual(config.get("foo.bar"), "baz") 44 self.assertEqual(config.get("foo.bar"), "bar")
Test patch decorator
@mock.patch.dict(environ, {'foo': 'bar'})
def
test_uri_env(self):
46 @mock.patch.dict(environ, {"foo": "bar"}) 47 def test_uri_env(self): 48 """Test URI parsing (environment)""" 49 config = ConfigLoader() 50 foo_uri = "env://foo" 51 foo_parsed = config.parse_uri(foo_uri) 52 self.assertEqual(foo_parsed.value, "bar") 53 self.assertEqual(foo_parsed.source_type, Attr.Source.URI) 54 self.assertEqual(foo_parsed.source, foo_uri) 55 foo_bar_uri = "env://foo?bar" 56 foo_bar_parsed = config.parse_uri(foo_bar_uri) 57 self.assertEqual(foo_bar_parsed.value, "bar") 58 self.assertEqual(foo_bar_parsed.source_type, Attr.Source.URI) 59 self.assertEqual(foo_bar_parsed.source, foo_bar_uri)
Test URI parsing (environment)
def
test_uri_file(self):
61 def test_uri_file(self): 62 """Test URI parsing (file load)""" 63 config = ConfigLoader() 64 file, file_name = mkstemp() 65 write(file, b"foo") 66 _, file2_name = mkstemp() 67 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 68 self.assertEqual(config.parse_uri(f"file://{file_name}").value, "foo") 69 self.assertEqual(config.parse_uri(f"file://{file2_name}?def").value, "def") 70 unlink(file_name) 71 unlink(file2_name)
Test URI parsing (file load)
def
test_uri_file_update(self):
73 def test_uri_file_update(self): 74 """Test URI parsing (file load and update)""" 75 file, file_name = mkstemp() 76 write(file, b"foo") 77 config = ConfigLoader(file_test=f"file://{file_name}") 78 self.assertEqual(config.get("file_test"), "foo") 79 80 # Update config file 81 write(file, b"bar") 82 config.refresh("file_test") 83 self.assertEqual(config.get("file_test"), "foobar") 84 85 unlink(file_name)
Test URI parsing (file load and update)
def
test_uri_env_full(self):
87 def test_uri_env_full(self): 88 """Test URI set as env variable""" 89 environ["AUTHENTIK_TEST_VAR"] = "file:///foo?bar" 90 config = ConfigLoader() 91 self.assertEqual(config.get("test_var"), "bar")
Test URI set as env variable
def
test_file_update(self):
93 def test_file_update(self): 94 """Test update_from_file""" 95 config = ConfigLoader() 96 file, file_name = mkstemp() 97 write(file, b"{") 98 file2, file2_name = mkstemp() 99 write(file2, b"{") 100 chmod(file2_name, 0o000) # Remove all permissions so we can't read the file 101 with self.assertRaises(ImproperlyConfigured): 102 config.update_from_file(file_name) 103 config.update_from_file(file2_name) 104 unlink(file_name) 105 unlink(file2_name)
Test update_from_file
def
test_get_int(self):
107 def test_get_int(self): 108 """Test get_int""" 109 config = ConfigLoader() 110 config.set("foo", 1234) 111 self.assertEqual(config.get_int("foo"), 1234)
Test get_int
def
test_get_int_invalid(self):
113 def test_get_int_invalid(self): 114 """Test get_int""" 115 config = ConfigLoader() 116 config.set("foo", "bar") 117 self.assertEqual(config.get_int("foo", 1234), 1234)
Test get_int
def
test_get_dict_from_b64_json(self):
119 def test_get_dict_from_b64_json(self): 120 """Test get_dict_from_b64_json""" 121 config = ConfigLoader() 122 test_value = b' { "foo": "bar" } ' 123 b64_value = base64.b64encode(test_value) 124 config.set("foo", b64_value) 125 self.assertEqual(config.get_dict_from_b64_json("foo"), {"foo": "bar"})
Test get_dict_from_b64_json
def
test_get_dict_from_b64_json_missing_brackets(self):
127 def test_get_dict_from_b64_json_missing_brackets(self): 128 """Test get_dict_from_b64_json with missing brackets""" 129 config = ConfigLoader() 130 test_value = b' "foo": "bar" ' 131 b64_value = base64.b64encode(test_value) 132 config.set("foo", b64_value) 133 self.assertEqual(config.get_dict_from_b64_json("foo"), {})
Test get_dict_from_b64_json with missing brackets
def
test_get_dict_from_b64_json_invalid(self):
135 def test_get_dict_from_b64_json_invalid(self): 136 """Test get_dict_from_b64_json with invalid value""" 137 config = ConfigLoader() 138 config.set("foo", "bar") 139 self.assertEqual(config.get_dict_from_b64_json("foo"), {})
Test get_dict_from_b64_json with invalid value
def
test_attr_json_encoder(self):
141 def test_attr_json_encoder(self): 142 """Test AttrEncoder""" 143 test_attr = Attr("foo", Attr.Source.ENV, "AUTHENTIK_POSTGRESQL__USERNAME") 144 json_attr = dumps(test_attr, indent=4, cls=AttrEncoder) 145 self.assertEqual(json_attr, '"foo"')
Test AttrEncoder
def
test_attr_json_encoder_no_attr(self):
147 def test_attr_json_encoder_no_attr(self): 148 """Test AttrEncoder if no Attr is passed""" 149 150 class Test: 151 """Non Attr class""" 152 153 with self.assertRaises(TypeError): 154 test_obj = Test() 155 dumps(test_obj, indent=4, cls=AttrEncoder)
Test AttrEncoder if no Attr is passed
def
test_get_optional_int(self):
157 def test_get_optional_int(self): 158 config = ConfigLoader() 159 self.assertEqual(config.get_optional_int("foo", 21), 21) 160 self.assertEqual(config.get_optional_int("foo"), None) 161 config.set("foo", "21") 162 self.assertEqual(config.get_optional_int("foo"), 21) 163 self.assertEqual(config.get_optional_int("foo", 0), 21) 164 self.assertEqual(config.get_optional_int("foo", "null"), 21) 165 config.set("foo", "null") 166 self.assertEqual(config.get_optional_int("foo"), None) 167 self.assertEqual(config.get_optional_int("foo", 21), None)
@mock.patch.dict(environ, check_deprecations_env_vars)
def
test_check_deprecations(self):
169 @mock.patch.dict(environ, check_deprecations_env_vars) 170 def test_check_deprecations(self): 171 """Test config key re-write for deprecated env vars""" 172 config = ConfigLoader() 173 config.update_from_env() 174 config.check_deprecations() 175 self.assertEqual(config.get("worker.concurrency", UNSET), UNSET) 176 self.assertEqual(config.get("worker.threads"), 2)
Test config key re-write for deprecated env vars
def
test_get_keys(self):
178 def test_get_keys(self): 179 """Test get_keys""" 180 config = ConfigLoader() 181 config.set("foo.bar", "baz") 182 self.assertEqual(list(config.get_keys("foo")), ["bar"])
Test get_keys
def
test_db_default(self):
184 def test_db_default(self): 185 """Test default DB Config""" 186 config = ConfigLoader() 187 config.set("postgresql.host", "foo") 188 config.set("postgresql.name", "foo") 189 config.set("postgresql.user", "foo") 190 config.set("postgresql.password", "foo") 191 config.set("postgresql.port", "foo") 192 config.set("postgresql.sslmode", "foo") 193 config.set("postgresql.sslrootcert", "foo") 194 config.set("postgresql.sslcert", "foo") 195 config.set("postgresql.sslkey", "foo") 196 config.set("postgresql.test.name", "foo") 197 conf = django_db_config(config) 198 self.assertEqual( 199 conf, 200 { 201 "default": { 202 "ENGINE": "psqlextra.backend", 203 "HOST": "foo", 204 "NAME": "foo", 205 "OPTIONS": { 206 "pool": False, 207 "sslcert": "foo", 208 "sslkey": "foo", 209 "sslmode": "foo", 210 "sslrootcert": "foo", 211 }, 212 "PASSWORD": "foo", 213 "PORT": "foo", 214 "TEST": {"NAME": "foo"}, 215 "USER": "foo", 216 "CONN_MAX_AGE": 0, 217 "CONN_HEALTH_CHECKS": False, 218 "DISABLE_SERVER_SIDE_CURSORS": False, 219 } 220 }, 221 )
Test default DB Config
def
test_db_conn_max_age(self):
223 def test_db_conn_max_age(self): 224 """Test DB conn_max_age Config""" 225 config = ConfigLoader() 226 config.set("postgresql.conn_max_age", "null") 227 conf = django_db_config(config) 228 self.assertEqual( 229 conf["default"]["CONN_MAX_AGE"], 230 None, 231 )
Test DB conn_max_age Config
def
test_db_read_replicas(self):
233 def test_db_read_replicas(self): 234 """Test read replicas""" 235 config = ConfigLoader() 236 config.set("postgresql.host", "foo") 237 config.set("postgresql.name", "foo") 238 config.set("postgresql.user", "foo") 239 config.set("postgresql.password", "foo") 240 config.set("postgresql.port", "foo") 241 config.set("postgresql.sslmode", "foo") 242 config.set("postgresql.sslrootcert", "foo") 243 config.set("postgresql.sslcert", "foo") 244 config.set("postgresql.sslkey", "foo") 245 config.set("postgresql.test.name", "foo") 246 # Read replica 247 config.set("postgresql.read_replicas.0.host", "bar") 248 conf = django_db_config(config) 249 self.assertEqual( 250 conf, 251 { 252 "default": { 253 "ENGINE": "psqlextra.backend", 254 "HOST": "foo", 255 "NAME": "foo", 256 "OPTIONS": { 257 "pool": False, 258 "sslcert": "foo", 259 "sslkey": "foo", 260 "sslmode": "foo", 261 "sslrootcert": "foo", 262 }, 263 "PASSWORD": "foo", 264 "PORT": "foo", 265 "TEST": {"NAME": "foo"}, 266 "USER": "foo", 267 "CONN_MAX_AGE": 0, 268 "CONN_HEALTH_CHECKS": False, 269 "DISABLE_SERVER_SIDE_CURSORS": False, 270 }, 271 "replica_0": { 272 "ENGINE": "psqlextra.backend", 273 "HOST": "bar", 274 "NAME": "foo", 275 "OPTIONS": { 276 "pool": False, 277 "sslcert": "foo", 278 "sslkey": "foo", 279 "sslmode": "foo", 280 "sslrootcert": "foo", 281 }, 282 "PASSWORD": "foo", 283 "PORT": "foo", 284 "TEST": {"NAME": "foo"}, 285 "USER": "foo", 286 "CONN_MAX_AGE": 0, 287 "CONN_HEALTH_CHECKS": False, 288 "DISABLE_SERVER_SIDE_CURSORS": False, 289 }, 290 }, 291 )
Test read replicas
def
test_db_read_replicas_pgbouncer(self):
293 def test_db_read_replicas_pgbouncer(self): 294 """Test read replicas""" 295 config = ConfigLoader() 296 config.set("postgresql.host", "foo") 297 config.set("postgresql.name", "foo") 298 config.set("postgresql.user", "foo") 299 config.set("postgresql.password", "foo") 300 config.set("postgresql.port", "foo") 301 config.set("postgresql.sslmode", "foo") 302 config.set("postgresql.sslrootcert", "foo") 303 config.set("postgresql.sslcert", "foo") 304 config.set("postgresql.sslkey", "foo") 305 config.set("postgresql.test.name", "foo") 306 config.set("postgresql.use_pgbouncer", True) 307 # Read replica 308 config.set("postgresql.read_replicas.0.host", "bar") 309 # Override conn_max_age 310 config.set("postgresql.read_replicas.0.conn_max_age", 10) 311 # This isn't supported 312 config.set("postgresql.read_replicas.0.use_pgbouncer", False) 313 conf = django_db_config(config) 314 self.assertEqual( 315 conf, 316 { 317 "default": { 318 "DISABLE_SERVER_SIDE_CURSORS": True, 319 "CONN_MAX_AGE": None, 320 "CONN_HEALTH_CHECKS": False, 321 "ENGINE": "psqlextra.backend", 322 "HOST": "foo", 323 "NAME": "foo", 324 "OPTIONS": { 325 "pool": False, 326 "sslcert": "foo", 327 "sslkey": "foo", 328 "sslmode": "foo", 329 "sslrootcert": "foo", 330 }, 331 "PASSWORD": "foo", 332 "PORT": "foo", 333 "TEST": {"NAME": "foo"}, 334 "USER": "foo", 335 }, 336 "replica_0": { 337 "DISABLE_SERVER_SIDE_CURSORS": True, 338 "CONN_MAX_AGE": 10, 339 "CONN_HEALTH_CHECKS": False, 340 "ENGINE": "psqlextra.backend", 341 "HOST": "bar", 342 "NAME": "foo", 343 "OPTIONS": { 344 "pool": False, 345 "sslcert": "foo", 346 "sslkey": "foo", 347 "sslmode": "foo", 348 "sslrootcert": "foo", 349 }, 350 "PASSWORD": "foo", 351 "PORT": "foo", 352 "TEST": {"NAME": "foo"}, 353 "USER": "foo", 354 }, 355 }, 356 )
Test read replicas
def
test_db_read_replicas_pgpool(self):
358 def test_db_read_replicas_pgpool(self): 359 """Test read replicas""" 360 config = ConfigLoader() 361 config.set("postgresql.host", "foo") 362 config.set("postgresql.name", "foo") 363 config.set("postgresql.user", "foo") 364 config.set("postgresql.password", "foo") 365 config.set("postgresql.port", "foo") 366 config.set("postgresql.sslmode", "foo") 367 config.set("postgresql.sslrootcert", "foo") 368 config.set("postgresql.sslcert", "foo") 369 config.set("postgresql.sslkey", "foo") 370 config.set("postgresql.test.name", "foo") 371 config.set("postgresql.use_pgpool", True) 372 # Read replica 373 config.set("postgresql.read_replicas.0.host", "bar") 374 # This isn't supported 375 config.set("postgresql.read_replicas.0.use_pgpool", False) 376 conf = django_db_config(config) 377 self.assertEqual( 378 conf, 379 { 380 "default": { 381 "DISABLE_SERVER_SIDE_CURSORS": True, 382 "CONN_MAX_AGE": 0, 383 "CONN_HEALTH_CHECKS": False, 384 "ENGINE": "psqlextra.backend", 385 "HOST": "foo", 386 "NAME": "foo", 387 "OPTIONS": { 388 "pool": False, 389 "sslcert": "foo", 390 "sslkey": "foo", 391 "sslmode": "foo", 392 "sslrootcert": "foo", 393 }, 394 "PASSWORD": "foo", 395 "PORT": "foo", 396 "TEST": {"NAME": "foo"}, 397 "USER": "foo", 398 }, 399 "replica_0": { 400 "DISABLE_SERVER_SIDE_CURSORS": True, 401 "CONN_MAX_AGE": 0, 402 "CONN_HEALTH_CHECKS": False, 403 "ENGINE": "psqlextra.backend", 404 "HOST": "bar", 405 "NAME": "foo", 406 "OPTIONS": { 407 "pool": False, 408 "sslcert": "foo", 409 "sslkey": "foo", 410 "sslmode": "foo", 411 "sslrootcert": "foo", 412 }, 413 "PASSWORD": "foo", 414 "PORT": "foo", 415 "TEST": {"NAME": "foo"}, 416 "USER": "foo", 417 }, 418 }, 419 )
Test read replicas
def
test_db_read_replicas_diff_ssl(self):
421 def test_db_read_replicas_diff_ssl(self): 422 """Test read replicas (with different SSL Settings)""" 423 """Test read replicas""" 424 config = ConfigLoader() 425 config.set("postgresql.host", "foo") 426 config.set("postgresql.name", "foo") 427 config.set("postgresql.user", "foo") 428 config.set("postgresql.password", "foo") 429 config.set("postgresql.port", "foo") 430 config.set("postgresql.sslmode", "foo") 431 config.set("postgresql.sslrootcert", "foo") 432 config.set("postgresql.sslcert", "foo") 433 config.set("postgresql.sslkey", "foo") 434 config.set("postgresql.test.name", "foo") 435 # Read replica 436 config.set("postgresql.read_replicas.0.host", "bar") 437 config.set("postgresql.read_replicas.0.sslcert", "bar") 438 conf = django_db_config(config) 439 self.assertEqual( 440 conf, 441 { 442 "default": { 443 "ENGINE": "psqlextra.backend", 444 "HOST": "foo", 445 "NAME": "foo", 446 "OPTIONS": { 447 "pool": False, 448 "sslcert": "foo", 449 "sslkey": "foo", 450 "sslmode": "foo", 451 "sslrootcert": "foo", 452 }, 453 "PASSWORD": "foo", 454 "PORT": "foo", 455 "TEST": {"NAME": "foo"}, 456 "USER": "foo", 457 "DISABLE_SERVER_SIDE_CURSORS": False, 458 "CONN_MAX_AGE": 0, 459 "CONN_HEALTH_CHECKS": False, 460 }, 461 "replica_0": { 462 "ENGINE": "psqlextra.backend", 463 "HOST": "bar", 464 "NAME": "foo", 465 "OPTIONS": { 466 "pool": False, 467 "sslcert": "bar", 468 "sslkey": "foo", 469 "sslmode": "foo", 470 "sslrootcert": "foo", 471 }, 472 "PASSWORD": "foo", 473 "PORT": "foo", 474 "TEST": {"NAME": "foo"}, 475 "USER": "foo", 476 "DISABLE_SERVER_SIDE_CURSORS": False, 477 "CONN_MAX_AGE": 0, 478 "CONN_HEALTH_CHECKS": False, 479 }, 480 }, 481 )
Test read replicas (with different SSL Settings)
def
test_db_conn_options(self):
483 def test_db_conn_options(self): 484 config = ConfigLoader() 485 config.set( 486 "postgresql.conn_options", 487 base64.b64encode( 488 dumps( 489 { 490 "connect_timeout": "10", 491 } 492 ).encode() 493 ).decode(), 494 ) 495 config.set("postgresql.read_replicas.0.host", "bar") 496 497 conf = django_db_config(config) 498 499 self.assertEqual( 500 conf["default"]["OPTIONS"]["connect_timeout"], 501 "10", 502 ) 503 self.assertNotIn("connect_timeout", conf["replica_0"]["OPTIONS"])
def
test_db_conn_options_read_replicas(self):
505 def test_db_conn_options_read_replicas(self): 506 config = ConfigLoader() 507 config.set( 508 "postgresql.replica_conn_options", 509 base64.b64encode( 510 dumps( 511 { 512 "connect_timeout": "10", 513 } 514 ).encode() 515 ).decode(), 516 ) 517 config.set("postgresql.read_replicas.0.host", "bar") 518 config.set("postgresql.read_replicas.1.host", "bar") 519 config.set( 520 "postgresql.read_replicas.1.conn_options", 521 base64.b64encode( 522 dumps( 523 { 524 "connect_timeout": "20", 525 } 526 ).encode() 527 ).decode(), 528 ) 529 530 conf = django_db_config(config) 531 532 self.assertNotIn("connect_timeout", conf["default"]["OPTIONS"]) 533 self.assertEqual( 534 conf["replica_0"]["OPTIONS"]["connect_timeout"], 535 "10", 536 ) 537 self.assertEqual( 538 conf["replica_1"]["OPTIONS"]["connect_timeout"], 539 "20", 540 )