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_connection_from_django ,
17+ psycopg_kwargs_from_settings_dict ,
18+ )
919
1020
1121@pytest .mark .django_db
@@ -21,6 +31,130 @@ def skip_if_sqlite(self):
2131 pytest .skip ('Advisory lock is not written for sqlite' )
2232
2333
34+ class TestPGNotifyConnection (SkipIfSqlite ):
35+ TEST_DATABASE_DICT = {
36+ "default" : {
37+ "ENGINE" : "django.db.backends.postgresql" ,
38+ "HOST" : "https://foo.invalid" ,
39+ "PORT" : 55434 ,
40+ "USER" : "dab_user" ,
41+ "PASSWORD" : "dabbing" ,
42+ "NAME" : "dab_db" ,
43+ }
44+ }
45+ PSYCOPG_KWARGS = {
46+ 'dbname' : 'dab_db' ,
47+ 'client_encoding' : 'UTF8' ,
48+ # kwargs containing objects can not be compared so they will be ignored
49+ # 'cursor_factory': <class 'django.db.backends.postgresql.base.Cursor'>,
50+ 'user' : 'dab_user' ,
51+ 'password' : 'dabbing' ,
52+ 'host' : 'https://foo.invalid' ,
53+ 'port' : 55434 ,
54+ # 'context': <psycopg.adapt.AdaptersMap object at 0x7f537f2d9f70>,
55+ 'prepare_threshold' : None ,
56+ }
57+
58+ @pytest .fixture
59+ def mock_settings (self ):
60+ with override_settings (DATABASES = self .TEST_DATABASE_DICT , USE_TZ = False ):
61+ yield
62+
63+ def test_default_behavior (self , mock_settings ):
64+ params = get_pg_notify_params ()
65+ assert params == self .PSYCOPG_KWARGS
66+
67+ def test_pg_notify_extra_options (self , mock_settings ):
68+ params = get_pg_notify_params (application_name = 'joe_connection' )
69+ expected = self .PSYCOPG_KWARGS .copy ()
70+ expected ['application_name' ] = 'joe_connection'
71+ assert params == expected
72+
73+ def test_lister_databases (self , mock_settings ):
74+ LISTENER_DATABASES = {"default" : {"HOST" : "https://foo.anotherhost.invalid" }}
75+ with override_settings (LISTENER_DATABASES = LISTENER_DATABASES ):
76+ params = get_pg_notify_params ()
77+ assert params ['host' ] == "https://foo.anotherhost.invalid"
78+
79+ def test_pg_notify_databases (self , mock_settings ):
80+ PG_NOTIFY_DATABASES = {"default" : {"HOST" : "https://foo.anotherhost2.invalid" }}
81+ with override_settings (PG_NOTIFY_DATABASES = PG_NOTIFY_DATABASES ):
82+ params = get_pg_notify_params ()
83+ assert params ['host' ] == "https://foo.anotherhost2.invalid"
84+
85+ def test_psycopg_kwargs_from_settings_dict (self ):
86+ "More of a unit test, doing the same thing"
87+ test_dict = self .TEST_DATABASE_DICT ["default" ].copy ()
88+ test_dict ['OPTIONS' ] = {'autocommit' : True }
89+ with override_settings (USE_TZ = False ):
90+ psycopg_params = psycopg_kwargs_from_settings_dict (test_dict )
91+ expected_kwargs = self .PSYCOPG_KWARGS .copy ()
92+ expected_kwargs ['autocommit' ] = True
93+ assert psycopg_params == expected_kwargs
94+
95+ def test_psycopg_kwargs_use (self ):
96+ "This assures that the data we get for the kwargs are usable, and demos how to use"
97+ if connection .vendor == 'sqlite' :
98+ pytest .skip ('Test needs to connect to postgres which is not running' )
99+
100+ test_dict = settings .DATABASES ['default' ].copy ()
101+ test_dict ['OPTIONS' ] = {'autocommit' : True }
102+ with override_settings (USE_TZ = False ):
103+ psycopg_params = psycopg_kwargs_from_settings_dict (test_dict )
104+
105+ psycopg .connect (** psycopg_params )
106+
107+ def test_listener_string_production (self ):
108+ "This is a test to correspond to PG_NOTIFY_DSN_SERVER type settings in eda-server"
109+ with override_settings (USE_TZ = False ):
110+ args = psycopg_conn_string_from_settings_dict (
111+ {
112+ "ENGINE" : "django.db.backends.postgresql" ,
113+ "HOST" : "127.0.0.1" ,
114+ "PORT" : 5432 ,
115+ "USER" : "postgres" ,
116+ "PASSWORD" : "DB_PASSWORD" ,
117+ "NAME" : "eda" ,
118+ "OPTIONS" : {
119+ "sslmode" : "allow" ,
120+ "sslcert" : "" ,
121+ "sslkey" : "" ,
122+ "sslrootcert" : "" ,
123+ },
124+ }
125+ )
126+ assert args == (
127+ "dbname=eda sslmode=allow sslcert='' sslkey='' sslrootcert='' client_encoding=UTF8 user=postgres password=DB_PASSWORD host=127.0.0.1 port=5432"
128+ )
129+
130+ def test_listener_string_production_use (self ):
131+ "This assures that the data we get for the connection string is usable, and demos how to use"
132+ if connection .vendor == 'sqlite' :
133+ pytest .skip ('Test needs to connect to postgres which is not running' )
134+ args = psycopg_conn_string_from_settings_dict (settings .DATABASES ['default' ])
135+ psycopg .connect (conninfo = args )
136+
137+ @pytest .mark .django_db
138+ def test_psycopg_connection_from_django_existing_conn (self ):
139+ if connection .vendor == 'sqlite' :
140+ pytest .skip ('Advisory lock is not written for sqlite' )
141+ assert isinstance (psycopg_connection_from_django (), psycopg .Connection )
142+
143+ @pytest .mark .django_db (transaction = True )
144+ def test_psycopg_connection_from_django_new_conn (self ):
145+ if connection .vendor == 'sqlite' :
146+ pytest .skip ('Advisory lock is not written for sqlite' )
147+ connection .close ()
148+ assert isinstance (psycopg_connection_from_django (), psycopg .Connection )
149+
150+
151+ class TestAdvisoryLock :
152+ @pytest .fixture (autouse = True )
153+ def skip_if_sqlite (self ):
154+ if connection .vendor == 'sqlite' :
155+ pytest .skip ('Advisory lock is not written for sqlite' )
156+
157+
24158class TestAdvisoryLock (SkipIfSqlite ):
25159 THREAD_WAIT_TIME = 0.1
26160
@@ -40,7 +174,7 @@ def background_task(django_db_blocker):
40174 def test_determine_lock_is_held (self , django_db_blocker ):
41175 thread = threading .Thread (target = TestAdvisoryLock .background_task , args = (django_db_blocker ,))
42176 thread .start ()
43- for _ in range (5 ):
177+ for _ in range (20 ):
44178 with advisory_lock ('background_task_lock' , wait = False ) as held :
45179 if held is False :
46180 break
0 commit comments