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`)
- 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:
- ✅ Builds successfully (`go build` passes)
- ✅ Tests pass (`go test` passes)
- ✅ Builds successfully (`make build` 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
- Commit messages should be clear and descriptive, referencing the story/epic when applicable
- Never commit directly to `main` branch

View File

@@ -49,11 +49,11 @@ help:
# Development commands
test:
@echo "Running tests..."
CGO_ENABLED=1 $(GO) test -v ./...
CGO_ENABLED=1 $(GO) test -v -race ./...
test-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
@echo "Coverage report generated: coverage.html"

View File

@@ -3,6 +3,7 @@ package errorbus
import (
"context"
"errors"
"sync"
"testing"
"time"
@@ -61,7 +62,10 @@ func TestChannelBus_Publish(t *testing.T) {
time.Sleep(100 * time.Millisecond)
// 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")
}
@@ -84,7 +88,10 @@ func TestChannelBus_Publish_NilError(t *testing.T) {
time.Sleep(50 * time.Millisecond)
// 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")
}
@@ -107,7 +114,10 @@ func TestChannelBus_Publish_WithContext(t *testing.T) {
time.Sleep(100 * time.Millisecond)
// 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")
}
@@ -181,12 +191,15 @@ func TestChannelBus_ChannelFull(t *testing.T) {
// 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)
}