Skip to content

Commit 1264ffd

Browse files
committed
fix: Error on zero time input
1 parent 51c23e7 commit 1264ffd

File tree

2 files changed

+44
-40
lines changed

2 files changed

+44
-40
lines changed

config/ui/ui.go

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,43 @@ import (
1111
)
1212

1313
const (
14-
defaultTitle = "Health Dashboard | Gatus"
15-
defaultDescription = "Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue"
16-
defaultHeader = "Gatus"
17-
defaultDashboardHeading = "Health Dashboard"
18-
defaultDashboardSubheading = "Monitor the health of your endpoints in real-time"
19-
defaultLogo = ""
20-
defaultLink = ""
21-
defaultCustomCSS = ""
22-
defaultSortBy = "name"
23-
defaultFilterBy = "none"
24-
defaultConfigRefreshInterval = 10 * time.Minute
14+
defaultTitle = "Health Dashboard | Gatus"
15+
defaultDescription = "Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue"
16+
defaultHeader = "Gatus"
17+
defaultDashboardHeading = "Health Dashboard"
18+
defaultDashboardSubheading = "Monitor the health of your endpoints in real-time"
19+
defaultLogo = ""
20+
defaultLink = ""
21+
defaultCustomCSS = ""
22+
defaultSortBy = "name"
23+
defaultFilterBy = "none"
2524
)
2625

2726
var (
28-
defaultDarkMode = true
27+
defaultDarkMode = true
28+
defaultConfigRefreshInterval = 10 * time.Minute
2929

30-
ErrButtonValidationFailed = errors.New("invalid button configuration: missing required name or link")
31-
ErrInvalidDefaultSortBy = errors.New("invalid default-sort-by value: must be 'name', 'group', or 'health'")
32-
ErrInvalidDefaultFilterBy = errors.New("invalid default-filter-by value: must be 'none', 'failing', or 'unstable'")
30+
ErrButtonValidationFailed = errors.New("invalid button configuration: missing required name or link")
31+
ErrInvalidDefaultSortBy = errors.New("invalid default-sort-by value: must be 'name', 'group', or 'health'")
32+
ErrInvalidDefaultFilterBy = errors.New("invalid default-filter-by value: must be 'none', 'failing', or 'unstable'")
33+
ErrInvalidConfigRefreshInterval = errors.New("invalid config-refresh-interval value: must be greater than zero")
3334
)
3435

3536
// Config is the configuration for the UI of Gatus
3637
type Config struct {
37-
Title string `yaml:"title,omitempty"` // Title of the page
38-
Description string `yaml:"description,omitempty"` // Meta description of the page
39-
DashboardHeading string `yaml:"dashboard-heading,omitempty"` // Dashboard Title between header and endpoints
40-
DashboardSubheading string `yaml:"dashboard-subheading,omitempty"` // Dashboard Description between header and endpoints
41-
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
42-
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
43-
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
44-
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header
45-
CustomCSS string `yaml:"custom-css,omitempty"` // Custom CSS to include in the page
46-
DarkMode *bool `yaml:"dark-mode,omitempty"` // DarkMode is a flag to enable dark mode by default
47-
DefaultSortBy string `yaml:"default-sort-by,omitempty"` // DefaultSortBy is the default sort option ('name', 'group', 'health')
48-
DefaultFilterBy string `yaml:"default-filter-by,omitempty"` // DefaultFilterBy is the default filter option ('none', 'failing', 'unstable')
49-
ConfigRefreshInterval time.Duration `yaml:"config-refresh-interval,omitempty"` // ConfigRefreshInterval is the interval at which to refresh the UI configuration via the API
38+
Title string `yaml:"title,omitempty"` // Title of the page
39+
Description string `yaml:"description,omitempty"` // Meta description of the page
40+
DashboardHeading string `yaml:"dashboard-heading,omitempty"` // Dashboard Title between header and endpoints
41+
DashboardSubheading string `yaml:"dashboard-subheading,omitempty"` // Dashboard Description between header and endpoints
42+
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
43+
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
44+
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
45+
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header
46+
CustomCSS string `yaml:"custom-css,omitempty"` // Custom CSS to include in the page
47+
DarkMode *bool `yaml:"dark-mode,omitempty"` // DarkMode is a flag to enable dark mode by default
48+
DefaultSortBy string `yaml:"default-sort-by,omitempty"` // DefaultSortBy is the default sort option ('name', 'group', 'health')
49+
DefaultFilterBy string `yaml:"default-filter-by,omitempty"` // DefaultFilterBy is the default filter option ('none', 'failing', 'unstable')
50+
ConfigRefreshInterval *time.Duration `yaml:"config-refresh-interval,omitempty"` // ConfigRefreshInterval is the interval at which to refresh the UI configuration via the API
5051
//////////////////////////////////////////////
5152
// Non-configurable - used for UI rendering //
5253
//////////////////////////////////////////////
@@ -89,7 +90,7 @@ func GetDefaultConfig() *Config {
8990
DarkMode: &defaultDarkMode,
9091
DefaultSortBy: defaultSortBy,
9192
DefaultFilterBy: defaultFilterBy,
92-
ConfigRefreshInterval: defaultConfigRefreshInterval,
93+
ConfigRefreshInterval: &defaultConfigRefreshInterval,
9394
MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults,
9495
ConfigRefreshIntervalMs: int64(defaultConfigRefreshInterval / time.Millisecond),
9596
}
@@ -134,10 +135,12 @@ func (cfg *Config) ValidateAndSetDefaults() error {
134135
} else if cfg.DefaultFilterBy != "none" && cfg.DefaultFilterBy != "failing" && cfg.DefaultFilterBy != "unstable" {
135136
return ErrInvalidDefaultFilterBy
136137
}
137-
if cfg.ConfigRefreshInterval == 0 {
138-
cfg.ConfigRefreshInterval = defaultConfigRefreshInterval
138+
if cfg.ConfigRefreshInterval == nil {
139+
cfg.ConfigRefreshInterval = &defaultConfigRefreshInterval
140+
} else if *cfg.ConfigRefreshInterval <= 0 {
141+
return ErrInvalidConfigRefreshInterval
139142
}
140-
cfg.ConfigRefreshIntervalMs = int64(cfg.ConfigRefreshInterval / time.Millisecond)
143+
cfg.ConfigRefreshIntervalMs = int64(*cfg.ConfigRefreshInterval / time.Millisecond)
141144
for _, btn := range cfg.Buttons {
142145
if err := btn.Validate(); err != nil {
143146
return err

config/ui/ui_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
4242
if cfg.DefaultFilterBy != defaultFilterBy {
4343
t.Errorf("expected defaultFilterBy to be %s, got %s", defaultFilterBy, cfg.DefaultFilterBy)
4444
}
45-
if cfg.ConfigRefreshInterval != defaultConfigRefreshInterval {
45+
if *cfg.ConfigRefreshInterval != defaultConfigRefreshInterval {
4646
t.Errorf("expected ConfigRefreshInterval to be %s, got %s", defaultConfigRefreshInterval, cfg.ConfigRefreshInterval)
4747
}
4848
var expectedInterval = int64(defaultConfigRefreshInterval.Milliseconds())
@@ -51,6 +51,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
5151
}
5252
})
5353
t.Run("custom-values", func(t *testing.T) {
54+
customConfigRefreshInterval := time.Hour * 2
5455
cfg := &Config{
5556
Title: "Custom Title",
5657
Description: "Custom Description",
@@ -61,7 +62,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
6162
Link: "https://example.com",
6263
DefaultSortBy: "health",
6364
DefaultFilterBy: "failing",
64-
ConfigRefreshInterval: time.Hour * 2,
65+
ConfigRefreshInterval: &customConfigRefreshInterval,
6566
}
6667
if err := cfg.ValidateAndSetDefaults(); err != nil {
6768
t.Error("expected no error, got", err.Error())
@@ -93,10 +94,10 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
9394
if cfg.DefaultFilterBy != "failing" {
9495
t.Errorf("expected defaultFilterBy to be preserved, got %s", cfg.DefaultFilterBy)
9596
}
96-
if cfg.ConfigRefreshInterval != time.Hour*2 {
97+
if *cfg.ConfigRefreshInterval != customConfigRefreshInterval {
9798
t.Errorf("expected ConfigRefreshInterval to be preserved, got %s", cfg.ConfigRefreshInterval)
9899
}
99-
var expectedIntervalMs = int64((time.Hour * 2).Milliseconds())
100+
var expectedIntervalMs = int64(customConfigRefreshInterval.Milliseconds())
100101
if cfg.ConfigRefreshIntervalMs != expectedIntervalMs {
101102
t.Errorf("expected ConfigRefreshIntervalMs to be %d, got %d", expectedIntervalMs, cfg.ConfigRefreshIntervalMs)
102103
}
@@ -308,8 +309,8 @@ func TestConfig_ValidateAndSetDefaults_ConfigRefreshInterval(t *testing.T) {
308309
{
309310
Name: "ZeroConfigRefreshInterval",
310311
ConfigRefreshInterval: 0,
311-
ExpectedError: nil,
312-
ExpectedValue: defaultConfigRefreshInterval,
312+
ExpectedError: ErrInvalidConfigRefreshInterval,
313+
ExpectedValue: 0,
313314
},
314315
{
315316
Name: "ValidConfigRefreshInterval",
@@ -320,12 +321,12 @@ func TestConfig_ValidateAndSetDefaults_ConfigRefreshInterval(t *testing.T) {
320321
}
321322
for _, scenario := range scenarios {
322323
t.Run(scenario.Name, func(t *testing.T) {
323-
cfg := &Config{ConfigRefreshInterval: scenario.ConfigRefreshInterval}
324+
cfg := &Config{ConfigRefreshInterval: &scenario.ConfigRefreshInterval}
324325
err := cfg.ValidateAndSetDefaults()
325326
if !errors.Is(err, scenario.ExpectedError) {
326327
t.Errorf("expected error %v, got %v", scenario.ExpectedError, err)
327328
}
328-
if cfg.ConfigRefreshInterval != scenario.ExpectedValue {
329+
if *cfg.ConfigRefreshInterval != scenario.ExpectedValue {
329330
t.Errorf("expected ConfigRefreshInterval to be %s, got %s", scenario.ExpectedValue, cfg.ConfigRefreshInterval)
330331
}
331332
var expectedIntervalMs = int64(scenario.ExpectedValue.Milliseconds())

0 commit comments

Comments
 (0)