1+ import hashlib
2+ import os
3+ import unittest
4+ from shutil import rmtree
5+
16from ravendb .documents .store .definition import DocumentStore
7+ from ravendb .http import topology_local_cache
8+ from ravendb .http .server_node import ServerNode
9+ from ravendb .http .topology import Topology
210from ravendb .serverwide .database_record import DatabaseRecord
311from ravendb .serverwide .operations .common import DeleteDatabaseOperation , CreateDatabaseOperation
412from ravendb .tests .test_base import TestBase
5- import hashlib
6- from shutil import rmtree
7- import os
8- import unittest
913
1014TOPOLOGY_FILES_DIR = os .path .join (os .getcwd (), "topology_files" )
1115DATABASE = "SystemTest"
@@ -17,17 +21,20 @@ def __init__(self, name):
1721
1822
1923class TestSystemTopologyCreation (TestBase ):
24+ def _customize_store (self , store : DocumentStore ) -> None :
25+ # opt in to the on-disk topology cache for this test's stores
26+ store .conventions .topology_cache_location = TOPOLOGY_FILES_DIR
27+
2028 def tearDown (self ):
21- self .store .maintenance .server .send (DeleteDatabaseOperation (database_name = DATABASE , hard_delete = True ))
29+ try :
30+ self .store .maintenance .server .send (DeleteDatabaseOperation (database_name = DATABASE , hard_delete = True ))
31+ except Exception :
32+ pass
2233 super (TestSystemTopologyCreation , self ).tearDown ()
2334 TestBase .delete_all_topology_files ()
2435 if os .path .exists (TOPOLOGY_FILES_DIR ):
25- try :
26- rmtree (TOPOLOGY_FILES_DIR , ignore_errors = True )
27- except OSError as ex :
28- pass
36+ rmtree (TOPOLOGY_FILES_DIR , ignore_errors = True )
2937
30- @unittest .skip ("Topology creation" )
3138 def test_topology_creation (self ):
3239 created = False
3340 while not created :
@@ -38,26 +45,69 @@ def test_topology_creation(self):
3845 created = True
3946 TestBase .wait_for_database_topology (self .store , DATABASE )
4047
41- with DocumentStore (urls = self .default_urls , database = DATABASE ) as store :
48+ # the embedded server uses a random port, so hash the real server url (not the placeholder default_urls)
49+ base_url = self .store .urls [0 ]
50+
51+ with DocumentStore (urls = self .store .urls , database = DATABASE ) as store :
52+ store .conventions .topology_cache_location = TOPOLOGY_FILES_DIR
4253 store .initialize ()
4354 with store .open_session () as session :
4455 session .store (Author ("Idan" ))
4556 session .save_changes ()
46- topology_hash = hashlib .md5 ("{0}{1}" .format (self .default_urls [0 ], DATABASE ).encode ("utf-8" )).hexdigest ()
4757
48- cluster_topology_hash = hashlib .md5 ("{0}" .format (self .default_urls [0 ]).encode ("utf-8" )).hexdigest ()
58+ topology_hash = hashlib .md5 ("{0}{1}" .format (base_url , DATABASE ).encode ("utf-8" )).hexdigest ()
59+ cluster_topology_hash = hashlib .md5 ("{0}" .format (base_url ).encode ("utf-8" )).hexdigest ()
4960
61+ self .assertTrue (os .path .exists (os .path .join (TOPOLOGY_FILES_DIR , topology_hash + ".raven-topology" )))
5062 self .assertTrue (
51- os .path .exists (os .path .join (TOPOLOGY_FILES_DIR , topology_hash + ".raven-topology" ))
52- ) # todo: fix from here - make sure the right folder and files appear
53- self .assertTrue (
54- os .path .exists (
55- os .path .join (
56- TOPOLOGY_FILES_DIR ,
57- cluster_topology_hash + ".raven-cluster-topology" ,
58- )
59- )
63+ os .path .exists (os .path .join (TOPOLOGY_FILES_DIR , cluster_topology_hash + ".raven-cluster-topology" ))
64+ )
65+
66+ def test_topology_cache_round_trip (self ):
67+ os .makedirs (TOPOLOGY_FILES_DIR , exist_ok = True )
68+ topology = Topology (3 , [ServerNode ("http://localhost:9999" , "db1" , "B" , ServerNode .Role .MEMBER )])
69+ topology_hash = topology_local_cache .server_hash ("http://localhost:9999" , "db1" )
70+ topology_local_cache .try_save (
71+ TOPOLOGY_FILES_DIR , topology_hash , topology , topology_local_cache .DATABASE_TOPOLOGY_EXTENSION
72+ )
73+
74+ loaded = topology_local_cache .try_load (
75+ TOPOLOGY_FILES_DIR , topology_hash , topology_local_cache .DATABASE_TOPOLOGY_EXTENSION
6076 )
77+ self .assertIsNotNone (loaded )
78+ self .assertEqual (3 , loaded .etag )
79+ self .assertEqual (1 , len (loaded .nodes ))
80+ node = loaded .nodes [0 ]
81+ self .assertEqual ("http://localhost:9999" , node .url )
82+ self .assertEqual ("db1" , node .database )
83+ self .assertEqual ("B" , node .cluster_tag )
84+ self .assertEqual (ServerNode .Role .MEMBER , node .server_role )
85+
86+ def test_topology_is_loaded_from_cache_when_urls_unreachable (self ):
87+ bad_url = "http://127.0.0.1:1"
88+ database = "CacheSeedTest"
89+ os .makedirs (TOPOLOGY_FILES_DIR , exist_ok = True )
90+ cached = Topology (9 , [ServerNode (bad_url , database , "A" , ServerNode .Role .MEMBER )])
91+ topology_local_cache .try_save (
92+ TOPOLOGY_FILES_DIR ,
93+ topology_local_cache .server_hash (bad_url , database ),
94+ cached ,
95+ topology_local_cache .DATABASE_TOPOLOGY_EXTENSION ,
96+ )
97+
98+ # the server is unreachable, so the first topology update must fall back to the on-disk cache
99+ with DocumentStore (urls = [bad_url ], database = database ) as store :
100+ store .conventions .topology_cache_location = TOPOLOGY_FILES_DIR
101+ store .initialize ()
102+ request_executor = store .get_request_executor ()
103+ request_executor ._first_topology_update_task .result (30 )
104+
105+ nodes = request_executor .topology_nodes
106+ self .assertEqual (1 , len (nodes ))
107+ self .assertEqual ("A" , nodes [0 ].cluster_tag )
108+ self .assertEqual (bad_url , nodes [0 ].url )
109+ self .assertEqual (ServerNode .Role .MEMBER , nodes [0 ].server_role )
110+ self .assertEqual (9 , request_executor .topology_etag )
61111
62112
63113if __name__ == "__main__" :
0 commit comments