annotations_test.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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. deleteCmd := dtos.DeleteAnnotationsCmd{
  88. DashboardId: 1,
  89. PanelId: 1,
  90. }
  91. viewerRole := m.ROLE_VIEWER
  92. editorRole := m.ROLE_EDITOR
  93. aclMockResp := []*m.DashboardAclInfoDTO{
  94. {Role: &viewerRole, Permission: m.PERMISSION_VIEW},
  95. {Role: &editorRole, Permission: m.PERMISSION_EDIT},
  96. }
  97. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  98. query.Result = aclMockResp
  99. return nil
  100. })
  101. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  102. query.Result = []*m.TeamDTO{}
  103. return nil
  104. })
  105. Convey("When user is an Org Viewer", func() {
  106. role := m.ROLE_VIEWER
  107. Convey("Should not be allowed to save an annotation", func() {
  108. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  109. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  110. So(sc.resp.Code, ShouldEqual, 403)
  111. })
  112. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  113. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  114. So(sc.resp.Code, ShouldEqual, 403)
  115. })
  116. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  117. sc.handlerFunc = DeleteAnnotationByID
  118. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  119. So(sc.resp.Code, ShouldEqual, 403)
  120. })
  121. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  122. sc.handlerFunc = DeleteAnnotationRegion
  123. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  124. So(sc.resp.Code, ShouldEqual, 403)
  125. })
  126. })
  127. })
  128. Convey("When user is an Org Editor", func() {
  129. role := m.ROLE_EDITOR
  130. Convey("Should be able to save an annotation", func() {
  131. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  132. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  133. So(sc.resp.Code, ShouldEqual, 200)
  134. })
  135. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  136. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  137. So(sc.resp.Code, ShouldEqual, 200)
  138. })
  139. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  140. sc.handlerFunc = DeleteAnnotationByID
  141. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  142. So(sc.resp.Code, ShouldEqual, 200)
  143. })
  144. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) {
  145. sc.handlerFunc = DeleteAnnotationRegion
  146. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  147. So(sc.resp.Code, ShouldEqual, 200)
  148. })
  149. })
  150. })
  151. Convey("When user is an Admin", func() {
  152. role := m.ROLE_ADMIN
  153. Convey("Should be able to do anything", func() {
  154. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  155. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  156. So(sc.resp.Code, ShouldEqual, 200)
  157. })
  158. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  159. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  160. So(sc.resp.Code, ShouldEqual, 200)
  161. })
  162. deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
  163. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  164. So(sc.resp.Code, ShouldEqual, 200)
  165. })
  166. })
  167. })
  168. })
  169. }
  170. type fakeAnnotationsRepo struct {
  171. }
  172. func (repo *fakeAnnotationsRepo) Delete(params *annotations.DeleteParams) error {
  173. return nil
  174. }
  175. func (repo *fakeAnnotationsRepo) Save(item *annotations.Item) error {
  176. item.Id = 1
  177. return nil
  178. }
  179. func (repo *fakeAnnotationsRepo) Update(item *annotations.Item) error {
  180. return nil
  181. }
  182. func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
  183. annotations := []*annotations.ItemDTO{{Id: 1}}
  184. return annotations, nil
  185. }
  186. var fakeAnnoRepo *fakeAnnotationsRepo
  187. func postAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
  188. Convey(desc+" "+url, func() {
  189. defer bus.ClearBusHandlers()
  190. sc := setupScenarioContext(url)
  191. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  192. sc.context = c
  193. sc.context.UserId = TestUserID
  194. sc.context.OrgId = TestOrgID
  195. sc.context.OrgRole = role
  196. return PostAnnotation(c, cmd)
  197. })
  198. fakeAnnoRepo = &fakeAnnotationsRepo{}
  199. annotations.SetRepository(fakeAnnoRepo)
  200. sc.m.Post(routePattern, sc.defaultHandler)
  201. fn(sc)
  202. })
  203. }
  204. func putAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
  205. Convey(desc+" "+url, func() {
  206. defer bus.ClearBusHandlers()
  207. sc := setupScenarioContext(url)
  208. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  209. sc.context = c
  210. sc.context.UserId = TestUserID
  211. sc.context.OrgId = TestOrgID
  212. sc.context.OrgRole = role
  213. return UpdateAnnotation(c, cmd)
  214. })
  215. fakeAnnoRepo = &fakeAnnotationsRepo{}
  216. annotations.SetRepository(fakeAnnoRepo)
  217. sc.m.Put(routePattern, sc.defaultHandler)
  218. fn(sc)
  219. })
  220. }
  221. func deleteAnnotationsScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
  222. Convey(desc+" "+url, func() {
  223. defer bus.ClearBusHandlers()
  224. sc := setupScenarioContext(url)
  225. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  226. sc.context = c
  227. sc.context.UserId = TestUserID
  228. sc.context.OrgId = TestOrgID
  229. sc.context.OrgRole = role
  230. return DeleteAnnotations(c, cmd)
  231. })
  232. fakeAnnoRepo = &fakeAnnotationsRepo{}
  233. annotations.SetRepository(fakeAnnoRepo)
  234. sc.m.Post(routePattern, sc.defaultHandler)
  235. fn(sc)
  236. })
  237. }