diff --git a/internal/config/concurrency_limits_internal_test.go b/internal/config/concurrency_limits_internal_test.go index c5f4b20..404d940 100644 --- a/internal/config/concurrency_limits_internal_test.go +++ b/internal/config/concurrency_limits_internal_test.go @@ -32,6 +32,28 @@ func TestOmittedConcurrencyLimitsUseDefaults(t *testing.T) { } } +// TestOmittedMaxConcurrentProcessingIsAtMostFour checks that an omitted +// max_concurrent_processing is the number of CPUs Go uses, but never more +// than 4, so a container with no CPU limit on a host with many CPUs does not +// process one image per CPU at once. +func TestOmittedMaxConcurrentProcessingIsAtMostFour(t *testing.T) { + t.Parallel() + + c, err := configFromYAML(t, signingKeyLine) + if err != nil { + t.Fatalf("minimal config should be valid, got error: %v", err) + } + + want := min(runtime.GOMAXPROCS(0), 4) + t.Logf("GOMAXPROCS %d, MaxConcurrentProcessing %d", + runtime.GOMAXPROCS(0), c.MaxConcurrentProcessing) + + if c.MaxConcurrentProcessing != want { + t.Errorf("MaxConcurrentProcessing = %d, want %d", + c.MaxConcurrentProcessing, want) + } +} + // TestExplicitConcurrencyLimitsAreUsed checks that valid values for the // two limits are used as given. func TestExplicitConcurrencyLimitsAreUsed(t *testing.T) { diff --git a/internal/imageprocessor/max_concurrent_processing_internal_test.go b/internal/imageprocessor/max_concurrent_processing_internal_test.go index ba5388c..e43146a 100644 --- a/internal/imageprocessor/max_concurrent_processing_internal_test.go +++ b/internal/imageprocessor/max_concurrent_processing_internal_test.go @@ -132,6 +132,27 @@ func TestNewDefaultsMaxConcurrentProcessingToCPUs(t *testing.T) { } } +// TestNewDefaultMaxConcurrentProcessingIsAtMostFour checks that New, given +// no MaxConcurrentProcessing, makes one slot per CPU Go uses, but never more +// than 4. +func TestNewDefaultMaxConcurrentProcessingIsAtMostFour(t *testing.T) { + t.Parallel() + + want := min(runtime.GOMAXPROCS(0), 4) + + for _, limit := range []int{0, -1} { + proc := New(Params{MaxConcurrentProcessing: limit}) + got := cap(proc.processingSemaphore) + t.Logf("MaxConcurrentProcessing %d, GOMAXPROCS %d: %d slots", + limit, runtime.GOMAXPROCS(0), got) + + if got != want { + t.Errorf("MaxConcurrentProcessing %d: %d slots, want %d", + limit, got, want) + } + } +} + // TestProcessNeverExceedsMaxConcurrentProcessing starts more Process calls // than MaxConcurrentProcessing allows and holds the first ones inside // Process until the test lets them go. No more than the limit may be