@@ -159,6 +159,68 @@ func readRESPArrayOfBulkStrings(r *bufio.Reader) ([][]byte, error) {
159159 return out , nil
160160}
161161
162+ func readTestRESPPubSubSubscribe (r * bufio.Reader ) (string , int , error ) {
163+ prefix , errRead := r .ReadByte ()
164+ if errRead != nil {
165+ return "" , 0 , errRead
166+ }
167+ if prefix != '*' {
168+ return "" , 0 , fmt .Errorf ("expected array prefix '*', got %q" , prefix )
169+ }
170+ line , errLine := readTestRESPLine (r )
171+ if errLine != nil {
172+ return "" , 0 , errLine
173+ }
174+ count , errParse := strconv .Atoi (line )
175+ if errParse != nil {
176+ return "" , 0 , fmt .Errorf ("invalid array length %q: %v" , line , errParse )
177+ }
178+ if count != 3 {
179+ return "" , 0 , fmt .Errorf ("subscribe ack length = %d, want 3" , count )
180+ }
181+ kind , errKind := readTestRESPBulkString (r )
182+ if errKind != nil {
183+ return "" , 0 , errKind
184+ }
185+ if string (kind ) != "subscribe" {
186+ return "" , 0 , fmt .Errorf ("subscribe ack kind = %q" , string (kind ))
187+ }
188+ channel , errChannel := readTestRESPBulkString (r )
189+ if errChannel != nil {
190+ return "" , 0 , errChannel
191+ }
192+ prefix , errRead = r .ReadByte ()
193+ if errRead != nil {
194+ return "" , 0 , errRead
195+ }
196+ if prefix != ':' {
197+ return "" , 0 , fmt .Errorf ("expected integer prefix ':', got %q" , prefix )
198+ }
199+ line , errLine = readTestRESPLine (r )
200+ if errLine != nil {
201+ return "" , 0 , errLine
202+ }
203+ subscriptions , errParse := strconv .Atoi (line )
204+ if errParse != nil {
205+ return "" , 0 , fmt .Errorf ("invalid subscription count %q: %v" , line , errParse )
206+ }
207+ return string (channel ), subscriptions , nil
208+ }
209+
210+ func readTestRESPPubSubMessage (r * bufio.Reader ) (string , []byte , error ) {
211+ items , errItems := readRESPArrayOfBulkStrings (r )
212+ if errItems != nil {
213+ return "" , nil , errItems
214+ }
215+ if len (items ) != 3 {
216+ return "" , nil , fmt .Errorf ("pubsub message length = %d, want 3" , len (items ))
217+ }
218+ if string (items [0 ]) != "message" {
219+ return "" , nil , fmt .Errorf ("pubsub message kind = %q" , string (items [0 ]))
220+ }
221+ return string (items [1 ]), items [2 ], nil
222+ }
223+
162224func TestRedisProtocol_ManagementDisabled_RejectsConnection (t * testing.T ) {
163225 t .Setenv ("MANAGEMENT_PASSWORD" , "" )
164226 redisqueue .SetEnabled (false )
@@ -235,6 +297,68 @@ func TestRedisProtocol_HomeEnabled_DisablesConnection(t *testing.T) {
235297 }
236298}
237299
300+ func TestRedisProtocol_SUBSCRIBE_UsageSendsSupportRefresh (t * testing.T ) {
301+ const managementPassword = "test-management-password"
302+
303+ t .Setenv ("MANAGEMENT_PASSWORD" , managementPassword )
304+ redisqueue .SetEnabled (false )
305+ t .Cleanup (func () { redisqueue .SetEnabled (false ) })
306+
307+ server := newTestServer (t )
308+ if ! server .managementRoutesEnabled .Load () {
309+ t .Fatalf ("expected managementRoutesEnabled to be true" )
310+ }
311+
312+ addr , stop := startRedisMuxListener (t , server )
313+ t .Cleanup (stop )
314+
315+ conn , errDial := net .DialTimeout ("tcp" , addr , time .Second )
316+ if errDial != nil {
317+ t .Fatalf ("failed to dial redis listener: %v" , errDial )
318+ }
319+ t .Cleanup (func () { _ = conn .Close () })
320+
321+ reader := bufio .NewReader (conn )
322+ _ = conn .SetDeadline (time .Now ().Add (5 * time .Second ))
323+
324+ if errWrite := writeTestRESPCommand (conn , "AUTH" , managementPassword ); errWrite != nil {
325+ t .Fatalf ("failed to write AUTH command: %v" , errWrite )
326+ }
327+ if msg , errRead := readTestRESPSimpleString (reader ); errRead != nil {
328+ t .Fatalf ("failed to read AUTH response: %v" , errRead )
329+ } else if msg != "OK" {
330+ t .Fatalf ("unexpected AUTH response: %q" , msg )
331+ }
332+
333+ if errWrite := writeTestRESPCommand (conn , "SUBSCRIBE" , "usage" ); errWrite != nil {
334+ t .Fatalf ("failed to write SUBSCRIBE command: %v" , errWrite )
335+ }
336+ channel , subscriptions , errSubscribe := readTestRESPPubSubSubscribe (reader )
337+ if errSubscribe != nil {
338+ t .Fatalf ("failed to read subscribe response: %v" , errSubscribe )
339+ }
340+ if channel != "usage" || subscriptions != 1 {
341+ t .Fatalf ("unexpected subscribe response channel=%q subscriptions=%d" , channel , subscriptions )
342+ }
343+
344+ channel , payload , errMessage := readTestRESPPubSubMessage (reader )
345+ if errMessage != nil {
346+ t .Fatalf ("failed to read support refresh message: %v" , errMessage )
347+ }
348+ if channel != "usage" || string (payload ) != `{"support_refresh":true}` {
349+ t .Fatalf ("unexpected support refresh message channel=%q payload=%q" , channel , string (payload ))
350+ }
351+
352+ redisqueue .Enqueue ([]byte (`{"id":1}` ))
353+ channel , payload , errMessage = readTestRESPPubSubMessage (reader )
354+ if errMessage != nil {
355+ t .Fatalf ("failed to read usage message: %v" , errMessage )
356+ }
357+ if channel != "usage" || string (payload ) != `{"id":1}` {
358+ t .Fatalf ("unexpected usage message channel=%q payload=%q" , channel , string (payload ))
359+ }
360+ }
361+
238362func TestRedisProtocol_AUTH_And_PopContracts (t * testing.T ) {
239363 const managementPassword = "test-management-password"
240364
0 commit comments