package config_test import ( "strings" "testing" "sneak.berlin/go/netwatch/internal/config" "sneak.berlin/go/netwatch/internal/globals" "sneak.berlin/go/netwatch/internal/logger" "go.uber.org/fx" ) // requireConfigError builds the config as main does and fails the // test unless that fails with an error naming setting. It uses // fx.New, because fxtest.New fails the test itself on an error. func requireConfigError(t *testing.T, setting string) { t.Helper() app := fx.New( fx.NopLogger, fx.Provide(globals.New, logger.New, config.New), fx.Invoke(func(*config.Config) {}), ) err := app.Err() if err == nil || !strings.Contains(err.Error(), setting) { t.Fatalf("config error = %v, want one naming %s", err, setting) } } // TestSettingsLoadAsGiven: valid values pass the checks and are used // as given. bin/entrypoint.sh starts the server with these // BIND_ADDRESS and PORT values. func TestSettingsLoadAsGiven(t *testing.T) { t.Setenv("BIND_ADDRESS", "127.0.0.1") t.Setenv("PORT", "8081") t.Setenv("DEBUG", "true") var cfg *config.Config app := fx.New( fx.NopLogger, fx.Provide(globals.New, logger.New, config.New), fx.Populate(&cfg), ) err := app.Err() if err != nil { t.Fatalf("config error = %v", err) } if cfg.BindAddress != "127.0.0.1" || cfg.Port != 8081 || !cfg.Debug { t.Fatalf("BindAddress, Port, Debug = %q, %d, %t; "+ "want \"127.0.0.1\", 8081, true", cfg.BindAddress, cfg.Port, cfg.Debug) } } // TestPortMustBeAPortNumber: viper reads a value that is not a number // as 0, on which the server would listen on a random port. func TestPortMustBeAPortNumber(t *testing.T) { for _, value := range []string{"abc", "0", "65536", "8080.5"} { t.Run(value, func(t *testing.T) { t.Setenv("PORT", value) requireConfigError(t, "PORT") }) } } // TestDebugMustBeTrueOrFalse: viper reads any other value, such as // "yes", as false. func TestDebugMustBeTrueOrFalse(t *testing.T) { t.Setenv("DEBUG", "yes") requireConfigError(t, "DEBUG") } // TestBindAddressMustBeAnIPAddress: a host name would be looked up // only once the server starts listening, and a mistyped one would stop // it then with an error that does not name the setting. func TestBindAddressMustBeAnIPAddress(t *testing.T) { t.Setenv("BIND_ADDRESS", "localhost") requireConfigError(t, "BIND_ADDRESS") } // TestReportsPerMinuteMustBePositive: unchecked, zero would panic // when the routes are built, and a negative rate would lift the // limit. func TestReportsPerMinuteMustBePositive(t *testing.T) { t.Setenv("REPORTS_PER_MINUTE", "0") requireConfigError(t, "REPORTS_PER_MINUTE") } // TestDataDirMaxBytesMustBeANumber: viper reads a value that is not // a number, such as "1GB", as 0, which would refuse every report. func TestDataDirMaxBytesMustBeANumber(t *testing.T) { t.Setenv("DATA_DIR_MAX_BYTES", "1GB") requireConfigError(t, "DATA_DIR_MAX_BYTES") } // TestCORSAllowedOriginsMustBeOrigins: "*" would let every origin in, // and an entry that is not a plain origin would match no page. func TestCORSAllowedOriginsMustBeOrigins(t *testing.T) { for _, entry := range []string{ "*", "https://*.netwatch.example", "netwatch.example", "https://netwatch.example/", } { t.Run(entry, func(t *testing.T) { t.Setenv("CORS_ALLOWED_ORIGINS", entry) requireConfigError(t, "CORS_ALLOWED_ORIGINS") }) } }