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  }