github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/configs/userconfig/config_test.go (about) 1 package userconfig 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/go-kit/log" 12 "github.com/prometheus/common/model" 13 "github.com/prometheus/prometheus/model/labels" 14 "github.com/prometheus/prometheus/model/rulefmt" 15 "github.com/prometheus/prometheus/promql/parser" 16 "github.com/prometheus/prometheus/rules" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "gopkg.in/yaml.v3" 20 21 util_log "github.com/grafana/loki/pkg/util/log" 22 ) 23 24 var legacyRulesFile = `ALERT TestAlert 25 IF up == 0 26 FOR 5m 27 LABELS { severity = "critical" } 28 ANNOTATIONS { 29 message = "I am a message" 30 }` 31 32 var ruleFile = `groups: 33 - name: example 34 rules: 35 - alert: TestAlert 36 expr: up == 0 37 for: 5m 38 labels: 39 severity: critical 40 annotations: 41 message: I am a message` 42 43 func TestUnmarshalJSONLegacyConfigWithMissingRuleFormatVersionSucceeds(t *testing.T) { 44 actual := Config{} 45 buf := []byte(`{"rules_files": {"a": "b"}}`) 46 assert.Nil(t, json.Unmarshal(buf, &actual)) 47 48 expected := Config{ 49 RulesConfig: RulesConfig{ 50 Files: map[string]string{ 51 "a": "b", 52 }, 53 FormatVersion: RuleFormatV1, 54 }, 55 } 56 57 assert.Equal(t, expected, actual) 58 } 59 60 func TestUnmarshalYAMLLegacyConfigWithMissingRuleFormatVersionSucceeds(t *testing.T) { 61 actual := Config{} 62 buf := []byte(strings.TrimSpace(` 63 rule_format_version: '1' 64 rules_files: 65 a: b 66 `)) 67 assert.Nil(t, yaml.Unmarshal(buf, &actual)) 68 69 expected := Config{ 70 RulesConfig: RulesConfig{ 71 Files: map[string]string{ 72 "a": "b", 73 }, 74 FormatVersion: RuleFormatV1, 75 }, 76 } 77 78 assert.Equal(t, expected, actual) 79 } 80 81 func TestParseLegacyAlerts(t *testing.T) { 82 parsed, err := parser.ParseExpr("up == 0") 83 require.NoError(t, err) 84 rule := rules.NewAlertingRule( 85 "TestAlert", 86 parsed, 87 5*time.Minute, 88 labels.Labels{ 89 labels.Label{Name: "severity", Value: "critical"}, 90 }, 91 labels.Labels{ 92 labels.Label{Name: "message", Value: "I am a message"}, 93 }, 94 nil, 95 "", 96 true, 97 log.With(util_log.Logger, "alert", "TestAlert"), 98 ) 99 100 for i, tc := range []struct { 101 cfg RulesConfig 102 expected map[string][]rules.Rule 103 wantErr error 104 }{ 105 { 106 cfg: RulesConfig{ 107 FormatVersion: RuleFormatV1, 108 Files: map[string]string{ 109 "legacy.rules": ` 110 ALERT TestAlert 111 IF up == 0 112 FOR 5m 113 LABELS { severity = "critical" } 114 ANNOTATIONS { 115 message = "I am a message" 116 } 117 `, 118 }, 119 }, 120 expected: map[string][]rules.Rule{ 121 "legacy.rules": {rule}, 122 }, 123 wantErr: fmt.Errorf("version 0 isn't supported"), 124 }, 125 { 126 cfg: RulesConfig{ 127 FormatVersion: RuleFormatV2, 128 Files: map[string]string{ 129 "alerts.yaml": ` 130 groups: 131 - name: example 132 rules: 133 - alert: TestAlert 134 expr: up == 0 135 for: 5m 136 labels: 137 severity: critical 138 annotations: 139 message: I am a message 140 `, 141 }, 142 }, 143 expected: map[string][]rules.Rule{ 144 "example;alerts.yaml": {rule}, 145 }, 146 wantErr: nil, 147 }, 148 } { 149 t.Run(strconv.Itoa(i), func(t *testing.T) { 150 rules, err := tc.cfg.Parse() 151 if tc.wantErr != nil { 152 require.EqualError(t, err, tc.wantErr.Error()) 153 } else { 154 require.NoError(t, err) 155 require.Equal(t, tc.expected, rules) 156 } 157 }) 158 } 159 } 160 161 func TestParseFormatted(t *testing.T) { 162 dur, err := model.ParseDuration("5m") 163 require.NoError(t, err) 164 165 rulesV1 := []rulefmt.RuleNode{ 166 { 167 Alert: yaml.Node{Value: "TestAlert"}, 168 Expr: yaml.Node{Value: "up == 0"}, 169 For: dur, 170 Labels: map[string]string{ 171 "severity": "critical", 172 }, 173 Annotations: map[string]string{ 174 "message": "I am a message", 175 }, 176 }, 177 } 178 179 alertNode := yaml.Node{Line: 4, Column: 12} 180 alertNode.SetString("TestAlert") 181 exprNode := yaml.Node{Line: 5, Column: 11} 182 exprNode.SetString("up == 0") 183 rulesV2 := []rulefmt.RuleNode{ 184 { 185 Alert: alertNode, 186 Expr: exprNode, 187 For: dur, 188 Labels: map[string]string{ 189 "severity": "critical", 190 }, 191 Annotations: map[string]string{ 192 "message": "I am a message", 193 }, 194 }, 195 } 196 197 for i, tc := range []struct { 198 cfg RulesConfig 199 expected map[string]rulefmt.RuleGroups 200 wantErr error 201 }{ 202 { 203 cfg: RulesConfig{ 204 FormatVersion: RuleFormatV1, 205 Files: map[string]string{ 206 "legacy.rules": legacyRulesFile, 207 }, 208 }, 209 expected: map[string]rulefmt.RuleGroups{ 210 "legacy.rules": { 211 Groups: []rulefmt.RuleGroup{ 212 { 213 Name: "rg:legacy.rules", 214 Rules: rulesV1, 215 }, 216 }, 217 }, 218 }, 219 wantErr: fmt.Errorf("version 0 isn't supported"), 220 }, 221 { 222 cfg: RulesConfig{ 223 FormatVersion: RuleFormatV2, 224 Files: map[string]string{ 225 "alerts.yaml": ruleFile, 226 }, 227 }, 228 expected: map[string]rulefmt.RuleGroups{ 229 "alerts.yaml": { 230 Groups: []rulefmt.RuleGroup{ 231 { 232 Name: "example", 233 Rules: rulesV2, 234 }, 235 }, 236 }, 237 }, 238 wantErr: nil, 239 }, 240 } { 241 t.Run(strconv.Itoa(i), func(t *testing.T) { 242 rules, err := tc.cfg.ParseFormatted() 243 if tc.wantErr != nil { 244 require.EqualError(t, err, tc.wantErr.Error()) 245 } else { 246 require.NoError(t, err) 247 require.Equal(t, tc.expected, rules) 248 } 249 }) 250 } 251 }