mirror of
https://github.com/redis/go-redis.git
synced 2025-07-18 00:20:57 +03:00
refactor: simplify push notification interface
- Remove RegisterPushNotificationHandlerFunc methods from all types - Remove PushNotificationHandlerFunc type adapter - Keep only RegisterPushNotificationHandler method for cleaner interface - Remove unnecessary push notification constants (keep only Redis Cluster ones) - Update all tests to use simplified interface with direct handler implementations Benefits: - Cleaner, simpler API with single registration method - Reduced code complexity and maintenance burden - Focus on essential Redis Cluster push notifications only - Users implement PushNotificationHandler interface directly - No functional changes, just interface simplification
This commit is contained in:
@ -11,6 +11,20 @@ import (
|
|||||||
"github.com/redis/go-redis/v9/internal/proto"
|
"github.com/redis/go-redis/v9/internal/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// testHandler is a simple implementation of PushNotificationHandler for testing
|
||||||
|
type testHandler struct {
|
||||||
|
handlerFunc func(ctx context.Context, notification []interface{}) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testHandler) HandlePushNotification(ctx context.Context, notification []interface{}) bool {
|
||||||
|
return h.handlerFunc(ctx, notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTestHandler creates a test handler from a function
|
||||||
|
func newTestHandler(f func(ctx context.Context, notification []interface{}) bool) *testHandler {
|
||||||
|
return &testHandler{handlerFunc: f}
|
||||||
|
}
|
||||||
|
|
||||||
// TestConnectionPoolPushNotificationIntegration tests the connection pool's
|
// TestConnectionPoolPushNotificationIntegration tests the connection pool's
|
||||||
// integration with push notifications for 100% coverage.
|
// integration with push notifications for 100% coverage.
|
||||||
func TestConnectionPoolPushNotificationIntegration(t *testing.T) {
|
func TestConnectionPoolPushNotificationIntegration(t *testing.T) {
|
||||||
@ -102,9 +116,9 @@ func TestConnectionHealthCheckWithPushNotifications(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
// Register a handler to ensure processor is active
|
// Register a handler to ensure processor is active
|
||||||
err := client.RegisterPushNotificationHandlerFunc("TEST_HEALTH", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST_HEALTH", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -147,7 +161,7 @@ func TestConnPushNotificationMethods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test RegisterPushNotificationHandler
|
// Test RegisterPushNotificationHandler
|
||||||
handler := PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -156,10 +170,10 @@ func TestConnPushNotificationMethods(t *testing.T) {
|
|||||||
t.Errorf("Failed to register handler on Conn: %v", err)
|
t.Errorf("Failed to register handler on Conn: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test RegisterPushNotificationHandlerFunc
|
// Test RegisterPushNotificationHandler with function wrapper
|
||||||
err = conn.RegisterPushNotificationHandlerFunc("TEST_CONN_FUNC", func(ctx context.Context, notification []interface{}) bool {
|
err = conn.RegisterPushNotificationHandler("TEST_CONN_FUNC", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to register handler func on Conn: %v", err)
|
t.Errorf("Failed to register handler func on Conn: %v", err)
|
||||||
}
|
}
|
||||||
@ -206,17 +220,17 @@ func TestConnWithoutPushNotifications(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test RegisterPushNotificationHandler returns nil (no error)
|
// Test RegisterPushNotificationHandler returns nil (no error)
|
||||||
err := conn.RegisterPushNotificationHandler("TEST", PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
err := conn.RegisterPushNotificationHandler("TEST", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should return nil error when no processor: %v", err)
|
t.Errorf("Should return nil error when no processor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test RegisterPushNotificationHandlerFunc returns nil (no error)
|
// Test RegisterPushNotificationHandler returns nil (no error)
|
||||||
err = conn.RegisterPushNotificationHandlerFunc("TEST", func(ctx context.Context, notification []interface{}) bool {
|
err = conn.RegisterPushNotificationHandler("TEST", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should return nil error when no processor: %v", err)
|
t.Errorf("Should return nil error when no processor: %v", err)
|
||||||
}
|
}
|
||||||
@ -263,9 +277,9 @@ func TestClonedClientPushNotifications(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register handler on original
|
// Register handler on original
|
||||||
err := client.RegisterPushNotificationHandlerFunc("TEST_CLONE", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST_CLONE", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -289,9 +303,9 @@ func TestClonedClientPushNotifications(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test registering new handler on cloned client
|
// Test registering new handler on cloned client
|
||||||
err = clonedClient.RegisterPushNotificationHandlerFunc("TEST_CLONE_NEW", func(ctx context.Context, notification []interface{}) bool {
|
err = clonedClient.RegisterPushNotificationHandler("TEST_CLONE_NEW", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to register handler on cloned client: %v", err)
|
t.Errorf("Failed to register handler on cloned client: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,6 @@ type PushNotificationHandler interface {
|
|||||||
HandlePushNotification(ctx context.Context, notification []interface{}) bool
|
HandlePushNotification(ctx context.Context, notification []interface{}) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushNotificationHandlerFunc is a function adapter for PushNotificationHandler.
|
|
||||||
type PushNotificationHandlerFunc func(ctx context.Context, notification []interface{}) bool
|
|
||||||
|
|
||||||
// HandlePushNotification implements PushNotificationHandler.
|
|
||||||
func (f PushNotificationHandlerFunc) HandlePushNotification(ctx context.Context, notification []interface{}) bool {
|
|
||||||
return f(ctx, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PushNotificationRegistry manages handlers for different types of push notifications.
|
// PushNotificationRegistry manages handlers for different types of push notifications.
|
||||||
type PushNotificationRegistry struct {
|
type PushNotificationRegistry struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
@ -185,42 +177,13 @@ func (p *PushNotificationProcessor) RegisterHandler(command string, handler Push
|
|||||||
return p.registry.RegisterHandler(command, handler)
|
return p.registry.RegisterHandler(command, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterHandlerFunc is a convenience method to register a function as a handler.
|
// Redis Cluster push notification commands
|
||||||
// Returns an error if a handler is already registered for this command.
|
|
||||||
func (p *PushNotificationProcessor) RegisterHandlerFunc(command string, handlerFunc func(ctx context.Context, notification []interface{}) bool) error {
|
|
||||||
return p.registry.RegisterHandler(command, PushNotificationHandlerFunc(handlerFunc))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common push notification commands
|
|
||||||
const (
|
const (
|
||||||
// Redis Cluster notifications
|
|
||||||
PushNotificationMoving = "MOVING"
|
PushNotificationMoving = "MOVING"
|
||||||
PushNotificationMigrating = "MIGRATING"
|
PushNotificationMigrating = "MIGRATING"
|
||||||
PushNotificationMigrated = "MIGRATED"
|
PushNotificationMigrated = "MIGRATED"
|
||||||
PushNotificationFailingOver = "FAILING_OVER"
|
PushNotificationFailingOver = "FAILING_OVER"
|
||||||
PushNotificationFailedOver = "FAILED_OVER"
|
PushNotificationFailedOver = "FAILED_OVER"
|
||||||
|
|
||||||
// Redis Pub/Sub notifications
|
|
||||||
PushNotificationPubSubMessage = "message"
|
|
||||||
PushNotificationPMessage = "pmessage"
|
|
||||||
PushNotificationSubscribe = "subscribe"
|
|
||||||
PushNotificationUnsubscribe = "unsubscribe"
|
|
||||||
PushNotificationPSubscribe = "psubscribe"
|
|
||||||
PushNotificationPUnsubscribe = "punsubscribe"
|
|
||||||
|
|
||||||
// Redis Stream notifications
|
|
||||||
PushNotificationXRead = "xread"
|
|
||||||
PushNotificationXReadGroup = "xreadgroup"
|
|
||||||
|
|
||||||
// Redis Keyspace notifications
|
|
||||||
PushNotificationKeyspace = "keyspace"
|
|
||||||
PushNotificationKeyevent = "keyevent"
|
|
||||||
|
|
||||||
// Redis Module notifications
|
|
||||||
PushNotificationModule = "module"
|
|
||||||
|
|
||||||
// Custom application notifications
|
|
||||||
PushNotificationCustom = "custom"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PushNotificationInfo contains metadata about a push notification.
|
// PushNotificationInfo contains metadata about a push notification.
|
||||||
|
@ -9,6 +9,20 @@ import (
|
|||||||
"github.com/redis/go-redis/v9/internal/pool"
|
"github.com/redis/go-redis/v9/internal/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// testHandler is a simple implementation of PushNotificationHandler for testing
|
||||||
|
type testHandler struct {
|
||||||
|
handlerFunc func(ctx context.Context, notification []interface{}) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testHandler) HandlePushNotification(ctx context.Context, notification []interface{}) bool {
|
||||||
|
return h.handlerFunc(ctx, notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTestHandler creates a test handler from a function
|
||||||
|
func newTestHandler(f func(ctx context.Context, notification []interface{}) bool) *testHandler {
|
||||||
|
return &testHandler{handlerFunc: f}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPushNotificationRegistry(t *testing.T) {
|
func TestPushNotificationRegistry(t *testing.T) {
|
||||||
// Test the push notification registry functionality
|
// Test the push notification registry functionality
|
||||||
registry := redis.NewPushNotificationRegistry()
|
registry := redis.NewPushNotificationRegistry()
|
||||||
@ -25,7 +39,7 @@ func TestPushNotificationRegistry(t *testing.T) {
|
|||||||
|
|
||||||
// Test registering a specific handler
|
// Test registering a specific handler
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
handler := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -58,7 +72,7 @@ func TestPushNotificationRegistry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test duplicate handler registration error
|
// Test duplicate handler registration error
|
||||||
duplicateHandler := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
duplicateHandler := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
err = registry.RegisterHandler("TEST_COMMAND", duplicateHandler)
|
err = registry.RegisterHandler("TEST_COMMAND", duplicateHandler)
|
||||||
@ -81,7 +95,7 @@ func TestPushNotificationProcessor(t *testing.T) {
|
|||||||
|
|
||||||
// Test registering handlers
|
// Test registering handlers
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
err := processor.RegisterHandlerFunc("CUSTOM_NOTIFICATION", func(ctx context.Context, notification []interface{}) bool {
|
err := processor.RegisterHandler("CUSTOM_NOTIFICATION", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
if len(notification) < 2 {
|
if len(notification) < 2 {
|
||||||
t.Error("Expected at least 2 elements in notification")
|
t.Error("Expected at least 2 elements in notification")
|
||||||
@ -92,7 +106,7 @@ func TestPushNotificationProcessor(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -138,10 +152,10 @@ func TestClientPushNotificationIntegration(t *testing.T) {
|
|||||||
|
|
||||||
// Test registering handlers through client
|
// Test registering handlers through client
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
err := client.RegisterPushNotificationHandlerFunc("CUSTOM_EVENT", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("CUSTOM_EVENT", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -175,9 +189,9 @@ func TestClientWithoutPushNotifications(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Registering handlers should not panic
|
// Registering handlers should not panic
|
||||||
err := client.RegisterPushNotificationHandlerFunc("TEST", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
||||||
}
|
}
|
||||||
@ -204,10 +218,10 @@ func TestPushNotificationEnabledClient(t *testing.T) {
|
|||||||
|
|
||||||
// Test registering a handler
|
// Test registering a handler
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
err := client.RegisterPushNotificationHandlerFunc("TEST_NOTIFICATION", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST_NOTIFICATION", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -228,17 +242,13 @@ func TestPushNotificationEnabledClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPushNotificationConstants(t *testing.T) {
|
func TestPushNotificationConstants(t *testing.T) {
|
||||||
// Test that push notification constants are defined correctly
|
// Test that Redis Cluster push notification constants are defined correctly
|
||||||
constants := map[string]string{
|
constants := map[string]string{
|
||||||
redis.PushNotificationMoving: "MOVING",
|
redis.PushNotificationMoving: "MOVING",
|
||||||
redis.PushNotificationMigrating: "MIGRATING",
|
redis.PushNotificationMigrating: "MIGRATING",
|
||||||
redis.PushNotificationMigrated: "MIGRATED",
|
redis.PushNotificationMigrated: "MIGRATED",
|
||||||
redis.PushNotificationPubSubMessage: "message",
|
redis.PushNotificationFailingOver: "FAILING_OVER",
|
||||||
redis.PushNotificationPMessage: "pmessage",
|
redis.PushNotificationFailedOver: "FAILED_OVER",
|
||||||
redis.PushNotificationSubscribe: "subscribe",
|
|
||||||
redis.PushNotificationUnsubscribe: "unsubscribe",
|
|
||||||
redis.PushNotificationKeyspace: "keyspace",
|
|
||||||
redis.PushNotificationKeyevent: "keyevent",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for constant, expected := range constants {
|
for constant, expected := range constants {
|
||||||
@ -293,11 +303,11 @@ func TestPubSubWithGenericPushNotifications(t *testing.T) {
|
|||||||
|
|
||||||
// Register a handler for custom push notifications
|
// Register a handler for custom push notifications
|
||||||
customNotificationReceived := false
|
customNotificationReceived := false
|
||||||
err := client.RegisterPushNotificationHandlerFunc("CUSTOM_PUBSUB_EVENT", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("CUSTOM_PUBSUB_EVENT", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
customNotificationReceived = true
|
customNotificationReceived = true
|
||||||
t.Logf("Received custom push notification in PubSub context: %v", notification)
|
t.Logf("Received custom push notification in PubSub context: %v", notification)
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -353,7 +363,7 @@ func TestPushNotificationRegistryUnregisterHandler(t *testing.T) {
|
|||||||
|
|
||||||
// Register a handler
|
// Register a handler
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
handler := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -440,11 +450,11 @@ func TestPushNotificationRegistryDuplicateHandlerError(t *testing.T) {
|
|||||||
registry := redis.NewPushNotificationRegistry()
|
registry := redis.NewPushNotificationRegistry()
|
||||||
|
|
||||||
// Test that registering duplicate handlers returns an error
|
// Test that registering duplicate handlers returns an error
|
||||||
handler1 := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler1 := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
handler2 := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler2 := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -478,7 +488,7 @@ func TestPushNotificationRegistrySpecificHandlerOnly(t *testing.T) {
|
|||||||
specificCalled := false
|
specificCalled := false
|
||||||
|
|
||||||
// Register specific handler
|
// Register specific handler
|
||||||
err := registry.RegisterHandler("SPECIFIC_CMD", redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
err := registry.RegisterHandler("SPECIFIC_CMD", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
specificCalled = true
|
specificCalled = true
|
||||||
return true
|
return true
|
||||||
}))
|
}))
|
||||||
@ -525,10 +535,10 @@ func TestPushNotificationProcessorEdgeCases(t *testing.T) {
|
|||||||
|
|
||||||
// Test that disabled processor doesn't process notifications
|
// Test that disabled processor doesn't process notifications
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
processor.RegisterHandlerFunc("TEST_CMD", func(ctx context.Context, notification []interface{}) bool {
|
processor.RegisterHandler("TEST_CMD", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
|
|
||||||
// Even with handlers registered, disabled processor shouldn't process
|
// Even with handlers registered, disabled processor shouldn't process
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -555,7 +565,7 @@ func TestPushNotificationProcessorConvenienceMethods(t *testing.T) {
|
|||||||
|
|
||||||
// Test RegisterHandler convenience method
|
// Test RegisterHandler convenience method
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
handler := redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
handler := newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
handlerCalled = true
|
handlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -565,12 +575,12 @@ func TestPushNotificationProcessorConvenienceMethods(t *testing.T) {
|
|||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test RegisterHandlerFunc convenience method
|
// Test RegisterHandler convenience method with function
|
||||||
funcHandlerCalled := false
|
funcHandlerCalled := false
|
||||||
err = processor.RegisterHandlerFunc("FUNC_CMD", func(ctx context.Context, notification []interface{}) bool {
|
err = processor.RegisterHandler("FUNC_CMD", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
funcHandlerCalled = true
|
funcHandlerCalled = true
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register func handler: %v", err)
|
t.Fatalf("Failed to register func handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -616,16 +626,16 @@ func TestClientPushNotificationEdgeCases(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
// These should not panic even when processor is nil and should return nil error
|
// These should not panic even when processor is nil and should return nil error
|
||||||
err := client.RegisterPushNotificationHandler("TEST", redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.RegisterPushNotificationHandlerFunc("TEST_FUNC", func(ctx context.Context, notification []interface{}) bool {
|
err = client.RegisterPushNotificationHandler("TEST_FUNC", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
t.Errorf("Expected nil error when processor is nil, got: %v", err)
|
||||||
}
|
}
|
||||||
@ -650,7 +660,7 @@ func TestPushNotificationHandlerFunc(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := redis.PushNotificationHandlerFunc(handlerFunc)
|
handler := newTestHandler(handlerFunc)
|
||||||
|
|
||||||
// Test that the adapter works correctly
|
// Test that the adapter works correctly
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -709,36 +719,14 @@ func TestPushNotificationInfoEdgeCases(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPushNotificationConstantsCompleteness(t *testing.T) {
|
func TestPushNotificationConstantsCompleteness(t *testing.T) {
|
||||||
// Test that all expected constants are defined
|
// Test that all Redis Cluster push notification constants are defined
|
||||||
expectedConstants := map[string]string{
|
expectedConstants := map[string]string{
|
||||||
// Cluster notifications
|
// Cluster notifications only (other types removed for simplicity)
|
||||||
redis.PushNotificationMoving: "MOVING",
|
redis.PushNotificationMoving: "MOVING",
|
||||||
redis.PushNotificationMigrating: "MIGRATING",
|
redis.PushNotificationMigrating: "MIGRATING",
|
||||||
redis.PushNotificationMigrated: "MIGRATED",
|
redis.PushNotificationMigrated: "MIGRATED",
|
||||||
redis.PushNotificationFailingOver: "FAILING_OVER",
|
redis.PushNotificationFailingOver: "FAILING_OVER",
|
||||||
redis.PushNotificationFailedOver: "FAILED_OVER",
|
redis.PushNotificationFailedOver: "FAILED_OVER",
|
||||||
|
|
||||||
// Pub/Sub notifications
|
|
||||||
redis.PushNotificationPubSubMessage: "message",
|
|
||||||
redis.PushNotificationPMessage: "pmessage",
|
|
||||||
redis.PushNotificationSubscribe: "subscribe",
|
|
||||||
redis.PushNotificationUnsubscribe: "unsubscribe",
|
|
||||||
redis.PushNotificationPSubscribe: "psubscribe",
|
|
||||||
redis.PushNotificationPUnsubscribe: "punsubscribe",
|
|
||||||
|
|
||||||
// Stream notifications
|
|
||||||
redis.PushNotificationXRead: "xread",
|
|
||||||
redis.PushNotificationXReadGroup: "xreadgroup",
|
|
||||||
|
|
||||||
// Keyspace notifications
|
|
||||||
redis.PushNotificationKeyspace: "keyspace",
|
|
||||||
redis.PushNotificationKeyevent: "keyevent",
|
|
||||||
|
|
||||||
// Module notifications
|
|
||||||
redis.PushNotificationModule: "module",
|
|
||||||
|
|
||||||
// Custom notifications
|
|
||||||
redis.PushNotificationCustom: "custom",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for constant, expected := range expectedConstants {
|
for constant, expected := range expectedConstants {
|
||||||
@ -767,7 +755,7 @@ func TestPushNotificationRegistryConcurrency(t *testing.T) {
|
|||||||
for j := 0; j < numOperations; j++ {
|
for j := 0; j < numOperations; j++ {
|
||||||
// Register handler (ignore errors in concurrency test)
|
// Register handler (ignore errors in concurrency test)
|
||||||
command := fmt.Sprintf("CMD_%d_%d", id, j)
|
command := fmt.Sprintf("CMD_%d_%d", id, j)
|
||||||
registry.RegisterHandler(command, redis.PushNotificationHandlerFunc(func(ctx context.Context, notification []interface{}) bool {
|
registry.RegisterHandler(command, newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -815,9 +803,9 @@ func TestPushNotificationProcessorConcurrency(t *testing.T) {
|
|||||||
for j := 0; j < numOperations; j++ {
|
for j := 0; j < numOperations; j++ {
|
||||||
// Register handlers (ignore errors in concurrency test)
|
// Register handlers (ignore errors in concurrency test)
|
||||||
command := fmt.Sprintf("PROC_CMD_%d_%d", id, j)
|
command := fmt.Sprintf("PROC_CMD_%d_%d", id, j)
|
||||||
processor.RegisterHandlerFunc(command, func(ctx context.Context, notification []interface{}) bool {
|
processor.RegisterHandler(command, newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
|
|
||||||
// Handle notifications
|
// Handle notifications
|
||||||
notification := []interface{}{command, "data"}
|
notification := []interface{}{command, "data"}
|
||||||
@ -869,9 +857,9 @@ func TestPushNotificationClientConcurrency(t *testing.T) {
|
|||||||
for j := 0; j < numOperations; j++ {
|
for j := 0; j < numOperations; j++ {
|
||||||
// Register handlers concurrently (ignore errors in concurrency test)
|
// Register handlers concurrently (ignore errors in concurrency test)
|
||||||
command := fmt.Sprintf("CLIENT_CMD_%d_%d", id, j)
|
command := fmt.Sprintf("CLIENT_CMD_%d_%d", id, j)
|
||||||
client.RegisterPushNotificationHandlerFunc(command, func(ctx context.Context, notification []interface{}) bool {
|
client.RegisterPushNotificationHandler(command, newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
|
|
||||||
// Access processor
|
// Access processor
|
||||||
processor := client.GetPushNotificationProcessor()
|
processor := client.GetPushNotificationProcessor()
|
||||||
@ -912,10 +900,10 @@ func TestPushNotificationConnectionHealthCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register a handler for testing
|
// Register a handler for testing
|
||||||
err := client.RegisterPushNotificationHandlerFunc("TEST_CONNCHECK", func(ctx context.Context, notification []interface{}) bool {
|
err := client.RegisterPushNotificationHandler("TEST_CONNCHECK", newTestHandler(func(ctx context.Context, notification []interface{}) bool {
|
||||||
t.Logf("Received test notification: %v", notification)
|
t.Logf("Received test notification: %v", notification)
|
||||||
return true
|
return true
|
||||||
})
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to register handler: %v", err)
|
t.Fatalf("Failed to register handler: %v", err)
|
||||||
}
|
}
|
||||||
|
18
redis.go
18
redis.go
@ -833,15 +833,6 @@ func (c *Client) RegisterPushNotificationHandler(command string, handler PushNot
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterPushNotificationHandlerFunc registers a function as a handler for a specific push notification command.
|
|
||||||
// Returns an error if a handler is already registered for this command.
|
|
||||||
func (c *Client) RegisterPushNotificationHandlerFunc(command string, handlerFunc func(ctx context.Context, notification []interface{}) bool) error {
|
|
||||||
if c.pushProcessor != nil {
|
|
||||||
return c.pushProcessor.RegisterHandlerFunc(command, handlerFunc)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPushNotificationProcessor returns the push notification processor.
|
// GetPushNotificationProcessor returns the push notification processor.
|
||||||
func (c *Client) GetPushNotificationProcessor() *PushNotificationProcessor {
|
func (c *Client) GetPushNotificationProcessor() *PushNotificationProcessor {
|
||||||
return c.pushProcessor
|
return c.pushProcessor
|
||||||
@ -1014,15 +1005,6 @@ func (c *Conn) RegisterPushNotificationHandler(command string, handler PushNotif
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterPushNotificationHandlerFunc registers a function as a handler for a specific push notification command.
|
|
||||||
// Returns an error if a handler is already registered for this command.
|
|
||||||
func (c *Conn) RegisterPushNotificationHandlerFunc(command string, handlerFunc func(ctx context.Context, notification []interface{}) bool) error {
|
|
||||||
if c.pushProcessor != nil {
|
|
||||||
return c.pushProcessor.RegisterHandlerFunc(command, handlerFunc)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPushNotificationProcessor returns the push notification processor.
|
// GetPushNotificationProcessor returns the push notification processor.
|
||||||
func (c *Conn) GetPushNotificationProcessor() *PushNotificationProcessor {
|
func (c *Conn) GetPushNotificationProcessor() *PushNotificationProcessor {
|
||||||
return c.pushProcessor
|
return c.pushProcessor
|
||||||
|
Reference in New Issue
Block a user