mirror of
https://github.com/prymitive/karma
synced 2026-05-11 03:46:48 +00:00
committed by
Łukasz Mierzwa
parent
3c1a2c7c31
commit
cae5a4c701
@@ -2,6 +2,10 @@
|
||||
|
||||
## v0.129
|
||||
|
||||
### Fixed
|
||||
|
||||
- Settings from the config file were not being pushed to the UI - #6696.
|
||||
|
||||
### Changed
|
||||
|
||||
- Switched logging from zerolog to slog. Log output format has changed.
|
||||
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
@@ -3008,3 +3009,106 @@ func TestLabelSettings(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndexUIDefaultsJSON(t *testing.T) {
|
||||
// Verifies that the index handler embeds a complete, valid JSON object
|
||||
// in the <script id="defaults"> tag, with all UI config fields present
|
||||
// and Refresh serialized as a nanosecond integer.
|
||||
type uiDefaults struct {
|
||||
Refresh float64 `json:"Refresh"`
|
||||
HideFiltersWhenIdle bool `json:"HideFiltersWhenIdle"`
|
||||
ColorTitlebar bool `json:"ColorTitlebar"`
|
||||
Theme string `json:"Theme"`
|
||||
Animations bool `json:"Animations"`
|
||||
MinimalGroupWidth int `json:"MinimalGroupWidth"`
|
||||
AlertsPerGroup int `json:"AlertsPerGroup"`
|
||||
CollapseGroups string `json:"CollapseGroups"`
|
||||
MultiGridLabel string `json:"MultiGridLabel"`
|
||||
MultiGridSortReverse bool `json:"MultiGridSortReverse"`
|
||||
}
|
||||
|
||||
type testCaseT struct {
|
||||
// scenario describes the behaviour being tested
|
||||
name string
|
||||
refresh time.Duration
|
||||
expectedRefreshNs float64
|
||||
alertsPerGroup int
|
||||
multiGridLabel string
|
||||
hideFiltersWhenIdle bool
|
||||
}
|
||||
|
||||
testCases := []testCaseT{
|
||||
{
|
||||
// default config values produce correct JSON with 30s refresh
|
||||
name: "default 30s refresh",
|
||||
refresh: 30 * time.Second,
|
||||
expectedRefreshNs: 30000000000,
|
||||
alertsPerGroup: 5,
|
||||
multiGridLabel: "",
|
||||
hideFiltersWhenIdle: true,
|
||||
},
|
||||
{
|
||||
// custom config values are all reflected in the embedded JSON
|
||||
name: "custom config values",
|
||||
refresh: 45 * time.Second,
|
||||
expectedRefreshNs: 45000000000,
|
||||
alertsPerGroup: 15,
|
||||
multiGridLabel: "cluster",
|
||||
hideFiltersWhenIdle: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mockConfig(t.Setenv)
|
||||
config.Config.UI.Refresh = tc.refresh
|
||||
config.Config.UI.AlertsPerGroup = tc.alertsPerGroup
|
||||
config.Config.UI.MultiGridLabel = tc.multiGridLabel
|
||||
config.Config.UI.HideFiltersWhenIdle = tc.hideFiltersWhenIdle
|
||||
|
||||
r := testRouter()
|
||||
setupRouter(r, nil)
|
||||
mockCache()
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
r.ServeHTTP(resp, req)
|
||||
if resp.Code != http.StatusOK {
|
||||
t.Fatalf("GET / returned status %d", resp.Code)
|
||||
}
|
||||
|
||||
body := resp.Body.String()
|
||||
re := regexp.MustCompile(`<script type="text/plain" id="defaults">\s*([A-Za-z0-9+/=]+)\s*</script>`)
|
||||
matches := re.FindStringSubmatch(body)
|
||||
if len(matches) < 2 {
|
||||
t.Fatal("Could not find <script id=\"defaults\"> content in HTML response")
|
||||
}
|
||||
|
||||
decoded, err := base64.StdEncoding.DecodeString(matches[1])
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to base64-decode defaults: %v", err)
|
||||
}
|
||||
|
||||
var got uiDefaults
|
||||
if err := json.Unmarshal(decoded, &got); err != nil {
|
||||
t.Fatalf("Failed to parse defaults JSON: %v\nraw: %s", err, string(decoded))
|
||||
}
|
||||
|
||||
expected := uiDefaults{
|
||||
Refresh: tc.expectedRefreshNs,
|
||||
HideFiltersWhenIdle: tc.hideFiltersWhenIdle,
|
||||
ColorTitlebar: config.Config.UI.ColorTitlebar,
|
||||
Theme: config.Config.UI.Theme,
|
||||
Animations: config.Config.UI.Animations,
|
||||
MinimalGroupWidth: config.Config.UI.MinimalGroupWidth,
|
||||
AlertsPerGroup: tc.alertsPerGroup,
|
||||
CollapseGroups: config.Config.UI.CollapseGroups,
|
||||
MultiGridLabel: tc.multiGridLabel,
|
||||
MultiGridSortReverse: config.Config.UI.MultiGridSortReverse,
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(expected, got); diff != "" {
|
||||
t.Errorf("UI defaults mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,15 +218,15 @@ type configSchema struct {
|
||||
} `yaml:"silenceForm" koanf:"silenceForm"`
|
||||
// nolint: maligned
|
||||
UI struct {
|
||||
Refresh time.Duration
|
||||
HideFiltersWhenIdle bool `yaml:"hideFiltersWhenIdle" koanf:"hideFiltersWhenIdle"`
|
||||
ColorTitlebar bool `yaml:"colorTitlebar" koanf:"colorTitlebar"`
|
||||
Theme string `yaml:"theme" koanf:"theme"`
|
||||
Animations bool `yaml:"animations" koanf:"animations"`
|
||||
MinimalGroupWidth int `yaml:"minimalGroupWidth" koanf:"minimalGroupWidth"`
|
||||
AlertsPerGroup int `yaml:"alertsPerGroup" koanf:"alertsPerGroup"`
|
||||
CollapseGroups string `yaml:"collapseGroups" koanf:"collapseGroups"`
|
||||
MultiGridLabel string `yaml:"multiGridLabel" koanf:"multiGridLabel"`
|
||||
MultiGridSortReverse bool `yaml:"multiGridSortReverse" koanf:"multiGridSortReverse"`
|
||||
Refresh time.Duration `json:",format:nano"`
|
||||
HideFiltersWhenIdle bool `yaml:"hideFiltersWhenIdle" koanf:"hideFiltersWhenIdle"`
|
||||
ColorTitlebar bool `yaml:"colorTitlebar" koanf:"colorTitlebar"`
|
||||
Theme string `yaml:"theme" koanf:"theme"`
|
||||
Animations bool `yaml:"animations" koanf:"animations"`
|
||||
MinimalGroupWidth int `yaml:"minimalGroupWidth" koanf:"minimalGroupWidth"`
|
||||
AlertsPerGroup int `yaml:"alertsPerGroup" koanf:"alertsPerGroup"`
|
||||
CollapseGroups string `yaml:"collapseGroups" koanf:"collapseGroups"`
|
||||
MultiGridLabel string `yaml:"multiGridLabel" koanf:"multiGridLabel"`
|
||||
MultiGridSortReverse bool `yaml:"multiGridSortReverse" koanf:"multiGridSortReverse"`
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user