diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index c9c1d184888..f17f9e85f3e 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -5,7 +5,8 @@ package sqlstore import ( "testing" - . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/services/annotations" ) @@ -14,275 +15,241 @@ func TestAnnotations(t *testing.T) { mockTimeNow() defer resetTimeNow() InitTestDB(t) + repo := SqlAnnotationRepo{} - Convey("Testing annotation saving/loading", t, func() { - repo := SqlAnnotationRepo{} + t.Run("Testing annotation create, read, update and delete", func(t *testing.T) { + t.Cleanup(func() { + _, err := x.Exec("DELETE FROM annotation WHERE 1=1") + assert.NoError(t, err) + _, err = x.Exec("DELETE FROM annotation_tag WHERE 1=1") + assert.NoError(t, err) + }) - Convey("Can save annotation", func() { - Reset(func() { - _, err := x.Exec("DELETE FROM annotation WHERE 1=1") - So(err, ShouldBeNil) - _, err = x.Exec("DELETE FROM annotation_tag WHERE 1=1") - So(err, ShouldBeNil) - }) + annotation := &annotations.Item{ + OrgId: 1, + UserId: 1, + DashboardId: 1, + Text: "hello", + Type: "alert", + Epoch: 10, + Tags: []string{"outage", "error", "type:outage", "server:server-1"}, + } + err := repo.Save(annotation) + require.NoError(t, err) + assert.Greater(t, annotation.Id, int64(0)) + assert.Equal(t, annotation.Epoch, annotation.EpochEnd) - annotation := &annotations.Item{ + annotation2 := &annotations.Item{ + OrgId: 1, + UserId: 1, + DashboardId: 2, + Text: "hello", + Type: "alert", + Epoch: 21, // Should swap epoch & epochEnd + EpochEnd: 20, + Tags: []string{"outage", "error", "type:outage", "server:server-1"}, + } + err = repo.Save(annotation2) + require.NoError(t, err) + assert.Greater(t, annotation2.Id, int64(0)) + assert.Equal(t, int64(20), annotation2.Epoch) + assert.Equal(t, int64(21), annotation2.EpochEnd) + + globalAnnotation1 := &annotations.Item{ + OrgId: 1, + UserId: 1, + Text: "deploy", + Type: "", + Epoch: 15, + Tags: []string{"deploy"}, + } + err = repo.Save(globalAnnotation1) + require.NoError(t, err) + assert.Greater(t, globalAnnotation1.Id, int64(0)) + + globalAnnotation2 := &annotations.Item{ + OrgId: 1, + UserId: 1, + Text: "rollback", + Type: "", + Epoch: 17, + Tags: []string{"rollback"}, + } + err = repo.Save(globalAnnotation2) + require.NoError(t, err) + assert.Greater(t, globalAnnotation2.Id, int64(0)) + + t.Run("Can query for annotation by dashboard id", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ OrgId: 1, - UserId: 1, DashboardId: 1, - Text: "hello", - Type: "alert", - Epoch: 10, - Tags: []string{"outage", "error", "type:outage", "server:server-1"}, - } - err := repo.Save(annotation) + From: 0, + To: 15, + }) - So(err, ShouldBeNil) - So(annotation.Id, ShouldBeGreaterThan, 0) - So(annotation.Epoch, ShouldEqual, annotation.EpochEnd) + require.NoError(t, err) + assert.Len(t, items, 1) - annotation2 := &annotations.Item{ + assert.Equal(t, []string{"outage", "error", "type:outage", "server:server-1"}, items[0].Tags) + + assert.GreaterOrEqual(t, items[0].Created, int64(0)) + assert.GreaterOrEqual(t, items[0].Updated, int64(0)) + assert.Equal(t, items[0].Updated, items[0].Created) + }) + + t.Run("Can query for annotation by id", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + AnnotationId: annotation2.Id, + }) + require.NoError(t, err) + assert.Len(t, items, 1) + assert.Equal(t, annotation2.Id, items[0].Id) + }) + + t.Run("Should not find any when item is outside time range", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ OrgId: 1, - UserId: 1, - DashboardId: 2, - Text: "hello", + DashboardId: 1, + From: 12, + To: 15, + }) + require.NoError(t, err) + assert.Empty(t, items) + }) + + t.Run("Should not find one when tag filter does not match", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 1, + To: 15, + Tags: []string{"asd"}, + }) + require.NoError(t, err) + assert.Empty(t, items) + }) + + t.Run("Should not find one when type filter does not match", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 1, + To: 15, Type: "alert", - Epoch: 21, // Should swap epoch & epochEnd - EpochEnd: 20, - Tags: []string{"outage", "error", "type:outage", "server:server-1"}, + }) + require.NoError(t, err) + assert.Empty(t, items) + }) + + t.Run("Should find one when all tag filters does match", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 1, + To: 15, // this will exclude the second test annotation + Tags: []string{"outage", "error"}, + }) + require.NoError(t, err) + assert.Len(t, items, 1) + }) + + t.Run("Should find two annotations using partial match", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + From: 1, + To: 25, + MatchAny: true, + Tags: []string{"rollback", "deploy"}, + }) + require.NoError(t, err) + assert.Len(t, items, 2) + }) + + t.Run("Should find one when all key value tag filters does match", func(t *testing.T) { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 1, + To: 15, + Tags: []string{"type:outage", "server:server-1"}, + }) + require.NoError(t, err) + assert.Len(t, items, 1) + }) + + t.Run("Can update annotation and remove all tags", func(t *testing.T) { + query := &annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 0, + To: 15, } - err = repo.Save(annotation2) - So(err, ShouldBeNil) - So(annotation2.Id, ShouldBeGreaterThan, 0) - So(annotation2.Epoch, ShouldEqual, 20) - So(annotation2.EpochEnd, ShouldEqual, 21) + items, err := repo.Find(query) + require.NoError(t, err) - globalAnnotation1 := &annotations.Item{ - OrgId: 1, - UserId: 1, - Text: "deploy", - Type: "", - Epoch: 15, - Tags: []string{"deploy"}, + annotationId := items[0].Id + err = repo.Update(&annotations.Item{ + Id: annotationId, + OrgId: 1, + Text: "something new", + Tags: []string{}, + }) + require.NoError(t, err) + + items, err = repo.Find(query) + require.NoError(t, err) + + assert.Equal(t, annotationId, items[0].Id) + assert.Empty(t, items[0].Tags) + assert.Equal(t, "something new", items[0].Text) + }) + + t.Run("Can update annotation with new tags", func(t *testing.T) { + query := &annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 0, + To: 15, } - err = repo.Save(globalAnnotation1) - So(err, ShouldBeNil) - So(globalAnnotation1.Id, ShouldBeGreaterThan, 0) + items, err := repo.Find(query) + require.NoError(t, err) - globalAnnotation2 := &annotations.Item{ - OrgId: 1, - UserId: 1, - Text: "rollback", - Type: "", - Epoch: 17, - Tags: []string{"rollback"}, + annotationId := items[0].Id + err = repo.Update(&annotations.Item{ + Id: annotationId, + OrgId: 1, + Text: "something new", + Tags: []string{"newtag1", "newtag2"}, + }) + require.NoError(t, err) + + items, err = repo.Find(query) + require.NoError(t, err) + + assert.Equal(t, annotationId, items[0].Id) + assert.Equal(t, []string{"newtag1", "newtag2"}, items[0].Tags) + assert.Equal(t, "something new", items[0].Text) + assert.Greater(t, items[0].Updated, items[0].Created) + }) + + t.Run("Can delete annotation", func(t *testing.T) { + query := &annotations.ItemQuery{ + OrgId: 1, + DashboardId: 1, + From: 0, + To: 15, } - err = repo.Save(globalAnnotation2) - So(err, ShouldBeNil) - So(globalAnnotation2.Id, ShouldBeGreaterThan, 0) + items, err := repo.Find(query) + require.NoError(t, err) - Convey("Can query for annotation by dashboard id", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 0, - To: 15, - }) + annotationId := items[0].Id + err = repo.Delete(&annotations.DeleteParams{Id: annotationId, OrgId: 1}) + require.NoError(t, err) - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 1) - - Convey("Can read tags", func() { - So(items[0].Tags, ShouldResemble, []string{"outage", "error", "type:outage", "server:server-1"}) - }) - - Convey("Has created and updated values", func() { - So(items[0].Created, ShouldBeGreaterThan, 0) - So(items[0].Updated, ShouldBeGreaterThan, 0) - So(items[0].Updated, ShouldEqual, items[0].Created) - }) - }) - - Convey("Can query for annotation by id", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - AnnotationId: annotation2.Id, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 1) - So(items[0].Id, ShouldEqual, annotation2.Id) - }) - - Convey("Should not find any when item is outside time range", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 12, - To: 15, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 0) - }) - - Convey("Should not find one when tag filter does not match", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 1, - To: 15, - Tags: []string{"asd"}, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 0) - }) - - Convey("Should not find one when type filter does not match", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 1, - To: 15, - Type: "alert", - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 0) - }) - - Convey("Should find one when all tag filters does match", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 1, - To: 15, // this will exclude the second test annotation - Tags: []string{"outage", "error"}, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 1) - }) - - Convey("Should find two annotations using partial match", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - From: 1, - To: 25, - MatchAny: true, - Tags: []string{"rollback", "deploy"}, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 2) - }) - - Convey("Should find one when all key value tag filters does match", func() { - items, err := repo.Find(&annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 1, - To: 15, - Tags: []string{"type:outage", "server:server-1"}, - }) - - So(err, ShouldBeNil) - So(items, ShouldHaveLength, 1) - }) - - Convey("Can update annotation and remove all tags", func() { - query := &annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 0, - To: 15, - } - items, err := repo.Find(query) - - So(err, ShouldBeNil) - - annotationId := items[0].Id - - err = repo.Update(&annotations.Item{ - Id: annotationId, - OrgId: 1, - Text: "something new", - Tags: []string{}, - }) - - So(err, ShouldBeNil) - - items, err = repo.Find(query) - - So(err, ShouldBeNil) - - Convey("Can read tags", func() { - So(items[0].Id, ShouldEqual, annotationId) - So(len(items[0].Tags), ShouldEqual, 0) - So(items[0].Text, ShouldEqual, "something new") - }) - }) - - Convey("Can update annotation with new tags", func() { - query := &annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 0, - To: 15, - } - items, err := repo.Find(query) - - So(err, ShouldBeNil) - - annotationId := items[0].Id - - err = repo.Update(&annotations.Item{ - Id: annotationId, - OrgId: 1, - Text: "something new", - Tags: []string{"newtag1", "newtag2"}, - }) - - So(err, ShouldBeNil) - - items, err = repo.Find(query) - - So(err, ShouldBeNil) - - Convey("Can read tags", func() { - So(items[0].Id, ShouldEqual, annotationId) - So(items[0].Tags, ShouldResemble, []string{"newtag1", "newtag2"}) - So(items[0].Text, ShouldEqual, "something new") - }) - - Convey("Updated time has increased", func() { - So(items[0].Updated, ShouldBeGreaterThan, items[0].Created) - }) - }) - - Convey("Can delete annotation", func() { - query := &annotations.ItemQuery{ - OrgId: 1, - DashboardId: 1, - From: 0, - To: 15, - } - items, err := repo.Find(query) - So(err, ShouldBeNil) - - annotationId := items[0].Id - - err = repo.Delete(&annotations.DeleteParams{Id: annotationId, OrgId: 1}) - So(err, ShouldBeNil) - - items, err = repo.Find(query) - So(err, ShouldBeNil) - - Convey("Should be deleted", func() { - So(len(items), ShouldEqual, 0) - }) - }) + items, err = repo.Find(query) + require.NoError(t, err) + assert.Empty(t, items) }) }) }