bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/sched/depends_test.go (about) 1 package sched 2 3 import ( 4 "testing" 5 "time" 6 7 "bosun.org/models" 8 "bosun.org/opentsdb" 9 ) 10 11 // Crit returns {a=b},{a=c}, but {a=b} is ignored by dependency expression. 12 // Result should be {a=c} only. 13 func TestDependency_Simple(t *testing.T) { 14 defer setup()() 15 testSched(t, &schedTest{ 16 conf: `alert a { 17 crit = avg(q("avg:c{a=*}", "5m", "")) > 0 18 depends = avg(q("avg:d{a=*}", "5m", "")) > 0 19 }`, 20 queries: map[string]opentsdb.ResponseSet{ 21 `q("avg:c{a=*}", ` + window5Min + `)`: { 22 { 23 Metric: "c", 24 Tags: opentsdb.TagSet{"a": "b"}, 25 DPS: map[string]opentsdb.Point{"0": 1}, 26 }, 27 { 28 Metric: "c", 29 Tags: opentsdb.TagSet{"a": "c"}, 30 DPS: map[string]opentsdb.Point{"0": 1}, 31 }, 32 }, 33 `q("avg:d{a=*}", ` + window5Min + `)`: { 34 { 35 Metric: "d", 36 Tags: opentsdb.TagSet{"a": "b"}, 37 DPS: map[string]opentsdb.Point{"0": 1}, 38 }, 39 { 40 Metric: "d", 41 Tags: opentsdb.TagSet{"a": "c"}, 42 DPS: map[string]opentsdb.Point{"0": 0}, 43 }, 44 }, 45 }, 46 state: map[schedState]bool{ 47 {"a{a=c}", "critical"}: true, 48 }, 49 }) 50 } 51 52 // Crit and depends don't have same tag sets. 53 func TestDependency_Overlap(t *testing.T) { 54 defer setup()() 55 testSched(t, &schedTest{ 56 conf: `alert a { 57 crit = avg(q("avg:c{a=*,b=*}", "5m", "")) > 0 58 depends = avg(q("avg:d{a=*,d=*}", "5m", "")) > 0 59 }`, 60 queries: map[string]opentsdb.ResponseSet{ 61 `q("avg:c{a=*,b=*}", ` + window5Min + `)`: { 62 { 63 Metric: "c", 64 Tags: opentsdb.TagSet{"a": "b", "b": "r"}, 65 DPS: map[string]opentsdb.Point{"0": 1}, 66 }, 67 { 68 Metric: "c", 69 Tags: opentsdb.TagSet{"a": "b", "b": "z"}, 70 DPS: map[string]opentsdb.Point{"0": 1}, 71 }, 72 { 73 Metric: "c", 74 Tags: opentsdb.TagSet{"a": "c", "b": "q"}, 75 DPS: map[string]opentsdb.Point{"0": 1}, 76 }, 77 }, 78 `q("avg:d{a=*,d=*}", ` + window5Min + `)`: { 79 { 80 Metric: "d", 81 Tags: opentsdb.TagSet{"a": "b", "d": "q"}, //this matches first and second datapoints from crit. 82 DPS: map[string]opentsdb.Point{"0": 1}, 83 }, 84 }, 85 }, 86 state: map[schedState]bool{ 87 {"a{a=c,b=q}", "critical"}: true, 88 }, 89 }) 90 } 91 92 func TestDependency_OtherAlert(t *testing.T) { 93 defer setup()() 94 testSched(t, &schedTest{ 95 conf: `alert a { 96 crit = avg(q("avg:a{host=*,cpu=*}", "5m", "")) > 0 97 } 98 alert b{ 99 depends = alert("a","crit") 100 crit = avg(q("avg:b{host=*}", "5m", "")) > 0 101 } 102 alert c{ 103 crit = avg(q("avg:b{host=*}", "5m", "")) > 0 104 } 105 alert d{ 106 #b will be unevaluated because of a. 107 depends = alert("b","crit") 108 crit = avg(q("avg:b{host=*}", "5m", "")) > 0 109 } 110 `, 111 queries: map[string]opentsdb.ResponseSet{ 112 `q("avg:a{cpu=*,host=*}", ` + window5Min + `)`: { 113 { 114 Metric: "a", 115 Tags: opentsdb.TagSet{"host": "ny01", "cpu": "0"}, 116 DPS: map[string]opentsdb.Point{"0": 1}, 117 }, 118 }, 119 `q("avg:b{host=*}", ` + window5Min + `)`: { 120 { 121 Metric: "b", 122 Tags: opentsdb.TagSet{"host": "ny01"}, 123 DPS: map[string]opentsdb.Point{"0": 1}, 124 }, 125 }, 126 }, 127 state: map[schedState]bool{ 128 {"a{cpu=0,host=ny01}", "critical"}: true, 129 {"c{host=ny01}", "critical"}: true, 130 }, 131 }) 132 } 133 134 func TestDependency_OtherAlert_Unknown(t *testing.T) { 135 defer setup()() 136 137 testSched(t, &schedTest{ 138 conf: `alert a { 139 warn = avg(q("avg:a{host=*}", "5m", "")) > 0 140 } 141 142 alert os.cpu { 143 depends = alert("a", "warn") 144 warn = avg(q("avg:os.cpu{host=*}", "5m", "")) > 5 145 } 146 `, 147 queries: map[string]opentsdb.ResponseSet{ 148 `q("avg:a{host=*}", ` + window5Min + `)`: { 149 { 150 Metric: "a", 151 Tags: opentsdb.TagSet{"host": "ny01"}, 152 DPS: map[string]opentsdb.Point{"0": 0}, 153 }, 154 //no results for ny02. Goes unkown here. 155 }, 156 `q("avg:os.cpu{host=*}", ` + window5Min + `)`: { 157 { 158 Metric: "os.cpu", 159 Tags: opentsdb.TagSet{"host": "ny01"}, 160 DPS: map[string]opentsdb.Point{"0": 10}, 161 }, 162 { 163 Metric: "os.cpu", 164 Tags: opentsdb.TagSet{"host": "ny02"}, 165 DPS: map[string]opentsdb.Point{"0": 10}, 166 }, 167 }, 168 }, 169 state: map[schedState]bool{ 170 {"a{host=ny02}", "unknown"}: true, 171 {"os.cpu{host=ny01}", "warning"}: true, 172 }, 173 touched: map[models.AlertKey]time.Time{ 174 "a{host=ny02}": queryTime.Add(-10 * time.Minute), 175 }, 176 }) 177 } 178 179 func TestDependency_OtherAlert_UnknownChain(t *testing.T) { 180 defer setup()() 181 ab := models.AlertKey("a{host=b}") 182 bb := models.AlertKey("b{host=b}") 183 cb := models.AlertKey("c{host=b}") 184 185 s := testSched(t, &schedTest{ 186 conf: ` 187 alert a { 188 warn = avg(q("avg:a{host=*}", "5m", "")) && 0 189 } 190 191 alert b { 192 depends = alert("a", "warn") 193 warn = avg(q("avg:b{host=*}", "5m", "")) > 0 194 } 195 196 alert c { 197 depends = alert("b", "warn") 198 warn = avg(q("avg:b{host=*}", "5m", "")) > 0 199 } 200 `, 201 queries: map[string]opentsdb.ResponseSet{ 202 `q("avg:a{host=*}", ` + window5Min + `)`: {}, 203 `q("avg:b{host=*}", ` + window5Min + `)`: {{ 204 Metric: "b", 205 Tags: opentsdb.TagSet{"host": "b"}, 206 DPS: map[string]opentsdb.Point{"0": 0}, 207 }}, 208 }, 209 state: map[schedState]bool{ 210 {string(ab), "unknown"}: true, 211 }, 212 touched: map[models.AlertKey]time.Time{ 213 ab: queryTime.Add(-time.Hour), 214 bb: queryTime, 215 cb: queryTime, 216 }, 217 }) 218 check := func(ak models.AlertKey, expec bool) { 219 _, uneval, err := s.DataAccess.State().GetUnknownAndUnevalAlertKeys(ak.Name()) 220 if err != nil { 221 t.Fatal(err) 222 } 223 for _, ak2 := range uneval { 224 if ak2 == ak { 225 if !expec { 226 t.Fatalf("Should not be unevaluated: %s", ak) 227 } else { 228 return 229 } 230 } 231 } 232 if expec { 233 t.Fatalf("Should be unevaluated: %s", ak) 234 } 235 } 236 check(ab, false) 237 check(bb, true) 238 check(cb, true) 239 } 240 241 func TestDependency_Blocks_Unknown(t *testing.T) { 242 defer setup()() 243 testSched(t, &schedTest{ 244 conf: `alert a { 245 depends = avg(q("avg:b{host=*}", "5m", "")) > 0 246 warn = avg(q("avg:a{host=*}", "5m", "")) > 0 247 }`, 248 queries: map[string]opentsdb.ResponseSet{ 249 `q("avg:a{host=*}", ` + window5Min + `)`: { 250 //no results for a. Goes unkown here. 251 }, 252 `q("avg:b{host=*}", ` + window5Min + `)`: { 253 { 254 Metric: "os.cpu", 255 Tags: opentsdb.TagSet{"host": "ny01"}, 256 DPS: map[string]opentsdb.Point{"0": 10}, 257 }, 258 }, 259 }, 260 state: map[schedState]bool{}, 261 touched: map[models.AlertKey]time.Time{ 262 "a{host=ny01}": queryTime.Add(-10 * time.Minute), 263 }, 264 }) 265 } 266 267 func TestDependency_AlertFunctionHasNoResults(t *testing.T) { 268 defer setup()() 269 270 testSched(t, &schedTest{ 271 conf: ` 272 alert a { 273 warn = max(rename(q("sum:bosun.ping.timeout{dst_host=*,host=*}", "5m", ""), "host=source,dst_host=host")) 274 } 275 276 alert b { 277 depends = alert("a", "warn") 278 warn = avg(q("avg:os.cpu{host=*}", "5m", "")) < -100 279 } 280 281 alert c { 282 depends = alert("b", "warn") 283 warn = avg(q("avg:rate{counter,,1}:os.cpu{host=*}", "5m", "")) 284 } 285 `, 286 queries: map[string]opentsdb.ResponseSet{ 287 `q("sum:bosun.ping.timeout{dst_host=*,host=*}", ` + window5Min + `)`: { 288 { 289 Metric: "bosun.ping.timeout", 290 Tags: opentsdb.TagSet{"host": "bosun01", "dst_host": "ny01"}, 291 DPS: map[string]opentsdb.Point{"0": 1}, //ping fails 292 }, 293 }, 294 `q("avg:os.cpu{host=*}", ` + window5Min + `)`: {}, //no other data 295 `q("avg:rate{counter,,1}:os.cpu{host=*}", ` + window5Min + `)`: {}, 296 }, 297 state: map[schedState]bool{ 298 {"a{host=ny01,source=bosun01}", "warning"}: true, 299 }, 300 touched: map[models.AlertKey]time.Time{ 301 "a{host=ny01,source=bosun01}": queryTime.Add(-5 * time.Minute), 302 "b{host=ny01}": queryTime.Add(-10 * time.Minute), 303 "c{host=ny01}": queryTime.Add(-10 * time.Minute), 304 }, 305 }) 306 }