Skip to content

Commit 46ce52b

Browse files
authored
Merge pull request #170 from rethinkdb/support-db-url-schemas
Implement DB URL connection support
2 parents 08b0b50 + 7317a80 commit 46ce52b

File tree

5 files changed

+275
-21
lines changed

5 files changed

+275
-21
lines changed

rethinkdb/net.py

+37-15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
import struct
2626
import time
2727

28+
try:
29+
from urllib.parse import urlparse, parse_qs
30+
except ImportError:
31+
from urlparse import urlparse, parse_qs
32+
2833
from rethinkdb import ql2_pb2
2934
from rethinkdb.ast import DB, ReQLDecoder, ReQLEncoder, Repl, expr
3035
from rethinkdb.errors import (
@@ -703,9 +708,6 @@ def __init__(self, *args, **kwargs):
703708
Connection.__init__(self, ConnectionInstance, *args, **kwargs)
704709

705710

706-
707-
708-
709711
def make_connection(
710712
connection_type,
711713
host=None,
@@ -716,20 +718,40 @@ def make_connection(
716718
password=None,
717719
timeout=20,
718720
ssl=None,
721+
url=None,
719722
_handshake_version=10,
720723
**kwargs):
721-
if host is None:
722-
host = 'localhost'
723-
if port is None:
724-
port = DEFAULT_PORT
725-
if user is None:
726-
user = 'admin'
727-
if timeout is None:
728-
timeout = 20
729-
if ssl is None:
730-
ssl = dict()
731-
if _handshake_version is None:
732-
_handshake_version = 10
724+
if url:
725+
connection_string = urlparse(url)
726+
query_string = parse_qs(connection_string.query)
727+
728+
user = connection_string.username
729+
password = connection_string.password
730+
host = connection_string.hostname
731+
port = connection_string.port
732+
733+
db = connection_string.path.replace("/", "") or None
734+
auth_key = query_string.get("auth_key")
735+
timeout = query_string.get("timeout")
736+
737+
if auth_key:
738+
auth_key = auth_key[0]
739+
740+
if timeout:
741+
timeout = int(timeout[0])
742+
743+
744+
host = host or 'localhost'
745+
port = port or DEFAULT_PORT
746+
user = user or 'admin'
747+
timeout = timeout or 20
748+
ssl = ssl or dict()
749+
_handshake_version = _handshake_version or 10
750+
751+
# The internal APIs will wait for none to deal with auth_key and password
752+
# TODO: refactor when we drop python2
753+
if not password and not password is None:
754+
password = None
733755

734756
conn = connection_type(host, port, db, auth_key, user, password, timeout, ssl, _handshake_version, **kwargs)
735757
return conn.reconnect(timeout=timeout)

tests/helpers.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@
66

77

88
class IntegrationTestCaseBase(object):
9+
def _create_database(self, conn):
10+
if INTEGRATION_TEST_DB not in self.r.db_list().run(conn):
11+
self.r.db_create(INTEGRATION_TEST_DB).run(conn)
12+
13+
conn.use(INTEGRATION_TEST_DB)
14+
915
def setup_method(self):
1016
self.r = r
11-
self.rethinkdb_host = os.getenv('RETHINKDB_HOST')
17+
self.rethinkdb_host = os.getenv('RETHINKDB_HOST', '127.0.0.1')
1218

1319
self.conn = self.r.connect(
1420
host=self.rethinkdb_host
1521
)
1622

17-
if INTEGRATION_TEST_DB not in self.r.db_list().run(self.conn):
18-
self.r.db_create(INTEGRATION_TEST_DB).run(self.conn)
19-
20-
self.conn.use(INTEGRATION_TEST_DB)
23+
self._create_database(self.conn)
2124

2225
def teardown_method(self):
2326
self.r.db_drop(INTEGRATION_TEST_DB).run(self.conn)

tests/integration/test_connect.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import os
2+
import pytest
3+
4+
from rethinkdb import r
5+
from tests.helpers import IntegrationTestCaseBase, INTEGRATION_TEST_DB
6+
7+
8+
@pytest.mark.integration
9+
class TestConnect(IntegrationTestCaseBase):
10+
def setup_method(self):
11+
super(TestConnect, self).setup_method()
12+
13+
def test_connect(self):
14+
db_url = "rethinkdb://{host}".format(host=self.rethinkdb_host)
15+
16+
assert self.r.connect(url=db_url) is not None
17+
18+
def test_connect_with_username(self):
19+
db_url = "rethinkdb://admin@{host}".format(host=self.rethinkdb_host)
20+
21+
assert self.r.connect(url=db_url) is not None
22+
23+
def test_connect_to_db(self):
24+
db_url = "rethinkdb://{host}/{database}".format(
25+
host=self.rethinkdb_host,
26+
database=INTEGRATION_TEST_DB
27+
)
28+
29+
assert self.r.connect(url=db_url) is not None

tests/integration/test_write_hooks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ def test_get_write_hook(self):
4848

4949
hook = self.r.table(self.table_name).get_write_hook().run(self.conn)
5050

51-
assert list(hook.keys()) == ['function', 'query']
51+
assert list(sorted(hook.keys())) == ['function', 'query']

tests/test_net.py

+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import pytest
2+
from mock import Mock, ANY
3+
from rethinkdb.net import make_connection, DefaultConnection, DEFAULT_PORT
4+
5+
6+
@pytest.mark.unit
7+
class TestMakeConnection(object):
8+
def setup_method(self):
9+
self.reconnect = Mock()
10+
self.conn_type = Mock()
11+
self.conn_type.return_value.reconnect.return_value = self.reconnect
12+
13+
self.host = "myhost"
14+
self.port = 1234
15+
self.db = "mydb"
16+
self.auth_key = None
17+
self.user = "gabor"
18+
self.password = "strongpass"
19+
self.timeout = 20
20+
21+
22+
def test_make_connection(self):
23+
ssl = dict()
24+
_handshake_version = 10
25+
26+
conn = make_connection(
27+
self.conn_type,
28+
host=self.host,
29+
port=self.port,
30+
db=self.db,
31+
auth_key=self.auth_key,
32+
user=self.user,
33+
password=self.password,
34+
timeout=self.timeout,
35+
)
36+
37+
assert conn == self.reconnect
38+
self.conn_type.assert_called_once_with(
39+
self.host,
40+
self.port,
41+
self.db,
42+
self.auth_key,
43+
self.user,
44+
self.password,
45+
self.timeout,
46+
ssl,
47+
_handshake_version
48+
)
49+
50+
51+
def test_make_connection_db_url(self):
52+
url = "rethinkdb://gabor:strongpass@myhost:1234/mydb?auth_key=mykey&timeout=30"
53+
ssl = dict()
54+
_handshake_version = 10
55+
56+
conn = make_connection(self.conn_type, url=url)
57+
58+
assert conn == self.reconnect
59+
self.conn_type.assert_called_once_with(
60+
self.host,
61+
self.port,
62+
self.db,
63+
"mykey",
64+
self.user,
65+
self.password,
66+
30,
67+
ssl,
68+
_handshake_version
69+
)
70+
71+
72+
def test_make_connection_no_host(self):
73+
conn = make_connection(
74+
self.conn_type,
75+
port=self.port,
76+
db=self.db,
77+
auth_key=self.auth_key,
78+
user=self.user,
79+
password=self.password,
80+
timeout=self.timeout,
81+
)
82+
83+
assert conn == self.reconnect
84+
self.conn_type.assert_called_once_with(
85+
"localhost",
86+
self.port,
87+
self.db,
88+
self.auth_key,
89+
self.user,
90+
self.password,
91+
self.timeout,
92+
ANY,
93+
ANY
94+
)
95+
96+
97+
def test_make_connection_no_port(self):
98+
conn = make_connection(
99+
self.conn_type,
100+
host=self.host,
101+
db=self.db,
102+
auth_key=self.auth_key,
103+
user=self.user,
104+
password=self.password,
105+
timeout=self.timeout,
106+
)
107+
108+
assert conn == self.reconnect
109+
self.conn_type.assert_called_once_with(
110+
self.host,
111+
DEFAULT_PORT,
112+
self.db,
113+
self.auth_key,
114+
self.user,
115+
self.password,
116+
self.timeout,
117+
ANY,
118+
ANY
119+
)
120+
121+
122+
def test_make_connection_no_user(self):
123+
conn = make_connection(
124+
self.conn_type,
125+
host=self.host,
126+
port=self.port,
127+
db=self.db,
128+
auth_key=self.auth_key,
129+
password=self.password,
130+
timeout=self.timeout,
131+
)
132+
133+
assert conn == self.reconnect
134+
self.conn_type.assert_called_once_with(
135+
self.host,
136+
self.port,
137+
self.db,
138+
self.auth_key,
139+
"admin",
140+
self.password,
141+
self.timeout,
142+
ANY,
143+
ANY
144+
)
145+
146+
147+
def test_make_connection_with_ssl(self):
148+
ssl = dict()
149+
150+
conn = make_connection(
151+
self.conn_type,
152+
host=self.host,
153+
port=self.port,
154+
db=self.db,
155+
auth_key=self.auth_key,
156+
user=self.user,
157+
password=self.password,
158+
timeout=self.timeout,
159+
ssl=ssl,
160+
)
161+
162+
assert conn == self.reconnect
163+
self.conn_type.assert_called_once_with(
164+
self.host,
165+
self.port,
166+
self.db,
167+
self.auth_key,
168+
self.user,
169+
self.password,
170+
self.timeout,
171+
ssl,
172+
ANY
173+
)
174+
175+
176+
def test_make_connection_different_handshake_version(self):
177+
conn = make_connection(
178+
self.conn_type,
179+
host=self.host,
180+
port=self.port,
181+
db=self.db,
182+
auth_key=self.auth_key,
183+
user=self.user,
184+
password=self.password,
185+
timeout=self.timeout,
186+
_handshake_version=20,
187+
)
188+
189+
assert conn == self.reconnect
190+
self.conn_type.assert_called_once_with(
191+
self.host,
192+
self.port,
193+
self.db,
194+
self.auth_key,
195+
self.user,
196+
self.password,
197+
self.timeout,
198+
ANY,
199+
20
200+
)

0 commit comments

Comments
 (0)