From bdd23c19b0da9f2ed21b6df2b5329556b791de50 Mon Sep 17 00:00:00 2001 From: Andrej Krejcir Date: Fri, 19 Jan 2024 12:46:28 +0100 Subject: [PATCH] feat: run unit tests for metrics rules Added metrics unit tests file and a Makefile target to run the tests. Signed-off-by: Andrej Krejcir --- Makefile | 13 ++++- hack/metrics-rules-test.sh | 52 ++++++++++++++++++++ pkg/monitoring/rules/rules-tests.yaml | 26 ++++++++++ tools/test-rules-writer/test_rules_writer.go | 32 ++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100755 hack/metrics-rules-test.sh create mode 100644 pkg/monitoring/rules/rules-tests.yaml create mode 100644 tools/test-rules-writer/test_rules_writer.go diff --git a/Makefile b/Makefile index 2f3719a9d..5c86cb056 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ endif all: manager .PHONY: unittest -unittest: generate lint fmt vet manifests +unittest: generate lint fmt vet manifests metrics-rules-test go test -v -coverprofile cover.out $(SRC_PATHS_TESTS) cd api && go test -v ./... @@ -325,3 +325,14 @@ lint: .PHONY: lint-metrics lint-metrics: ./hack/prom_metric_linter.sh --operator-name="kubevirt" --sub-operator-name="ssp" + + +METRIC_RULES_WRITER ?= $(LOCALBIN)/metrics-rules-writer + +.PHONY: build-metric-rules-writer +build-metric-rules-writer: $(LOCALBIN) + go build -o $(METRIC_RULES_WRITER) tools/test-rules-writer/test_rules_writer.go + +.PHONY: metrics-rules-test +metrics-rules-test: build-metric-rules-writer + ./hack/metrics-rules-test.sh $(METRIC_RULES_WRITER) "./pkg/monitoring/rules/rules-tests.yaml" diff --git a/hack/metrics-rules-test.sh b/hack/metrics-rules-test.sh new file mode 100755 index 000000000..2ba360ea7 --- /dev/null +++ b/hack/metrics-rules-test.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +source $(dirname "$0")/config.sh + +readonly PROM_IMAGE="quay.io/prometheus/prometheus:v2.44.0" + +function cleanup() { + local cleanup_files=("${@:?}") + + for file in "${cleanup_files[@]}"; do + rm -f "$file" + done +} + +function lint() { + local target_file="${1:?}" + + ${KUBEVIRT_CRI} run --rm --entrypoint=/bin/promtool \ + -v "$target_file":/tmp/rules.verify:ro,Z "$PROM_IMAGE" \ + check rules /tmp/rules.verify +} + +function unit_test() { + local target_file="${1:?}" + local tests_file="${2:?}" + + ${KUBEVIRT_CRI} run --rm --entrypoint=/bin/promtool \ + -v "$tests_file":/tmp/rules.test:ro,Z \ + -v "$target_file":/tmp/rules.verify:ro,Z \ + "$PROM_IMAGE" \ + test rules /tmp/rules.test +} + +function main() { + local prom_spec_dumper="${1:?}" + local tests_file="${2:?}" + local target_file + + target_file="$(mktemp --tmpdir -u tmp.prom_rules.XXXXX)" + trap "cleanup $target_file" RETURN EXIT INT + + "$prom_spec_dumper" > "$target_file" + + echo "INFO: Rules file content:" + cat "$target_file" + echo + + lint "$target_file" + unit_test "$target_file" "$tests_file" +} + +main "$@" diff --git a/pkg/monitoring/rules/rules-tests.yaml b/pkg/monitoring/rules/rules-tests.yaml new file mode 100644 index 000000000..2a7144f5c --- /dev/null +++ b/pkg/monitoring/rules/rules-tests.yaml @@ -0,0 +1,26 @@ +# Unit tests for the prometheus rules +rule_files: + - /tmp/rules.verify + +tests: + - interval: "1m" + input_series: + - series: 'up{pod="ssp-operator-12345"}' + values: '0x5 1' + + alert_rule_test: + - eval_time: "5m" + alertname: "SSPDown" + exp_alerts: + - exp_annotations: + summary: "All SSP operator pods are down." + runbook_url: "test-runbook:SSPDown" + exp_labels: + severity: "critical" + operator_health_impact: "critical" + kubernetes_operator_part_of: "kubevirt" + kubernetes_operator_component: "ssp-operator" + + - eval_time: "6m" + alertname: "SSPDown" + exp_alerts: [] diff --git a/tools/test-rules-writer/test_rules_writer.go b/tools/test-rules-writer/test_rules_writer.go new file mode 100644 index 000000000..af5efd505 --- /dev/null +++ b/tools/test-rules-writer/test_rules_writer.go @@ -0,0 +1,32 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + + promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + + "kubevirt.io/ssp-operator/pkg/monitoring/rules" +) + +func main() { + const runbookTemplate = "test-runbook:%s" + + allRules := append(rules.RecordRules(), rules.AlertRules(runbookTemplate)...) + + spec := promv1.PrometheusRuleSpec{ + Groups: []promv1.RuleGroup{{ + Name: "test.rules", + Rules: allRules, + }}, + } + + encoder := json.NewEncoder(os.Stdout) + encoder.SetIndent("", " ") + err := encoder.Encode(spec) + if err != nil { + fmt.Fprintf(os.Stderr, "Error encoding prometheus spec: %v", err) + return + } +}