rule_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package alerting
  2. import (
  3. "testing"
  4. "github.com/grafana/grafana/pkg/bus"
  5. "github.com/grafana/grafana/pkg/components/simplejson"
  6. "github.com/grafana/grafana/pkg/models"
  7. m "github.com/grafana/grafana/pkg/models"
  8. . "github.com/smartystreets/goconvey/convey"
  9. )
  10. var (
  11. fakeRepo *fakeRepository
  12. )
  13. type FakeCondition struct{}
  14. func (f *FakeCondition) Eval(context *EvalContext) (*ConditionResult, error) {
  15. return &ConditionResult{}, nil
  16. }
  17. func TestAlertRuleFrequencyParsing(t *testing.T) {
  18. tcs := []struct {
  19. input string
  20. err error
  21. result int64
  22. }{
  23. {input: "10s", result: 10},
  24. {input: "10m", result: 600},
  25. {input: "1h", result: 3600},
  26. {input: "1o", result: 1},
  27. {input: "0s", err: ErrFrequencyCannotBeZeroOrLess},
  28. {input: "0m", err: ErrFrequencyCannotBeZeroOrLess},
  29. {input: "0h", err: ErrFrequencyCannotBeZeroOrLess},
  30. {input: "0", err: ErrFrequencyCannotBeZeroOrLess},
  31. {input: "-1s", err: ErrFrequencyCouldNotBeParsed},
  32. }
  33. for _, tc := range tcs {
  34. r, err := getTimeDurationStringToSeconds(tc.input)
  35. if err != tc.err {
  36. t.Errorf("expected error: '%v' got: '%v'", tc.err, err)
  37. return
  38. }
  39. if r != tc.result {
  40. t.Errorf("expected result: %d got %d", tc.result, r)
  41. }
  42. }
  43. }
  44. func TestAlertRuleModel(t *testing.T) {
  45. Convey("Testing alert rule", t, func() {
  46. RegisterCondition("test", func(model *simplejson.Json, index int) (Condition, error) {
  47. return &FakeCondition{}, nil
  48. })
  49. Convey("should return err for empty string", func() {
  50. _, err := getTimeDurationStringToSeconds("")
  51. So(err, ShouldNotBeNil)
  52. })
  53. Convey("can construct alert rule model", func() {
  54. json := `
  55. {
  56. "name": "name2",
  57. "description": "desc2",
  58. "handler": 0,
  59. "noDataMode": "critical",
  60. "enabled": true,
  61. "frequency": "60s",
  62. "conditions": [
  63. {
  64. "type": "test",
  65. "prop": 123
  66. }
  67. ],
  68. "notifications": [
  69. {"id": 1134},
  70. {"id": 22}
  71. ]
  72. }
  73. `
  74. alertJSON, jsonErr := simplejson.NewJson([]byte(json))
  75. So(jsonErr, ShouldBeNil)
  76. alert := &m.Alert{
  77. Id: 1,
  78. OrgId: 1,
  79. DashboardId: 1,
  80. PanelId: 1,
  81. Settings: alertJSON,
  82. }
  83. alertRule, err := NewRuleFromDBAlert(alert)
  84. So(err, ShouldBeNil)
  85. So(len(alertRule.Conditions), ShouldEqual, 1)
  86. Convey("Can read notifications", func() {
  87. So(len(alertRule.Notifications), ShouldEqual, 2)
  88. })
  89. })
  90. Convey("can construct alert rule model with invalid frequency", func() {
  91. json := `
  92. {
  93. "name": "name2",
  94. "description": "desc2",
  95. "noDataMode": "critical",
  96. "enabled": true,
  97. "frequency": "0s",
  98. "conditions": [ { "type": "test", "prop": 123 } ],
  99. "notifications": []
  100. }`
  101. alertJSON, jsonErr := simplejson.NewJson([]byte(json))
  102. So(jsonErr, ShouldBeNil)
  103. alert := &m.Alert{
  104. Id: 1,
  105. OrgId: 1,
  106. DashboardId: 1,
  107. PanelId: 1,
  108. Frequency: 0,
  109. Settings: alertJSON,
  110. }
  111. alertRule, err := NewRuleFromDBAlert(alert)
  112. So(err, ShouldBeNil)
  113. So(alertRule.Frequency, ShouldEqual, 60)
  114. })
  115. Convey("can construct alert rule model mixed notification ids and names", func() {
  116. json := `
  117. {
  118. "name": "name2",
  119. "description": "desc2",
  120. "handler": 0,
  121. "noDataMode": "critical",
  122. "enabled": true,
  123. "frequency": "60s",
  124. "conditions": [
  125. {
  126. "type": "test",
  127. "prop": 123
  128. }
  129. ],
  130. "notifications": [
  131. {"id": 1134},
  132. {"id": 22},
  133. {"name": "channel1"},
  134. {"name": "channel2"}
  135. ]
  136. }
  137. `
  138. alertJSON, jsonErr := simplejson.NewJson([]byte(json))
  139. So(jsonErr, ShouldBeNil)
  140. alert := &m.Alert{
  141. Id: 1,
  142. OrgId: 1,
  143. DashboardId: 1,
  144. PanelId: 1,
  145. Settings: alertJSON,
  146. }
  147. fakeRepo = &fakeRepository{}
  148. bus.ClearBusHandlers()
  149. bus.AddHandler("test", mockGet)
  150. fakeRepo.loadAll = []*models.AlertNotification{
  151. {Name: "channel1", OrgId: 1, Id: 1},
  152. {Name: "channel2", OrgId: 1, Id: 2},
  153. }
  154. alertRule, err := NewRuleFromDBAlert(alert)
  155. So(err, ShouldBeNil)
  156. Convey("Can read notifications", func() {
  157. So(len(alertRule.Notifications), ShouldEqual, 4)
  158. So(alertRule.Notifications, ShouldResemble, []int64{1134, 22, 1, 2})
  159. })
  160. })
  161. Convey("raise error in case of left id", func() {
  162. json := `
  163. {
  164. "name": "name2",
  165. "description": "desc2",
  166. "handler": 0,
  167. "noDataMode": "critical",
  168. "enabled": true,
  169. "frequency": "60s",
  170. "conditions": [
  171. {
  172. "type": "test",
  173. "prop": 123
  174. }
  175. ],
  176. "notifications": [
  177. {"not_id": 1134}
  178. ]
  179. }
  180. `
  181. alertJSON, jsonErr := simplejson.NewJson([]byte(json))
  182. So(jsonErr, ShouldBeNil)
  183. alert := &m.Alert{
  184. Id: 1,
  185. OrgId: 1,
  186. DashboardId: 1,
  187. PanelId: 1,
  188. Settings: alertJSON,
  189. }
  190. _, err := NewRuleFromDBAlert(alert)
  191. So(err, ShouldNotBeNil)
  192. })
  193. Convey("raise error in case of left id but existed name with alien orgId", func() {
  194. json := `
  195. {
  196. "name": "name2",
  197. "description": "desc2",
  198. "handler": 0,
  199. "noDataMode": "critical",
  200. "enabled": true,
  201. "frequency": "60s",
  202. "conditions": [
  203. {
  204. "type": "test",
  205. "prop": 123
  206. }
  207. ],
  208. "notifications": [
  209. {"not_id": 1134, "name": "channel1"}
  210. ]
  211. }
  212. `
  213. alertJSON, jsonErr := simplejson.NewJson([]byte(json))
  214. So(jsonErr, ShouldBeNil)
  215. alert := &m.Alert{
  216. Id: 1,
  217. OrgId: 1,
  218. DashboardId: 1,
  219. PanelId: 1,
  220. Settings: alertJSON,
  221. }
  222. fakeRepo = &fakeRepository{}
  223. bus.ClearBusHandlers()
  224. bus.AddHandler("test", mockGet)
  225. fakeRepo.loadAll = []*models.AlertNotification{
  226. {Name: "channel1", OrgId: 2, Id: 1},
  227. }
  228. _, err := NewRuleFromDBAlert(alert)
  229. So(err, ShouldNotBeNil)
  230. })
  231. })
  232. }
  233. type fakeRepository struct {
  234. loadAll []*models.AlertNotification
  235. }
  236. func mockGet(cmd *models.GetAlertNotificationsQuery) error {
  237. for _, v := range fakeRepo.loadAll {
  238. if cmd.Name == v.Name && cmd.OrgId == v.OrgId {
  239. cmd.Result = v
  240. return nil
  241. }
  242. }
  243. return nil
  244. }