eval_context_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. "errors"
  18. "testing"
  19. "time"
  20. "github.com/stretchr/testify/assert"
  21. "yunion.io/x/onecloud/pkg/apis/monitor"
  22. )
  23. func TestStateIsUpdatedWhenNeeded(t *testing.T) {
  24. ctx := NewEvalContext(context.TODO(), nil, &Rule{Conditions: []Condition{&conditionStub{firing: true}}})
  25. t.Run("ok -> alerting", func(t *testing.T) {
  26. ctx.PrevAlertState = monitor.AlertStateOK
  27. ctx.Rule.State = monitor.AlertStateAlerting
  28. if !ctx.shouldUpdateAlertState() {
  29. t.Fatalf("expected should updated to be true")
  30. }
  31. })
  32. t.Run("ok -> ok", func(t *testing.T) {
  33. ctx.PrevAlertState = monitor.AlertStateOK
  34. ctx.Rule.State = monitor.AlertStateOK
  35. if ctx.shouldUpdateAlertState() {
  36. t.Fatalf("expected should updated to be false")
  37. }
  38. })
  39. }
  40. func TestGetStateFromEvalContext(t *testing.T) {
  41. tcs := []struct {
  42. name string
  43. expected monitor.AlertStateType
  44. applyFn func(ec *EvalContext)
  45. }{
  46. {
  47. name: "ok -> alerting",
  48. expected: monitor.AlertStateAlerting,
  49. applyFn: func(ec *EvalContext) {
  50. ec.Firing = true
  51. ec.PrevAlertState = monitor.AlertStateOK
  52. },
  53. },
  54. {
  55. name: "ok -> error(alerting)",
  56. expected: monitor.AlertStateAlerting,
  57. applyFn: func(ec *EvalContext) {
  58. ec.PrevAlertState = monitor.AlertStateOK
  59. ec.Error = errors.New("test error")
  60. ec.Rule.ExecutionErrorState = monitor.ExecutionErrorSetAlerting
  61. },
  62. },
  63. {
  64. name: "ok -> pending. since its been firing for less than FOR",
  65. expected: monitor.AlertStatePending,
  66. applyFn: func(ec *EvalContext) {
  67. ec.PrevAlertState = monitor.AlertStateOK
  68. ec.Firing = true
  69. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 2)
  70. ec.Rule.For = time.Minute * 5
  71. },
  72. },
  73. {
  74. name: "ok -> pending. since it has to be pending longer than FOR and prev state is ok",
  75. expected: monitor.AlertStatePending,
  76. applyFn: func(ec *EvalContext) {
  77. ec.PrevAlertState = monitor.AlertStateOK
  78. ec.Firing = true
  79. ec.Rule.LastStateChange = time.Now().Add(-(time.Hour * 5))
  80. ec.Rule.For = time.Minute * 2
  81. },
  82. },
  83. {
  84. name: "pending -> alerting. since its been firing for more than FOR and prev state is pending",
  85. expected: monitor.AlertStateAlerting,
  86. applyFn: func(ec *EvalContext) {
  87. ec.PrevAlertState = monitor.AlertStatePending
  88. ec.Firing = true
  89. ec.Rule.LastStateChange = time.Now().Add(-(time.Hour * 5))
  90. ec.Rule.For = time.Minute * 2 / time.Second
  91. },
  92. },
  93. {
  94. name: "alerting -> alerting. should not update regardless of FOR",
  95. expected: monitor.AlertStateAlerting,
  96. applyFn: func(ec *EvalContext) {
  97. ec.PrevAlertState = monitor.AlertStateAlerting
  98. ec.Firing = true
  99. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  100. ec.Rule.For = time.Minute * 2 / time.Second
  101. },
  102. },
  103. {
  104. name: "ok -> ok. should not update regardless of FOR",
  105. expected: monitor.AlertStateOK,
  106. applyFn: func(ec *EvalContext) {
  107. ec.PrevAlertState = monitor.AlertStateOK
  108. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  109. ec.Rule.For = time.Minute * 2 / time.Second
  110. },
  111. },
  112. {
  113. name: "ok -> error(keep_last)",
  114. expected: monitor.AlertStateOK,
  115. applyFn: func(ec *EvalContext) {
  116. ec.PrevAlertState = monitor.AlertStateOK
  117. ec.Error = errors.New("test error")
  118. ec.Rule.ExecutionErrorState = monitor.ExecutionErrorKeepState
  119. },
  120. },
  121. {
  122. name: "pending -> error(keep_last)",
  123. expected: monitor.AlertStatePending,
  124. applyFn: func(ec *EvalContext) {
  125. ec.PrevAlertState = monitor.AlertStatePending
  126. ec.Error = errors.New("test error")
  127. ec.Rule.ExecutionErrorState = monitor.ExecutionErrorKeepState
  128. },
  129. },
  130. {
  131. name: "ok -> no_data(alerting)",
  132. expected: monitor.AlertStateAlerting,
  133. applyFn: func(ec *EvalContext) {
  134. ec.PrevAlertState = monitor.AlertStateOK
  135. ec.Rule.NoDataState = monitor.NoDataSetAlerting
  136. ec.NoDataFound = true
  137. },
  138. },
  139. {
  140. name: "ok -> no_data(keep_last)",
  141. expected: monitor.AlertStateOK,
  142. applyFn: func(ec *EvalContext) {
  143. ec.PrevAlertState = monitor.AlertStateOK
  144. ec.Rule.NoDataState = monitor.NoDataKeepState
  145. ec.NoDataFound = true
  146. },
  147. },
  148. {
  149. name: "pending -> no_data(keep_last)",
  150. expected: monitor.AlertStatePending,
  151. applyFn: func(ec *EvalContext) {
  152. ec.PrevAlertState = monitor.AlertStatePending
  153. ec.Rule.NoDataState = monitor.NoDataKeepState
  154. ec.NoDataFound = true
  155. },
  156. },
  157. {
  158. name: "pending -> no_data(alerting) with for duration have not passed",
  159. expected: monitor.AlertStatePending,
  160. applyFn: func(ec *EvalContext) {
  161. ec.PrevAlertState = monitor.AlertStatePending
  162. ec.Rule.NoDataState = monitor.NoDataSetAlerting
  163. ec.NoDataFound = true
  164. ec.Rule.For = time.Minute * 5 / time.Second
  165. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 2)
  166. },
  167. },
  168. {
  169. name: "pending -> no_data(alerting) should set alerting since time passed FOR",
  170. expected: monitor.AlertStateAlerting,
  171. applyFn: func(ec *EvalContext) {
  172. ec.PrevAlertState = monitor.AlertStatePending
  173. ec.Rule.NoDataState = monitor.NoDataSetAlerting
  174. ec.NoDataFound = true
  175. ec.Rule.For = time.Minute * 2 / time.Second
  176. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  177. },
  178. },
  179. {
  180. name: "pending -> error(alerting) with for duration have not passed ",
  181. expected: monitor.AlertStatePending,
  182. applyFn: func(ec *EvalContext) {
  183. ec.PrevAlertState = monitor.AlertStatePending
  184. ec.Rule.ExecutionErrorState = monitor.ExecutionErrorSetAlerting
  185. ec.Error = errors.New("test error")
  186. ec.Rule.For = time.Minute * 5 / time.Second
  187. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 2)
  188. },
  189. },
  190. {
  191. name: "pending -> error(alerting) should set alerting since time passed FOR",
  192. expected: monitor.AlertStateAlerting,
  193. applyFn: func(ec *EvalContext) {
  194. ec.PrevAlertState = monitor.AlertStatePending
  195. ec.Rule.ExecutionErrorState = monitor.ExecutionErrorSetAlerting
  196. ec.Error = errors.New("test error")
  197. ec.Rule.For = time.Minute * 2 / time.Second
  198. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  199. },
  200. },
  201. }
  202. for _, tc := range tcs {
  203. evalContext := NewEvalContext(context.Background(), nil, &Rule{Conditions: []Condition{&conditionStub{firing: true}}})
  204. tc.applyFn(evalContext)
  205. newState := evalContext.GetNewState()
  206. assert.Equal(t, tc.expected, newState, "failed: %s \n expected '%s' have '%s'\n", tc.name, tc.expected, string(newState))
  207. }
  208. }