Skip to content

Commit 16cf815

Browse files
authored
Merge pull request #204 from poissoncorp/RDBC-788
RDBC-788 Secured Changes API
2 parents 4990617 + def555a commit 16cf815

File tree

9 files changed

+208
-95
lines changed

9 files changed

+208
-95
lines changed

ravendb/changes/database_changes.py

Lines changed: 122 additions & 78 deletions
Large diffs are not rendered by default.

ravendb/changes/observers.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
from __future__ import annotations
2-
from concurrent.futures import Future
2+
from concurrent.futures import Future, ThreadPoolExecutor
33
from threading import Lock
4-
from typing import Callable, Generic, TypeVar
4+
from typing import Callable, Generic, TypeVar, Optional
55

66
from ravendb.tools.concurrentset import ConcurrentSet
77

88
_T_Change = TypeVar("_T_Change")
99

1010

1111
class Observable(Generic[_T_Change]):
12-
def __init__(self, on_connect=None, on_disconnect=None, executor=None):
12+
def __init__(
13+
self,
14+
on_connect: Optional[Callable[[], None]] = None,
15+
on_disconnect: Optional[Callable[[], None]] = None,
16+
executor: Optional[ThreadPoolExecutor] = None,
17+
):
1318
self.on_connect = on_connect
1419
self._on_disconnect = on_disconnect
1520
self.last_exception = None
@@ -75,7 +80,7 @@ def dec(self):
7580
if self._value == 0:
7681
self.set(self._executor.submit(self._on_disconnect))
7782

78-
def set(self, future):
83+
def set(self, future: Future) -> None:
7984
if not self._future_set.done():
8085

8186
def done_callback(f):
@@ -92,7 +97,7 @@ def done_callback(f):
9297
future.add_done_callback(done_callback)
9398
self._future = future
9499

95-
def error(self, exception):
100+
def error(self, exception: Exception):
96101
future = Future()
97102
self.set(future)
98103
future.set_exception(exception)

ravendb/documents/store/definition.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ def __init__(self, urls: Union[str, List[str]] = None, database: Optional[str] =
320320
self.__multi_db_hilo: Optional[MultiDatabaseHiLoGenerator] = None
321321
self.__identifier: Optional[str] = None
322322
self.__add_change_lock = threading.Lock()
323-
self.__database_changes = {}
323+
self.__database_changes: Dict[str, DatabaseChanges] = {}
324324
self.__after_close: List[Callable[[], None]] = []
325325
self.__before_close: List[Callable[[], None]] = []
326326
self.__time_series_operation: Optional[TimeSeriesOperations] = None
@@ -493,8 +493,8 @@ def changes(self, database=None, on_error=None, executor=None) -> DatabaseChange
493493
)
494494
return self.__database_changes[database]
495495

496-
def __on_close_change(self, database):
497-
self.__database_changes.pop(database, None)
496+
def __on_close_change(self, database_name: str):
497+
self.__database_changes.pop(database_name, None)
498498

499499
def set_request_timeout(self, timeout: datetime.timedelta, database: Optional[str] = None) -> Callable[[], None]:
500500
self.assert_initialized()

ravendb/serverwide/operations/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ def __init__(
143143

144144
def create_request(self, node: ServerNode) -> requests.Request:
145145
url = (
146-
f"{node.url}/admin/databases?name={self.__database_name}&replicationFactor={self.__replication_factor}"
146+
f"{node.url}/admin/databases?name={self.__database_name}"
147+
f"&replicationFactor={self.__replication_factor}&?raft-request-id={self.get_raft_unique_request_id}"
147148
)
148149

149150
request = requests.Request("PUT")

ravendb/tests/jvm_migrated_tests/client_tests/indexing_tests/test_indexes_from_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_can_stop_and_start(self):
173173

174174
self.assertEqual(IndexRunningStatus.RUNNING, status.status)
175175

176-
self.assertEquals(1, len(status.indexes))
176+
self.assertEqual(1, len(status.indexes))
177177

178178
self.assertEqual(IndexRunningStatus.RUNNING, status.indexes[0].status)
179179

ravendb/tests/jvm_migrated_tests/issues_tests/test_ravenDB_6967.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def test_can_delete_index_errors(self):
7878
index_errors3 = self.store.maintenance.send(GetIndexErrorsOperation("Index3"))
7979

8080
self.assertGreater(sum([len(x.errors) for x in index_errors1]), 0)
81-
self.assertEquals(sum([len(x.errors) for x in index_errors2]), 0)
81+
self.assertEqual(sum([len(x.errors) for x in index_errors2]), 0)
8282
self.assertGreater(sum([len(x.errors) for x in index_errors3]), 0)
8383

8484
self.store.maintenance.send(DeleteIndexErrorsOperation())
@@ -87,8 +87,8 @@ def test_can_delete_index_errors(self):
8787
index_errors2 = self.store.maintenance.send(GetIndexErrorsOperation("Index2"))
8888
index_errors3 = self.store.maintenance.send(GetIndexErrorsOperation("Index3"))
8989

90-
self.assertEquals(sum([len(x.errors) for x in index_errors1]), 0)
91-
self.assertEquals(sum([len(x.errors) for x in index_errors2]), 0)
92-
self.assertEquals(sum([len(x.errors) for x in index_errors3]), 0)
90+
self.assertEqual(sum([len(x.errors) for x in index_errors1]), 0)
91+
self.assertEqual(sum([len(x.errors) for x in index_errors2]), 0)
92+
self.assertEqual(sum([len(x.errors) for x in index_errors3]), 0)
9393

9494
RavenTestHelper.assert_no_index_errors(self.store)

ravendb/tests/jvm_migrated_tests/server_tests/documents/notifications/test_changes.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from ravendb import AbstractIndexCreationTask, SetIndexesPriorityOperation
55
from ravendb.changes.observers import ActionObserver
6-
from ravendb.changes.types import DocumentChange, IndexChange
6+
from ravendb.changes.types import DocumentChange, IndexChange, DocumentChangeType
77
from ravendb.documents.indexes.definitions import IndexPriority
88
from ravendb.infrastructure.entities import User
99
from ravendb.infrastructure.orders import Order
@@ -235,3 +235,62 @@ def __ev(value: DocumentChange):
235235
self.assertEqual("users/2", document_changes[1].key)
236236

237237
close_action()
238+
239+
def test_changes_with_https(self):
240+
event = Event()
241+
changes_list = []
242+
exception = None
243+
244+
def _on_error(e):
245+
nonlocal exception
246+
exception = e
247+
248+
changes = self.secured_document_store.changes(on_error=_on_error)
249+
observable = changes.for_document("users/1")
250+
251+
def __ev(value: DocumentChange):
252+
changes_list.append(value)
253+
event.set()
254+
255+
observer = ActionObserver(__ev)
256+
close_action = observable.subscribe_with_observer(observer)
257+
try:
258+
observable.ensure_subscribe_now()
259+
except Exception:
260+
raise exception
261+
262+
with self.secured_document_store.open_session() as session:
263+
user = User()
264+
session.store(user, "users/1")
265+
session.save_changes()
266+
267+
event.wait(2)
268+
document_change = changes_list[0]
269+
self.assertIsNotNone(document_change)
270+
self.assertEqual("users/1", document_change.key)
271+
self.assertEqual(DocumentChangeType.PUT, document_change.type_of_change)
272+
273+
changes_list.clear()
274+
275+
try:
276+
event.wait(1)
277+
except Exception:
278+
pass
279+
280+
self.assertEqual(0, len(changes_list))
281+
close_action()
282+
# at this point we should be unsubscribed from changes on 'users/1'
283+
284+
with self.secured_document_store.open_session() as session:
285+
user = User()
286+
user.name = "another name"
287+
session.store(user, "users/1")
288+
session.save_changes()
289+
290+
# it should be empty
291+
try:
292+
event.wait(1)
293+
except Exception:
294+
pass
295+
296+
self.assertEqual(0, len(changes_list))

ravendb/tools/parsers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from decimal import InvalidOperation
2+
from typing import Any, Dict, Optional
3+
24
from ijson.common import integer_or_decimal, IncompleteJSONError
35
from ijson.backends.python import UnexpectedSymbol
46
from _elementtree import ParseError
@@ -112,7 +114,7 @@ def create_object(self, gen):
112114

113115
raise ParseError("End object expected, but the generator ended before we got it")
114116

115-
def next_object(self):
117+
def next_object(self) -> Optional[Dict[str, Any]]:
116118
try:
117119
(_, text) = next(self.lexer)
118120
if IS_WEBSOCKET and text == ",":

ravendb/util/tcp_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ def connect(
1717
) -> socket.socket:
1818
hostname, port = url_string.replace("tcp://", "").split(":")
1919
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
20+
2021
is_ssl_socket = server_certificate_base64 and client_certificate_pem_path
21-
if server_certificate_base64 and client_certificate_pem_path:
22+
if is_ssl_socket:
2223
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
2324
context.load_cert_chain(client_certificate_pem_path, password=certificate_private_key_password)
2425
s = context.wrap_socket(s)
26+
2527
s.connect((hostname, int(port)))
2628
if is_ssl_socket and base64.b64decode(server_certificate_base64) != s.getpeercert(True):
2729
raise ConnectionError("Failed to validate public server certificate.")

0 commit comments

Comments
 (0)