Updated config file and config struct
All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 23s

This commit is contained in:
2025-05-27 22:52:02 -04:00
parent c00d0d4abf
commit ea31ffb651
5 changed files with 266 additions and 659 deletions

View File

@ -1,20 +1,33 @@
package config
import (
"encoding/json"
"log/slog"
"os"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
const (
LoggingOutputJson = "JSON"
LoggingOutputText = "TEXT"
)
// Config .
type Config struct {
MySubaru MySubaru
TimeZone string
Logger *slog.Logger
}
// config defines the structure of configuration data to be parsed from a config source.
type config struct {
MySubaru MySubaru `json:"mysubaru" yaml:"mysubaru"`
Timezone string `json:"timezone" yaml:"timezone"`
TimeZone string `json:"timezone" yaml:"timezone"`
Logging *Logging `json:"logging" yaml:"logging"`
}
// Emporia .
// MySubaru .
type MySubaru struct {
Credentials Credentials `json:"credentials" yaml:"credentials"`
Region string `json:"region" yaml:"region"`
@ -37,36 +50,49 @@ type Logging struct {
Source bool `json:"source,omitempty" yaml:"source,omitempty"`
}
func New() (*Config, error) {
viper.SetConfigName("config") // name of config file (without extension)
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
viper.AddConfigPath(".") // optionally look for config in the working directory
viper.AddConfigPath("/etc/mysubaru") // optionally look for config in the working directory
viper.AutomaticEnv()
viper.SetDefault("Timezone", "America/New_York")
viper.SetDefault("MySubaru.AutoReconnect", true)
viper.SetDefault("Logging.Level", "INFO")
viper.SetDefault("Logging.Output", "TEXT")
viper.SetDefault("Logging.Source", "false")
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
slog.Error("cannot open config file", "error", err.Error())
os.Exit(1)
func (l Logging) ToLogger() *slog.Logger {
var level slog.Level
if err := level.UnmarshalText([]byte(l.Level)); err != nil {
level = slog.LevelInfo
}
// viper.WatchConfig()
// viper.OnConfigChange(func(e fsnotify.Event) {
// log.Println("Config file changed:", e.Name)
// })
var config Config
if err := viper.Unmarshal(&config); err != nil {
slog.Error("cannot unmarshal config file", "error", err.Error())
os.Exit(1)
var handler slog.Handler
switch l.Output {
case LoggingOutputJson:
handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: l.Source, Level: level})
case LoggingOutputText:
handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: l.Source, Level: level})
default:
handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: l.Source, Level: level})
}
return &config, nil
return slog.New(handler)
}
// FromBytes unmarshals a byte slice of JSON or YAML config data into a valid server options value.
func FromBytes(b []byte) (*Config, error) {
c := new(config)
o := Config{}
if len(b) == 0 {
return nil, nil
}
if b[0] == '{' {
err := json.Unmarshal(b, c)
if err != nil {
return nil, err
}
} else {
err := yaml.Unmarshal(b, c)
if err != nil {
return nil, err
}
}
o.MySubaru = c.MySubaru
o.TimeZone = c.TimeZone
o.Logger = c.Logging.ToLogger()
return &o, nil
}

93
config/config_test.go Normal file
View File

@ -0,0 +1,93 @@
package config
import (
"log/slog"
"os"
"testing"
"github.com/stretchr/testify/require"
)
var (
yamlBytes = []byte(`
mysubaru:
credentials:
username: username@mysubaru.golang
password: "PASSWORD"
pin: "1234"
deviceid: AaBbCcDdEeFf0123456789
devicename: MySubaru Golang Client
region: USA
auto_reconnect: true
timezone: "America/New_York"
logging:
level: INFO
output: TEXT
source: false
`)
jsonBytes = []byte(`{
"mysubaru": {
"credentials": {
"username": "username@mysubaru.golang",
"password": "PASSWORD",
"pin": "1234",
"deviceid": "AaBbCcDdEeFf0123456789",
"devicename": "MySubaru Golang Client"
},
"region": "USA",
"auto_reconnect": true
},
"timezone": "America/New_York",
"logging": {
"level": "INFO",
"output": "TEXT",
"source": false
}
}
`)
parsedOptions = Config{
MySubaru: MySubaru{
Credentials: Credentials{
Username: "username@mysubaru.golang",
Password: "PASSWORD",
PIN: "1234",
DeviceID: "AaBbCcDdEeFf0123456789",
DeviceName: "MySubaru Golang Client",
},
Region: "USA",
AutoReconnect: true,
},
TimeZone: "America/New_York",
Logger: slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})),
}
)
func TestFromBytesEmptyL(t *testing.T) {
_, err := FromBytes([]byte{})
require.NoError(t, err)
}
func TestFromBytesYAML(t *testing.T) {
o, err := FromBytes(yamlBytes)
require.NoError(t, err)
require.Equal(t, parsedOptions, *o)
}
func TestFromBytesYAMLError(t *testing.T) {
_, err := FromBytes(append(yamlBytes, 'a'))
require.Error(t, err)
}
func TestFromBytesJSON(t *testing.T) {
o, err := FromBytes(jsonBytes)
require.NoError(t, err)
require.Equal(t, parsedOptions, *o)
}
func TestFromBytesJSONError(t *testing.T) {
_, err := FromBytes(append(jsonBytes, 'a'))
require.Error(t, err)
}