fix: add mutex to mockLogger in errorbus tests to prevent race conditions
Some checks failed
CI / Test (pull_request) Successful in 22s
CI / Lint (pull_request) Failing after 17s
CI / Build (pull_request) Successful in 12s
CI / Format Check (pull_request) Successful in 2s

The mockLogger's errors slice was being accessed concurrently from
multiple goroutines (the error bus consumer and the test goroutine),
causing race conditions when running tests with the race detector.

Added sync.Mutex to protect the errors slice and proper locking when
accessing it in test assertions.
This commit is contained in:
2025-11-05 21:11:14 +01:00
parent 3f3545ba15
commit 7ffacb6620
3 changed files with 22 additions and 7 deletions

View File

@@ -150,8 +150,10 @@ When working on this project, follow this workflow:
- Use descriptive branch names (e.g., `feature/epic1-http-server`, `bugfix/auth-token-expiry`, `enhancement/rate-limiting`) - Use descriptive branch names (e.g., `feature/epic1-http-server`, `bugfix/auth-token-expiry`, `enhancement/rate-limiting`)
- Branch names should follow the pattern: `{type}/{epic}-{short-description}` or `{type}/{story-id}-{short-description}` - Branch names should follow the pattern: `{type}/{epic}-{short-description}` or `{type}/{story-id}-{short-description}`
- **ALWAYS create a commit** after successfully implementing a feature that: - **ALWAYS create a commit** after successfully implementing a feature that:
- ✅ Builds successfully (`go build` passes) - ✅ Builds successfully (`make build` passes)
- ✅ Tests pass (`go test` passes) - ✅ Tests pass (`make test` passes)
- ✅ Lint pass (`make lint` passes)
- ✅ fmt-check pass (`make fmt-check` passes)
- ✅ Meets all acceptance criteria from the story - ✅ Meets all acceptance criteria from the story
- Commit messages should be clear and descriptive, referencing the story/epic when applicable - Commit messages should be clear and descriptive, referencing the story/epic when applicable
- Never commit directly to `main` branch - Never commit directly to `main` branch

View File

@@ -49,11 +49,11 @@ help:
# Development commands # Development commands
test: test:
@echo "Running tests..." @echo "Running tests..."
CGO_ENABLED=1 $(GO) test -v ./... CGO_ENABLED=1 $(GO) test -v -race ./...
test-coverage: test-coverage:
@echo "Running tests with coverage..." @echo "Running tests with coverage..."
CGO_ENABLED=1 $(GO) test -v -coverprofile=coverage.out ./... CGO_ENABLED=1 $(GO) test -v -race -coverprofile=coverage.out ./...
$(GO) tool cover -html=coverage.out -o coverage.html $(GO) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html" @echo "Coverage report generated: coverage.html"

View File

@@ -3,6 +3,7 @@ package errorbus
import ( import (
"context" "context"
"errors" "errors"
"sync"
"testing" "testing"
"time" "time"
@@ -61,7 +62,10 @@ func TestChannelBus_Publish(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Verify error was logged // Verify error was logged
if len(mockLogger.errors) == 0 { mockLogger.mu.Lock()
errorCount := len(mockLogger.errors)
mockLogger.mu.Unlock()
if errorCount == 0 {
t.Error("Expected error to be logged") t.Error("Expected error to be logged")
} }
@@ -84,7 +88,10 @@ func TestChannelBus_Publish_NilError(t *testing.T) {
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
// Verify nil error was not logged // Verify nil error was not logged
if len(mockLogger.errors) > 0 { mockLogger.mu.Lock()
errorCount := len(mockLogger.errors)
mockLogger.mu.Unlock()
if errorCount > 0 {
t.Error("Expected nil error to be ignored") t.Error("Expected nil error to be ignored")
} }
@@ -107,7 +114,10 @@ func TestChannelBus_Publish_WithContext(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Verify error was logged with context // Verify error was logged with context
if len(mockLogger.errors) == 0 { mockLogger.mu.Lock()
errorCount := len(mockLogger.errors)
mockLogger.mu.Unlock()
if errorCount == 0 {
t.Error("Expected error to be logged") t.Error("Expected error to be logged")
} }
@@ -181,12 +191,15 @@ func TestChannelBus_ChannelFull(t *testing.T) {
// mockLogger implements logger.Logger for testing. // mockLogger implements logger.Logger for testing.
type mockLogger struct { type mockLogger struct {
errors []string errors []string
mu sync.Mutex
} }
func (m *mockLogger) Debug(msg string, fields ...logger.Field) {} func (m *mockLogger) Debug(msg string, fields ...logger.Field) {}
func (m *mockLogger) Info(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) Warn(msg string, fields ...logger.Field) {}
func (m *mockLogger) Error(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) m.errors = append(m.errors, msg)
} }