eval_context_test.go 6.1 KB

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