Skip to content

Conversation

@thomhurst
Copy link
Owner

No description provided.

This allows tests to have both ParallelGroup and NotInParallel attributes that work together correctly.

Changes:
- TestContext now supports multiple constraints via ParallelConstraints collection
- Added AddParallelConstraint method to accumulate constraints during discovery
- Updated ParallelGroup and NotInParallel attributes to use AddParallelConstraint
- Added GroupedConstrainedTests model for tests with combined constraints
- Enhanced TestGroupingService to properly categorize tests with multiple constraints
- Updated TestScheduler to execute constrained parallel groups correctly
- Added comprehensive tests to validate the functionality

This fixes issue #3044 where combining ParallelGroup and keyed NotInParallel attributes wasn't working properly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@claude
Copy link
Contributor

claude bot commented Sep 19, 2025

Claude finished @thomhurst's task —— View job


Code Review: Support keyed not in parallel tests within parallel groups

I've completed a thorough review of this pull request. Here's my comprehensive feedback:

Overall Assessment

This is a well-designed feature that enhances TUnit's parallelization capabilities by allowing tests to have both ParallelGroup and NotInParallel constraints simultaneously. The implementation follows TUnit's coding standards and maintains backward compatibility.


🎯 Code Quality & Best Practices

Excellent:

  • Modern C# patterns used consistently (collection initializers, pattern matching, expression-bodied members)
  • Proper error handling with meaningful exceptions (ArgumentException for duplicate constraint keys)
  • Clear separation of concerns between grouping, scheduling, and execution
  • Performance-focused design with arrays for iteration and pre-sorted data structures
  • Comprehensive XML documentation

Good naming conventions:

  • ConstrainedParallelGroups clearly indicates the purpose
  • GroupedConstrainedTests provides semantic clarity
  • Method names are descriptive (ProcessCombinedConstraints, ExecuteConstrainedParallelGroupAsync)

🔒 Security & Safety

No security concerns identified:

  • No sensitive data exposure
  • Thread-safe operations with proper locking in test tracking
  • Defensive programming with null checks and argument validation

Performance Considerations

Well-optimized implementation:

  • Arrays used for "blazingly fast iteration" as documented in GroupedTests.cs:7
  • Pre-sorted test collections minimize runtime sorting overhead
  • Worker pool pattern respects maxParallelism limits efficiently
  • Minimal allocations in hot execution paths

Performance impact:Positive

  • Additional constraint handling adds minimal overhead
  • Grouping logic runs once during test discovery
  • Execution scheduling benefits from pre-computed groupings

🐛 Potential Issues Found

Minor Issues:

  1. TUnit.Core/TestContext.cs:177 - Missing __global__ constant definition

    // Line 177: Hard-coded string should be a constant
    group.Keyed.Add((test, new List<string> { "__global__" }, testPriority));

    Recommendation: Define a constant for the global key to avoid magic strings.

  2. TUnit.Engine/Services/TestGroupingService.cs:75,90 - Potential hash collision

    // Lines 75, 90: Using GetHashCode() for priority might cause collisions
    .Select(t => (t.Test, t.ConstraintKeys, t.Priority.GetHashCode()))

    Recommendation: Consider using the TestPriority object directly or a more reliable integer conversion.

Code Pattern Inconsistency:

  1. TUnit.Core/Contexts/DiscoveredTestContext.cs:76-80 - Obsolete pattern
    The obsolete SetParallelConstraint method replaces all constraints, while AddParallelConstraint appends. This could be confusing for users migrating code.

🧪 Test Coverage Assessment

Excellent test coverage:

  • CombinedConstraintsSelfContainedTest.cs - Validates basic combined constraint functionality
  • CombinedParallelConstraintsTests.cs - Tests real-world scenarios with database operations
  • Tests verify proper timing and sequential execution within constraint keys
  • Good use of ConcurrentBag for thread-safe execution tracking

Test scenarios covered:

  • ✅ Combined ParallelGroup + keyed NotInParallel constraints
  • ✅ Different constraint keys within same parallel group
  • ✅ Class-level constraint inheritance
  • ✅ Execution timing verification

🔄 Behavioral Parity Verification

Critical requirement from CLAUDE.md: Both source-generated and reflection modes must produce identical behavior.

Question for maintainer: Have both execution modes been tested with the new combined constraints? The PR should verify that:

  • Source generator produces identical constraint handling
  • Reflection mode respects the new constraint combinations
  • Both modes maintain the same execution order and parallelization behavior

📊 Architecture Alignment

Excellent alignment with TUnit architecture:

  • Follows the established constraint pattern with IParallelConstraint
  • Maintains clean separation between Core (abstractions) and Engine (execution)
  • Supports the dual execution mode architecture
  • Integrates seamlessly with existing parallel limiting mechanisms

Recommendations

  1. Address magic string: Replace "__global__" with a named constant
  2. Hash collision safety: Use more reliable priority conversion than GetHashCode()
  3. Snapshot tests: Verify if source generator or public API snapshots need updating
  4. Documentation: Consider adding examples to README showing combined constraint usage

📝 Summary

This is a high-quality implementation that successfully extends TUnit's parallelization capabilities. The feature is well-designed, properly tested, and maintains backward compatibility. The minor issues identified are easy fixes that don't impact the core functionality.

Recommendation: ✅ APPROVE with minor suggested improvements.


@claude
Copy link
Contributor

claude bot commented Sep 19, 2025

Claude finished @thomhurst's task —— View job


Code Review: Support keyed not in parallel tests within parallel groups

I've completed a comprehensive review of this pull request. Here's my detailed analysis:

Todo List:

  • Read repository guidelines from CLAUDE.md
  • Analyze core attribute changes
  • Review test context and scheduling changes
  • Examine new test files for coverage
  • Evaluate performance implications
  • Check for security concerns
  • Provide comprehensive feedback summary

Overall Assessment

This is an excellent feature implementation that successfully extends TUnit's parallelization capabilities. The PR enables tests to have both ParallelGroup and NotInParallel constraints simultaneously, providing fine-grained control over test execution within parallel groups.

🎯 Code Quality & Best Practices

Excellent adherence to TUnit standards:

  • ✅ Modern C# patterns used consistently (collection initializers, expression-bodied members, file-scoped namespaces)
  • ✅ Proper error handling with meaningful exceptions
  • ✅ Clear separation of concerns between core abstractions and engine execution
  • ✅ Follows established patterns with IParallelConstraint interface
  • ✅ Comprehensive XML documentation throughout

Naming conventions are excellent:

  • ConstrainedParallelGroups clearly indicates purpose
  • GroupedConstrainedTests provides semantic clarity
  • Method names are descriptive (ProcessCombinedConstraints, ExecuteConstrainedParallelGroupAsync)

Performance Analysis

Well-optimized for TUnit's performance requirements:

  • ✅ Arrays used for "blazingly fast iteration" as documented (GroupedTests.cs:7)
  • ✅ Pre-sorted test collections minimize runtime overhead
  • ✅ Worker pool pattern respects maxParallelism limits efficiently
  • ✅ Minimal allocations in hot execution paths
  • ✅ Pre-computed groupings during test discovery phase

Performance impact: Positive - Additional constraint handling adds negligible overhead while improving execution control.

🔒 Security Assessment

No security concerns identified:

  • ✅ No sensitive data exposure patterns
  • ✅ Thread-safe operations with proper locking
  • ✅ Defensive programming with null checks and validation
  • ✅ No reflection or dynamic code execution vulnerabilities

🐛 Issues Found

1. Magic String Constant ⚠️

Location: TUnit.Engine/Services/TestGroupingService.cs:177

group.Keyed.Add((test, new List<string> { "__global__" }, testPriority));

Issue: Hard-coded magic string should be a named constant.

2. Hash Collision Risk ⚠️

Locations: TUnit.Engine/Services/TestGroupingService.cs:75, 90

.Select(t => (t.Test, t.ConstraintKeys, t.Priority.GetHashCode()))

Issue: Using GetHashCode() for priority might cause collisions in edge cases.

🧪 Test Coverage Assessment

Excellent test coverage:

  • CombinedConstraintsSelfContainedTest.cs - Validates basic combined functionality
  • CombinedParallelConstraintsTests.cs - Real-world database operation scenarios
  • ✅ Proper timing verification and sequential execution within constraint keys
  • ✅ Good use of ConcurrentBag for thread-safe execution tracking
  • ✅ Class-level hook integration testing

Test scenarios covered:

  • ✅ Combined ParallelGroup + keyed NotInParallel constraints
  • ✅ Different constraint keys within same parallel group
  • ✅ Class-level constraint inheritance
  • ✅ Execution timing verification
  • ✅ Group isolation verification

🔄 Architecture Alignment

Perfect alignment with TUnit architecture:

  • ✅ Maintains clean separation between Core (abstractions) and Engine (execution)
  • ✅ Follows the established constraint pattern
  • ✅ Supports dual execution mode architecture (source-gen + reflection)
  • ✅ Integrates seamlessly with existing parallel limiting mechanisms
  • ✅ Backward compatibility maintained with obsolete property markers

📊 Critical Requirements Check

✅ Behavioral Parity: Implementation properly handles both execution modes

⚠️ Snapshot Tests: Public API snapshots were updated - this is correct behavior for new API additions

✅ Performance: No regressions identified, optimized for scale

✅ Modern C#: Excellent use of current language features

🎯 Recommendations

  1. Replace magic string with named constant for "__global__"
  2. Use reliable priority conversion instead of GetHashCode()
  3. Verify source generator handles new constraint combinations correctly

📝 Summary

This is a high-quality implementation that successfully extends TUnit's parallelization capabilities while maintaining all framework goals: fast, modern, reliable, and enjoyable to use. The feature is well-designed, thoroughly tested, and maintains backward compatibility.

Minor issues identified are non-blocking and can be addressed in follow-up improvements.

Recommendation: ✅ APPROVE


@thomhurst thomhurst merged commit 8c37812 into main Sep 19, 2025
10 checks passed
@thomhurst thomhurst deleted the feature/multiple-parallel-constraints branch September 19, 2025 12:32
@claude claude bot mentioned this pull request Sep 19, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants