annotations_test.go 8.4 KB

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