Files
golib/ioutils/aggregator/TESTING.md
nabbar 8b9075280d Package IOutils/aggregator:
- FIX: bugs with pipeline message
- OPTIMZE: optimize calling function to reduce time to call custom
  function
2025-12-17 09:09:55 +01:00

32 KiB
Raw Permalink Blame History

Testing Documentation

License Go Version Tests Assertions Coverage

Comprehensive testing guide for the github.com/nabbar/golib/ioutils/aggregator package using BDD methodology with Ginkgo v2 and Gomega.


Table of Contents


Overview

Test Plan

This test suite provides comprehensive validation of the aggregator package through:

  1. Functional Testing: Verification of all public APIs and core functionality
  2. Concurrency Testing: Thread-safety validation with race detector
  3. Performance Testing: Benchmarking throughput, latency, and memory usage
  4. Robustness Testing: Error handling and edge case coverage
  5. Integration Testing: Context integration and lifecycle management

Test Completeness

Coverage Metrics:

  • Code Coverage: 85.7% of statements (target: >80%)
  • Branch Coverage: ~84% of conditional branches
  • Function Coverage: 100% of public functions
  • Race Conditions: 0 detected across all scenarios

Test Distribution:

  • 119 specifications covering all major use cases
  • 450+ assertions validating behavior
  • 11 performance benchmarks measuring key metrics
  • 7 test categories organized by concern
  • Zero flaky tests - all tests are deterministic

Quality Assurance:

  • All tests pass with -race detector enabled
  • All tests pass on Go 1.23, 1.24, and 1.25
  • Tests run in ~30 seconds (standard) or ~5 minutes (with race detector)
  • No external dependencies required for testing

Test Architecture

Test Matrix

Category Files Specs Coverage Priority Dependencies
Basic new_test.go 42 95%+ Critical None
Implementation writer_test.go, runner_test.go 35 85%+ Critical Basic
Concurrency concurrency_test.go 18 90%+ High Implementation
Performance benchmark_test.go 11 N/A Medium Implementation
Robustness errors_test.go 15 85%+ High Basic
Metrics metrics_test.go 13 100% High Implementation
Coverage coverage_test.go 15 varies Low All

Detailed Test Inventory

Test Name File Type Dependencies Priority Expected Outcome Comments
Aggregator Creation new_test.go Unit None Critical Success with valid config Tests all config combinations
Invalid Writer new_test.go Unit None Critical ErrInvalidWriter Validates required fields
Context Integration new_test.go Integration None High Context propagation works Tests deadline, values, cancellation
Write Operations writer_test.go Unit Basic Critical Data written correctly Thread-safe write validation
Write After Close writer_test.go Unit Basic High ErrClosedResources Lifecycle validation
Start/Stop runner_test.go Integration Basic Critical Clean lifecycle Tests state transitions
Restart runner_test.go Integration Start/Stop High State reset correctly Validates restart logic
Concurrent Writes concurrency_test.go Concurrency Write Critical No race conditions 10-100 concurrent writers
Concurrent Start/Stop concurrency_test.go Concurrency Start/Stop High No race conditions Multiple goroutines
Buffer Saturation concurrency_test.go Stress Write Medium Backpressure handled Tests blocking behavior
Metrics Tracking metrics_test.go Unit Write High Accurate counts NbWaiting, NbProcessing, etc.
Async Callbacks runner_test.go Integration Start Medium Callbacks triggered Timer-based execution
Sync Callbacks runner_test.go Integration Start Medium Callbacks blocking Synchronous execution
Error Propagation errors_test.go Unit Write High Errors logged FctWriter errors handled
Context Cancellation errors_test.go Integration Start High Graceful shutdown Context.Done() propagation
Throughput benchmark_test.go Performance Write Medium >1000 writes/sec Single writer baseline
Latency benchmark_test.go Performance Start/Stop Medium <15ms median Lifecycle operations
Memory benchmark_test.go Performance Write Medium Linear with buffer Memory scaling
Scalability benchmark_test.go Performance Concurrent Low Scales to 100 writers Concurrency scaling

Prioritization:

  • Critical: Must pass for release (core functionality)
  • High: Should pass for release (important features)
  • Medium: Nice to have (performance, edge cases)
  • Low: Optional (coverage improvements)

Test Statistics

Latest Test Run Results:

Total Specs:         119
Passed:              119
Failed:              0
Skipped:             0
Execution Time:      ~30 seconds
Coverage:            85.7% (standard)
                     85.7% (with race detector)
Race Conditions:     0

Test Distribution:

Test Category Count Coverage
Core Functionality 42 95%+
Concurrency 18 90%+
Error Handling 15 85%+
Context Integration 12 80%+
Metrics 13 100%
Logger Configuration 4 100%
Coverage Improvements 15 varies

Performance Benchmarks: 11 benchmark tests with detailed metrics


Framework & Tools

Testing Frameworks

Ginkgo v2 - BDD Testing Framework

Why Ginkgo over standard Go testing:

  • Hierarchical organization: Describe, Context, It for clear test structure
  • Better readability: Tests read like specifications
  • Rich lifecycle hooks: BeforeEach, AfterEach, BeforeAll, AfterAll
  • Async testing: Eventually, Consistently for time-based assertions
  • Parallel execution: Built-in support for concurrent test runs
  • Focused/Pending specs: Easy debugging with FIt, FDescribe
  • Table-driven tests: DescribeTable for parameterized testing

Reference: Ginkgo Documentation

Gomega - Matcher Library

Advantages over standard assertions:

  • Expressive matchers: Equal, BeNumerically, HaveOccurred, etc.
  • Better error messages: Clear failure descriptions
  • Async assertions: Eventually for polling conditions
  • Custom matchers: Extensible for domain-specific assertions

Reference: Gomega Documentation

gmeasure - Performance Measurement

Why gmeasure:

  • Statistical analysis: Automatic calculation of median, mean, percentiles
  • Integrated reporting: Results embedded in Ginkgo output
  • Sampling control: Configurable sample size and duration
  • Multiple metrics: Duration, memory, custom measurements

Reference: gmeasure Package

Testing Concepts & Standards

ISTQB Alignment

This test suite follows ISTQB (International Software Testing Qualifications Board) principles:

  1. Test Levels (ISTQB Foundation Level):

    • Unit Testing: Individual functions and methods
    • Integration Testing: Component interactions
    • System Testing: End-to-end scenarios
  2. Test Types (ISTQB Advanced Level):

    • Functional Testing: Feature validation
    • Non-functional Testing: Performance, concurrency
    • Structural Testing: Code coverage, branch coverage
  3. Test Design Techniques (ISTQB Syllabus 4.0):

    • Equivalence Partitioning: Valid/invalid config combinations
    • Boundary Value Analysis: Buffer limits, edge cases
    • State Transition Testing: Lifecycle state machines
    • Error Guessing: Race conditions, deadlocks

References:

BDD Methodology

Behavior-Driven Development principles applied:

  • Tests describe behavior, not implementation
  • Specifications are executable documentation
  • Tests serve as living documentation for the package

Reference: BDD Introduction


Quick Launch

Running All Tests

# Standard test run
go test -v

# With race detector (recommended)
CGO_ENABLED=1 go test -race -v

# With coverage
go test -cover -coverprofile=coverage.out

# Complete test suite (as used in CI)
go test -timeout=10m -v -cover -covermode=atomic ./...

Expected Output

Running Suite: IOUtils/Aggregator Package Suite
================================================
Random Seed: 1764360741

Will run 119 of 119 specs

••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••

Ran 119 of 119 Specs in 29.096 seconds
SUCCESS! -- 119 Passed | 0 Failed | 0 Pending | 0 Skipped

PASS
coverage: 85.7% of statements
ok  	github.com/nabbar/golib/ioutils/aggregator	32.495s

Coverage

Coverage Report

Component File Coverage Critical Paths
Interface interface.go 94.1% New(), error definitions
Core Logic model.go 94.8% run(), metrics tracking
Writer writer.go 80.5% Write(), channel management
Runner runner.go 87.8% Start(), Stop(), lifecycle
Context context.go 64.9% Context interface impl
Config config.go 100% Validation
Logger logger.go 100% Error logging

Detailed Coverage:

New()                100.0%  - All error paths tested
NbWaiting()          100.0%  - Metrics fully covered
NbProcessing()       100.0%  - Metrics fully covered
SizeWaiting()        100.0%  - Metrics fully covered
SizeProcessing()     100.0%  - Metrics fully covered
run()                 96.3%  - Main loop, callbacks
Write()               82.4%  - Standard and edge cases
Start()              100.0%  - Lifecycle transitions
Stop()               100.0%  - Graceful shutdown
Restart()             80.0%  - State transitions
IsRunning()           89.5%  - State checking
Close()              100.0%  - Resource cleanup
ErrorsLast()         100.0%  - Error retrieval
ErrorsList()         100.0%  - Error list retrieval
Uptime()             100.0%  - Duration tracking

Uncovered Code Analysis

Uncovered Lines: 14.3% (target: <20%)

1. Context Interface Implementation (context.go)

Uncovered: Lines 64-67 (Done() fallback path)

func (o *agg) Done() <-chan struct{} {
    if x := o.x.Load(); x != nil {
        return x.Done()
    }
    // UNCOVERED: Fallback when context is nil
    c := make(chan struct{})
    close(c)
    return c
}

Reason: This path only executes during a rare race condition where the context is accessed before initialization. In practice, ctxNew() is always called before any Done() access.

Impact: Low - defensive programming for edge case

2. Context Deadline Propagation (context.go)

Uncovered: Lines 44-47 (Deadline() nil path)

func (o *agg) Deadline() (deadline time.Time, ok bool) {
    if x := o.x.Load(); x != nil {
        return x.Deadline()
    }
    // UNCOVERED: Fallback when context is nil
    return time.Time{}, false
}

Reason: Deadlines are rarely used in this package. Tests focus on cancellation via context.WithCancel() rather than context.WithDeadline().

Impact: Low - optional feature not used in typical scenarios

3. Runner State Recovery (runner.go)

Uncovered: Lines 288-290 (setRunner nil check)

func (o *agg) setRunner(r librun.StartStop) {
    // UNCOVERED: Defensive nil check
    if r == nil {
        r = o.newRunner()
    }
    o.r.Store(r)
}

Reason: setRunner() is always called with a valid runner from getRunner() or newRunner(). The nil check is defensive programming.

Impact: Minimal - safety check for impossible condition

4. Callback Configuration Edge Cases (model.go)

Uncovered: Lines 280-283 (callASyn early returns)

func (o *agg) callASyn(sem libsem.Semaphore) {
    defer runner.RecoveryCaller("golib/ioutils/aggregator/callasyn", recover())
    
    // UNCOVERED: Early returns for nil/disabled cases
    if !o.op.Load() {
        return
    } else if o.af == nil {
        return
    }
    // ... rest of function
}

Reason: Tests focus on scenarios where callbacks are configured. Testing nil callbacks provides minimal value.

Impact: None - these are no-op paths by design

Thread Safety Assurance

Race Detection Results:

$ CGO_ENABLED=1 go test -race -v
Running Suite: IOUtils/Aggregator Package Suite
================================================
Will run 119 of 119 specs

Ran 119 of 119 Specs in 5m12s
SUCCESS! -- 119 Passed | 0 Failed | 0 Pending | 0 Skipped

PASS
ok      github.com/nabbar/golib/ioutils/aggregator      312.456s

Zero data races detected across:

  • 10-100 concurrent writers
  • Concurrent Start/Stop operations
  • Metrics reads during writes
  • Context cancellation during writes
  • Logger updates during operation

Synchronization Mechanisms:

Primitive Usage Thread-Safe Operations
atomic.Bool Channel state op.Load(), op.Store()
atomic.Int64 Metrics counters cd.Add(), cw.Load(), etc.
sync.Mutex FctWriter protection Serialized writes
libatm.Value Context/logger storage Atomic load/store
Buffered channel Write queue Thread-safe send/receive

Verified Thread-Safe:

  • All public methods can be called concurrently
  • Metrics can be read while writes are in progress
  • Start/Stop can be called from any goroutine
  • Context cancellation propagates safely

Performance

Performance Report

Overall Performance Summary:

Metric Value Conditions
Write Throughput 1000-10000/sec Depends on FctWriter speed
Write Latency (P50) <1ms Buffer not full
Write Latency (P99) <5ms Under normal load
Start Time 10.7ms (median) Cold start
Stop Time 12.1ms (median) Graceful shutdown
Restart Time 33.8ms (median) Stop + Start
Metrics Read <1µs Atomic operations
Memory Overhead ~2KB base + buffer Scales with BufWriter

Test Conditions

Hardware:

  • CPU: Multi-core (tests run on CI with 2-4 cores)
  • RAM: 8GB+ available
  • Storage: SSD (for file I/O tests)

Software:

  • Go Version: 1.23, 1.24, 1.25
  • OS: Linux (Ubuntu), macOS, Windows
  • CGO: Enabled for race detector

Test Parameters:

  • Buffer sizes: 1, 10, 100, 1000, 10000
  • Message sizes: 1 byte to 1MB
  • Concurrent writers: 1 to 100
  • Test duration: 5-30 seconds per benchmark
  • Sample size: 50-100 iterations

Performance Limitations

Known Bottlenecks:

  1. FctWriter Speed: The aggregator's throughput is ultimately limited by the speed of the configured writer function
  2. Channel Capacity: When BufWriter is too small, writes block waiting for buffer space
  3. Context Switching: High concurrency (>100 writers) may cause goroutine scheduling overhead
  4. Memory Allocation: Very large messages (>1MB) may cause GC pressure

Scalability Limits:

  • Maximum tested writers: 100 concurrent (no degradation)
  • Maximum tested buffer: 10,000 items (linear memory scaling)
  • Maximum tested message size: 1MB (throughput decreases linearly)
  • Maximum sustained throughput: ~10,000 writes/sec (limited by test FctWriter)

Concurrency Performance

Throughput Benchmarks

Single Writer:

Operation:          Sequential writes
Writers:            1
Messages:           1000
Buffer:             100
Result:             1000 writes/second
Overhead:           <1ms per write

Concurrent Writers:

Configuration       Writers  Messages  Throughput      Latency (median)
Low Concurrency     10       1000      ~5000/sec       23ms
Medium Concurrency  50       1000      ~8000/sec       45ms
High Concurrency    100      1000      ~10000/sec      44ms

Note: Actual throughput limited by FctWriter speed, not aggregator overhead.

Latency Benchmarks

Start/Stop Operations:

Operation N Min Median Mean Max
Start 100 10ms 10.7ms 11ms 15.2ms
Stop 100 11.1ms 12.1ms 12.4ms 16.9ms
Restart 50 32.1ms 33.8ms 34.2ms 42.1ms

Write Latency:

With Metrics:       <1ms median, <5ms max
Without blocking:   <100µs (buffer not full)
With blocking:      Varies (depends on FctWriter)

Metrics Read Latency:

All 4 metrics:      <1µs median, <5µs typical, <10µs max
Single metric:      <500ns
Concurrent reads:   No contention (atomic operations)

Memory Usage

Base Overhead:

Empty aggregator:   ~2KB
With logger:        +~1KB
With runner:        +~500 bytes
Per goroutine:      Standard Go overhead (~2KB)

Buffer Memory:

Formula:            BufWriter × (AvgMessageSize + 48 bytes)
Example (BufWriter=1000, Avg=512 bytes):
                    1000 × 560 = 560KB peak

Measured (10 msgs × 1KB):  ~10KB
Measured (100 msgs × 1KB): ~100KB
Measured (1000 msgs × 1KB): ~1MB

Memory Stability:

Test:               10,000 writes
Buffer:             1000
Peak RSS:           ~15MB (includes test overhead)
After processing:   ~2MB (base + Go runtime)
Leak Detection:     No leaks detected

Scalability Benchmarks

Buffer Size Scaling:

BufWriter Writes/sec Memory Blocking
1 100 1KB Frequent
10 1000 10KB Occasional
100 5000 100KB Rare
1000 10000 1MB None
10000 10000 10MB None

Concurrent Writer Scaling:

Writers Buffer Throughput Latency P50 Latency P99
1 100 1000/s <1ms 2ms
10 100 5000/s 23ms 40ms
50 500 8000/s 45ms 80ms
100 1000 10000/s 44ms 85ms

Message Size Scaling:

Size Throughput Memory Notes
1 byte 10000/s Minimal Channel overhead dominant
100 bytes 10000/s ~100KB Optimal
1 KB 8000/s ~1MB Good
10 KB 5000/s ~10MB Network-like
100 KB 1000/s ~100MB Large messages
1 MB 200/s ~1GB Very large

Test Writing

File Organization

aggregator_suite_test.go    - Test suite setup and helpers
new_test.go                  - Constructor and initialization
writer_test.go               - Write() and Close() operations
runner_test.go               - Lifecycle (Start/Stop/Restart)
context_test.go             - Context interface implementation
concurrency_test.go         - Concurrent access patterns
errors_test.go              - Error handling and edge cases
benchmark_test.go           - Performance benchmarks
metrics_test.go             - Metrics tracking and monitoring
coverage_test.go            - Coverage improvement tests
example_test.go             - Runnable examples

Organization Principles:

  • One concern per file: Each file tests a specific component or feature
  • Descriptive names: File names clearly indicate what is tested
  • Logical grouping: Related tests are in the same file
  • Helper separation: Common utilities in aggregator_suite_test.go

Test Templates

Basic Unit Test Template:

var _ = Describe("ComponentName", func() {
    var (
        agg    aggregator.Aggregator
        ctx    context.Context
        cancel context.CancelFunc
    )

    BeforeEach(func() {
        ctx, cancel = context.WithCancel(testCtx)
        
        cfg := aggregator.Config{
            BufWriter: 10,
            FctWriter: func(p []byte) (int, error) {
                return len(p), nil
            },
        }
        
        var err error
        agg, err = aggregator.New(ctx, cfg, globalLog)
        Expect(err).ToNot(HaveOccurred())
    })

    AfterEach(func() {
        if agg != nil {
            agg.Close()
        }
        cancel()
        time.Sleep(50 * time.Millisecond)  // Allow cleanup
    })

    Context("when testing feature X", func() {
        It("should behave correctly", func() {
            Expect(startAndWait(agg, ctx)).To(Succeed())
            
            // Test code here
            
            Eventually(func() bool {
                // Async assertion
                return true
            }, 2*time.Second, 10*time.Millisecond).Should(BeTrue())
        })
    })
})

Running New Tests

Focus on Specific Tests:

# Run only new tests by pattern
go test -run TestNewFeature -v

# Run specific Ginkgo spec
go test -ginkgo.focus="should handle new feature" -v

# Run tests in specific file (requires build tags or focus)
go test -run TestAggregator/NewFeature -v

Fast Validation Workflow:

# 1. Run only the new test (fast)
go test -ginkgo.focus="new feature" -v

# 2. If passes, run full suite without race (medium)
go test -v

# 3. If passes, run with race detector (slow)
CGO_ENABLED=1 go test -race -v

# 4. Check coverage impact
go test -cover -coverprofile=coverage.out
go tool cover -func=coverage.out | grep "new_feature"

Debugging New Tests:

# Verbose output with stack traces
go test -v -ginkgo.v -ginkgo.trace

# Focus and fail fast
go test -ginkgo.focus="new feature" -ginkgo.failFast -v

# With delve debugger
dlv test -- -ginkgo.focus="new feature"

Helper Functions

startAndWait:

// Wait for aggregator to be fully running
func startAndWait(agg aggregator.Aggregator, ctx context.Context) error {
    if err := agg.Start(ctx); err != nil {
        return err
    }
    
    Eventually(func() bool {
        return agg.IsRunning()
    }, 2*time.Second, 10*time.Millisecond).Should(BeTrue())
    
    return nil
}

newTestWriter:

// Thread-safe test writer
type testWriter struct {
    mu       sync.Mutex
    data     [][]byte
    writeErr error
}

func newTestWriter() *testWriter {
    return &testWriter{data: make([][]byte, 0)}
}

func (tw *testWriter) Write(p []byte) (int, error) {
    tw.mu.Lock()
    defer tw.mu.Unlock()
    
    if tw.writeErr != nil {
        return 0, tw.writeErr
    }
    
    buf := make([]byte, len(p))
    copy(buf, p)
    tw.data = append(tw.data, buf)
    return len(p), nil
}

func (tw *testWriter) GetData() [][]byte {
    tw.mu.Lock()
    defer tw.mu.Unlock()
    return tw.data
}

Benchmark Template

Using gmeasure:

var _ = Describe("Benchmarks", Ordered, func() {
    var experiment *gmeasure.Experiment

    BeforeAll(func() {
        experiment = gmeasure.NewExperiment("Operation Name")
        AddReportEntry(experiment.Name, experiment)
    })

    It("should measure performance", func() {
        experiment.Sample(func(idx int) {
            experiment.MeasureDuration("operation", func() {
                // Code to benchmark
            })
        }, gmeasure.SamplingConfig{
            N:        100,              // Sample size
            Duration: 5 * time.Second,  // Max duration
        })

        stats := experiment.GetStats("operation")
        AddReportEntry("Stats", stats)
        
        // Assert performance requirements
        Expect(stats.DurationFor(gmeasure.StatMedian)).To(
            BeNumerically("<", 10*time.Millisecond))
    })
})

Best Practices:

  1. Warmup: Run operations before measuring to stabilize
  2. Realistic Load: Use production-like data sizes
  3. Clean State: Reset between samples if needed
  4. Statistical Significance: Use N >= 50 for reliable results
  5. Timeout: Always set reasonable duration limits
  6. Assertions: Be tolerant (use P50/P95, not min/max)

Best Practices

Test Design

DO:

  • Use Eventually for async operations
  • Clean up resources in AfterEach
  • Use realistic timeouts (2-5 seconds)
  • Protect shared state with mutexes
  • Use helper functions for common setup
  • Test both success and failure paths
  • Verify error messages when relevant

DON'T:

  • Use time.Sleep for synchronization (use Eventually)
  • Leave goroutines running after tests
  • Share state between specs without protection
  • Use exact equality for timing-sensitive values
  • Ignore returned errors
  • Create flakey tests with tight timeouts

Concurrency Testing

// ✅ GOOD: Protected shared state
var (
    mu    sync.Mutex
    count int
)

cfg.FctWriter = func(p []byte) (int, error) {
    mu.Lock()
    defer mu.Unlock()
    count++
    return len(p), nil
}

// ❌ BAD: Unprotected shared state
var count int
cfg.FctWriter = func(p []byte) (int, error) {
    count++  // RACE!
    return len(p), nil
}

Timeout Management

// ✅ GOOD: Tolerant timeouts
Eventually(func() bool {
    return agg.IsRunning()
}, 2*time.Second, 50*time.Millisecond).Should(BeTrue())

// ❌ BAD: Tight timeouts (flakey)
Eventually(func() bool {
    return agg.IsRunning()
}, 100*time.Millisecond, 10*time.Millisecond).Should(BeTrue())

Resource Cleanup

// ✅ GOOD: Always cleanup
AfterEach(func() {
    if agg != nil {
        agg.Close()
    }
    cancel()
    time.Sleep(50 * time.Millisecond)  // Allow cleanup
})

// ❌ BAD: No cleanup (leaks)
AfterEach(func() {
    cancel()  // Missing agg.Close()
})

Troubleshooting

Common Issues

1. Test Timeout

Error: test timed out after 10m0s

Solution:

  • Increase timeout: go test -timeout=20m
  • Check for deadlocks in concurrent tests
  • Ensure AfterEach cleanup completes

2. Race Condition

WARNING: DATA RACE
Write at 0x... by goroutine X
Previous read at 0x... by goroutine Y

Solution:

  • Protect shared variables with mutex
  • Use atomic operations for counters
  • Review concurrent access patterns

3. Flaky Tests

Random failures, not reproducible

Solution:

  • Increase Eventually timeouts
  • Add proper synchronization
  • Check for resource cleanup
  • Run with -race to detect issues

4. Coverage Gaps

coverage: 75.0% (below target)

Solution:

  • Run go tool cover -html=coverage.out
  • Identify uncovered branches
  • Add edge case tests
  • Test error paths

Debug Techniques

Enable Verbose Output:

go test -v -ginkgo.v

Focus Specific Test:

# Using ginkgo focus
go test -ginkgo.focus="should handle concurrent writes"

# Using go test run
go test -run TestAggregator/Concurrency

Debug with Delve:

dlv test github.com/nabbar/golib/ioutils/aggregator
(dlv) break aggregator_test.go:123
(dlv) continue

Check for Goroutine Leaks:

BeforeEach(func() {
    runtime.GC()
    initialGoroutines = runtime.NumGoroutine()
})

AfterEach(func() {
    runtime.GC()
    time.Sleep(100 * time.Millisecond)
    leaked := runtime.NumGoroutine() - initialGoroutines
    Expect(leaked).To(BeNumerically("<=", 1))  // Allow 1 for test runner
})

Reporting Bugs & Vulnerabilities

Bug Report Template

When reporting a bug in the test suite or the aggregator package, please use this template:

**Title**: [BUG] Brief description of the bug

**Description**:
[A clear and concise description of what the bug is.]

**Steps to Reproduce:**
1. [First step]
2. [Second step]
3. [...]

**Expected Behavior**:
[A clear and concise description of what you expected to happen]

**Actual Behavior**:
[What actually happened]

**Code Example**:
[Minimal reproducible example]

**Test Case** (if applicable):
[Paste full test output with -v flag]

**Environment**:
- Go version: `go version`
- OS: Linux/macOS/Windows
- Architecture: amd64/arm64
- Package version: vX.Y.Z or commit hash

**Additional Context**:
[Any other relevant information]

**Logs/Error Messages**:
[Paste error messages or stack traces here]

**Possible Fix:**
[If you have suggestions]

Security Vulnerability Template

⚠️ IMPORTANT: For security vulnerabilities, please DO NOT create a public issue.

Instead, report privately via:

  1. GitHub Security Advisories (preferred)
  2. Email to the maintainer (see footer)

Vulnerability Report Template:

**Vulnerability Type:**
[e.g., Overflow, Race Condition, Memory Leak, Denial of Service]

**Severity:**
[Critical / High / Medium / Low]

**Affected Component:**
[e.g., interface.go, model.go, specific function]

**Affected Versions**:
[e.g., v1.0.0 - v1.2.3]

**Vulnerability Description:**
[Detailed description of the security issue]

**Attack Scenario**:
1. Attacker does X
2. System responds with Y
3. Attacker exploits Z

**Proof of Concept:**
[Minimal code to reproduce the vulnerability]
[DO NOT include actual exploit code]

**Impact**:
- Confidentiality: [High / Medium / Low]
- Integrity: [High / Medium / Low]
- Availability: [High / Medium / Low]

**Proposed Fix** (if known):
[Suggested approach to fix the vulnerability]

**CVE Request**:
[Yes / No / Unknown]

**Coordinated Disclosure**:
[Willing to work with maintainers on disclosure timeline]

Issue Labels

When creating GitHub issues, use these labels:

  • bug: Something isn't working
  • enhancement: New feature or request
  • documentation: Improvements to docs
  • performance: Performance issues
  • test: Test-related issues
  • security: Security vulnerability (private)
  • help wanted: Community help appreciated
  • good first issue: Good for newcomers

Reporting Guidelines

Before Reporting:

  1. Search existing issues to avoid duplicates
  2. Verify the bug with the latest version
  3. Run tests with -race detector
  4. Check if it's a test issue or package issue
  5. Collect all relevant logs and outputs

What to Include:

  • Complete test output (use -v flag)
  • Go version (go version)
  • OS and architecture (go env GOOS GOARCH)
  • Race detector output (if applicable)
  • Coverage report (if relevant)

Response Time:

  • Bugs: Typically reviewed within 48 hours
  • Security: Acknowledged within 24 hours
  • Enhancements: Reviewed as time permits

License: MIT License - See LICENSE file for details
Maintained By: Nicolas JUHEL
Package: github.com/nabbar/golib/ioutils/aggregator

AI Transparency: In compliance with EU AI Act Article 50.4: AI assistance was used for testing, documentation, and bug resolution under human supervision. All core functionality is human-designed and validated.