eval_context_test.go 6.2 KB

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