@@ -110,16 +110,16 @@ def test_process_permanent_slots(self):
110110 self .p .reset_cluster_info_state (None )
111111 mock_query .return_value = [(
112112 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , None , None ,
113- [{"slot_name" : "ls" , "type" : "logical" , "datoid" : 5 , "plugin" : "b" ,
113+ [{"slot_name" : "ls" , "type" : "logical" , "datoid" : 5 , "plugin" : "b" , "xmin" : 105 ,
114114 "confirmed_flush_lsn" : 12345 , "catalog_xmin" : 105 , "restart_lsn" : 12344 },
115- {"slot_name" : "blabla" , "type" : "physical" , "datoid" : None , "plugin" : None ,
115+ {"slot_name" : "blabla" , "type" : "physical" , "datoid" : None , "plugin" : None , "xmin" : 105 ,
116116 "confirmed_flush_lsn" : None , "catalog_xmin" : 105 , "restart_lsn" : 12344 }])]
117117 self .assertEqual (self .p .slots (), {'ls' : 12345 , 'blabla' : 12344 , 'postgresql0' : 0 })
118118
119119 self .p .reset_cluster_info_state (None )
120120 mock_query .return_value = [(
121121 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , None , None ,
122- [{"slot_name" : "ls" , "type" : "logical" , "datoid" : 6 , "plugin" : "b" ,
122+ [{"slot_name" : "ls" , "type" : "logical" , "datoid" : 6 , "plugin" : "b" , "xmin" : 105 ,
123123 "confirmed_flush_lsn" : 12345 , "catalog_xmin" : 105 }])]
124124 self .assertEqual (self .p .slots (), {'postgresql0' : 0 })
125125
@@ -151,7 +151,8 @@ def test_nostream_slot_processing(self):
151151 {'foo' : {'type' : 'logical' , 'database' : 'a' , 'plugin' : 'b' }, 'bar' : {'type' : 'physical' }})
152152 self .assertEqual (
153153 cluster ._get_members_slots (self .p .name , 'primary' , False , True ),
154- {'test_3' : {'type' : 'physical' , 'lsn' : 98 }, 'test_4' : {'type' : 'physical' , 'lsn' : 98 }})
154+ {'test_3' : {'type' : 'physical' , 'lsn' : 98 , 'expected_active' : False },
155+ 'test_4' : {'type' : 'physical' , 'lsn' : 98 , 'expected_active' : True }})
155156
156157 # nostream node must not have slot on primary
157158 self .p .name = nostream_node .name
@@ -166,9 +167,9 @@ def test_nostream_slot_processing(self):
166167 # check cascade member-slot existence on nostream node
167168 self .assertEqual (
168169 cluster ._get_members_slots (nostream_node .name , 'replica' , False , True ),
169- {'leader' : {'type' : 'physical' , 'lsn' : 99 },
170- 'test_3' : {'type' : 'physical' , 'lsn' : 98 },
171- 'test_4' : {'type' : 'physical' , 'lsn' : 98 }})
170+ {'leader' : {'type' : 'physical' , 'lsn' : 99 , 'expected_active' : False },
171+ 'test_3' : {'type' : 'physical' , 'lsn' : 98 , 'expected_active' : True },
172+ 'test_4' : {'type' : 'physical' , 'lsn' : 98 , 'expected_active' : False }})
172173
173174 # cascade also does not entitled to have logical slot on itself ...
174175 self .p .name = cascade_node .name
@@ -222,7 +223,8 @@ def test__ensure_logical_slots_replica(self):
222223 self .cluster .status .slots ['ls' ] = 12346
223224 with patch .object (SlotsHandler , 'check_logical_slots_readiness' , Mock (return_value = False )):
224225 self .assertEqual (self .s .sync_replication_slots (self .cluster , self .tags ), [])
225- with patch .object (SlotsHandler , '_query' , Mock (return_value = [('ls' , 'logical' , 499 , 'b' , 'a' , 5 , 100 , 500 )])), \
226+ with patch .object (SlotsHandler , '_query' , Mock (return_value = [('ls' , 'logical' , 1 , 499 , 'b' ,
227+ 'a' , 5 , 100 , 500 )])), \
226228 patch .object (MockCursor , 'execute' , Mock (side_effect = psycopg .OperationalError )), \
227229 patch .object (SlotsAdvanceThread , 'schedule' , Mock (return_value = (True , ['ls' ]))), \
228230 patch .object (psycopg .OperationalError , 'diag' ) as mock_diag :
@@ -300,11 +302,28 @@ def test_advance_physical_slots(self):
300302 [self .me , self .other , self .leadermem ], None , SyncState .empty (), None , None )
301303 global_config .update (cluster )
302304 self .s .sync_replication_slots (cluster , self .tags )
303- with patch .object (SlotsHandler , '_query' , Mock (side_effect = [[('blabla' , 'physical' , 12345 , None , None , None ,
304- None , None )], Exception ])) as mock_query , \
305+ with patch .object (SlotsHandler , '_query' , Mock (side_effect = [[('blabla' , 'physical' , None , 12345 , None , None ,
306+ None , None , None )], Exception ])) as mock_query , \
305307 patch ('patroni.postgresql.slots.logger.error' ) as mock_error :
306308 self .s .sync_replication_slots (cluster , self .tags )
307309 self .assertEqual (mock_query .call_args [0 ],
308310 ("SELECT pg_catalog.pg_replication_slot_advance(%s, %s)" , "blabla" , '0/303A' ))
309311 self .assertEqual (mock_error .call_args [0 ][0 ],
310312 "Error while advancing replication slot %s to position '%s': %r" )
313+
314+ with patch .object (SlotsHandler , '_query' , Mock (side_effect = [[('test_1' , 'physical' , 1 , 12345 , None , None ,
315+ None , None , None )], Exception ])), \
316+ patch .object (SlotsHandler , 'drop_replication_slot' , Mock (return_value = (False , True ))):
317+ self .s .sync_replication_slots (cluster , self .tags )
318+
319+ with patch .object (SlotsHandler , '_query' , Mock (side_effect = [[('test_1' , 'physical' , 1 , 12345 , None , None ,
320+ None , None , None )], Exception ])), \
321+ patch .object (SlotsHandler , 'drop_replication_slot' , Mock (return_value = (True , False ))), \
322+ patch ('patroni.postgresql.slots.logger.warning' ) as mock_warning :
323+ self .s .sync_replication_slots (cluster , self .tags )
324+ self .assertEqual (mock_warning .call_args_list [- 1 ][0 ], ("Unable to drop replication slot '%s', slot is active" , 'test_1' ))
325+
326+ with patch .object (SlotsHandler , '_query' , Mock (side_effect = [[('test_1' , 'physical' , 1 , 12345 , None , None ,
327+ None , None , None )], Exception ])), \
328+ patch .object (SlotsHandler , 'drop_replication_slot' , Mock (return_value = (False , False ))):
329+ self .s .sync_replication_slots (cluster , self .tags )
0 commit comments