package config import ( "runtime" "testing" ) // The variables that set the two concurrency limits. const ( testMaxConcurrentProcessingVar = "PIXA_MAX_CONCURRENT_PROCESSING" testUpstreamConnectionsVar = "PIXA_UPSTREAM_CONNECTIONS" ) // TestOmittedConcurrencyLimitsUseDefaults checks that an omitted // max_concurrent_processing is the number of CPUs Go uses and an omitted // upstream_connections is 64. func TestOmittedConcurrencyLimitsUseDefaults(t *testing.T) { t.Parallel() c, err := configFromYAML(t, signingKeyLine) if err != nil { t.Fatalf("minimal config should be valid, got error: %v", err) } if c.MaxConcurrentProcessing != runtime.GOMAXPROCS(0) { t.Errorf("MaxConcurrentProcessing = %d, want %d, one per CPU", c.MaxConcurrentProcessing, runtime.GOMAXPROCS(0)) } if c.UpstreamConnections != 64 { t.Errorf("UpstreamConnections = %d, want 64", c.UpstreamConnections) } } // TestExplicitConcurrencyLimitsAreUsed checks that valid values for the // two limits are used as given. func TestExplicitConcurrencyLimitsAreUsed(t *testing.T) { t.Parallel() c, err := configFromYAML(t, signingKeyLine+ "max_concurrent_processing: 3\nupstream_connections: 10\n") if err != nil { t.Fatalf("valid config should load, got error: %v", err) } if c.MaxConcurrentProcessing != 3 { t.Errorf("MaxConcurrentProcessing = %d, want 3", c.MaxConcurrentProcessing) } if c.UpstreamConnections != 10 { t.Errorf("UpstreamConnections = %d, want 10", c.UpstreamConnections) } } // TestInvalidConcurrencyLimitAbortsStartup checks that a limit that is // not a whole number of at least 1, or is null, aborts startup naming the // key and the value, and the variable too where the value could have come // from it. func TestInvalidConcurrencyLimitAbortsStartup(t *testing.T) { t.Parallel() processing := keyMaxConcurrentProcessing connections := keyUpstreamConnections runAbortCases(t, []abortCase{ { name: "max_concurrent_processing zero", yaml: signingKeyLine + processing + ": 0\n", wantErrSubstrings: []string{ processing, testMaxConcurrentProcessingVar, "value 0", }, }, { name: "max_concurrent_processing negative", yaml: signingKeyLine + processing + ": -2\n", wantErrSubstrings: []string{ processing, testMaxConcurrentProcessingVar, "value -2", }, }, { name: "max_concurrent_processing not a number", yaml: signingKeyLine + processing + ": lots\n", wantErrSubstrings: []string{ processing, testMaxConcurrentProcessingVar, "lots", }, }, { name: "max_concurrent_processing fractional", yaml: signingKeyLine + processing + ": 1.5\n", wantErrSubstrings: []string{processing, "1.5"}, }, { name: "max_concurrent_processing null", yaml: signingKeyLine + processing + ": null\n", wantErrSubstrings: []string{processing, nullValueText}, }, { name: "upstream_connections zero", yaml: signingKeyLine + connections + ": 0\n", wantErrSubstrings: []string{ connections, testUpstreamConnectionsVar, "value 0", }, }, { name: "upstream_connections negative", yaml: signingKeyLine + connections + ": -5\n", wantErrSubstrings: []string{ connections, testUpstreamConnectionsVar, "value -5", }, }, { name: "upstream_connections not a number", yaml: signingKeyLine + connections + ": many\n", wantErrSubstrings: []string{ connections, testUpstreamConnectionsVar, "many", }, }, { name: "upstream_connections null", yaml: signingKeyLine + connections + ": null\n", wantErrSubstrings: []string{connections, nullValueText}, }, }) } // TestConcurrencyLimitsFromEnvironment checks that the two variables set // the limits over the config file, and that an invalid value in either // aborts startup naming the variable and the value. func TestConcurrencyLimitsFromEnvironment(t *testing.T) { t.Setenv(testMaxConcurrentProcessingVar, "3") t.Setenv(testUpstreamConnectionsVar, "10") c, err := configFromYAML(t, signingKeyLine+ "max_concurrent_processing: 5\nupstream_connections: 50\n") if err != nil { t.Fatalf("limits from the environment should load: %v", err) } if c.MaxConcurrentProcessing != 3 || c.UpstreamConnections != 10 { t.Errorf("limits = %d and %d, want 3 and 10 from the environment", c.MaxConcurrentProcessing, c.UpstreamConnections) } cases := []struct { variable string value string }{ {testMaxConcurrentProcessingVar, "lots"}, {testMaxConcurrentProcessingVar, "0"}, {testUpstreamConnectionsVar, "-1"}, {testUpstreamConnectionsVar, "ten"}, } for _, tc := range cases { t.Run(tc.variable+"="+tc.value, func(t *testing.T) { t.Setenv(tc.variable, tc.value) _, err := configFromYAML(t, signingKeyLine) wantStartupError(t, err, tc.variable, tc.value) }) } }