eval_handler_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package alerting
  15. import (
  16. "context"
  17. "testing"
  18. . "github.com/smartystreets/goconvey/convey"
  19. "yunion.io/x/onecloud/pkg/apis/monitor"
  20. )
  21. type conditionStub struct {
  22. firing bool
  23. operator string
  24. matches []*monitor.EvalMatch
  25. noData bool
  26. }
  27. func (c *conditionStub) Eval(context *EvalContext) (*ConditionResult, error) {
  28. return &ConditionResult{Firing: c.firing, EvalMatches: c.matches, Operator: c.operator, NoDataFound: c.noData}, nil
  29. }
  30. func TestAlertingEvaluationHandler(t *testing.T) {
  31. Convey("Test alert evaluation handler", t, func() {
  32. handler := NewEvalHandler()
  33. Convey("Show return triggered with single passing condition", func() {
  34. ctx := NewEvalContext(context.TODO(), nil, &Rule{
  35. Conditions: []Condition{&conditionStub{firing: true}},
  36. })
  37. handler.Eval(ctx)
  38. So(ctx.Firing, ShouldEqual, true)
  39. So(ctx.ConditionEvals, ShouldEqual, "true = true")
  40. })
  41. Convey("Show return triggered with single passing conditions2", func() {
  42. ctx := NewEvalContext(context.TODO(), nil, &Rule{
  43. Conditions: []Condition{&conditionStub{firing: true, operator: "and"}},
  44. })
  45. handler.Eval(ctx)
  46. So(ctx.Firing, ShouldEqual, true)
  47. So(ctx.ConditionEvals, ShouldEqual, "true = true")
  48. })
  49. Convey("Show return false with not passing asdf", func() {
  50. ctx := NewEvalContext(context.TODO(), nil, &Rule{
  51. Conditions: []Condition{
  52. &conditionStub{firing: true, operator: "and", matches: []*monitor.EvalMatch{{}, {}}},
  53. &conditionStub{firing: false, operator: "and"},
  54. }})
  55. handler.Eval(ctx)
  56. So(ctx.Firing, ShouldEqual, false)
  57. So(ctx.ConditionEvals, ShouldEqual, "[true AND false] = false")
  58. })
  59. Convey("Show return true if any of condition is passing with OR operator", func() {
  60. ctx := NewEvalContext(context.TODO(), nil, &Rule{
  61. Conditions: []Condition{
  62. &conditionStub{firing: true, operator: "and"},
  63. &conditionStub{firing: false, operator: "or"},
  64. },
  65. })
  66. handler.Eval(ctx)
  67. So(ctx.Firing, ShouldEqual, true)
  68. So(ctx.ConditionEvals, ShouldEqual, "[true OR false] = true")
  69. })
  70. Convey("Show return false if any of the condition is failing with AND operator", func() {
  71. context := NewEvalContext(context.TODO(), nil, &Rule{
  72. Conditions: []Condition{
  73. &conditionStub{firing: true, operator: "and"},
  74. &conditionStub{firing: false, operator: "and"},
  75. },
  76. })
  77. handler.Eval(context)
  78. So(context.Firing, ShouldEqual, false)
  79. So(context.ConditionEvals, ShouldEqual, "[true AND false] = false")
  80. })
  81. Convey("Show return true if one condition is failing with nested OR operator", func() {
  82. context := NewEvalContext(context.TODO(), nil, &Rule{
  83. Conditions: []Condition{
  84. &conditionStub{firing: true, operator: "and"},
  85. &conditionStub{firing: true, operator: "and"},
  86. &conditionStub{firing: false, operator: "or"},
  87. },
  88. })
  89. handler.Eval(context)
  90. So(context.Firing, ShouldEqual, true)
  91. So(context.ConditionEvals, ShouldEqual, "[[true AND true] OR false] = true")
  92. })
  93. Convey("Show return false if one condition is passing with nested OR operator", func() {
  94. context := NewEvalContext(context.TODO(), nil, &Rule{
  95. Conditions: []Condition{
  96. &conditionStub{firing: true, operator: "and"},
  97. &conditionStub{firing: false, operator: "and"},
  98. &conditionStub{firing: false, operator: "or"},
  99. },
  100. })
  101. handler.Eval(context)
  102. So(context.Firing, ShouldEqual, false)
  103. So(context.ConditionEvals, ShouldEqual, "[[true AND false] OR false] = false")
  104. })
  105. Convey("Show return false if a condition is failing with nested AND operator", func() {
  106. context := NewEvalContext(context.TODO(), nil, &Rule{
  107. Conditions: []Condition{
  108. &conditionStub{firing: true, operator: "and"},
  109. &conditionStub{firing: false, operator: "and"},
  110. &conditionStub{firing: true, operator: "and"},
  111. },
  112. })
  113. handler.Eval(context)
  114. So(context.Firing, ShouldEqual, false)
  115. So(context.ConditionEvals, ShouldEqual, "[[true AND false] AND true] = false")
  116. })
  117. Convey("Show return true if a condition is passing with nested OR operator", func() {
  118. context := NewEvalContext(context.TODO(), nil, &Rule{
  119. Conditions: []Condition{
  120. &conditionStub{firing: true, operator: "and"},
  121. &conditionStub{firing: false, operator: "or"},
  122. &conditionStub{firing: true, operator: "or"},
  123. },
  124. })
  125. handler.Eval(context)
  126. So(context.Firing, ShouldEqual, true)
  127. So(context.ConditionEvals, ShouldEqual, "[[true OR false] OR true] = true")
  128. })
  129. Convey("Should return false if no condition is firing using OR operator", func() {
  130. context := NewEvalContext(context.TODO(), nil, &Rule{
  131. Conditions: []Condition{
  132. &conditionStub{firing: false, operator: "or"},
  133. &conditionStub{firing: false, operator: "or"},
  134. &conditionStub{firing: false, operator: "or"},
  135. },
  136. })
  137. handler.Eval(context)
  138. So(context.Firing, ShouldEqual, false)
  139. So(context.ConditionEvals, ShouldEqual, "[[false OR false] OR false] = false")
  140. })
  141. Convey("Should retuasdfrn no data if one condition has nodata", func() {
  142. context := NewEvalContext(context.TODO(), nil, &Rule{
  143. Conditions: []Condition{
  144. &conditionStub{operator: "or", noData: false},
  145. &conditionStub{operator: "or", noData: false},
  146. &conditionStub{operator: "or", noData: false},
  147. },
  148. })
  149. handler.Eval(context)
  150. So(context.NoDataFound, ShouldBeFalse)
  151. })
  152. Convey("Should return no data if one condition has nodata", func() {
  153. context := NewEvalContext(context.TODO(), nil, &Rule{
  154. Conditions: []Condition{
  155. &conditionStub{operator: "and", noData: true},
  156. },
  157. })
  158. handler.Eval(context)
  159. So(context.Firing, ShouldEqual, false)
  160. So(context.NoDataFound, ShouldBeTrue)
  161. })
  162. Convey("Should return no data if both conditions have no data and using AND", func() {
  163. context := NewEvalContext(context.TODO(), nil, &Rule{
  164. Conditions: []Condition{
  165. &conditionStub{operator: "and", noData: true},
  166. &conditionStub{operator: "and", noData: false},
  167. },
  168. })
  169. handler.Eval(context)
  170. So(context.NoDataFound, ShouldBeFalse)
  171. })
  172. Convey("Should not return no data if both conditions have no data and using OR", func() {
  173. ctx := NewEvalContext(context.TODO(), nil, &Rule{
  174. Conditions: []Condition{
  175. &conditionStub{operator: "or", noData: true},
  176. &conditionStub{operator: "or", noData: false},
  177. },
  178. })
  179. handler.Eval(ctx)
  180. So(ctx.NoDataFound, ShouldBeTrue)
  181. })
  182. })
  183. }