Skip to content

Commit 03bfd9f

Browse files
committed
feat: remove GetRegistry from PushNotificationProcessorInterface for better encapsulation
- Remove GetRegistry() method from PushNotificationProcessorInterface - Enforce use of GetHandler() method for cleaner API design - Add GetRegistryForTesting() method for test access only - Update all tests to use new testing helper methods - Maintain clean separation between public API and internal implementation Benefits: - Better encapsulation - no direct registry access from public interface - Cleaner API - forces use of GetHandler() for specific handler access - Consistent interface design across all processor types - Internal registry access only available for testing purposes - Prevents misuse of registry in production code
1 parent e6c5590 commit 03bfd9f

File tree

3 files changed

+91
-44
lines changed

3 files changed

+91
-44
lines changed

push_notification_coverage_test.go

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ import (
1111
"github.com/redis/go-redis/v9/internal/proto"
1212
)
1313

14+
// Helper function to access registry for testing
15+
func getRegistryForTestingCoverage(processor PushNotificationProcessorInterface) *PushNotificationRegistry {
16+
switch p := processor.(type) {
17+
case *PushNotificationProcessor:
18+
return p.GetRegistryForTesting()
19+
case *VoidPushNotificationProcessor:
20+
return p.GetRegistryForTesting()
21+
default:
22+
return nil
23+
}
24+
}
25+
1426
// testHandler is a simple implementation of PushNotificationHandler for testing
1527
type testHandler struct {
1628
handlerFunc func(ctx context.Context, notification []interface{}) bool
@@ -154,9 +166,10 @@ func TestConnPushNotificationMethods(t *testing.T) {
154166
t.Error("Conn should have push notification processor")
155167
}
156168

157-
// Processor should have a registry when enabled
158-
if processor.GetRegistry() == nil {
159-
t.Error("Conn push notification processor should have a registry when enabled")
169+
// Test that processor can handle handlers when enabled
170+
testHandler := processor.GetHandler("TEST")
171+
if testHandler != nil {
172+
t.Error("Should not have handler for TEST initially")
160173
}
161174

162175
// Test RegisterPushNotificationHandler
@@ -183,16 +196,25 @@ func TestConnPushNotificationMethods(t *testing.T) {
183196
t.Error("Should get error when registering duplicate handler")
184197
}
185198

186-
// Test that handlers work
187-
registry := processor.GetRegistry()
199+
// Test that handlers work using GetHandler
188200
ctx := context.Background()
189201

190-
handled := registry.HandleNotification(ctx, []interface{}{"TEST_CONN_HANDLER", "data"})
202+
connHandler := processor.GetHandler("TEST_CONN_HANDLER")
203+
if connHandler == nil {
204+
t.Error("Should have handler for TEST_CONN_HANDLER after registration")
205+
return
206+
}
207+
handled := connHandler.HandlePushNotification(ctx, []interface{}{"TEST_CONN_HANDLER", "data"})
191208
if !handled {
192209
t.Error("Handler should have been called")
193210
}
194211

195-
handled = registry.HandleNotification(ctx, []interface{}{"TEST_CONN_FUNC", "data"})
212+
funcHandler := processor.GetHandler("TEST_CONN_FUNC")
213+
if funcHandler == nil {
214+
t.Error("Should have handler for TEST_CONN_FUNC after registration")
215+
return
216+
}
217+
handled = funcHandler.HandlePushNotification(ctx, []interface{}{"TEST_CONN_FUNC", "data"})
196218
if !handled {
197219
t.Error("Handler func should have been called")
198220
}
@@ -217,9 +239,10 @@ func TestConnWithoutPushNotifications(t *testing.T) {
217239
if processor == nil {
218240
t.Error("Conn should always have a push notification processor")
219241
}
220-
// VoidPushNotificationProcessor should have nil registry
221-
if processor.GetRegistry() != nil {
222-
t.Error("VoidPushNotificationProcessor should have nil registry for RESP2")
242+
// VoidPushNotificationProcessor should return nil for all handlers
243+
handler := processor.GetHandler("TEST")
244+
if handler != nil {
245+
t.Error("VoidPushNotificationProcessor should return nil for all handlers")
223246
}
224247

225248
// Test RegisterPushNotificationHandler returns nil (no error)
@@ -297,10 +320,14 @@ func TestClonedClientPushNotifications(t *testing.T) {
297320
t.Error("Cloned client should have same push notification processor")
298321
}
299322

300-
// Test that handlers work on cloned client
301-
registry := clonedProcessor.GetRegistry()
323+
// Test that handlers work on cloned client using GetHandler
302324
ctx := context.Background()
303-
handled := registry.HandleNotification(ctx, []interface{}{"TEST_CLONE", "data"})
325+
cloneHandler := clonedProcessor.GetHandler("TEST_CLONE")
326+
if cloneHandler == nil {
327+
t.Error("Cloned client should have TEST_CLONE handler")
328+
return
329+
}
330+
handled := cloneHandler.HandlePushNotification(ctx, []interface{}{"TEST_CLONE", "data"})
304331
if !handled {
305332
t.Error("Cloned client should handle notifications")
306333
}

push_notifications.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ func (r *PushNotificationRegistry) GetHandler(pushNotificationName string) PushN
112112
// PushNotificationProcessorInterface defines the interface for push notification processors.
113113
type PushNotificationProcessorInterface interface {
114114
GetHandler(pushNotificationName string) PushNotificationHandler
115-
GetRegistry() *PushNotificationRegistry // For backward compatibility and testing
116115
ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error
117116
RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error
118117
}
@@ -135,9 +134,9 @@ func (p *PushNotificationProcessor) GetHandler(pushNotificationName string) Push
135134
return p.registry.GetHandler(pushNotificationName)
136135
}
137136

138-
// GetRegistry returns the push notification registry for internal use.
139-
// This method is primarily for testing and internal operations.
140-
func (p *PushNotificationProcessor) GetRegistry() *PushNotificationRegistry {
137+
// GetRegistryForTesting returns the push notification registry for testing.
138+
// This method should only be used by tests.
139+
func (p *PushNotificationProcessor) GetRegistryForTesting() *PushNotificationRegistry {
141140
return p.registry
142141
}
143142

@@ -248,8 +247,9 @@ func (v *VoidPushNotificationProcessor) GetHandler(pushNotificationName string)
248247
return nil
249248
}
250249

251-
// GetRegistry returns nil for void processor since it doesn't maintain handlers.
252-
func (v *VoidPushNotificationProcessor) GetRegistry() *PushNotificationRegistry {
250+
// GetRegistryForTesting returns nil for void processor since it doesn't maintain handlers.
251+
// This method should only be used by tests.
252+
func (v *VoidPushNotificationProcessor) GetRegistryForTesting() *PushNotificationRegistry {
253253
return nil
254254
}
255255

push_notifications_test.go

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ import (
99
"github.com/redis/go-redis/v9/internal/pool"
1010
)
1111

12+
// Helper function to access registry for testing
13+
func getRegistryForTesting(processor redis.PushNotificationProcessorInterface) *redis.PushNotificationRegistry {
14+
switch p := processor.(type) {
15+
case *redis.PushNotificationProcessor:
16+
return p.GetRegistryForTesting()
17+
case *redis.VoidPushNotificationProcessor:
18+
return p.GetRegistryForTesting()
19+
default:
20+
return nil
21+
}
22+
}
23+
1224
// testHandler is a simple implementation of PushNotificationHandler for testing
1325
type testHandler struct {
1426
handlerFunc func(ctx context.Context, notification []interface{}) bool
@@ -84,8 +96,10 @@ func TestPushNotificationProcessor(t *testing.T) {
8496
// Test the push notification processor
8597
processor := redis.NewPushNotificationProcessor()
8698

87-
if processor.GetRegistry() == nil {
88-
t.Error("Processor should have a registry")
99+
// Test that we can get a handler (should be nil since none registered yet)
100+
handler := processor.GetHandler("TEST")
101+
if handler != nil {
102+
t.Error("Should not have handler for TEST initially")
89103
}
90104

91105
// Test registering handlers
@@ -106,10 +120,15 @@ func TestPushNotificationProcessor(t *testing.T) {
106120
t.Fatalf("Failed to register handler: %v", err)
107121
}
108122

109-
// Simulate handling a notification
123+
// Simulate handling a notification using GetHandler
110124
ctx := context.Background()
111125
notification := []interface{}{"CUSTOM_NOTIFICATION", "data"}
112-
handled := processor.GetRegistry().HandleNotification(ctx, notification)
126+
customHandler := processor.GetHandler("CUSTOM_NOTIFICATION")
127+
if customHandler == nil {
128+
t.Error("Should have handler for CUSTOM_NOTIFICATION after registration")
129+
return
130+
}
131+
handled := customHandler.HandlePushNotification(ctx, notification)
113132

114133
if !handled {
115134
t.Error("Notification should have been handled")
@@ -119,9 +138,10 @@ func TestPushNotificationProcessor(t *testing.T) {
119138
t.Error("Specific handler should have been called")
120139
}
121140

122-
// Test that processor always has a registry (no enable/disable anymore)
123-
if processor.GetRegistry() == nil {
124-
t.Error("Processor should always have a registry")
141+
// Test that processor can retrieve handlers (no enable/disable anymore)
142+
retrievedHandler := processor.GetHandler("CUSTOM_NOTIFICATION")
143+
if retrievedHandler == nil {
144+
t.Error("Should be able to retrieve registered handler")
125145
}
126146
}
127147

@@ -140,7 +160,7 @@ func TestClientPushNotificationIntegration(t *testing.T) {
140160
t.Error("Push notification processor should be initialized")
141161
}
142162

143-
if processor.GetRegistry() == nil {
163+
if getRegistryForTesting(processor) == nil {
144164
t.Error("Push notification processor should have a registry when enabled")
145165
}
146166

@@ -157,7 +177,7 @@ func TestClientPushNotificationIntegration(t *testing.T) {
157177
// Simulate notification handling
158178
ctx := context.Background()
159179
notification := []interface{}{"CUSTOM_EVENT", "test_data"}
160-
handled := processor.GetRegistry().HandleNotification(ctx, notification)
180+
handled := getRegistryForTesting(processor).HandleNotification(ctx, notification)
161181

162182
if !handled {
163183
t.Error("Notification should have been handled")
@@ -183,7 +203,7 @@ func TestClientWithoutPushNotifications(t *testing.T) {
183203
t.Error("Push notification processor should never be nil")
184204
}
185205
// VoidPushNotificationProcessor should have nil registry
186-
if processor.GetRegistry() != nil {
206+
if getRegistryForTesting(processor) != nil {
187207
t.Error("VoidPushNotificationProcessor should have nil registry")
188208
}
189209

@@ -211,8 +231,9 @@ func TestPushNotificationEnabledClient(t *testing.T) {
211231
t.Error("Push notification processor should be initialized when enabled")
212232
}
213233

214-
if processor.GetRegistry() == nil {
215-
t.Error("Push notification processor should have a registry when enabled")
234+
registry := getRegistryForTesting(processor)
235+
if registry == nil {
236+
t.Errorf("Push notification processor should have a registry when enabled. Processor type: %T", processor)
216237
}
217238

218239
// Test registering a handler
@@ -226,7 +247,6 @@ func TestPushNotificationEnabledClient(t *testing.T) {
226247
}
227248

228249
// Test that the handler works
229-
registry := processor.GetRegistry()
230250
ctx := context.Background()
231251
notification := []interface{}{"TEST_NOTIFICATION", "data"}
232252
handled := registry.HandleNotification(ctx, notification)
@@ -375,7 +395,7 @@ func TestPubSubWithGenericPushNotifications(t *testing.T) {
375395

376396
// Test that the processor can handle notifications
377397
notification := []interface{}{"CUSTOM_PUBSUB_EVENT", "arg1", "arg2"}
378-
handled := processor.GetRegistry().HandleNotification(context.Background(), notification)
398+
handled := getRegistryForTesting(processor).HandleNotification(context.Background(), notification)
379399

380400
if !handled {
381401
t.Error("Push notification should have been handled")
@@ -559,7 +579,7 @@ func TestPushNotificationProcessorEdgeCases(t *testing.T) {
559579
// Test processor with disabled state
560580
processor := redis.NewPushNotificationProcessor()
561581

562-
if processor.GetRegistry() == nil {
582+
if getRegistryForTesting(processor) == nil {
563583
t.Error("Processor should have a registry")
564584
}
565585

@@ -573,7 +593,7 @@ func TestPushNotificationProcessorEdgeCases(t *testing.T) {
573593
// Even with handlers registered, disabled processor shouldn't process
574594
ctx := context.Background()
575595
notification := []interface{}{"TEST_CMD", "data"}
576-
handled := processor.GetRegistry().HandleNotification(ctx, notification)
596+
handled := getRegistryForTesting(processor).HandleNotification(ctx, notification)
577597

578598
if !handled {
579599
t.Error("Registry should still handle notifications even when processor is disabled")
@@ -584,7 +604,7 @@ func TestPushNotificationProcessorEdgeCases(t *testing.T) {
584604
}
585605

586606
// Test that processor always has a registry
587-
if processor.GetRegistry() == nil {
607+
if getRegistryForTesting(processor) == nil {
588608
t.Error("Processor should always have a registry")
589609
}
590610
}
@@ -619,7 +639,7 @@ func TestPushNotificationProcessorConvenienceMethods(t *testing.T) {
619639

620640
// Test specific handler
621641
notification := []interface{}{"CONV_CMD", "data"}
622-
handled := processor.GetRegistry().HandleNotification(ctx, notification)
642+
handled := getRegistryForTesting(processor).HandleNotification(ctx, notification)
623643

624644
if !handled {
625645
t.Error("Notification should be handled")
@@ -635,7 +655,7 @@ func TestPushNotificationProcessorConvenienceMethods(t *testing.T) {
635655

636656
// Test func handler
637657
notification = []interface{}{"FUNC_CMD", "data"}
638-
handled = processor.GetRegistry().HandleNotification(ctx, notification)
658+
handled = getRegistryForTesting(processor).HandleNotification(ctx, notification)
639659

640660
if !handled {
641661
t.Error("Notification should be handled")
@@ -676,7 +696,7 @@ func TestClientPushNotificationEdgeCases(t *testing.T) {
676696
t.Error("Processor should never be nil")
677697
}
678698
// VoidPushNotificationProcessor should have nil registry
679-
if processor.GetRegistry() != nil {
699+
if getRegistryForTesting(processor) != nil {
680700
t.Error("VoidPushNotificationProcessor should have nil registry when disabled")
681701
}
682702
}
@@ -838,10 +858,10 @@ func TestPushNotificationProcessorConcurrency(t *testing.T) {
838858

839859
// Handle notifications
840860
notification := []interface{}{command, "data"}
841-
processor.GetRegistry().HandleNotification(context.Background(), notification)
861+
getRegistryForTesting(processor).HandleNotification(context.Background(), notification)
842862

843863
// Access processor state
844-
processor.GetRegistry()
864+
getRegistryForTesting(processor)
845865
}
846866
}(i)
847867
}
@@ -852,7 +872,7 @@ func TestPushNotificationProcessorConcurrency(t *testing.T) {
852872
}
853873

854874
// Verify processor is still functional
855-
registry := processor.GetRegistry()
875+
registry := getRegistryForTesting(processor)
856876
if registry == nil {
857877
t.Error("Processor registry should not be nil after concurrent operations")
858878
}
@@ -887,7 +907,7 @@ func TestPushNotificationClientConcurrency(t *testing.T) {
887907
// Access processor
888908
processor := client.GetPushNotificationProcessor()
889909
if processor != nil {
890-
processor.GetRegistry()
910+
getRegistryForTesting(processor)
891911
}
892912
}
893913
}(i)
@@ -921,7 +941,7 @@ func TestPushNotificationConnectionHealthCheck(t *testing.T) {
921941
if processor == nil {
922942
t.Fatal("Push notification processor should not be nil")
923943
}
924-
if processor.GetRegistry() == nil {
944+
if getRegistryForTesting(processor) == nil {
925945
t.Fatal("Push notification registry should not be nil when enabled")
926946
}
927947

0 commit comments

Comments
 (0)