File: test_db.py

package info (click to toggle)
django-environ 0.12.0-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 516 kB
  • sloc: python: 2,434; makefile: 171
file content (278 lines) | stat: -rw-r--r-- 8,024 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# This file is part of the django-environ.
#
# Copyright (c) 2021-2024, Serghei Iakovlev <oss@serghei.pl>
# Copyright (c) 2013-2021, Daniele Faraglia <daniele.faraglia@gmail.com>
#
# For the full copyright and license information, please view
# the LICENSE.txt file that was distributed with this source code.

import warnings

import pytest

from environ import Env
from environ.compat import DJANGO_POSTGRES


@pytest.mark.parametrize(
    'url,engine,name,host,user,passwd,port',
    [
        # postgres://user:password@host:port/dbname
        ('postgres://enigma:secret@example.com:5431/dbname',
         DJANGO_POSTGRES,
         'dbname',
         'example.com',
         'enigma',
         'secret',
         5431),
        # postgres://path/dbname
        ('postgres:////var/run/postgresql/dbname',
         DJANGO_POSTGRES,
         'dbname',
         '/var/run/postgresql',
         '',
         '',
         ''),
        # postgis://user:password@host:port/dbname
        ('postgis://enigma:secret@example.com:5431/dbname',
         'django.contrib.gis.db.backends.postgis',
         'dbname',
         'example.com',
         'enigma',
         'secret',
         5431),
        # postgres://host,host,host/dbname
        ('postgres://node1,node2,node3/db',
         DJANGO_POSTGRES,
         'db',
         'node1,node2,node3',
         '',
         '',
         ''
         ),
        # cockroachdb://username:secret@test.example.com:26258/dbname
        ('cockroachdb://username:secret@test.example.com:26258/dbname',
         'django_cockroachdb',
         'dbname',
         'test.example.com',
         'username',
         'secret',
         26258),
        # mysqlgis://user:password@host:port/dbname
        ('mysqlgis://enigma:secret@example.com:5431/dbname',
         'django.contrib.gis.db.backends.mysql',
         'dbname',
         'example.com',
         'enigma',
         'secret',
         5431),
        # mysql://user:password@host/dbname?options
        ('mysql://enigma:secret@reconnect.com/dbname?reconnect=true',
         'django.db.backends.mysql',
         'dbname',
         'reconnect.com',
         'enigma',
         'secret',
         ''),
        # mysql://user@host/dbname
        ('mysql://enigma@localhost/dbname',
         'django.db.backends.mysql',
         'dbname',
         'localhost',
         'enigma',
         '',
         ''),
        # sqlite://
        ('sqlite://',
         'django.db.backends.sqlite3',
         ':memory:',
         '',
         '',
         '',
         ''),
        # sqlite:////absolute/path/to/db/file
        ('sqlite:////full/path/to/your/file.sqlite',
         'django.db.backends.sqlite3',
         '/full/path/to/your/file.sqlite',
         '',
         '',
         '',
         ''),
        # sqlite://:memory:
        ('sqlite://:memory:',
         'django.db.backends.sqlite3',
         ':memory:',
         '',
         '',
         '',
         ''),
        # ldap://user:password@host
        ('ldap://cn=admin,dc=nodomain,dc=org:secret@example.com',
         'ldapdb.backends.ldap',
         'ldap://example.com',
         'example.com',
         'cn=admin,dc=nodomain,dc=org',
         'secret',
         ''),
        # mysql://user:password@host/dbname
        ('mssql://enigma:secret@example.com/dbname'
         '?driver=ODBC Driver 13 for SQL Server',
         'mssql',
         'dbname',
         'example.com',
         'enigma',
         'secret',
         ''),
        # mysql://user:password@host:port/dbname
        ('mssql://enigma:secret@amazonaws.com\\insnsnss:12345/dbname'
         '?driver=ODBC Driver 13 for SQL Server',
         'mssql',
         'dbname',
         'amazonaws.com\\insnsnss',
         'enigma',
         'secret',
         12345),
         # mysql://user:password@host:port/dbname
        ('mysql://enigma:><{~!@#$%^&*}[]@example.com:1234/dbname',
         'django.db.backends.mysql',
         'dbname',
         'example.com',
         'enigma',
         '><{~!@#$%^&*}[]',
         1234),
        # mysql://user:password@host/dbname
        ('mysql://enigma:]password]@example.com/dbname',
         'django.db.backends.mysql',
         'dbname',
         'example.com',
         'enigma',
         ']password]',
         ''),
    ],
    ids=[
        'postgres',
        'postgres_unix_domain',
        'postgis',
        'postgres_no_ports',
        'cockroachdb',
        'mysqlgis',
        'cleardb',
        'mysql_no_password',
        'sqlite_empty',
        'sqlite_file',
        'sqlite_memory',
        'ldap',
        'mssql',
        'mssql_port',
        'mysql_password_special_chars',
        'mysql_invalid_ipv6_password',
    ],
)
def test_db_parsing(url, engine, name, host, user, passwd, port):
    config = Env.db_url_config(url)

    assert config['ENGINE'] == engine
    assert config['NAME'] == name

    if url != 'sqlite://:memory:':
        if config['PORT']:
            assert config['PORT'] == port
        assert config['PASSWORD'] == passwd
        assert config['USER'] == user
        assert config['HOST'] == host

    if engine == 'sql_server.pyodbc':
        assert config['OPTIONS'] == {'driver': 'ODBC Driver 13 for SQL Server'}

    if host == 'reconnect.com':
        assert config['OPTIONS'] == {'reconnect': 'true'}


def test_custom_db_engine():
    """Override ENGINE determined from schema."""
    env_url = 'postgres://enigma:secret@example.com:5431/dbname'

    engine = 'mypackage.backends.whatever'
    url = Env.db_url_config(env_url, engine=engine)

    assert url['ENGINE'] == engine


def test_postgres_complex_db_name_parsing():
    """Make sure we can use complex postgres host."""
    env_url = (
        'postgres://user:password@//cloudsql/'
        'project-1234:us-central1:instance/dbname'
    )

    url = Env.db_url_config(env_url)

    assert url['ENGINE'] == DJANGO_POSTGRES
    assert url['HOST'] == '/cloudsql/project-1234:us-central1:instance'
    assert url['NAME'] == 'dbname'
    assert url['USER'] == 'user'
    assert url['PASSWORD'] == 'password'
    assert url['PORT'] == ''


@pytest.mark.parametrize(
    'scheme',
    ['postgres', 'postgresql', 'psql', 'pgsql', 'postgis'],
)
def test_postgres_like_scheme_parsing(scheme):
    """Verify all the postgres-like schemes parsed the same as postgres."""
    env_url1 = (
        'postgres://user:password@//cloudsql/'
        'project-1234:us-central1:instance/dbname'
    )
    env_url2 = (
        '{}://user:password@//cloudsql/'
        'project-1234:us-central1:instance/dbname'
    ).format(scheme)

    url1 = Env.db_url_config(env_url1)
    url2 = Env.db_url_config(env_url2)

    assert url2['NAME'] == url1['NAME']
    assert url2['PORT'] == url1['PORT']
    assert url2['PASSWORD'] == url1['PASSWORD']
    assert url2['USER'] == url1['USER']
    assert url2['HOST'] == url1['HOST']

    if scheme == 'postgis':
        assert url2['ENGINE'] == 'django.contrib.gis.db.backends.postgis'
    else:
        assert url2['ENGINE'] == url1['ENGINE']


def test_memory_sqlite_url_warns_about_netloc(recwarn):
    warnings.simplefilter("always")

    url = 'sqlite://missing-slash-path'
    url = Env.db_url_config(url)

    assert len(recwarn) == 1
    assert recwarn.pop(UserWarning)

    assert url['ENGINE'] == 'django.db.backends.sqlite3'
    assert url['NAME'] == ':memory:'


def test_database_options_parsing():
    url = 'postgres://user:pass@host:1234/dbname?conn_max_age=600'
    url = Env.db_url_config(url)
    assert url['CONN_MAX_AGE'] == 600

    url = ('postgres://user:pass@host:1234/dbname?'
           'conn_max_age=None&autocommit=True&atomic_requests=False')
    url = Env.db_url_config(url)
    assert url['CONN_MAX_AGE'] is None
    assert url['AUTOCOMMIT'] is True
    assert url['ATOMIC_REQUESTS'] is False

    url = ('mysql://user:pass@host:1234/dbname?init_command=SET '
           'storage_engine=INNODB')
    url = Env.db_url_config(url)
    assert url['OPTIONS'] == {
        'init_command': 'SET storage_engine=INNODB',
    }