Implement Monlet MVP stack and UI updates
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -20,12 +22,13 @@ agent_id = "host-1"
|
||||
state_dir = "/tmp/x"
|
||||
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`
|
||||
@@ -35,14 +38,105 @@ func TestLoadMinimal(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c.Mode != "hybrid" {
|
||||
t.Errorf("default mode: %q", c.Mode)
|
||||
if !c.PushesToServer() || c.ExposesMetrics() {
|
||||
t.Errorf("features: push=%v metrics=%v", c.PushesToServer(), c.ExposesMetrics())
|
||||
}
|
||||
if c.Server.HeartbeatInterval.Duration == 0 {
|
||||
t.Error("default heartbeat not applied")
|
||||
}
|
||||
if c.Checks[0].NotificationOwner != "server" {
|
||||
t.Errorf("default notification_owner: %q", c.Checks[0].NotificationOwner)
|
||||
if !c.Checks[0].NotificationsOn() {
|
||||
t.Error("notifications should default on")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadMultilineCommand(t *testing.T) {
|
||||
c, err := Load(writeTmp(t, `
|
||||
agent_id = "host-1"
|
||||
state_dir = "/tmp/x"
|
||||
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = '''
|
||||
set -eu
|
||||
echo ok
|
||||
'''
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(c.Checks[0].Command, "echo ok") {
|
||||
t.Fatalf("command not loaded: %q", c.Checks[0].Command)
|
||||
}
|
||||
if got := c.Checks[0].Argv(); len(got) != 3 || got[0] != "/bin/sh" || got[1] != "-c" {
|
||||
t.Fatalf("argv: %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandArrayRejected(t *testing.T) {
|
||||
_, err := Load(writeTmp(t, `
|
||||
agent_id = "host-1"
|
||||
state_dir = "/tmp/x"
|
||||
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
if err == nil {
|
||||
t.Fatal("expected command array to be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadLabels(t *testing.T) {
|
||||
c, err := Load(writeTmp(t, `
|
||||
agent_id = "host-1"
|
||||
state_dir = "/tmp/x"
|
||||
|
||||
[labels]
|
||||
env = "prod"
|
||||
role = "api"
|
||||
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
labels := c.HeartbeatLabels("1.2.3")
|
||||
if labels["env"] != "prod" || labels["role"] != "api" {
|
||||
t.Fatalf("configured labels missing: %#v", labels)
|
||||
}
|
||||
if labels[AgentVersionLabel] != "1.2.3" {
|
||||
t.Fatalf("version label missing: %#v", labels)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeartbeatLabelsVersionLabelWins(t *testing.T) {
|
||||
c := &Config{Labels: map[string]string{AgentVersionLabel: "manual"}}
|
||||
labels := c.HeartbeatLabels("real")
|
||||
if labels[AgentVersionLabel] != "real" {
|
||||
t.Fatalf("version label must be generated from binary version, got %q", labels[AgentVersionLabel])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +146,12 @@ func TestValidateBadID(t *testing.T) {
|
||||
agent_id = "bad id!"
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
@@ -70,11 +165,12 @@ func TestValidateTimeoutExceedsInterval(t *testing.T) {
|
||||
agent_id = "x"
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "5s"
|
||||
timeout = "10s"
|
||||
`))
|
||||
@@ -83,13 +179,69 @@ timeout = "10s"
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrometheusOnlyAllowsMissingServer(t *testing.T) {
|
||||
c, err := Load(writeTmp(t, `
|
||||
mode = "prometheus_only"
|
||||
func TestValidateBadLabelKey(t *testing.T) {
|
||||
_, err := Load(writeTmp(t, `
|
||||
agent_id = "x"
|
||||
state_dir = "/tmp/x"
|
||||
[labels]
|
||||
"bad key" = "x"
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
if err == nil {
|
||||
t.Fatal("expected bad label key error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSensitiveLabelKey(t *testing.T) {
|
||||
for _, key := range []string{"token", "api_key", "api-key", "password", "credential", "authorization", "cookie"} {
|
||||
if err := validateLabels(map[string]string{key: "x"}); err == nil {
|
||||
t.Fatalf("expected sensitive label key error for %q", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateLabelsReservedSlot(t *testing.T) {
|
||||
labels := make(map[string]string, maxLabels)
|
||||
for i := 0; i < maxLabels; i++ {
|
||||
labels[fmt.Sprintf("k%d", i)] = "v"
|
||||
}
|
||||
if err := validateLabels(labels); err == nil {
|
||||
t.Fatal("expected reserved label slot error")
|
||||
}
|
||||
delete(labels, "k0")
|
||||
labels[AgentVersionLabel] = "manual"
|
||||
if err := validateLabels(labels); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateLabelValueMaxLength(t *testing.T) {
|
||||
if err := validateLabels(map[string]string{"note": strings.Repeat("ю", maxLabelValueLen)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := validateLabels(map[string]string{"note": strings.Repeat("x", maxLabelValueLen+1)}); err == nil {
|
||||
t.Fatal("expected label value length error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrometheusOnlyAllowsMissingServer(t *testing.T) {
|
||||
c, err := Load(writeTmp(t, `
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = false
|
||||
[metrics]
|
||||
enabled = true
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
@@ -97,17 +249,21 @@ timeout = "5s"
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c.PushesToServer() {
|
||||
t.Fatal("prometheus_only must not push")
|
||||
t.Fatal("metrics-only config must not push")
|
||||
}
|
||||
if !c.ExposesMetrics() {
|
||||
t.Fatal("metrics-only config must expose metrics")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushOnlyRequiresServer(t *testing.T) {
|
||||
_, err := Load(writeTmp(t, `
|
||||
mode = "push_only"
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = true
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
@@ -116,21 +272,52 @@ timeout = "5s"
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownConfigKeyRejected(t *testing.T) {
|
||||
_, err := Load(writeTmp(t, `
|
||||
mode = "hybrid"
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
if err == nil {
|
||||
t.Fatal("expected unknown key error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotificationsEnabledCanDisable(t *testing.T) {
|
||||
c, err := Load(writeTmp(t, minimal+`
|
||||
notifications_enabled = false
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c.Checks[0].NotificationsOn() {
|
||||
t.Fatal("notifications_enabled=false was not applied")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExposesMetricsGate(t *testing.T) {
|
||||
cases := []struct {
|
||||
mode string
|
||||
enabled bool
|
||||
server bool
|
||||
metrics bool
|
||||
want bool
|
||||
}{
|
||||
{"hybrid", true, true},
|
||||
{"hybrid", false, false},
|
||||
{"prometheus_only", true, true},
|
||||
{"push_only", true, false},
|
||||
{true, true, true},
|
||||
{true, false, false},
|
||||
{false, true, true},
|
||||
{false, false, false},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
c := &Config{Mode: tc.mode, Metrics: MetricsConfig{Enabled: tc.enabled}}
|
||||
c := &Config{Server: ServerConfig{Enabled: &tc.server}, Metrics: MetricsConfig{Enabled: tc.metrics}}
|
||||
if got := c.ExposesMetrics(); got != tc.want {
|
||||
t.Errorf("mode=%s enabled=%v want=%v got=%v", tc.mode, tc.enabled, tc.want, got)
|
||||
t.Errorf("server=%v metrics=%v want=%v got=%v", tc.server, tc.metrics, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,16 +327,17 @@ func TestValidateDuplicateCheckID(t *testing.T) {
|
||||
agent_id = "x"
|
||||
state_dir = "/tmp/x"
|
||||
[server]
|
||||
enabled = true
|
||||
url = "http://localhost"
|
||||
token = "t"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
[[checks]]
|
||||
id = "c1"
|
||||
command = ["true"]
|
||||
command = "true"
|
||||
interval = "10s"
|
||||
timeout = "5s"
|
||||
`))
|
||||
|
||||
Reference in New Issue
Block a user