1
1
import logging
2
2
import socket
3
3
import unittest
4
- from unittest .mock import ANY , patch
4
+ from unittest .mock import patch
5
5
6
6
from lxml import etree
7
7
8
8
from cmapi_server import node_manipulation
9
9
from cmapi_server .constants import MCS_DATA_PATH
10
- from cmapi_server .node_manipulation import add_dbroots_of_other_nodes , remove_dbroots_of_node
10
+ from cmapi_server .node_manipulation import add_dbroots_of_other_nodes , remove_dbroots_of_node , update_dbroots_of_readonly_nodes
11
11
from cmapi_server .test .unittest_global import BaseNodeManipTestCase , tmp_mcs_config_filename
12
12
from mcs_node_control .models .node_config import NodeConfig
13
13
@@ -23,12 +23,18 @@ def test_add_remove_node(self):
23
23
'./test-output0.xml' ,'./test-output1.xml' ,'./test-output2.xml'
24
24
)
25
25
hostaddr = socket .gethostbyname (socket .gethostname ())
26
- node_manipulation .add_node (
27
- self .NEW_NODE_NAME , tmp_mcs_config_filename , self .tmp_files [0 ]
28
- )
29
- node_manipulation .add_node (
30
- hostaddr , self .tmp_files [0 ], self .tmp_files [1 ]
31
- )
26
+
27
+ with patch ('cmapi_server.node_manipulation.update_dbroots_of_readonly_nodes' ) as mock_update_dbroots_of_readonly_nodes :
28
+ node_manipulation .add_node (
29
+ self .NEW_NODE_NAME , tmp_mcs_config_filename , self .tmp_files [0 ]
30
+ )
31
+ mock_update_dbroots_of_readonly_nodes .assert_called_once ()
32
+ mock_update_dbroots_of_readonly_nodes .reset_mock ()
33
+
34
+ node_manipulation .add_node (
35
+ hostaddr , self .tmp_files [0 ], self .tmp_files [1 ]
36
+ )
37
+ mock_update_dbroots_of_readonly_nodes .assert_called_once ()
32
38
33
39
# get a NodeConfig, read test.xml
34
40
# look for some of the expected changes.
@@ -42,10 +48,13 @@ def test_add_remove_node(self):
42
48
node = root .find ("./ExeMgr2/IPAddr" )
43
49
self .assertEqual (node .text , hostaddr )
44
50
45
- node_manipulation .remove_node (
46
- self .NEW_NODE_NAME , self .tmp_files [1 ], self .tmp_files [2 ],
47
- test_mode = True
48
- )
51
+ with patch ('cmapi_server.node_manipulation.update_dbroots_of_readonly_nodes' ) as mock_update_dbroots_of_readonly_nodes :
52
+ node_manipulation .remove_node (
53
+ self .NEW_NODE_NAME , self .tmp_files [1 ], self .tmp_files [2 ],
54
+ test_mode = True
55
+ )
56
+ mock_update_dbroots_of_readonly_nodes .assert_called_once ()
57
+
49
58
nc = NodeConfig ()
50
59
root = nc .get_current_config_root (self .tmp_files [2 ])
51
60
node = root .find ('./PMS1/IPAddr' )
@@ -67,8 +76,7 @@ def test_add_remove_read_only_node(self):
67
76
# Mock _rebalance_dbroots and _move_primary_node (only after the first node is added)
68
77
with patch ('cmapi_server.node_manipulation._rebalance_dbroots' ) as mock_rebalance_dbroots , \
69
78
patch ('cmapi_server.node_manipulation._move_primary_node' ) as mock_move_primary_node , \
70
- patch ('cmapi_server.node_manipulation.add_dbroots_of_other_nodes' ) as mock_add_dbroots_of_other_nodes , \
71
- patch ('cmapi_server.node_manipulation.remove_dbroots_of_node' ) as mock_remove_dbroots_of_node :
79
+ patch ('cmapi_server.node_manipulation.update_dbroots_of_readonly_nodes' ) as mock_update_dbroots_of_readonly_nodes :
72
80
73
81
# Add a read-only node
74
82
node_manipulation .add_node (
@@ -94,7 +102,8 @@ def test_add_remove_read_only_node(self):
94
102
95
103
mock_rebalance_dbroots .assert_not_called ()
96
104
mock_move_primary_node .assert_not_called ()
97
- mock_add_dbroots_of_other_nodes .assert_called_once_with (ANY , 2 )
105
+ mock_update_dbroots_of_readonly_nodes .assert_called_once ()
106
+ mock_update_dbroots_of_readonly_nodes .reset_mock ()
98
107
99
108
# Test read-only node removal
100
109
node_manipulation .remove_node (
@@ -109,7 +118,7 @@ def test_add_remove_read_only_node(self):
109
118
110
119
mock_rebalance_dbroots .assert_not_called ()
111
120
mock_move_primary_node .assert_not_called ()
112
- mock_remove_dbroots_of_node . assert_called_once_with ( ANY , 2 )
121
+ mock_update_dbroots_of_readonly_nodes . assert_called_once ( )
113
122
114
123
115
124
def test_add_dbroots_nodes_rebalance (self ):
@@ -271,13 +280,23 @@ def test_unassign_dbroot1(self):
271
280
self .assertTrue (caught_it )
272
281
273
282
274
- class TestReadOnlyNodeDBRootsManip (unittest .TestCase ):
275
- our_module_idx = 2
283
+ class TestDBRootsManipulation (unittest .TestCase ):
284
+ our_module_idx = 3
285
+ ro_node1_ip = '192.168.1.3'
286
+ ro_node2_ip = '192.168.1.4'
276
287
277
288
def setUp (self ):
278
- # Mock initial XML structure (add two dbroots)
289
+ # Mock initial XML structure (add two nodes and two dbroots)
279
290
self .root = etree .Element ('Columnstore' )
280
- etree .SubElement (self .root , 'SystemModuleConfig' )
291
+ # Add two PM modules with IP addresses
292
+ smc = etree .SubElement (self .root , 'SystemModuleConfig' )
293
+ module_count = etree .SubElement (smc , 'ModuleCount3' )
294
+ module_count .text = '2'
295
+ module1_ip = etree .SubElement (smc , 'ModuleIPAddr1-1-3' )
296
+ module1_ip .text = '192.168.1.1'
297
+ module2_ip = etree .SubElement (smc , 'ModuleIPAddr2-1-3' )
298
+ module2_ip .text = '192.168.1.2'
299
+
281
300
system_config = etree .SubElement (self .root , 'SystemConfig' )
282
301
dbroot_count = etree .SubElement (system_config , 'DBRootCount' )
283
302
dbroot_count .text = '2'
@@ -286,6 +305,15 @@ def setUp(self):
286
305
dbroot2 = etree .SubElement (system_config , 'DBRoot2' )
287
306
dbroot2 .text = '/data/dbroot2'
288
307
308
+ def test_get_pm_module_num_to_addr_map (self ):
309
+ result = node_manipulation .get_pm_module_num_to_addr_map (self .root )
310
+
311
+ expected = {
312
+ 1 : '192.168.1.1' ,
313
+ 2 : '192.168.1.2' ,
314
+ }
315
+ self .assertEqual (result , expected )
316
+
289
317
def test_add_dbroots_of_other_nodes (self ):
290
318
'''add_dbroots_of_other_nodes must add dbroots of other nodes into mapping of the node.'''
291
319
add_dbroots_of_other_nodes (self .root , self .our_module_idx )
@@ -325,3 +353,36 @@ def test_remove_dbroots_of_node(self):
325
353
dbroot2 = self .root .find (f'./SystemModuleConfig/ModuleDBRootID{ self .our_module_idx } -2-3' )
326
354
self .assertIsNone (dbroot1 )
327
355
self .assertIsNone (dbroot2 )
356
+
357
+ def test_update_dbroots_of_readonly_nodes (self ):
358
+ """Test that update_dbroots_of_readonly_nodes adds all existing dbroots to all existing read-only nodes"""
359
+ # Add two new new modules to the XML structure (two already exist)
360
+ smc = self .root .find ('./SystemModuleConfig' )
361
+ module_count = smc .find ('./ModuleCount3' )
362
+ module_count .text = '4'
363
+ module3_ip = etree .SubElement (smc , 'ModuleIPAddr3-1-3' )
364
+ module3_ip .text = self .ro_node1_ip
365
+ module4_ip = etree .SubElement (smc , 'ModuleIPAddr4-1-3' )
366
+ module4_ip .text = self .ro_node2_ip
367
+ # Add them to ReadOnlyNodes
368
+ read_only_nodes = etree .SubElement (self .root , 'ReadOnlyNodes' )
369
+ for ip in [self .ro_node1_ip , self .ro_node2_ip ]:
370
+ node = etree .SubElement (read_only_nodes , 'Node' )
371
+ node .text = ip
372
+
373
+ update_dbroots_of_readonly_nodes (self .root )
374
+
375
+ # Check that read only nodes have all the dbroots
376
+ for ro_module_idx in range (3 , 5 ):
377
+ module_count = self .root .find (f'./SystemModuleConfig/ModuleDBRootCount{ ro_module_idx } -3' )
378
+ self .assertIsNotNone (module_count )
379
+ self .assertEqual (module_count .text , '2' )
380
+
381
+ dbroot1 = self .root .find (f'./SystemModuleConfig/ModuleDBRootID{ ro_module_idx } -1-3' )
382
+ dbroot2 = self .root .find (f'./SystemModuleConfig/ModuleDBRootID{ ro_module_idx } -2-3' )
383
+ self .assertIsNotNone (dbroot1 )
384
+ self .assertIsNotNone (dbroot2 )
385
+ self .assertEqual (dbroot1 .text , '1' )
386
+ self .assertEqual (dbroot2 .text , '2' )
387
+
388
+
0 commit comments