mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			323 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
package api
 | 
						|
 | 
						|
import (
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/api/dtos"
 | 
						|
	"github.com/grafana/grafana/pkg/bus"
 | 
						|
	"github.com/grafana/grafana/pkg/models"
 | 
						|
	"github.com/grafana/grafana/pkg/services/annotations"
 | 
						|
 | 
						|
	. "github.com/smartystreets/goconvey/convey"
 | 
						|
)
 | 
						|
 | 
						|
func TestAnnotationsApiEndpoint(t *testing.T) {
 | 
						|
	Convey("Given an annotation without a dashboard id", t, func() {
 | 
						|
		cmd := dtos.PostAnnotationsCmd{
 | 
						|
			Time: 1000,
 | 
						|
			Text: "annotation text",
 | 
						|
			Tags: []string{"tag1", "tag2"},
 | 
						|
		}
 | 
						|
 | 
						|
		updateCmd := dtos.UpdateAnnotationsCmd{
 | 
						|
			Time: 1000,
 | 
						|
			Text: "annotation text",
 | 
						|
			Tags: []string{"tag1", "tag2"},
 | 
						|
		}
 | 
						|
 | 
						|
		patchCmd := dtos.PatchAnnotationsCmd{
 | 
						|
			Time: 1000,
 | 
						|
			Text: "annotation text",
 | 
						|
			Tags: []string{"tag1", "tag2"},
 | 
						|
		}
 | 
						|
 | 
						|
		Convey("When user is an Org Viewer", func() {
 | 
						|
			role := models.ROLE_VIEWER
 | 
						|
			Convey("Should not be allowed to save an annotation", func() {
 | 
						|
				postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
 | 
						|
					sc.handlerFunc = DeleteAnnotationByID
 | 
						|
					sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
			})
 | 
						|
		})
 | 
						|
 | 
						|
		Convey("When user is an Org Editor", func() {
 | 
						|
			role := models.ROLE_EDITOR
 | 
						|
			Convey("Should be able to save an annotation", func() {
 | 
						|
				postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
 | 
						|
					sc.handlerFunc = DeleteAnnotationByID
 | 
						|
					sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
			})
 | 
						|
		})
 | 
						|
	})
 | 
						|
 | 
						|
	Convey("Given an annotation with a dashboard id and the dashboard does not have an acl", t, func() {
 | 
						|
		cmd := dtos.PostAnnotationsCmd{
 | 
						|
			Time:        1000,
 | 
						|
			Text:        "annotation text",
 | 
						|
			Tags:        []string{"tag1", "tag2"},
 | 
						|
			DashboardId: 1,
 | 
						|
			PanelId:     1,
 | 
						|
		}
 | 
						|
 | 
						|
		updateCmd := dtos.UpdateAnnotationsCmd{
 | 
						|
			Time: 1000,
 | 
						|
			Text: "annotation text",
 | 
						|
			Tags: []string{"tag1", "tag2"},
 | 
						|
			Id:   1,
 | 
						|
		}
 | 
						|
 | 
						|
		patchCmd := dtos.PatchAnnotationsCmd{
 | 
						|
			Time: 8000,
 | 
						|
			Text: "annotation text 50",
 | 
						|
			Tags: []string{"foo", "bar"},
 | 
						|
			Id:   1,
 | 
						|
		}
 | 
						|
 | 
						|
		deleteCmd := dtos.DeleteAnnotationsCmd{
 | 
						|
			DashboardId: 1,
 | 
						|
			PanelId:     1,
 | 
						|
		}
 | 
						|
 | 
						|
		viewerRole := models.ROLE_VIEWER
 | 
						|
		editorRole := models.ROLE_EDITOR
 | 
						|
 | 
						|
		aclMockResp := []*models.DashboardAclInfoDTO{
 | 
						|
			{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
 | 
						|
			{Role: &editorRole, Permission: models.PERMISSION_EDIT},
 | 
						|
		}
 | 
						|
 | 
						|
		bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
 | 
						|
			query.Result = aclMockResp
 | 
						|
			return nil
 | 
						|
		})
 | 
						|
 | 
						|
		bus.AddHandler("test", func(query *models.GetTeamsByUserQuery) error {
 | 
						|
			query.Result = []*models.TeamDTO{}
 | 
						|
			return nil
 | 
						|
		})
 | 
						|
 | 
						|
		Convey("When user is an Org Viewer", func() {
 | 
						|
			role := models.ROLE_VIEWER
 | 
						|
			Convey("Should not be allowed to save an annotation", func() {
 | 
						|
				postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
 | 
						|
				loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
 | 
						|
					sc.handlerFunc = DeleteAnnotationByID
 | 
						|
					sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 403)
 | 
						|
				})
 | 
						|
			})
 | 
						|
		})
 | 
						|
 | 
						|
		Convey("When user is an Org Editor", func() {
 | 
						|
			role := models.ROLE_EDITOR
 | 
						|
			Convey("Should be able to save an annotation", func() {
 | 
						|
				postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
 | 
						|
					sc.handlerFunc = DeleteAnnotationByID
 | 
						|
					sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
			})
 | 
						|
		})
 | 
						|
 | 
						|
		Convey("When user is an Admin", func() {
 | 
						|
			role := models.ROLE_ADMIN
 | 
						|
			Convey("Should be able to do anything", func() {
 | 
						|
				postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
 | 
						|
				deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
 | 
						|
					sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
 | 
						|
					So(sc.resp.Code, ShouldEqual, 200)
 | 
						|
				})
 | 
						|
			})
 | 
						|
		})
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
type fakeAnnotationsRepo struct {
 | 
						|
}
 | 
						|
 | 
						|
func (repo *fakeAnnotationsRepo) Delete(params *annotations.DeleteParams) error {
 | 
						|
	return nil
 | 
						|
}
 | 
						|
func (repo *fakeAnnotationsRepo) Save(item *annotations.Item) error {
 | 
						|
	item.Id = 1
 | 
						|
	return nil
 | 
						|
}
 | 
						|
func (repo *fakeAnnotationsRepo) Update(item *annotations.Item) error {
 | 
						|
	return nil
 | 
						|
}
 | 
						|
func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
 | 
						|
	annotations := []*annotations.ItemDTO{{Id: 1}}
 | 
						|
	return annotations, nil
 | 
						|
}
 | 
						|
 | 
						|
var fakeAnnoRepo *fakeAnnotationsRepo
 | 
						|
 | 
						|
func postAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
 | 
						|
	Convey(desc+" "+url, func() {
 | 
						|
		defer bus.ClearBusHandlers()
 | 
						|
 | 
						|
		sc := setupScenarioContext(url)
 | 
						|
		sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
 | 
						|
			sc.context = c
 | 
						|
			sc.context.UserId = TestUserID
 | 
						|
			sc.context.OrgId = TestOrgID
 | 
						|
			sc.context.OrgRole = role
 | 
						|
 | 
						|
			return PostAnnotation(c, cmd)
 | 
						|
		})
 | 
						|
 | 
						|
		fakeAnnoRepo = &fakeAnnotationsRepo{}
 | 
						|
		annotations.SetRepository(fakeAnnoRepo)
 | 
						|
 | 
						|
		sc.m.Post(routePattern, sc.defaultHandler)
 | 
						|
 | 
						|
		fn(sc)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func putAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
 | 
						|
	Convey(desc+" "+url, func() {
 | 
						|
		defer bus.ClearBusHandlers()
 | 
						|
 | 
						|
		sc := setupScenarioContext(url)
 | 
						|
		sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
 | 
						|
			sc.context = c
 | 
						|
			sc.context.UserId = TestUserID
 | 
						|
			sc.context.OrgId = TestOrgID
 | 
						|
			sc.context.OrgRole = role
 | 
						|
 | 
						|
			return UpdateAnnotation(c, cmd)
 | 
						|
		})
 | 
						|
 | 
						|
		fakeAnnoRepo = &fakeAnnotationsRepo{}
 | 
						|
		annotations.SetRepository(fakeAnnoRepo)
 | 
						|
 | 
						|
		sc.m.Put(routePattern, sc.defaultHandler)
 | 
						|
 | 
						|
		fn(sc)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func patchAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
 | 
						|
	Convey(desc+" "+url, func() {
 | 
						|
		defer bus.ClearBusHandlers()
 | 
						|
 | 
						|
		sc := setupScenarioContext(url)
 | 
						|
		sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
 | 
						|
			sc.context = c
 | 
						|
			sc.context.UserId = TestUserID
 | 
						|
			sc.context.OrgId = TestOrgID
 | 
						|
			sc.context.OrgRole = role
 | 
						|
 | 
						|
			return PatchAnnotation(c, cmd)
 | 
						|
		})
 | 
						|
 | 
						|
		fakeAnnoRepo = &fakeAnnotationsRepo{}
 | 
						|
		annotations.SetRepository(fakeAnnoRepo)
 | 
						|
 | 
						|
		sc.m.Patch(routePattern, sc.defaultHandler)
 | 
						|
 | 
						|
		fn(sc)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func deleteAnnotationsScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
 | 
						|
	Convey(desc+" "+url, func() {
 | 
						|
		defer bus.ClearBusHandlers()
 | 
						|
 | 
						|
		sc := setupScenarioContext(url)
 | 
						|
		sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
 | 
						|
			sc.context = c
 | 
						|
			sc.context.UserId = TestUserID
 | 
						|
			sc.context.OrgId = TestOrgID
 | 
						|
			sc.context.OrgRole = role
 | 
						|
 | 
						|
			return DeleteAnnotations(c, cmd)
 | 
						|
		})
 | 
						|
 | 
						|
		fakeAnnoRepo = &fakeAnnotationsRepo{}
 | 
						|
		annotations.SetRepository(fakeAnnoRepo)
 | 
						|
 | 
						|
		sc.m.Post(routePattern, sc.defaultHandler)
 | 
						|
 | 
						|
		fn(sc)
 | 
						|
	})
 | 
						|
}
 |