dashboard_snapshot_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package api
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/http/httptest"
  6. "testing"
  7. "time"
  8. "github.com/grafana/grafana/pkg/bus"
  9. "github.com/grafana/grafana/pkg/components/simplejson"
  10. m "github.com/grafana/grafana/pkg/models"
  11. . "github.com/smartystreets/goconvey/convey"
  12. )
  13. func TestDashboardSnapshotApiEndpoint(t *testing.T) {
  14. Convey("Given a single snapshot", t, func() {
  15. var externalRequest *http.Request
  16. jsonModel, _ := simplejson.NewJson([]byte(`{"id":100}`))
  17. mockSnapshotResult := &m.DashboardSnapshot{
  18. Id: 1,
  19. Key: "12345",
  20. DeleteKey: "54321",
  21. Dashboard: jsonModel,
  22. Expires: time.Now().Add(time.Duration(1000) * time.Second),
  23. UserId: 999999,
  24. External: true,
  25. }
  26. bus.AddHandler("test", func(query *m.GetDashboardSnapshotQuery) error {
  27. query.Result = mockSnapshotResult
  28. return nil
  29. })
  30. bus.AddHandler("test", func(cmd *m.DeleteDashboardSnapshotCommand) error {
  31. return nil
  32. })
  33. viewerRole := m.ROLE_VIEWER
  34. editorRole := m.ROLE_EDITOR
  35. aclMockResp := []*m.DashboardAclInfoDTO{}
  36. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  37. query.Result = aclMockResp
  38. return nil
  39. })
  40. teamResp := []*m.TeamDTO{}
  41. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  42. query.Result = teamResp
  43. return nil
  44. })
  45. setupRemoteServer := func(fn func(http.ResponseWriter, *http.Request)) *httptest.Server {
  46. return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  47. fn(rw, r)
  48. }))
  49. }
  50. Convey("When user has editor role and is not in the ACL", func() {
  51. Convey("Should not be able to delete snapshot", func() {
  52. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  53. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  54. externalRequest = req
  55. })
  56. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  57. sc.handlerFunc = DeleteDashboardSnapshot
  58. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  59. So(sc.resp.Code, ShouldEqual, 403)
  60. So(externalRequest, ShouldBeNil)
  61. })
  62. })
  63. })
  64. Convey("When user is anonymous", func() {
  65. Convey("Should be able to delete snapshot by deleteKey", func() {
  66. anonymousUserScenario("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", func(sc *scenarioContext) {
  67. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  68. rw.WriteHeader(200)
  69. externalRequest = req
  70. })
  71. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  72. sc.handlerFunc = DeleteDashboardSnapshotByDeleteKey
  73. sc.fakeReqWithParams("GET", sc.url, map[string]string{"deleteKey": "12345"}).exec()
  74. So(sc.resp.Code, ShouldEqual, 200)
  75. respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
  76. So(err, ShouldBeNil)
  77. So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
  78. So(externalRequest.Method, ShouldEqual, http.MethodGet)
  79. So(fmt.Sprintf("http://%s", externalRequest.Host), ShouldEqual, ts.URL)
  80. So(externalRequest.URL.EscapedPath(), ShouldEqual, "/")
  81. })
  82. })
  83. })
  84. Convey("When user is editor and dashboard has default ACL", func() {
  85. aclMockResp = []*m.DashboardAclInfoDTO{
  86. {Role: &viewerRole, Permission: m.PERMISSION_VIEW},
  87. {Role: &editorRole, Permission: m.PERMISSION_EDIT},
  88. }
  89. Convey("Should be able to delete a snapshot", func() {
  90. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  91. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  92. rw.WriteHeader(200)
  93. externalRequest = req
  94. })
  95. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  96. sc.handlerFunc = DeleteDashboardSnapshot
  97. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  98. So(sc.resp.Code, ShouldEqual, 200)
  99. respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
  100. So(err, ShouldBeNil)
  101. So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
  102. So(fmt.Sprintf("http://%s", externalRequest.Host), ShouldEqual, ts.URL)
  103. So(externalRequest.URL.EscapedPath(), ShouldEqual, "/")
  104. })
  105. })
  106. })
  107. Convey("When user is editor and is the creator of the snapshot", func() {
  108. aclMockResp = []*m.DashboardAclInfoDTO{}
  109. mockSnapshotResult.UserId = TestUserID
  110. mockSnapshotResult.External = false
  111. Convey("Should be able to delete a snapshot", func() {
  112. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  113. sc.handlerFunc = DeleteDashboardSnapshot
  114. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  115. So(sc.resp.Code, ShouldEqual, 200)
  116. respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
  117. So(err, ShouldBeNil)
  118. So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
  119. })
  120. })
  121. })
  122. Convey("When deleting an external snapshot", func() {
  123. aclMockResp = []*m.DashboardAclInfoDTO{}
  124. mockSnapshotResult.UserId = TestUserID
  125. Convey("Should gracefully delete local snapshot when remote snapshot has already been removed", func() {
  126. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  127. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  128. rw.Write([]byte(`{"message":"Failed to get dashboard snapshot"}`))
  129. rw.WriteHeader(500)
  130. })
  131. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  132. sc.handlerFunc = DeleteDashboardSnapshot
  133. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  134. So(sc.resp.Code, ShouldEqual, 200)
  135. })
  136. })
  137. Convey("Should fail to delete local snapshot when an unexpected 500 error occurs", func() {
  138. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  139. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  140. rw.WriteHeader(500)
  141. rw.Write([]byte(`{"message":"Unexpected"}`))
  142. })
  143. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  144. sc.handlerFunc = DeleteDashboardSnapshot
  145. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  146. So(sc.resp.Code, ShouldEqual, 500)
  147. })
  148. })
  149. Convey("Should fail to delete local snapshot when an unexpected remote error occurs", func() {
  150. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
  151. ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
  152. rw.WriteHeader(404)
  153. })
  154. mockSnapshotResult.ExternalDeleteUrl = ts.URL
  155. sc.handlerFunc = DeleteDashboardSnapshot
  156. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
  157. So(sc.resp.Code, ShouldEqual, 500)
  158. })
  159. })
  160. })
  161. })
  162. }