dashboard_test.go 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. package api
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "testing"
  6. "github.com/grafana/grafana/pkg/api/dtos"
  7. "github.com/grafana/grafana/pkg/bus"
  8. "github.com/grafana/grafana/pkg/components/simplejson"
  9. m "github.com/grafana/grafana/pkg/models"
  10. "github.com/grafana/grafana/pkg/services/alerting"
  11. "github.com/grafana/grafana/pkg/services/dashboards"
  12. "github.com/grafana/grafana/pkg/services/provisioning"
  13. "github.com/grafana/grafana/pkg/setting"
  14. . "github.com/smartystreets/goconvey/convey"
  15. )
  16. // This tests three main scenarios.
  17. // If a user has access to execute an action on a dashboard:
  18. // 1. and the dashboard is in a folder which does not have an acl
  19. // 2. and the dashboard is in a folder which does have an acl
  20. // 3. Post dashboard response tests
  21. func TestDashboardApiEndpoint(t *testing.T) {
  22. Convey("Given a dashboard with a parent folder which does not have an acl", t, func() {
  23. fakeDash := m.NewDashboard("Child dash")
  24. fakeDash.Id = 1
  25. fakeDash.FolderId = 1
  26. fakeDash.HasAcl = false
  27. bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
  28. dashboards := []*m.Dashboard{fakeDash}
  29. query.Result = dashboards
  30. return nil
  31. })
  32. var getDashboardQueries []*m.GetDashboardQuery
  33. bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
  34. query.Result = fakeDash
  35. getDashboardQueries = append(getDashboardQueries, query)
  36. return nil
  37. })
  38. bus.AddHandler("test", func(query *m.GetProvisionedDashboardDataByIdQuery) error {
  39. query.Result = nil
  40. return nil
  41. })
  42. viewerRole := m.ROLE_VIEWER
  43. editorRole := m.ROLE_EDITOR
  44. aclMockResp := []*m.DashboardAclInfoDTO{
  45. {Role: &viewerRole, Permission: m.PERMISSION_VIEW},
  46. {Role: &editorRole, Permission: m.PERMISSION_EDIT},
  47. }
  48. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  49. query.Result = aclMockResp
  50. return nil
  51. })
  52. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  53. query.Result = []*m.TeamDTO{}
  54. return nil
  55. })
  56. // This tests two scenarios:
  57. // 1. user is an org viewer
  58. // 2. user is an org editor
  59. Convey("When user is an Org Viewer", func() {
  60. role := m.ROLE_VIEWER
  61. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  62. dash := GetDashboardShouldReturn200(sc)
  63. Convey("Should lookup dashboard by slug", func() {
  64. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  65. })
  66. Convey("Should not be able to edit or save dashboard", func() {
  67. So(dash.Meta.CanEdit, ShouldBeFalse)
  68. So(dash.Meta.CanSave, ShouldBeFalse)
  69. So(dash.Meta.CanAdmin, ShouldBeFalse)
  70. })
  71. })
  72. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  73. dash := GetDashboardShouldReturn200(sc)
  74. Convey("Should lookup dashboard by uid", func() {
  75. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  76. })
  77. Convey("Should not be able to edit or save dashboard", func() {
  78. So(dash.Meta.CanEdit, ShouldBeFalse)
  79. So(dash.Meta.CanSave, ShouldBeFalse)
  80. So(dash.Meta.CanAdmin, ShouldBeFalse)
  81. })
  82. })
  83. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  84. CallDeleteDashboardBySlug(sc)
  85. So(sc.resp.Code, ShouldEqual, 403)
  86. Convey("Should lookup dashboard by slug", func() {
  87. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  88. })
  89. })
  90. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  91. CallDeleteDashboardByUID(sc)
  92. So(sc.resp.Code, ShouldEqual, 403)
  93. Convey("Should lookup dashboard by uid", func() {
  94. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  95. })
  96. })
  97. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  98. CallGetDashboardVersion(sc)
  99. So(sc.resp.Code, ShouldEqual, 403)
  100. })
  101. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  102. CallGetDashboardVersions(sc)
  103. So(sc.resp.Code, ShouldEqual, 403)
  104. })
  105. })
  106. Convey("When user is an Org Editor", func() {
  107. role := m.ROLE_EDITOR
  108. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  109. dash := GetDashboardShouldReturn200(sc)
  110. Convey("Should lookup dashboard by slug", func() {
  111. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  112. })
  113. Convey("Should be able to edit or save dashboard", func() {
  114. So(dash.Meta.CanEdit, ShouldBeTrue)
  115. So(dash.Meta.CanSave, ShouldBeTrue)
  116. So(dash.Meta.CanAdmin, ShouldBeFalse)
  117. })
  118. })
  119. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  120. dash := GetDashboardShouldReturn200(sc)
  121. Convey("Should lookup dashboard by uid", func() {
  122. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  123. })
  124. Convey("Should be able to edit or save dashboard", func() {
  125. So(dash.Meta.CanEdit, ShouldBeTrue)
  126. So(dash.Meta.CanSave, ShouldBeTrue)
  127. So(dash.Meta.CanAdmin, ShouldBeFalse)
  128. })
  129. })
  130. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  131. CallDeleteDashboardBySlug(sc)
  132. So(sc.resp.Code, ShouldEqual, 200)
  133. Convey("Should lookup dashboard by slug", func() {
  134. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  135. })
  136. })
  137. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  138. CallDeleteDashboardByUID(sc)
  139. So(sc.resp.Code, ShouldEqual, 200)
  140. Convey("Should lookup dashboard by uid", func() {
  141. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  142. })
  143. })
  144. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  145. CallGetDashboardVersion(sc)
  146. So(sc.resp.Code, ShouldEqual, 200)
  147. })
  148. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  149. CallGetDashboardVersions(sc)
  150. So(sc.resp.Code, ShouldEqual, 200)
  151. })
  152. })
  153. })
  154. Convey("Given a dashboard with a parent folder which has an acl", t, func() {
  155. fakeDash := m.NewDashboard("Child dash")
  156. fakeDash.Id = 1
  157. fakeDash.FolderId = 1
  158. fakeDash.HasAcl = true
  159. setting.ViewersCanEdit = false
  160. bus.AddHandler("test", func(query *m.GetProvisionedDashboardDataByIdQuery) error {
  161. query.Result = nil
  162. return nil
  163. })
  164. bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
  165. dashboards := []*m.Dashboard{fakeDash}
  166. query.Result = dashboards
  167. return nil
  168. })
  169. aclMockResp := []*m.DashboardAclInfoDTO{
  170. {
  171. DashboardId: 1,
  172. Permission: m.PERMISSION_EDIT,
  173. UserId: 200,
  174. },
  175. }
  176. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  177. query.Result = aclMockResp
  178. return nil
  179. })
  180. var getDashboardQueries []*m.GetDashboardQuery
  181. bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
  182. query.Result = fakeDash
  183. getDashboardQueries = append(getDashboardQueries, query)
  184. return nil
  185. })
  186. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  187. query.Result = []*m.TeamDTO{}
  188. return nil
  189. })
  190. hs := &HTTPServer{
  191. Cfg: setting.NewCfg(),
  192. }
  193. // This tests six scenarios:
  194. // 1. user is an org viewer AND has no permissions for this dashboard
  195. // 2. user is an org editor AND has no permissions for this dashboard
  196. // 3. user is an org viewer AND has been granted edit permission for the dashboard
  197. // 4. user is an org viewer AND all viewers have edit permission for this dashboard
  198. // 5. user is an org viewer AND has been granted an admin permission
  199. // 6. user is an org editor AND has been granted a view permission
  200. Convey("When user is an Org Viewer and has no permissions for this dashboard", func() {
  201. role := m.ROLE_VIEWER
  202. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  203. sc.handlerFunc = hs.GetDashboard
  204. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  205. Convey("Should lookup dashboard by slug", func() {
  206. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  207. })
  208. Convey("Should be denied access", func() {
  209. So(sc.resp.Code, ShouldEqual, 403)
  210. })
  211. })
  212. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  213. sc.handlerFunc = hs.GetDashboard
  214. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  215. Convey("Should lookup dashboard by uid", func() {
  216. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  217. })
  218. Convey("Should be denied access", func() {
  219. So(sc.resp.Code, ShouldEqual, 403)
  220. })
  221. })
  222. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  223. CallDeleteDashboardBySlug(sc)
  224. So(sc.resp.Code, ShouldEqual, 403)
  225. Convey("Should lookup dashboard by slug", func() {
  226. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  227. })
  228. })
  229. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  230. CallDeleteDashboardByUID(sc)
  231. So(sc.resp.Code, ShouldEqual, 403)
  232. Convey("Should lookup dashboard by uid", func() {
  233. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  234. })
  235. })
  236. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  237. CallGetDashboardVersion(sc)
  238. So(sc.resp.Code, ShouldEqual, 403)
  239. })
  240. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  241. CallGetDashboardVersions(sc)
  242. So(sc.resp.Code, ShouldEqual, 403)
  243. })
  244. })
  245. Convey("When user is an Org Editor and has no permissions for this dashboard", func() {
  246. role := m.ROLE_EDITOR
  247. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  248. sc.handlerFunc = hs.GetDashboard
  249. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  250. Convey("Should lookup dashboard by slug", func() {
  251. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  252. })
  253. Convey("Should be denied access", func() {
  254. So(sc.resp.Code, ShouldEqual, 403)
  255. })
  256. })
  257. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  258. sc.handlerFunc = hs.GetDashboard
  259. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  260. Convey("Should lookup dashboard by uid", func() {
  261. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  262. })
  263. Convey("Should be denied access", func() {
  264. So(sc.resp.Code, ShouldEqual, 403)
  265. })
  266. })
  267. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  268. CallDeleteDashboardBySlug(sc)
  269. So(sc.resp.Code, ShouldEqual, 403)
  270. Convey("Should lookup dashboard by slug", func() {
  271. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  272. })
  273. })
  274. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  275. CallDeleteDashboardByUID(sc)
  276. So(sc.resp.Code, ShouldEqual, 403)
  277. Convey("Should lookup dashboard by uid", func() {
  278. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  279. })
  280. })
  281. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  282. CallGetDashboardVersion(sc)
  283. So(sc.resp.Code, ShouldEqual, 403)
  284. })
  285. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  286. CallGetDashboardVersions(sc)
  287. So(sc.resp.Code, ShouldEqual, 403)
  288. })
  289. })
  290. Convey("When user is an Org Viewer but has an edit permission", func() {
  291. role := m.ROLE_VIEWER
  292. mockResult := []*m.DashboardAclInfoDTO{
  293. {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_EDIT},
  294. }
  295. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  296. query.Result = mockResult
  297. return nil
  298. })
  299. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  300. dash := GetDashboardShouldReturn200(sc)
  301. Convey("Should lookup dashboard by slug", func() {
  302. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  303. })
  304. Convey("Should be able to get dashboard with edit rights", func() {
  305. So(dash.Meta.CanEdit, ShouldBeTrue)
  306. So(dash.Meta.CanSave, ShouldBeTrue)
  307. So(dash.Meta.CanAdmin, ShouldBeFalse)
  308. })
  309. })
  310. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  311. dash := GetDashboardShouldReturn200(sc)
  312. Convey("Should lookup dashboard by uid", func() {
  313. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  314. })
  315. Convey("Should be able to get dashboard with edit rights", func() {
  316. So(dash.Meta.CanEdit, ShouldBeTrue)
  317. So(dash.Meta.CanSave, ShouldBeTrue)
  318. So(dash.Meta.CanAdmin, ShouldBeFalse)
  319. })
  320. })
  321. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  322. CallDeleteDashboardBySlug(sc)
  323. So(sc.resp.Code, ShouldEqual, 200)
  324. Convey("Should lookup dashboard by slug", func() {
  325. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  326. })
  327. })
  328. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  329. CallDeleteDashboardByUID(sc)
  330. So(sc.resp.Code, ShouldEqual, 200)
  331. Convey("Should lookup dashboard by uid", func() {
  332. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  333. })
  334. })
  335. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  336. CallGetDashboardVersion(sc)
  337. So(sc.resp.Code, ShouldEqual, 200)
  338. })
  339. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  340. CallGetDashboardVersions(sc)
  341. So(sc.resp.Code, ShouldEqual, 200)
  342. })
  343. })
  344. Convey("When user is an Org Viewer and viewers can edit", func() {
  345. role := m.ROLE_VIEWER
  346. setting.ViewersCanEdit = true
  347. mockResult := []*m.DashboardAclInfoDTO{
  348. {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW},
  349. }
  350. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  351. query.Result = mockResult
  352. return nil
  353. })
  354. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  355. dash := GetDashboardShouldReturn200(sc)
  356. Convey("Should lookup dashboard by slug", func() {
  357. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  358. })
  359. Convey("Should be able to get dashboard with edit rights but can save should be false", func() {
  360. So(dash.Meta.CanEdit, ShouldBeTrue)
  361. So(dash.Meta.CanSave, ShouldBeFalse)
  362. So(dash.Meta.CanAdmin, ShouldBeFalse)
  363. })
  364. })
  365. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  366. dash := GetDashboardShouldReturn200(sc)
  367. Convey("Should lookup dashboard by uid", func() {
  368. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  369. })
  370. Convey("Should be able to get dashboard with edit rights but can save should be false", func() {
  371. So(dash.Meta.CanEdit, ShouldBeTrue)
  372. So(dash.Meta.CanSave, ShouldBeFalse)
  373. So(dash.Meta.CanAdmin, ShouldBeFalse)
  374. })
  375. })
  376. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  377. CallDeleteDashboardBySlug(sc)
  378. So(sc.resp.Code, ShouldEqual, 403)
  379. Convey("Should lookup dashboard by slug", func() {
  380. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  381. })
  382. })
  383. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  384. CallDeleteDashboardByUID(sc)
  385. So(sc.resp.Code, ShouldEqual, 403)
  386. Convey("Should lookup dashboard by uid", func() {
  387. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  388. })
  389. })
  390. })
  391. Convey("When user is an Org Viewer but has an admin permission", func() {
  392. role := m.ROLE_VIEWER
  393. mockResult := []*m.DashboardAclInfoDTO{
  394. {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN},
  395. }
  396. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  397. query.Result = mockResult
  398. return nil
  399. })
  400. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  401. dash := GetDashboardShouldReturn200(sc)
  402. Convey("Should lookup dashboard by slug", func() {
  403. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  404. })
  405. Convey("Should be able to get dashboard with edit rights", func() {
  406. So(dash.Meta.CanEdit, ShouldBeTrue)
  407. So(dash.Meta.CanSave, ShouldBeTrue)
  408. So(dash.Meta.CanAdmin, ShouldBeTrue)
  409. })
  410. })
  411. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  412. dash := GetDashboardShouldReturn200(sc)
  413. Convey("Should lookup dashboard by uid", func() {
  414. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  415. })
  416. Convey("Should be able to get dashboard with edit rights", func() {
  417. So(dash.Meta.CanEdit, ShouldBeTrue)
  418. So(dash.Meta.CanSave, ShouldBeTrue)
  419. So(dash.Meta.CanAdmin, ShouldBeTrue)
  420. })
  421. })
  422. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  423. CallDeleteDashboardBySlug(sc)
  424. So(sc.resp.Code, ShouldEqual, 200)
  425. Convey("Should lookup dashboard by slug", func() {
  426. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  427. })
  428. })
  429. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  430. CallDeleteDashboardByUID(sc)
  431. So(sc.resp.Code, ShouldEqual, 200)
  432. Convey("Should lookup dashboard by uid", func() {
  433. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  434. })
  435. })
  436. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  437. CallGetDashboardVersion(sc)
  438. So(sc.resp.Code, ShouldEqual, 200)
  439. })
  440. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  441. CallGetDashboardVersions(sc)
  442. So(sc.resp.Code, ShouldEqual, 200)
  443. })
  444. })
  445. Convey("When user is an Org Editor but has a view permission", func() {
  446. role := m.ROLE_EDITOR
  447. mockResult := []*m.DashboardAclInfoDTO{
  448. {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW},
  449. }
  450. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  451. query.Result = mockResult
  452. return nil
  453. })
  454. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  455. dash := GetDashboardShouldReturn200(sc)
  456. Convey("Should lookup dashboard by slug", func() {
  457. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  458. })
  459. Convey("Should not be able to edit or save dashboard", func() {
  460. So(dash.Meta.CanEdit, ShouldBeFalse)
  461. So(dash.Meta.CanSave, ShouldBeFalse)
  462. })
  463. })
  464. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  465. dash := GetDashboardShouldReturn200(sc)
  466. Convey("Should lookup dashboard by uid", func() {
  467. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  468. })
  469. Convey("Should not be able to edit or save dashboard", func() {
  470. So(dash.Meta.CanEdit, ShouldBeFalse)
  471. So(dash.Meta.CanSave, ShouldBeFalse)
  472. })
  473. })
  474. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  475. CallDeleteDashboardBySlug(sc)
  476. So(sc.resp.Code, ShouldEqual, 403)
  477. Convey("Should lookup dashboard by slug", func() {
  478. So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash")
  479. })
  480. })
  481. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
  482. CallDeleteDashboardByUID(sc)
  483. So(sc.resp.Code, ShouldEqual, 403)
  484. Convey("Should lookup dashboard by uid", func() {
  485. So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi")
  486. })
  487. })
  488. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
  489. CallGetDashboardVersion(sc)
  490. So(sc.resp.Code, ShouldEqual, 403)
  491. })
  492. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
  493. CallGetDashboardVersions(sc)
  494. So(sc.resp.Code, ShouldEqual, 403)
  495. })
  496. })
  497. })
  498. Convey("Given two dashboards with the same title in different folders", t, func() {
  499. dashOne := m.NewDashboard("dash")
  500. dashOne.Id = 2
  501. dashOne.FolderId = 1
  502. dashOne.HasAcl = false
  503. dashTwo := m.NewDashboard("dash")
  504. dashTwo.Id = 4
  505. dashTwo.FolderId = 3
  506. dashTwo.HasAcl = false
  507. bus.AddHandler("test", func(query *m.GetProvisionedDashboardDataByIdQuery) error {
  508. query.Result = nil
  509. return nil
  510. })
  511. bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
  512. dashboards := []*m.Dashboard{dashOne, dashTwo}
  513. query.Result = dashboards
  514. return nil
  515. })
  516. role := m.ROLE_EDITOR
  517. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) {
  518. CallDeleteDashboardBySlug(sc)
  519. Convey("Should result in 412 Precondition failed", func() {
  520. So(sc.resp.Code, ShouldEqual, 412)
  521. result := sc.ToJSON()
  522. So(result.Get("status").MustString(), ShouldEqual, "multiple-slugs-exists")
  523. So(result.Get("message").MustString(), ShouldEqual, m.ErrDashboardsWithSameSlugExists.Error())
  524. })
  525. })
  526. })
  527. Convey("Post dashboard response tests", t, func() {
  528. // This tests that a valid request returns correct response
  529. Convey("Given a correct request for creating a dashboard", func() {
  530. cmd := m.SaveDashboardCommand{
  531. OrgId: 1,
  532. UserId: 5,
  533. Dashboard: simplejson.NewFromAny(map[string]interface{}{
  534. "title": "Dash",
  535. }),
  536. Overwrite: true,
  537. FolderId: 3,
  538. IsFolder: false,
  539. Message: "msg",
  540. }
  541. mock := &dashboards.FakeDashboardService{
  542. SaveDashboardResult: &m.Dashboard{
  543. Id: 2,
  544. Uid: "uid",
  545. Title: "Dash",
  546. Slug: "dash",
  547. Version: 2,
  548. },
  549. }
  550. postDashboardScenario("When calling POST on", "/api/dashboards", "/api/dashboards", mock, cmd, func(sc *scenarioContext) {
  551. CallPostDashboardShouldReturnSuccess(sc)
  552. Convey("It should call dashboard service with correct data", func() {
  553. dto := mock.SavedDashboards[0]
  554. So(dto.OrgId, ShouldEqual, cmd.OrgId)
  555. So(dto.User.UserId, ShouldEqual, cmd.UserId)
  556. So(dto.Dashboard.FolderId, ShouldEqual, 3)
  557. So(dto.Dashboard.Title, ShouldEqual, "Dash")
  558. So(dto.Overwrite, ShouldBeTrue)
  559. So(dto.Message, ShouldEqual, "msg")
  560. })
  561. Convey("It should return correct response data", func() {
  562. result := sc.ToJSON()
  563. So(result.Get("status").MustString(), ShouldEqual, "success")
  564. So(result.Get("id").MustInt64(), ShouldEqual, 2)
  565. So(result.Get("uid").MustString(), ShouldEqual, "uid")
  566. So(result.Get("slug").MustString(), ShouldEqual, "dash")
  567. So(result.Get("url").MustString(), ShouldEqual, "/d/uid/dash")
  568. })
  569. })
  570. })
  571. // This tests that invalid requests returns expected error responses
  572. Convey("Given incorrect requests for creating a dashboard", func() {
  573. testCases := []struct {
  574. SaveError error
  575. ExpectedStatusCode int
  576. }{
  577. {SaveError: m.ErrDashboardNotFound, ExpectedStatusCode: 404},
  578. {SaveError: m.ErrFolderNotFound, ExpectedStatusCode: 400},
  579. {SaveError: m.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400},
  580. {SaveError: m.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412},
  581. {SaveError: m.ErrDashboardVersionMismatch, ExpectedStatusCode: 412},
  582. {SaveError: m.ErrDashboardTitleEmpty, ExpectedStatusCode: 400},
  583. {SaveError: m.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400},
  584. {SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: 422},
  585. {SaveError: m.ErrDashboardFailedGenerateUniqueUid, ExpectedStatusCode: 500},
  586. {SaveError: m.ErrDashboardTypeMismatch, ExpectedStatusCode: 400},
  587. {SaveError: m.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400},
  588. {SaveError: m.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400},
  589. {SaveError: m.ErrDashboardFolderNameExists, ExpectedStatusCode: 400},
  590. {SaveError: m.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
  591. {SaveError: m.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
  592. {SaveError: m.ErrDashboardUidToLong, ExpectedStatusCode: 400},
  593. {SaveError: m.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
  594. {SaveError: m.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
  595. }
  596. cmd := m.SaveDashboardCommand{
  597. OrgId: 1,
  598. Dashboard: simplejson.NewFromAny(map[string]interface{}{
  599. "title": "",
  600. }),
  601. }
  602. for _, tc := range testCases {
  603. mock := &dashboards.FakeDashboardService{
  604. SaveDashboardError: tc.SaveError,
  605. }
  606. postDashboardScenario(fmt.Sprintf("Expect '%s' error when calling POST on", tc.SaveError.Error()), "/api/dashboards", "/api/dashboards", mock, cmd, func(sc *scenarioContext) {
  607. CallPostDashboard(sc)
  608. So(sc.resp.Code, ShouldEqual, tc.ExpectedStatusCode)
  609. })
  610. }
  611. })
  612. })
  613. Convey("Given two dashboards being compared", t, func() {
  614. mockResult := []*m.DashboardAclInfoDTO{}
  615. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  616. query.Result = mockResult
  617. return nil
  618. })
  619. bus.AddHandler("test", func(query *m.GetProvisionedDashboardDataByIdQuery) error {
  620. query.Result = nil
  621. return nil
  622. })
  623. bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error {
  624. query.Result = &m.DashboardVersion{
  625. Data: simplejson.NewFromAny(map[string]interface{}{
  626. "title": "Dash" + string(query.DashboardId),
  627. }),
  628. }
  629. return nil
  630. })
  631. cmd := dtos.CalculateDiffOptions{
  632. Base: dtos.CalculateDiffTarget{
  633. DashboardId: 1,
  634. Version: 1,
  635. },
  636. New: dtos.CalculateDiffTarget{
  637. DashboardId: 2,
  638. Version: 2,
  639. },
  640. DiffType: "basic",
  641. }
  642. Convey("when user does not have permission", func() {
  643. role := m.ROLE_VIEWER
  644. postDiffScenario("When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
  645. CallPostDashboard(sc)
  646. So(sc.resp.Code, ShouldEqual, 403)
  647. })
  648. })
  649. Convey("when user does have permission", func() {
  650. role := m.ROLE_ADMIN
  651. postDiffScenario("When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
  652. CallPostDashboard(sc)
  653. So(sc.resp.Code, ShouldEqual, 200)
  654. })
  655. })
  656. })
  657. Convey("Given dashboard in folder being restored should restore to folder", t, func() {
  658. fakeDash := m.NewDashboard("Child dash")
  659. fakeDash.Id = 2
  660. fakeDash.FolderId = 1
  661. fakeDash.HasAcl = false
  662. bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
  663. query.Result = fakeDash
  664. return nil
  665. })
  666. bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error {
  667. query.Result = &m.DashboardVersion{
  668. DashboardId: 2,
  669. Version: 1,
  670. Data: fakeDash.Data,
  671. }
  672. return nil
  673. })
  674. mock := &dashboards.FakeDashboardService{
  675. SaveDashboardResult: &m.Dashboard{
  676. Id: 2,
  677. Uid: "uid",
  678. Title: "Dash",
  679. Slug: "dash",
  680. Version: 1,
  681. },
  682. }
  683. cmd := dtos.RestoreDashboardVersionCommand{
  684. Version: 1,
  685. }
  686. restoreDashboardVersionScenario("When calling POST on", "/api/dashboards/id/1/restore", "/api/dashboards/id/:dashboardId/restore", mock, cmd, func(sc *scenarioContext) {
  687. CallRestoreDashboardVersion(sc)
  688. So(sc.resp.Code, ShouldEqual, 200)
  689. dto := mock.SavedDashboards[0]
  690. So(dto.Dashboard.FolderId, ShouldEqual, 1)
  691. So(dto.Dashboard.Title, ShouldEqual, "Child dash")
  692. So(dto.Message, ShouldEqual, "Restored from version 1")
  693. })
  694. })
  695. Convey("Given dashboard in general folder being restored should restore to general folder", t, func() {
  696. fakeDash := m.NewDashboard("Child dash")
  697. fakeDash.Id = 2
  698. fakeDash.HasAcl = false
  699. bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
  700. query.Result = fakeDash
  701. return nil
  702. })
  703. bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error {
  704. query.Result = &m.DashboardVersion{
  705. DashboardId: 2,
  706. Version: 1,
  707. Data: fakeDash.Data,
  708. }
  709. return nil
  710. })
  711. mock := &dashboards.FakeDashboardService{
  712. SaveDashboardResult: &m.Dashboard{
  713. Id: 2,
  714. Uid: "uid",
  715. Title: "Dash",
  716. Slug: "dash",
  717. Version: 1,
  718. },
  719. }
  720. cmd := dtos.RestoreDashboardVersionCommand{
  721. Version: 1,
  722. }
  723. restoreDashboardVersionScenario("When calling POST on", "/api/dashboards/id/1/restore", "/api/dashboards/id/:dashboardId/restore", mock, cmd, func(sc *scenarioContext) {
  724. CallRestoreDashboardVersion(sc)
  725. So(sc.resp.Code, ShouldEqual, 200)
  726. dto := mock.SavedDashboards[0]
  727. So(dto.Dashboard.FolderId, ShouldEqual, 0)
  728. So(dto.Dashboard.Title, ShouldEqual, "Child dash")
  729. So(dto.Message, ShouldEqual, "Restored from version 1")
  730. })
  731. })
  732. Convey("Given provisioned dashboard", t, func() {
  733. bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
  734. query.Result = []*m.Dashboard{{}}
  735. return nil
  736. })
  737. bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
  738. query.Result = &m.Dashboard{Id: 1, Data: &simplejson.Json{}}
  739. return nil
  740. })
  741. bus.AddHandler("test", func(query *m.GetProvisionedDashboardDataByIdQuery) error {
  742. query.Result = &m.DashboardProvisioning{ExternalId: "/tmp/grafana/dashboards/test/dashboard1.json"}
  743. return nil
  744. })
  745. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  746. query.Result = []*m.DashboardAclInfoDTO{
  747. {OrgId: TestOrgID, DashboardId: 1, UserId: TestUserID, Permission: m.PERMISSION_EDIT},
  748. }
  749. return nil
  750. })
  751. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/dash", "/api/dashboards/db/:slug", m.ROLE_EDITOR, func(sc *scenarioContext) {
  752. CallDeleteDashboardBySlug(sc)
  753. Convey("Should result in 400", func() {
  754. So(sc.resp.Code, ShouldEqual, 400)
  755. result := sc.ToJSON()
  756. So(result.Get("error").MustString(), ShouldEqual, m.ErrDashboardCannotDeleteProvisionedDashboard.Error())
  757. })
  758. })
  759. loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/abcdefghi", "/api/dashboards/db/:uid", m.ROLE_EDITOR, func(sc *scenarioContext) {
  760. CallDeleteDashboardByUID(sc)
  761. Convey("Should result in 400", func() {
  762. So(sc.resp.Code, ShouldEqual, 400)
  763. result := sc.ToJSON()
  764. So(result.Get("error").MustString(), ShouldEqual, m.ErrDashboardCannotDeleteProvisionedDashboard.Error())
  765. })
  766. })
  767. loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", m.ROLE_EDITOR, func(sc *scenarioContext) {
  768. mock := provisioning.NewProvisioningServiceMock()
  769. mock.GetDashboardProvisionerResolvedPathFunc = func(name string) string {
  770. return "/tmp/grafana/dashboards"
  771. }
  772. dash := GetDashboardShouldReturn200WithConfig(sc, mock)
  773. Convey("Should return relative path to provisioning file", func() {
  774. So(dash.Meta.ProvisionedExternalId, ShouldEqual, "test/dashboard1.json")
  775. })
  776. })
  777. })
  778. }
  779. func GetDashboardShouldReturn200WithConfig(sc *scenarioContext, provisioningService ProvisioningService) dtos.DashboardFullWithMeta {
  780. if provisioningService == nil {
  781. provisioningService = provisioning.NewProvisioningServiceMock()
  782. }
  783. hs := &HTTPServer{
  784. Cfg: setting.NewCfg(),
  785. ProvisioningService: provisioningService,
  786. }
  787. CallGetDashboard(sc, hs)
  788. So(sc.resp.Code, ShouldEqual, 200)
  789. dash := dtos.DashboardFullWithMeta{}
  790. err := json.NewDecoder(sc.resp.Body).Decode(&dash)
  791. So(err, ShouldBeNil)
  792. return dash
  793. }
  794. func GetDashboardShouldReturn200(sc *scenarioContext) dtos.DashboardFullWithMeta {
  795. return GetDashboardShouldReturn200WithConfig(sc, nil)
  796. }
  797. func CallGetDashboard(sc *scenarioContext, hs *HTTPServer) {
  798. sc.handlerFunc = hs.GetDashboard
  799. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  800. }
  801. func CallGetDashboardVersion(sc *scenarioContext) {
  802. bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error {
  803. query.Result = &m.DashboardVersion{}
  804. return nil
  805. })
  806. sc.handlerFunc = GetDashboardVersion
  807. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  808. }
  809. func CallGetDashboardVersions(sc *scenarioContext) {
  810. bus.AddHandler("test", func(query *m.GetDashboardVersionsQuery) error {
  811. query.Result = []*m.DashboardVersionDTO{}
  812. return nil
  813. })
  814. sc.handlerFunc = GetDashboardVersions
  815. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  816. }
  817. func CallDeleteDashboardBySlug(sc *scenarioContext) {
  818. bus.AddHandler("test", func(cmd *m.DeleteDashboardCommand) error {
  819. return nil
  820. })
  821. sc.handlerFunc = DeleteDashboardBySlug
  822. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  823. }
  824. func CallDeleteDashboardByUID(sc *scenarioContext) {
  825. bus.AddHandler("test", func(cmd *m.DeleteDashboardCommand) error {
  826. return nil
  827. })
  828. sc.handlerFunc = DeleteDashboardByUID
  829. sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
  830. }
  831. func CallPostDashboard(sc *scenarioContext) {
  832. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  833. }
  834. func CallRestoreDashboardVersion(sc *scenarioContext) {
  835. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  836. }
  837. func CallPostDashboardShouldReturnSuccess(sc *scenarioContext) {
  838. CallPostDashboard(sc)
  839. So(sc.resp.Code, ShouldEqual, 200)
  840. }
  841. func postDashboardScenario(desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd m.SaveDashboardCommand, fn scenarioFunc) {
  842. Convey(desc+" "+url, func() {
  843. defer bus.ClearBusHandlers()
  844. hs := HTTPServer{
  845. Bus: bus.GetBus(),
  846. Cfg: setting.NewCfg(),
  847. }
  848. sc := setupScenarioContext(url)
  849. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  850. sc.context = c
  851. sc.context.SignedInUser = &m.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId}
  852. return hs.PostDashboard(c, cmd)
  853. })
  854. origNewDashboardService := dashboards.NewService
  855. dashboards.MockDashboardService(mock)
  856. sc.m.Post(routePattern, sc.defaultHandler)
  857. defer func() {
  858. dashboards.NewService = origNewDashboardService
  859. }()
  860. fn(sc)
  861. })
  862. }
  863. func postDiffScenario(desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions, role m.RoleType, fn scenarioFunc) {
  864. Convey(desc+" "+url, func() {
  865. defer bus.ClearBusHandlers()
  866. sc := setupScenarioContext(url)
  867. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  868. sc.context = c
  869. sc.context.SignedInUser = &m.SignedInUser{
  870. OrgId: TestOrgID,
  871. UserId: TestUserID,
  872. }
  873. sc.context.OrgRole = role
  874. return CalculateDashboardDiff(c, cmd)
  875. })
  876. sc.m.Post(routePattern, sc.defaultHandler)
  877. fn(sc)
  878. })
  879. }
  880. func restoreDashboardVersionScenario(desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc) {
  881. Convey(desc+" "+url, func() {
  882. defer bus.ClearBusHandlers()
  883. hs := HTTPServer{
  884. Cfg: setting.NewCfg(),
  885. Bus: bus.GetBus(),
  886. }
  887. sc := setupScenarioContext(url)
  888. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  889. sc.context = c
  890. sc.context.SignedInUser = &m.SignedInUser{
  891. OrgId: TestOrgID,
  892. UserId: TestUserID,
  893. }
  894. sc.context.OrgRole = m.ROLE_ADMIN
  895. return hs.RestoreDashboardVersion(c, cmd)
  896. })
  897. origNewDashboardService := dashboards.NewService
  898. dashboards.MockDashboardService(mock)
  899. sc.m.Post(routePattern, sc.defaultHandler)
  900. defer func() {
  901. dashboards.NewService = origNewDashboardService
  902. }()
  903. fn(sc)
  904. })
  905. }
  906. func (sc *scenarioContext) ToJSON() *simplejson.Json {
  907. var result *simplejson.Json
  908. err := json.NewDecoder(sc.resp.Body).Decode(&result)
  909. So(err, ShouldBeNil)
  910. return result
  911. }