annotations_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. }
  17. updateCmd := dtos.UpdateAnnotationsCmd{
  18. Time: 1000,
  19. Text: "annotation text",
  20. Tags: []string{"tag1", "tag2"},
  21. }
  22. patchCmd := dtos.PatchAnnotationsCmd{
  23. Time: 1000,
  24. Text: "annotation text",
  25. Tags: []string{"tag1", "tag2"},
  26. }
  27. Convey("When user is an Org Viewer", func() {
  28. role := m.ROLE_VIEWER
  29. Convey("Should not be allowed to save an annotation", func() {
  30. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  31. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  32. So(sc.resp.Code, ShouldEqual, 403)
  33. })
  34. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  35. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  36. So(sc.resp.Code, ShouldEqual, 403)
  37. })
  38. patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
  39. sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
  40. So(sc.resp.Code, ShouldEqual, 403)
  41. })
  42. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  43. sc.handlerFunc = DeleteAnnotationByID
  44. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  45. So(sc.resp.Code, ShouldEqual, 403)
  46. })
  47. })
  48. })
  49. Convey("When user is an Org Editor", func() {
  50. role := m.ROLE_EDITOR
  51. Convey("Should be able to save an annotation", func() {
  52. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  53. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  54. So(sc.resp.Code, ShouldEqual, 200)
  55. })
  56. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  57. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  58. So(sc.resp.Code, ShouldEqual, 200)
  59. })
  60. patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
  61. sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
  62. So(sc.resp.Code, ShouldEqual, 200)
  63. })
  64. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  65. sc.handlerFunc = DeleteAnnotationByID
  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. DashboardId: 1,
  78. PanelId: 1,
  79. }
  80. updateCmd := dtos.UpdateAnnotationsCmd{
  81. Time: 1000,
  82. Text: "annotation text",
  83. Tags: []string{"tag1", "tag2"},
  84. Id: 1,
  85. }
  86. patchCmd := dtos.PatchAnnotationsCmd{
  87. Time: 8000,
  88. Text: "annotation text 50",
  89. Tags: []string{"foo", "bar"},
  90. Id: 1,
  91. }
  92. deleteCmd := dtos.DeleteAnnotationsCmd{
  93. DashboardId: 1,
  94. PanelId: 1,
  95. }
  96. viewerRole := m.ROLE_VIEWER
  97. editorRole := m.ROLE_EDITOR
  98. aclMockResp := []*m.DashboardAclInfoDTO{
  99. {Role: &viewerRole, Permission: m.PERMISSION_VIEW},
  100. {Role: &editorRole, Permission: m.PERMISSION_EDIT},
  101. }
  102. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  103. query.Result = aclMockResp
  104. return nil
  105. })
  106. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  107. query.Result = []*m.TeamDTO{}
  108. return nil
  109. })
  110. Convey("When user is an Org Viewer", func() {
  111. role := m.ROLE_VIEWER
  112. Convey("Should not be allowed to save an annotation", func() {
  113. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  114. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  115. So(sc.resp.Code, ShouldEqual, 403)
  116. })
  117. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  118. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  119. So(sc.resp.Code, ShouldEqual, 403)
  120. })
  121. patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
  122. sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
  123. So(sc.resp.Code, ShouldEqual, 403)
  124. })
  125. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  126. sc.handlerFunc = DeleteAnnotationByID
  127. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  128. So(sc.resp.Code, ShouldEqual, 403)
  129. })
  130. })
  131. })
  132. Convey("When user is an Org Editor", func() {
  133. role := m.ROLE_EDITOR
  134. Convey("Should be able to save an annotation", func() {
  135. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  136. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  137. So(sc.resp.Code, ShouldEqual, 200)
  138. })
  139. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  140. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  141. So(sc.resp.Code, ShouldEqual, 200)
  142. })
  143. patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
  144. sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
  145. So(sc.resp.Code, ShouldEqual, 200)
  146. })
  147. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
  148. sc.handlerFunc = DeleteAnnotationByID
  149. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  150. So(sc.resp.Code, ShouldEqual, 200)
  151. })
  152. })
  153. })
  154. Convey("When user is an Admin", func() {
  155. role := m.ROLE_ADMIN
  156. Convey("Should be able to do anything", func() {
  157. postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
  158. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  159. So(sc.resp.Code, ShouldEqual, 200)
  160. })
  161. putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
  162. sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
  163. So(sc.resp.Code, ShouldEqual, 200)
  164. })
  165. patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
  166. sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
  167. So(sc.resp.Code, ShouldEqual, 200)
  168. })
  169. deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
  170. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  171. So(sc.resp.Code, ShouldEqual, 200)
  172. })
  173. })
  174. })
  175. })
  176. }
  177. type fakeAnnotationsRepo struct {
  178. }
  179. func (repo *fakeAnnotationsRepo) Delete(params *annotations.DeleteParams) error {
  180. return nil
  181. }
  182. func (repo *fakeAnnotationsRepo) Save(item *annotations.Item) error {
  183. item.Id = 1
  184. return nil
  185. }
  186. func (repo *fakeAnnotationsRepo) Update(item *annotations.Item) error {
  187. return nil
  188. }
  189. func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
  190. annotations := []*annotations.ItemDTO{{Id: 1}}
  191. return annotations, nil
  192. }
  193. var fakeAnnoRepo *fakeAnnotationsRepo
  194. func postAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
  195. Convey(desc+" "+url, func() {
  196. defer bus.ClearBusHandlers()
  197. sc := setupScenarioContext(url)
  198. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  199. sc.context = c
  200. sc.context.UserId = TestUserID
  201. sc.context.OrgId = TestOrgID
  202. sc.context.OrgRole = role
  203. return PostAnnotation(c, cmd)
  204. })
  205. fakeAnnoRepo = &fakeAnnotationsRepo{}
  206. annotations.SetRepository(fakeAnnoRepo)
  207. sc.m.Post(routePattern, sc.defaultHandler)
  208. fn(sc)
  209. })
  210. }
  211. func putAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
  212. Convey(desc+" "+url, func() {
  213. defer bus.ClearBusHandlers()
  214. sc := setupScenarioContext(url)
  215. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  216. sc.context = c
  217. sc.context.UserId = TestUserID
  218. sc.context.OrgId = TestOrgID
  219. sc.context.OrgRole = role
  220. return UpdateAnnotation(c, cmd)
  221. })
  222. fakeAnnoRepo = &fakeAnnotationsRepo{}
  223. annotations.SetRepository(fakeAnnoRepo)
  224. sc.m.Put(routePattern, sc.defaultHandler)
  225. fn(sc)
  226. })
  227. }
  228. func patchAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
  229. Convey(desc+" "+url, func() {
  230. defer bus.ClearBusHandlers()
  231. sc := setupScenarioContext(url)
  232. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  233. sc.context = c
  234. sc.context.UserId = TestUserID
  235. sc.context.OrgId = TestOrgID
  236. sc.context.OrgRole = role
  237. return PatchAnnotation(c, cmd)
  238. })
  239. fakeAnnoRepo = &fakeAnnotationsRepo{}
  240. annotations.SetRepository(fakeAnnoRepo)
  241. sc.m.Patch(routePattern, sc.defaultHandler)
  242. fn(sc)
  243. })
  244. }
  245. func deleteAnnotationsScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
  246. Convey(desc+" "+url, func() {
  247. defer bus.ClearBusHandlers()
  248. sc := setupScenarioContext(url)
  249. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  250. sc.context = c
  251. sc.context.UserId = TestUserID
  252. sc.context.OrgId = TestOrgID
  253. sc.context.OrgRole = role
  254. return DeleteAnnotations(c, cmd)
  255. })
  256. fakeAnnoRepo = &fakeAnnotationsRepo{}
  257. annotations.SetRepository(fakeAnnoRepo)
  258. sc.m.Post(routePattern, sc.defaultHandler)
  259. fn(sc)
  260. })
  261. }