11import threading
22import time
33
4+ import psycopg
45import pytest
6+ from django .conf import settings
57from django .db import connection
68from django .db .utils import OperationalError
9+ from django .test import override_settings
710
8- from ansible_base .lib .utils .db import advisory_lock , migrations_are_complete
11+ from ansible_base .lib .utils .db import (
12+ advisory_lock ,
13+ get_pg_notify_params ,
14+ migrations_are_complete ,
15+ psycopg_conn_string_from_settings_dict ,
16+ psycopg_kwargs_from_settings_dict ,
17+ )
918
1019
1120@pytest .mark .django_db
@@ -14,6 +23,110 @@ def test_migrations_are_complete():
1423 assert migrations_are_complete ()
1524
1625
26+ class TestPGNotifyConnection :
27+ TEST_DATABASE_DICT = {
28+ "default" : {
29+ "ENGINE" : "django.db.backends.postgresql" ,
30+ "HOST" : "https://foo.invalid" ,
31+ "PORT" : 55434 ,
32+ "USER" : "dab_user" ,
33+ "PASSWORD" : "dabbing" ,
34+ "NAME" : "dab_db" ,
35+ }
36+ }
37+ PSYCOPG_KWARGS = {
38+ 'dbname' : 'dab_db' ,
39+ 'client_encoding' : 'UTF8' ,
40+ # kwargs containing objects can not be compared so they will be ignored
41+ # 'cursor_factory': <class 'django.db.backends.postgresql.base.Cursor'>,
42+ 'user' : 'dab_user' ,
43+ 'password' : 'dabbing' ,
44+ 'host' : 'https://foo.invalid' ,
45+ 'port' : 55434 ,
46+ # 'context': <psycopg.adapt.AdaptersMap object at 0x7f537f2d9f70>,
47+ 'prepare_threshold' : None ,
48+ }
49+
50+ @pytest .fixture
51+ def mock_settings (self ):
52+ with override_settings (DATABASES = self .TEST_DATABASE_DICT , USE_TZ = False ):
53+ yield
54+
55+ def test_default_behavior (self , mock_settings ):
56+ params = get_pg_notify_params ()
57+ assert params == self .PSYCOPG_KWARGS
58+
59+ def test_pg_notify_extra_options (self , mock_settings ):
60+ params = get_pg_notify_params (application_name = 'joe_connection' )
61+ expected = self .PSYCOPG_KWARGS .copy ()
62+ expected ['application_name' ] = 'joe_connection'
63+ assert params == expected
64+
65+ def test_lister_databases (self , mock_settings ):
66+ LISTENER_DATABASES = {"default" : {"HOST" : "https://foo.anotherhost.invalid" }}
67+ with override_settings (LISTENER_DATABASES = LISTENER_DATABASES ):
68+ params = get_pg_notify_params ()
69+ assert params ['host' ] == "https://foo.anotherhost.invalid"
70+
71+ def test_pg_notify_databases (self , mock_settings ):
72+ PG_NOTIFY_DATABASES = {"default" : {"HOST" : "https://foo.anotherhost2.invalid" }}
73+ with override_settings (PG_NOTIFY_DATABASES = PG_NOTIFY_DATABASES ):
74+ params = get_pg_notify_params ()
75+ assert params ['host' ] == "https://foo.anotherhost2.invalid"
76+
77+ def test_psycopg_kwargs_from_settings_dict (self ):
78+ "More of a unit test, doing the same thing"
79+ test_dict = self .TEST_DATABASE_DICT ["default" ].copy ()
80+ test_dict ['OPTIONS' ] = {'autocommit' : True }
81+ with override_settings (USE_TZ = False ):
82+ psycopg_params = psycopg_kwargs_from_settings_dict (test_dict )
83+ expected_kwargs = self .PSYCOPG_KWARGS .copy ()
84+ expected_kwargs ['autocommit' ] = True
85+ assert psycopg_params == expected_kwargs
86+
87+ def test_psycopg_kwargs_use (self ):
88+ "This assures that the data we get for the kwargs are usable, and demos how to use"
89+ if connection .vendor == 'sqlite' :
90+ pytest .skip ('Test needs to connect to postgres which is not running' )
91+
92+ test_dict = settings .DATABASES ['default' ].copy ()
93+ test_dict ['OPTIONS' ] = {'autocommit' : True }
94+ with override_settings (USE_TZ = False ):
95+ psycopg_params = psycopg_kwargs_from_settings_dict (test_dict )
96+
97+ psycopg .connect (** psycopg_params )
98+
99+ def test_listener_string_production (self ):
100+ "This is a test to correspond to PG_NOTIFY_DSN_SERVER type settings in eda-server"
101+ with override_settings (USE_TZ = False ):
102+ args = psycopg_conn_string_from_settings_dict (
103+ {
104+ "ENGINE" : "django.db.backends.postgresql" ,
105+ "HOST" : "127.0.0.1" ,
106+ "PORT" : 5432 ,
107+ "USER" : "postgres" ,
108+ "PASSWORD" : "DB_PASSWORD" ,
109+ "NAME" : "eda" ,
110+ "OPTIONS" : {
111+ "sslmode" : "allow" ,
112+ "sslcert" : "" ,
113+ "sslkey" : "" ,
114+ "sslrootcert" : "" ,
115+ },
116+ }
117+ )
118+ assert args == (
119+ "dbname=eda sslmode=allow sslcert='' sslkey='' sslrootcert='' client_encoding=UTF8 user=postgres password=DB_PASSWORD host=127.0.0.1 port=5432"
120+ )
121+
122+ def test_listener_string_production_use (self ):
123+ "This assures that the data we get for the connection string is usable, and demos how to use"
124+ if connection .vendor == 'sqlite' :
125+ pytest .skip ('Test needs to connect to postgres which is not running' )
126+ args = psycopg_conn_string_from_settings_dict (settings .DATABASES ['default' ])
127+ psycopg .connect (conninfo = args )
128+
129+
17130class TestAdvisoryLock :
18131 @pytest .fixture (autouse = True )
19132 def skip_if_sqlite (self ):
@@ -36,7 +149,7 @@ def background_task(django_db_blocker):
36149 def test_determine_lock_is_held (self , django_db_blocker ):
37150 thread = threading .Thread (target = TestAdvisoryLock .background_task , args = (django_db_blocker ,))
38151 thread .start ()
39- for _ in range (5 ):
152+ for _ in range (20 ):
40153 with advisory_lock ('background_task_lock' , wait = False ) as held :
41154 if held is False :
42155 break
0 commit comments