diff --git a/config.go b/config.go new file mode 100644 index 0000000..da9ea9d --- /dev/null +++ b/config.go @@ -0,0 +1,102 @@ +package main + +import ( + "errors" + + netatmo "github.com/exzz/netatmo-api-go" + "github.com/spf13/pflag" +) + +const ( + envVarListenAddress = "NETATMO_EXPORTER_ADDR" + envVarNetatmoClientID = "NETATMO_CLIENT_ID" + envVarNetatmoClientSecret = "NETATMO_CLIENT_SECRET" + envVarNetatmoUsername = "NETATMO_CLIENT_USERNAME" + envVarNetatmoPassword = "NETATMO_CLIENT_PASSWORD" + + flagListenAddress = "addr" + flagNetatmoClientID = "client-id" + flagNetatmoClientSecret = "client-secret" + flagNetatmoUsername = "username" + flagNetatmoPassword = "password" +) + +var ( + defaultConfig = config{ + Addr: ":9210", + } + + errNoBinaryName = errors.New("need the binary name as first argument") + errNoListenAddress = errors.New("no listen address") + errNoNetatmoClientID = errors.New("need a NetAtmo client ID") + errNoNetatmoClientSecret = errors.New("need a NetAtmo client secret") + errNoNetatmoUsername = errors.New("username can not be blank") + errNoNetatmoPassword = errors.New("password can not be blank") +) + +type config struct { + Addr string + Netatmo netatmo.Config +} + +func parseConfig(args []string, getenv func(string) string) (config, error) { + cfg := defaultConfig + + if len(args) < 1 { + return cfg, errNoBinaryName + } + + flagSet := pflag.NewFlagSet(args[0], pflag.ExitOnError) + flagSet.StringVarP(&cfg.Addr, "addr", "a", cfg.Addr, "Address to listen on.") + flagSet.StringVarP(&cfg.Netatmo.ClientID, "client-id", "i", cfg.Netatmo.ClientID, "Client ID for NetAtmo app.") + flagSet.StringVarP(&cfg.Netatmo.ClientSecret, "client-secret", "s", cfg.Netatmo.ClientSecret, "Client secret for NetAtmo app.") + flagSet.StringVarP(&cfg.Netatmo.Username, "username", "u", cfg.Netatmo.Username, "Username of NetAtmo account.") + flagSet.StringVarP(&cfg.Netatmo.Password, "password", "p", cfg.Netatmo.Password, "Password of NetAtmo account.") + flagSet.Parse(args[1:]) + + applyEnvironment(&cfg, getenv) + + if len(cfg.Addr) == 0 { + return cfg, errNoListenAddress + } + + if len(cfg.Netatmo.ClientID) == 0 { + return cfg, errNoNetatmoClientID + } + + if len(cfg.Netatmo.ClientSecret) == 0 { + return cfg, errNoNetatmoClientSecret + } + + if len(cfg.Netatmo.Username) == 0 { + return cfg, errNoNetatmoUsername + } + + if len(cfg.Netatmo.Password) == 0 { + return cfg, errNoNetatmoPassword + } + + return cfg, nil +} + +func applyEnvironment(cfg *config, getenv func(string) string) { + if envAddr := getenv(envVarListenAddress); envAddr != "" { + cfg.Addr = envAddr + } + + if envClientID := getenv(envVarNetatmoClientID); envClientID != "" { + cfg.Netatmo.ClientID = envClientID + } + + if envClientSecret := getenv(envVarNetatmoClientSecret); envClientSecret != "" { + cfg.Netatmo.ClientSecret = envClientSecret + } + + if envUsername := getenv(envVarNetatmoUsername); envUsername != "" { + cfg.Netatmo.Username = envUsername + } + + if envPassword := getenv(envVarNetatmoPassword); envPassword != "" { + cfg.Netatmo.Password = envPassword + } +} diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..b363169 --- /dev/null +++ b/config_test.go @@ -0,0 +1,219 @@ +package main + +import ( + "reflect" + "testing" + + netatmo "github.com/exzz/netatmo-api-go" +) + +func TestParseConfig(t *testing.T) { + tests := []struct { + name string + args []string + env map[string]string + wantConfig config + wantErr error + }{ + { + name: "no args", + args: []string{}, + env: map[string]string{}, + wantConfig: config{}, + wantErr: errNoBinaryName, + }, + { + name: "success", + args: []string{ + "test-cmd", + "--" + flagNetatmoClientID, + "id", + "--" + flagNetatmoClientSecret, + "secret", + "--" + flagNetatmoUsername, + "username", + "--" + flagNetatmoPassword, + "password", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: nil, + }, + { + name: "all env", + args: []string{ + "test-cmd", + }, + env: map[string]string{ + envVarListenAddress: ":8080", + envVarNetatmoClientID: "id", + envVarNetatmoClientSecret: "secret", + envVarNetatmoUsername: "username", + envVarNetatmoPassword: "password", + }, + wantConfig: config{ + Addr: ":8080", + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: nil, + }, + { + name: "no addr", + args: []string{ + "test-cmd", + "--" + flagListenAddress, + "", + "--" + flagNetatmoClientID, + "id", + "--" + flagNetatmoClientSecret, + "secret", + "--" + flagNetatmoUsername, + "username", + "--" + flagNetatmoPassword, + "password", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: errNoListenAddress, + }, + { + name: "no client id", + args: []string{ + "test-cmd", + "--" + flagNetatmoClientSecret, + "secret", + "--" + flagNetatmoUsername, + "username", + "--" + flagNetatmoPassword, + "password", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: errNoNetatmoClientID, + }, + { + name: "no client secret", + args: []string{ + "test-cmd", + "--" + flagNetatmoClientID, + "id", + "--" + flagNetatmoUsername, + "username", + "--" + flagNetatmoPassword, + "password", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: errNoNetatmoClientSecret, + }, + { + name: "no username", + args: []string{ + "test-cmd", + "--" + flagNetatmoClientID, + "id", + "--" + flagNetatmoClientSecret, + "secret", + "--" + flagNetatmoPassword, + "password", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: errNoNetatmoUsername, + }, + { + name: "no password", + args: []string{ + "test-cmd", + "--" + flagNetatmoClientID, + "id", + "--" + flagNetatmoClientSecret, + "secret", + "--" + flagNetatmoUsername, + "username", + }, + env: map[string]string{}, + wantConfig: config{ + Addr: defaultConfig.Addr, + Netatmo: netatmo.Config{ + ClientID: "id", + ClientSecret: "secret", + Username: "username", + Password: "password", + }, + }, + wantErr: errNoNetatmoPassword, + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + getenv := func(key string) string { + return tt.env[key] + } + + config, err := parseConfig(tt.args, getenv) + + if err != tt.wantErr { + t.Errorf("got error %q, want %q", err, tt.wantErr) + } + + if err != nil { + return + } + + if !reflect.DeepEqual(config, tt.wantConfig) { + t.Errorf("got config %v, want %v", config, tt.wantConfig) + } + }) + } +} diff --git a/main.go b/main.go index 39da8f8..5851271 100644 --- a/main.go +++ b/main.go @@ -1,62 +1,16 @@ package main import ( - "errors" "log" "net/http" "os" netatmo "github.com/exzz/netatmo-api-go" "github.com/prometheus/client_golang/prometheus" - "github.com/spf13/pflag" ) -type config struct { - Addr string - Netatmo netatmo.Config -} - -func parseConfig() (config, error) { - cfg := config{} - - // Set default port to bind to - addr := ":9210" - if envAddr := os.Getenv("NETATMO_EXPORTER_ADDR"); envAddr != "" { - addr = envAddr - } - - pflag.StringVarP(&cfg.Addr, "addr", "a", addr, "Address to listen on.") - pflag.StringVarP(&cfg.Netatmo.ClientID, "client-id", "i", os.Getenv("NETATMO_CLIENT_ID"), "Client ID for NetAtmo app.") - pflag.StringVarP(&cfg.Netatmo.ClientSecret, "client-secret", "s", os.Getenv("NETATMO_CLIENT_SECRET"), "Client secret for NetAtmo app.") - pflag.StringVarP(&cfg.Netatmo.Username, "username", "u", os.Getenv("NETATMO_CLIENT_USERNAME"), "Username of NetAtmo account.") - pflag.StringVarP(&cfg.Netatmo.Password, "password", "p", os.Getenv("NETATMO_CLIENT_PASSWORD"), "Password of NetAtmo account.") - pflag.Parse() - - if len(cfg.Addr) == 0 { - return cfg, errors.New("no listen address") - } - - if len(cfg.Netatmo.ClientID) == 0 { - return cfg, errors.New("need a NetAtmo client ID") - } - - if len(cfg.Netatmo.ClientSecret) == 0 { - return cfg, errors.New("need a NetAtmo client secret") - } - - if len(cfg.Netatmo.Username) == 0 { - return cfg, errors.New("username can not be blank") - } - - if len(cfg.Netatmo.Password) == 0 { - return cfg, errors.New("password can not be blank") - } - - return cfg, nil -} - func main() { - cfg, err := parseConfig() + cfg, err := parseConfig(os.Args, os.Getenv) if err != nil { log.Fatalf("Error in configuration: %s", err) }