eval_handler_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package alerting
  2. import (
  3. "context"
  4. "testing"
  5. . "github.com/smartystreets/goconvey/convey"
  6. )
  7. type conditionStub struct {
  8. firing bool
  9. operator string
  10. matches []*EvalMatch
  11. noData bool
  12. }
  13. func (c *conditionStub) Eval(context *EvalContext) (*ConditionResult, error) {
  14. return &ConditionResult{Firing: c.firing, EvalMatches: c.matches, Operator: c.operator, NoDataFound: c.noData}, nil
  15. }
  16. func TestAlertingEvaluationHandler(t *testing.T) {
  17. Convey("Test alert evaluation handler", t, func() {
  18. handler := NewEvalHandler()
  19. Convey("Show return triggered with single passing condition", func() {
  20. context := NewEvalContext(context.TODO(), &Rule{
  21. Conditions: []Condition{&conditionStub{
  22. firing: true,
  23. }},
  24. })
  25. handler.Eval(context)
  26. So(context.Firing, ShouldEqual, true)
  27. So(context.ConditionEvals, ShouldEqual, "true = true")
  28. })
  29. Convey("Show return triggered with single passing condition2", func() {
  30. context := NewEvalContext(context.TODO(), &Rule{
  31. Conditions: []Condition{&conditionStub{firing: true, operator: "and"}},
  32. })
  33. handler.Eval(context)
  34. So(context.Firing, ShouldEqual, true)
  35. So(context.ConditionEvals, ShouldEqual, "true = true")
  36. })
  37. Convey("Show return false with not passing asdf", func() {
  38. context := NewEvalContext(context.TODO(), &Rule{
  39. Conditions: []Condition{
  40. &conditionStub{firing: true, operator: "and", matches: []*EvalMatch{{}, {}}},
  41. &conditionStub{firing: false, operator: "and"},
  42. },
  43. })
  44. handler.Eval(context)
  45. So(context.Firing, ShouldEqual, false)
  46. So(context.ConditionEvals, ShouldEqual, "[true AND false] = false")
  47. })
  48. Convey("Show return true if any of the condition is passing with OR operator", func() {
  49. context := NewEvalContext(context.TODO(), &Rule{
  50. Conditions: []Condition{
  51. &conditionStub{firing: true, operator: "and"},
  52. &conditionStub{firing: false, operator: "or"},
  53. },
  54. })
  55. handler.Eval(context)
  56. So(context.Firing, ShouldEqual, true)
  57. So(context.ConditionEvals, ShouldEqual, "[true OR false] = true")
  58. })
  59. Convey("Show return false if any of the condition is failing with AND operator", func() {
  60. context := NewEvalContext(context.TODO(), &Rule{
  61. Conditions: []Condition{
  62. &conditionStub{firing: true, operator: "and"},
  63. &conditionStub{firing: false, operator: "and"},
  64. },
  65. })
  66. handler.Eval(context)
  67. So(context.Firing, ShouldEqual, false)
  68. So(context.ConditionEvals, ShouldEqual, "[true AND false] = false")
  69. })
  70. Convey("Show return true if one condition is failing with nested OR operator", func() {
  71. context := NewEvalContext(context.TODO(), &Rule{
  72. Conditions: []Condition{
  73. &conditionStub{firing: true, operator: "and"},
  74. &conditionStub{firing: true, operator: "and"},
  75. &conditionStub{firing: false, operator: "or"},
  76. },
  77. })
  78. handler.Eval(context)
  79. So(context.Firing, ShouldEqual, true)
  80. So(context.ConditionEvals, ShouldEqual, "[[true AND true] OR false] = true")
  81. })
  82. Convey("Show return false if one condition is passing with nested OR operator", func() {
  83. context := NewEvalContext(context.TODO(), &Rule{
  84. Conditions: []Condition{
  85. &conditionStub{firing: true, operator: "and"},
  86. &conditionStub{firing: false, operator: "and"},
  87. &conditionStub{firing: false, operator: "or"},
  88. },
  89. })
  90. handler.Eval(context)
  91. So(context.Firing, ShouldEqual, false)
  92. So(context.ConditionEvals, ShouldEqual, "[[true AND false] OR false] = false")
  93. })
  94. Convey("Show return false if a condition is failing with nested AND operator", func() {
  95. context := NewEvalContext(context.TODO(), &Rule{
  96. Conditions: []Condition{
  97. &conditionStub{firing: true, operator: "and"},
  98. &conditionStub{firing: false, operator: "and"},
  99. &conditionStub{firing: true, operator: "and"},
  100. },
  101. })
  102. handler.Eval(context)
  103. So(context.Firing, ShouldEqual, false)
  104. So(context.ConditionEvals, ShouldEqual, "[[true AND false] AND true] = false")
  105. })
  106. Convey("Show return true if a condition is passing with nested OR operator", func() {
  107. context := NewEvalContext(context.TODO(), &Rule{
  108. Conditions: []Condition{
  109. &conditionStub{firing: true, operator: "and"},
  110. &conditionStub{firing: false, operator: "or"},
  111. &conditionStub{firing: true, operator: "or"},
  112. },
  113. })
  114. handler.Eval(context)
  115. So(context.Firing, ShouldEqual, true)
  116. So(context.ConditionEvals, ShouldEqual, "[[true OR false] OR true] = true")
  117. })
  118. Convey("Should return false if no condition is firing using OR operator", func() {
  119. context := NewEvalContext(context.TODO(), &Rule{
  120. Conditions: []Condition{
  121. &conditionStub{firing: false, operator: "or"},
  122. &conditionStub{firing: false, operator: "or"},
  123. &conditionStub{firing: false, operator: "or"},
  124. },
  125. })
  126. handler.Eval(context)
  127. So(context.Firing, ShouldEqual, false)
  128. So(context.ConditionEvals, ShouldEqual, "[[false OR false] OR false] = false")
  129. })
  130. Convey("Should retuasdfrn no data if one condition has nodata", func() {
  131. context := NewEvalContext(context.TODO(), &Rule{
  132. Conditions: []Condition{
  133. &conditionStub{operator: "or", noData: false},
  134. &conditionStub{operator: "or", noData: false},
  135. &conditionStub{operator: "or", noData: false},
  136. },
  137. })
  138. handler.Eval(context)
  139. So(context.NoDataFound, ShouldBeFalse)
  140. })
  141. Convey("Should return no data if one condition has nodata", func() {
  142. context := NewEvalContext(context.TODO(), &Rule{
  143. Conditions: []Condition{
  144. &conditionStub{operator: "and", noData: true},
  145. },
  146. })
  147. handler.Eval(context)
  148. So(context.Firing, ShouldEqual, false)
  149. So(context.NoDataFound, ShouldBeTrue)
  150. })
  151. Convey("Should return no data if both conditions have no data and using AND", func() {
  152. context := NewEvalContext(context.TODO(), &Rule{
  153. Conditions: []Condition{
  154. &conditionStub{operator: "and", noData: true},
  155. &conditionStub{operator: "and", noData: false},
  156. },
  157. })
  158. handler.Eval(context)
  159. So(context.NoDataFound, ShouldBeFalse)
  160. })
  161. Convey("Should not return no data if both conditions have no data and using OR", func() {
  162. context := NewEvalContext(context.TODO(), &Rule{
  163. Conditions: []Condition{
  164. &conditionStub{operator: "or", noData: true},
  165. &conditionStub{operator: "or", noData: false},
  166. },
  167. })
  168. handler.Eval(context)
  169. So(context.NoDataFound, ShouldBeTrue)
  170. })
  171. })
  172. }