- Use typed context key instead of string in errorbus test to avoid collisions - Remove unused imports (health.HealthChecker, trace.TracerProvider) from test files - Simplify interface verification checks (removed unnecessary type assertions) All linting errors resolved. make lint now passes.
215 lines
4.3 KiB
Go
215 lines
4.3 KiB
Go
package errorbus
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
|
)
|
|
|
|
func TestNewChannelBus(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 100)
|
|
|
|
if bus == nil {
|
|
t.Fatal("Expected bus, got nil")
|
|
}
|
|
|
|
if bus.errors == nil {
|
|
t.Error("Expected errors channel, got nil")
|
|
}
|
|
|
|
if bus.logger == nil {
|
|
t.Error("Expected logger, got nil")
|
|
}
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
func TestNewChannelBus_DefaultBufferSize(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 0)
|
|
|
|
if bus == nil {
|
|
t.Fatal("Expected bus, got nil")
|
|
}
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
func TestChannelBus_Publish(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 10)
|
|
|
|
testErr := errors.New("test error")
|
|
ctx := context.Background()
|
|
|
|
// Publish error
|
|
bus.Publish(ctx, testErr)
|
|
|
|
// Wait a bit for the error to be processed
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Verify error was logged
|
|
mockLogger.mu.Lock()
|
|
errorCount := len(mockLogger.errors)
|
|
mockLogger.mu.Unlock()
|
|
if errorCount == 0 {
|
|
t.Error("Expected error to be logged")
|
|
}
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
func TestChannelBus_Publish_NilError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 10)
|
|
|
|
ctx := context.Background()
|
|
|
|
// Publish nil error (should be ignored)
|
|
bus.Publish(ctx, nil)
|
|
|
|
// Wait a bit
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Verify nil error was not logged
|
|
mockLogger.mu.Lock()
|
|
errorCount := len(mockLogger.errors)
|
|
mockLogger.mu.Unlock()
|
|
if errorCount > 0 {
|
|
t.Error("Expected nil error to be ignored")
|
|
}
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
func TestChannelBus_Publish_WithContext(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 10)
|
|
|
|
testErr := errors.New("test error")
|
|
type contextKey string
|
|
const requestIDKey contextKey = "request_id"
|
|
ctx := context.WithValue(context.Background(), requestIDKey, "test-request-id")
|
|
|
|
bus.Publish(ctx, testErr)
|
|
|
|
// Wait for processing
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Verify error was logged with context
|
|
mockLogger.mu.Lock()
|
|
errorCount := len(mockLogger.errors)
|
|
mockLogger.mu.Unlock()
|
|
if errorCount == 0 {
|
|
t.Error("Expected error to be logged")
|
|
}
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
func TestChannelBus_Close(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 10)
|
|
|
|
// Publish some errors
|
|
for i := 0; i < 5; i++ {
|
|
bus.Publish(context.Background(), errors.New("test error"))
|
|
}
|
|
|
|
// Close and wait
|
|
if err := bus.Close(); err != nil {
|
|
t.Errorf("Close failed: %v", err)
|
|
}
|
|
|
|
// Verify channel is closed
|
|
select {
|
|
case <-bus.errors:
|
|
// Channel is closed, this is expected
|
|
default:
|
|
t.Error("Expected errors channel to be closed")
|
|
}
|
|
}
|
|
|
|
func TestChannelBus_Close_MultipleTimes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
bus := NewChannelBus(mockLogger, 10)
|
|
|
|
// Close first time
|
|
if err := bus.Close(); err != nil {
|
|
t.Errorf("First Close failed: %v", err)
|
|
}
|
|
|
|
// Close second time should be safe (uses sync.Once)
|
|
// The channel is already closed, but Close() should handle this gracefully
|
|
if err := bus.Close(); err != nil {
|
|
t.Errorf("Second Close failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestChannelBus_ChannelFull(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockLogger := &mockLogger{}
|
|
// Use small buffer to test channel full scenario
|
|
bus := NewChannelBus(mockLogger, 1)
|
|
|
|
// Fill the channel
|
|
bus.Publish(context.Background(), errors.New("error1"))
|
|
|
|
// This should not block (channel is full, should log directly)
|
|
bus.Publish(context.Background(), errors.New("error2"))
|
|
|
|
// Wait a bit
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Clean up
|
|
_ = bus.Close()
|
|
}
|
|
|
|
// mockLogger implements logger.Logger for testing.
|
|
type mockLogger struct {
|
|
errors []string
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func (m *mockLogger) Debug(msg string, fields ...logger.Field) {}
|
|
func (m *mockLogger) Info(msg string, fields ...logger.Field) {}
|
|
func (m *mockLogger) Warn(msg string, fields ...logger.Field) {}
|
|
func (m *mockLogger) Error(msg string, fields ...logger.Field) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.errors = append(m.errors, msg)
|
|
}
|
|
|
|
func (m *mockLogger) With(fields ...logger.Field) logger.Logger {
|
|
return m
|
|
}
|
|
|
|
func (m *mockLogger) WithContext(ctx context.Context) logger.Logger {
|
|
return m
|
|
}
|