1515import java .util .stream .Collectors ;
1616
1717import static org .hamcrest .MatcherAssert .assertThat ;
18+ import static org .hamcrest .Matchers .aMapWithSize ;
19+ import static org .hamcrest .Matchers .equalTo ;
20+ import static org .hamcrest .Matchers .hasEntry ;
1821import static org .hamcrest .Matchers .hasItem ;
1922import static org .junit .jupiter .api .Assertions .assertEquals ;
2023import static org .junit .jupiter .api .Assertions .assertNotNull ;
2124import static org .junit .jupiter .api .Assertions .assertNull ;
2225import static org .mockito .ArgumentMatchers .argThat ;
2326import static org .mockito .Mockito .when ;
27+ import static redis .clients .jedis .JedisClusterInfoCache .getNodeKey ;
2428import static redis .clients .jedis .Protocol .Command .CLUSTER ;
2529import static redis .clients .jedis .util .CommandArgumentMatchers .commandWithArgs ;
2630
@@ -49,7 +53,7 @@ public void testReplicaNodeRemovalAndRediscovery() {
4953
5054 // Mock the cluster slots responses
5155 when (mockConnection .executeCommand (argThat (commandWithArgs (CLUSTER , "SLOTS" )))).thenReturn (
52- masterReplicaSlotsResponse ()).thenReturn (masterOnlySlotsResponse ())
56+ masterReplicaSlotsResponse (MASTER_HOST , REPLICA_1_HOST )).thenReturn (masterOnlySlotsResponse ())
5357 .thenReturn (masterReplica2SlotsResponse ());
5458
5559 // Initial discovery with one master and one replica (replica-1)
@@ -78,7 +82,7 @@ public void testResetWithReplicaSlots() {
7882
7983 // Mock the cluster slots responses
8084 when (mockConnection .executeCommand (argThat (commandWithArgs (CLUSTER , "SLOTS" )))).thenReturn (
81- masterReplicaSlotsResponse ());
85+ masterReplicaSlotsResponse (MASTER_HOST , REPLICA_1_HOST ));
8286
8387 // Initial discovery
8488 cache .discoverClusterNodesAndSlots (mockConnection );
@@ -94,10 +98,68 @@ public void testResetWithReplicaSlots() {
9498 assertReplicasAvailable (cache , REPLICA_1_HOST );
9599 }
96100
97- private List <Object > masterReplicaSlotsResponse () {
101+ @ Test
102+ public void getPrimaryNodesAfterReplicaNodeRemovalAndRediscovery () {
103+ // Create client config with read-only replicas enabled
104+ JedisClientConfig clientConfig = DefaultJedisClientConfig .builder ()
105+ .readOnlyForRedisClusterReplicas ().build ();
106+
107+ Set <HostAndPort > startNodes = new HashSet <>();
108+ startNodes .add (MASTER_HOST );
109+
110+ JedisClusterInfoCache cache = new JedisClusterInfoCache (clientConfig , startNodes );
111+
112+ // Mock the cluster slots responses
113+ when (mockConnection .executeCommand (argThat (commandWithArgs (CLUSTER , "SLOTS" )))).thenReturn (
114+ masterReplicaSlotsResponse (MASTER_HOST , REPLICA_1_HOST )).thenReturn (masterOnlySlotsResponse ())
115+ .thenReturn (masterReplica2SlotsResponse ());
116+
117+ // Initial discovery with one master and one replica (replica-1)
118+ cache .discoverClusterNodesAndSlots (mockConnection );
119+ assertThat (cache .getPrimaryNodes (),aMapWithSize (1 ));
120+ assertThat (cache .getPrimaryNodes (),
121+ hasEntry (equalTo (getNodeKey (MASTER_HOST )), equalTo (cache .getNode (MASTER_HOST ))));
122+
123+ // Simulate rediscovery - master only
124+ cache .discoverClusterNodesAndSlots (mockConnection );
125+ assertThat ( cache .getPrimaryNodes (),aMapWithSize (1 ));
126+ assertThat (cache .getPrimaryNodes (),
127+ hasEntry (equalTo (getNodeKey (MASTER_HOST )), equalTo (cache .getNode (MASTER_HOST ))));
128+ }
129+
130+ @ Test
131+ public void getPrimaryNodesAfterMasterReplicaFailover () {
132+ // Create client config with read-only replicas enabled
133+ JedisClientConfig clientConfig = DefaultJedisClientConfig .builder ()
134+ .readOnlyForRedisClusterReplicas ().build ();
135+
136+ Set <HostAndPort > startNodes = new HashSet <>();
137+ startNodes .add (MASTER_HOST );
138+
139+ JedisClusterInfoCache cache = new JedisClusterInfoCache (clientConfig , startNodes );
140+
141+ // Mock the cluster slots responses
142+ when (mockConnection .executeCommand (argThat (commandWithArgs (CLUSTER , "SLOTS" ))))
143+ .thenReturn (masterReplicaSlotsResponse (MASTER_HOST , REPLICA_1_HOST ))
144+ .thenReturn (masterReplicaSlotsResponse (REPLICA_1_HOST , MASTER_HOST ));
145+
146+ // Initial discovery with one master and one replica (replica-1)
147+ cache .discoverClusterNodesAndSlots (mockConnection );
148+ assertThat (cache .getPrimaryNodes (),aMapWithSize (1 ));
149+ assertThat (cache .getPrimaryNodes (),
150+ hasEntry (equalTo (getNodeKey (MASTER_HOST )), equalTo (cache .getNode (MASTER_HOST ))));
151+
152+ // Simulate rediscovery - master only
153+ cache .discoverClusterNodesAndSlots (mockConnection );
154+ assertThat ( cache .getPrimaryNodes (),aMapWithSize (1 ));
155+ assertThat (cache .getPrimaryNodes (),
156+ hasEntry (equalTo (getNodeKey (REPLICA_1_HOST )), equalTo (cache .getNode (REPLICA_1_HOST ))));
157+ }
158+
159+ private List <Object > masterReplicaSlotsResponse (HostAndPort masterHost , HostAndPort replicaHost ) {
98160 return createClusterSlotsResponse (
99- new SlotRange .Builder (0 , 16383 ).master (MASTER_HOST , "master -id-1 " )
100- .replica (REPLICA_1_HOST , "replica -id-1 " ).build ());
161+ new SlotRange .Builder (0 , 16383 ).master (masterHost , masterHost . toString () + " -id" )
162+ .replica (replicaHost , replicaHost . toString () + " -id" ).build ());
101163 }
102164
103165 private List <Object > masterOnlySlotsResponse () {
0 commit comments