eval_context_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package alerting
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. "time"
  7. "github.com/grafana/grafana/pkg/models"
  8. )
  9. func TestStateIsUpdatedWhenNeeded(t *testing.T) {
  10. ctx := NewEvalContext(context.TODO(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}})
  11. t.Run("ok -> alerting", func(t *testing.T) {
  12. ctx.PrevAlertState = models.AlertStateOK
  13. ctx.Rule.State = models.AlertStateAlerting
  14. if !ctx.ShouldUpdateAlertState() {
  15. t.Fatalf("expected should updated to be true")
  16. }
  17. })
  18. t.Run("ok -> ok", func(t *testing.T) {
  19. ctx.PrevAlertState = models.AlertStateOK
  20. ctx.Rule.State = models.AlertStateOK
  21. if ctx.ShouldUpdateAlertState() {
  22. t.Fatalf("expected should updated to be false")
  23. }
  24. })
  25. }
  26. func TestGetStateFromEvalContext(t *testing.T) {
  27. tcs := []struct {
  28. name string
  29. expected models.AlertStateType
  30. applyFn func(ec *EvalContext)
  31. focus bool
  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 -> alerting. since its been firing for more than FOR",
  62. expected: models.AlertStateAlerting,
  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: "alerting -> alerting. should not update regardless of FOR",
  72. expected: models.AlertStateAlerting,
  73. applyFn: func(ec *EvalContext) {
  74. ec.PrevAlertState = models.AlertStateAlerting
  75. ec.Firing = true
  76. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  77. ec.Rule.For = time.Minute * 2
  78. },
  79. },
  80. {
  81. name: "ok -> ok. should not update regardless of FOR",
  82. expected: models.AlertStateOK,
  83. applyFn: func(ec *EvalContext) {
  84. ec.PrevAlertState = models.AlertStateOK
  85. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  86. ec.Rule.For = time.Minute * 2
  87. },
  88. },
  89. {
  90. name: "ok -> error(keep_last)",
  91. expected: models.AlertStateOK,
  92. applyFn: func(ec *EvalContext) {
  93. ec.PrevAlertState = models.AlertStateOK
  94. ec.Error = errors.New("test error")
  95. ec.Rule.ExecutionErrorState = models.ExecutionErrorKeepState
  96. },
  97. },
  98. {
  99. name: "pending -> error(keep_last)",
  100. expected: models.AlertStatePending,
  101. applyFn: func(ec *EvalContext) {
  102. ec.PrevAlertState = models.AlertStatePending
  103. ec.Error = errors.New("test error")
  104. ec.Rule.ExecutionErrorState = models.ExecutionErrorKeepState
  105. },
  106. },
  107. {
  108. name: "ok -> no_data(alerting)",
  109. expected: models.AlertStateAlerting,
  110. applyFn: func(ec *EvalContext) {
  111. ec.PrevAlertState = models.AlertStateOK
  112. ec.Rule.NoDataState = models.NoDataSetAlerting
  113. ec.NoDataFound = true
  114. },
  115. },
  116. {
  117. name: "ok -> no_data(keep_last)",
  118. expected: models.AlertStateOK,
  119. applyFn: func(ec *EvalContext) {
  120. ec.PrevAlertState = models.AlertStateOK
  121. ec.Rule.NoDataState = models.NoDataKeepState
  122. ec.NoDataFound = true
  123. },
  124. },
  125. {
  126. name: "pending -> no_data(keep_last)",
  127. expected: models.AlertStatePending,
  128. applyFn: func(ec *EvalContext) {
  129. ec.PrevAlertState = models.AlertStatePending
  130. ec.Rule.NoDataState = models.NoDataKeepState
  131. ec.NoDataFound = true
  132. },
  133. },
  134. {
  135. name: "pending -> no_data(alerting) with for duration have not passed",
  136. expected: models.AlertStatePending,
  137. applyFn: func(ec *EvalContext) {
  138. ec.PrevAlertState = models.AlertStatePending
  139. ec.Rule.NoDataState = models.NoDataSetAlerting
  140. ec.NoDataFound = true
  141. ec.Rule.For = time.Minute * 5
  142. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 2)
  143. },
  144. },
  145. {
  146. name: "pending -> no_data(alerting) should set alerting since time passed FOR",
  147. expected: models.AlertStateAlerting,
  148. applyFn: func(ec *EvalContext) {
  149. ec.PrevAlertState = models.AlertStatePending
  150. ec.Rule.NoDataState = models.NoDataSetAlerting
  151. ec.NoDataFound = true
  152. ec.Rule.For = time.Minute * 2
  153. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  154. },
  155. },
  156. {
  157. name: "pending -> error(alerting) with for duration have not passed ",
  158. expected: models.AlertStatePending,
  159. applyFn: func(ec *EvalContext) {
  160. ec.PrevAlertState = models.AlertStatePending
  161. ec.Rule.ExecutionErrorState = models.ExecutionErrorSetAlerting
  162. ec.Error = errors.New("test error")
  163. ec.Rule.For = time.Minute * 5
  164. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 2)
  165. },
  166. },
  167. {
  168. name: "pending -> error(alerting) should set alerting since time passed FOR",
  169. expected: models.AlertStateAlerting,
  170. applyFn: func(ec *EvalContext) {
  171. ec.PrevAlertState = models.AlertStatePending
  172. ec.Rule.ExecutionErrorState = models.ExecutionErrorSetAlerting
  173. ec.Error = errors.New("test error")
  174. ec.Rule.For = time.Minute * 2
  175. ec.Rule.LastStateChange = time.Now().Add(-time.Minute * 5)
  176. },
  177. },
  178. }
  179. for _, tc := range tcs {
  180. ctx := NewEvalContext(context.TODO(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}})
  181. tc.applyFn(ctx)
  182. have := ctx.GetNewState()
  183. if have != tc.expected {
  184. t.Errorf("failed: %s \n expected '%s' have '%s'\n", tc.name, tc.expected, string(have))
  185. }
  186. }
  187. }