annotations_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package api
  2. import (
  3. "testing"
  4. "github.com/grafana/grafana/pkg/api/dtos"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/middleware"
  7. m "github.com/grafana/grafana/pkg/models"
  8. "github.com/grafana/grafana/pkg/services/annotations"
  9. . "github.com/smartystreets/goconvey/convey"
  10. )
  11. func TestAnnotationsApiEndpoint(t *testing.T) {
  12. Convey("Given an annotation without a dashboard id", t, func() {
  13. cmd := dtos.PostAnnotationsCmd{
  14. Time: 1000,
  15. Text: "annotation text",
  16. Tags: []string{"tag1", "tag2"},
  17. IsRegion: false,
  18. }
  19. updateCmd := dtos.UpdateAnnotationsCmd{
  20. Time: 1000,
  21. Text: "annotation text",
  22. Tags: []string{"tag1", "tag2"},
  23. IsRegion: false,
  24. }
  25. Convey("When user is an Org Viewer", func() {
  26. role := m.ROLE_VIEWER
  27. Convey("Should not be allowed to save an annotation", func() {
  28. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  29. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  30. So(sc.resp.Code, ShouldEqual, 403)
  31. })
  32. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  33. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  34. So(sc.resp.Code, ShouldEqual, 403)
  35. })
  36. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  37. sc.handlerFunc = DeleteAnnotationById
  38. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  39. So(sc.resp.Code, ShouldEqual, 403)
  40. })
  41. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  42. sc.handlerFunc = DeleteAnnotationRegion
  43. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  44. So(sc.resp.Code, ShouldEqual, 403)
  45. })
  46. })
  47. })
  48. Convey("When user is an Org Editor", func() {
  49. role := m.ROLE_EDITOR
  50. Convey("Should be able to save an annotation", func() {
  51. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  52. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  53. So(sc.resp.Code, ShouldEqual, 200)
  54. })
  55. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  56. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  57. So(sc.resp.Code, ShouldEqual, 200)
  58. })
  59. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  60. sc.handlerFunc = DeleteAnnotationById
  61. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  62. So(sc.resp.Code, ShouldEqual, 200)
  63. })
  64. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  65. sc.handlerFunc = DeleteAnnotationRegion
  66. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  67. So(sc.resp.Code, ShouldEqual, 200)
  68. })
  69. })
  70. })
  71. })
  72. Convey("Given an annotation with a dashboard id and the dashboard does not have an acl", t, func() {
  73. cmd := dtos.PostAnnotationsCmd{
  74. Time: 1000,
  75. Text: "annotation text",
  76. Tags: []string{"tag1", "tag2"},
  77. IsRegion: false,
  78. DashboardId: 1,
  79. PanelId: 1,
  80. }
  81. updateCmd := dtos.UpdateAnnotationsCmd{
  82. Time: 1000,
  83. Text: "annotation text",
  84. Tags: []string{"tag1", "tag2"},
  85. IsRegion: false,
  86. Id: 1,
  87. }
  88. viewerRole := m.ROLE_VIEWER
  89. editorRole := m.ROLE_EDITOR
  90. aclMockResp := []*m.DashboardAclInfoDTO{
  91. {Role: &viewerRole, Permission: m.PERMISSION_VIEW},
  92. {Role: &editorRole, Permission: m.PERMISSION_EDIT},
  93. }
  94. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  95. query.Result = aclMockResp
  96. return nil
  97. })
  98. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  99. query.Result = []*m.Team{}
  100. return nil
  101. })
  102. Convey("When user is an Org Viewer", func() {
  103. role := m.ROLE_VIEWER
  104. Convey("Should not be allowed to save an annotation", func() {
  105. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  106. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  107. So(sc.resp.Code, ShouldEqual, 403)
  108. })
  109. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  110. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  111. So(sc.resp.Code, ShouldEqual, 403)
  112. })
  113. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  114. sc.handlerFunc = DeleteAnnotationById
  115. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  116. So(sc.resp.Code, ShouldEqual, 403)
  117. })
  118. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  119. sc.handlerFunc = DeleteAnnotationRegion
  120. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  121. So(sc.resp.Code, ShouldEqual, 403)
  122. })
  123. })
  124. })
  125. Convey("When user is an Org Editor", func() {
  126. role := m.ROLE_EDITOR
  127. Convey("Should be able to save an annotation", func() {
  128. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  129. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  130. So(sc.resp.Code, ShouldEqual, 200)
  131. })
  132. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  133. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  134. So(sc.resp.Code, ShouldEqual, 200)
  135. })
  136. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  137. sc.handlerFunc = DeleteAnnotationById
  138. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  139. So(sc.resp.Code, ShouldEqual, 200)
  140. })
  141. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  142. sc.handlerFunc = DeleteAnnotationRegion
  143. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  144. So(sc.resp.Code, ShouldEqual, 200)
  145. })
  146. })
  147. })
  148. })
  149. }
  150. type fakeAnnotationsRepo struct {
  151. }
  152. func (repo *fakeAnnotationsRepo) Delete(params *annotations.DeleteParams) error {
  153. return nil
  154. }
  155. func (repo *fakeAnnotationsRepo) Save(item *annotations.Item) error {
  156. item.Id = 1
  157. return nil
  158. }
  159. func (repo *fakeAnnotationsRepo) Update(item *annotations.Item) error {
  160. return nil
  161. }
  162. func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
  163. annotations := []*annotations.ItemDTO{{Id: 1}}
  164. return annotations, nil
  165. }
  166. var fakeAnnoRepo *fakeAnnotationsRepo
  167. func postAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
  168. Convey(desc+" "+url, func() {
  169. defer bus.ClearBusHandlers()
  170. sc := setupScenarioContext(url)
  171. sc.defaultHandler = wrap(func(c *middleware.Context) Response {
  172. sc.context = c
  173. sc.context.UserId = TestUserID
  174. sc.context.OrgId = TestOrgID
  175. sc.context.OrgRole = role
  176. return PostAnnotation(c, cmd)
  177. })
  178. fakeAnnoRepo = &fakeAnnotationsRepo{}
  179. annotations.SetRepository(fakeAnnoRepo)
  180. sc.m.Post(routePattern, sc.defaultHandler)
  181. fn(sc)
  182. })
  183. }
  184. func putAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
  185. Convey(desc+" "+url, func() {
  186. defer bus.ClearBusHandlers()
  187. sc := setupScenarioContext(url)
  188. sc.defaultHandler = wrap(func(c *middleware.Context) Response {
  189. sc.context = c
  190. sc.context.UserId = TestUserID
  191. sc.context.OrgId = TestOrgID
  192. sc.context.OrgRole = role
  193. return UpdateAnnotation(c, cmd)
  194. })
  195. fakeAnnoRepo = &fakeAnnotationsRepo{}
  196. annotations.SetRepository(fakeAnnoRepo)
  197. sc.m.Put(routePattern, sc.defaultHandler)
  198. fn(sc)
  199. })
  200. }