TestPubSubConn_PassesPersistedChannelsToNewConn is a regression test for https://github.com/redis/go-redis/issues/3806. ClusterClient.pubSub() installs a newConn closure that picks the target node by hash slot of channels[0]. Before the fix, PubSub.conn() only passed c.channels (regular SUBSCRIBE)
(t *testing.T)
| 1099 | // channel list it receives. The cluster routing layer is not under test |
| 1100 | // here — the regression is whether the channel list reaches the closure. |
| 1101 | func TestPubSubConn_PassesPersistedChannelsToNewConn(t *testing.T) { |
| 1102 | const ( |
| 1103 | regularCh = "regular-ch" |
| 1104 | shardCh = "{shardA}-ch1" |
| 1105 | freshCh = "fresh-ch" |
| 1106 | ) |
| 1107 | |
| 1108 | tests := []struct { |
| 1109 | name string |
| 1110 | channels map[string]struct{} |
| 1111 | schannels map[string]struct{} |
| 1112 | newChannels []string |
| 1113 | wantIn []string // strings that MUST be present in the captured slice |
| 1114 | }{ |
| 1115 | { |
| 1116 | name: "subscribe-only reconnect: existing channels forwarded", |
| 1117 | channels: map[string]struct{}{regularCh: {}}, |
| 1118 | wantIn: []string{regularCh}, |
| 1119 | }, |
| 1120 | { |
| 1121 | // The bug from #3806: SSubscribe-only reconnect dropped |
| 1122 | // c.schannels and reached newConn with an empty list. |
| 1123 | name: "ssubscribe-only reconnect: schannels forwarded (#3806)", |
| 1124 | schannels: map[string]struct{}{shardCh: {}}, |
| 1125 | wantIn: []string{shardCh}, |
| 1126 | }, |
| 1127 | { |
| 1128 | name: "initial ssubscribe: newChannels forwarded", |
| 1129 | newChannels: []string{shardCh}, |
| 1130 | wantIn: []string{shardCh}, |
| 1131 | }, |
| 1132 | { |
| 1133 | name: "mixed subscribe + ssubscribe: both kinds forwarded", |
| 1134 | channels: map[string]struct{}{regularCh: {}}, |
| 1135 | schannels: map[string]struct{}{shardCh: {}}, |
| 1136 | wantIn: []string{regularCh, shardCh}, |
| 1137 | }, |
| 1138 | { |
| 1139 | name: "newChannels appended after persisted ones", |
| 1140 | schannels: map[string]struct{}{shardCh: {}}, |
| 1141 | newChannels: []string{freshCh}, |
| 1142 | wantIn: []string{shardCh, freshCh}, |
| 1143 | }, |
| 1144 | } |
| 1145 | |
| 1146 | for _, tt := range tests { |
| 1147 | t.Run(tt.name, func(t *testing.T) { |
| 1148 | var captured []string |
| 1149 | stubErr := errors.New("stub: newConn does not create a real conn") |
| 1150 | |
| 1151 | ps := &PubSub{ |
| 1152 | opt: &Options{Addr: "stub:6379"}, |
| 1153 | channels: tt.channels, |
| 1154 | schannels: tt.schannels, |
| 1155 | newConn: func(_ context.Context, _ string, channels []string) (*pool.Conn, error) { |
| 1156 | captured = append([]string(nil), channels...) |
| 1157 | return nil, stubErr |
| 1158 | }, |