diff --git a/pkg/services/ngalert/notifier/channels/sensugo_test.go b/pkg/services/ngalert/notifier/channels/sensugo_test.go index ec4d7274ae8..85156d5c496 100644 --- a/pkg/services/ngalert/notifier/channels/sensugo_test.go +++ b/pkg/services/ngalert/notifier/channels/sensugo_test.go @@ -27,7 +27,7 @@ func TestSensuGoNotifier(t *testing.T) { require.NoError(t, err) tmpl.ExternalURL = externalURL - images := newFakeImageStore() + images := newFakeImageStore(2) cases := []struct { name string @@ -44,7 +44,7 @@ func TestSensuGoNotifier(t *testing.T) { { Alert: model.Alert{ Labels: model.LabelSet{"__alert_rule_uid__": "rule uid", "alertname": "alert1", "lbl1": "val1"}, - Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh", "__alertScreenshotToken__": "test-image"}, + Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh", "__alertScreenshotToken__": "test-image-1"}, }, }, }, @@ -59,7 +59,7 @@ func TestSensuGoNotifier(t *testing.T) { "metadata": map[string]interface{}{ "name": "default", "labels": map[string]string{ - "imageURL": "https://www.example.com/test-image.jpg", + "imageURL": "https://www.example.com/test-image-1.jpg", "ruleURL": "http://localhost/alerting/list", }, }, @@ -87,7 +87,7 @@ func TestSensuGoNotifier(t *testing.T) { { Alert: model.Alert{ Labels: model.LabelSet{"__alert_rule_uid__": "rule uid", "alertname": "alert1", "lbl1": "val1"}, - Annotations: model.LabelSet{"ann1": "annv1", "__alertScreenshotToken__": "test-image"}, + Annotations: model.LabelSet{"ann1": "annv1", "__alertScreenshotToken__": "test-image-1"}, }, }, { Alert: model.Alert{ @@ -107,7 +107,7 @@ func TestSensuGoNotifier(t *testing.T) { "metadata": map[string]interface{}{ "name": "grafana_rule_0", "labels": map[string]string{ - "imageURL": "https://www.example.com/test-image.jpg", + "imageURL": "https://www.example.com/test-image-1.jpg", "ruleURL": "http://localhost/alerting/list", }, }, diff --git a/pkg/services/ngalert/notifier/channels/testing.go b/pkg/services/ngalert/notifier/channels/testing.go index 3cd6302d54d..bf2e23b1108 100644 --- a/pkg/services/ngalert/notifier/channels/testing.go +++ b/pkg/services/ngalert/notifier/channels/testing.go @@ -3,6 +3,7 @@ package channels import ( "context" "encoding/base64" + "fmt" "os" "testing" "time" @@ -11,10 +12,6 @@ import ( ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" ) -// deleteFunc deletes the fake image. -// nolint:unused -type deleteFunc func() - type fakeImageStore struct { Images []*ngmodels.Image } @@ -29,63 +26,79 @@ func (f *fakeImageStore) GetImage(_ context.Context, token string) (*ngmodels.Im return nil, ngmodels.ErrImageNotFound } -// newFakeImageStore returns an image store with a test image. -// The image has a token and a URL, but does not have a file on disk. -func newFakeImageStore() ImageStore { - return &fakeImageStore{ - Images: []*ngmodels.Image{ - { - Token: "test-image", - URL: "https://www.example.com/test-image.jpg", - CreatedAt: time.Now().UTC(), - }, - }, +// newFakeImageStore returns an image store with N test images. +// Each image has a token and a URL, but does not have a file on disk. +func newFakeImageStore(n int) ImageStore { + s := fakeImageStore{} + for i := 0; i < n; i++ { + s.Images = append(s.Images, &ngmodels.Image{ + Token: fmt.Sprintf("test-image-%d", i), + URL: fmt.Sprintf("https://www.example.com/test-image-%d.jpg", 1), + CreatedAt: time.Now().UTC(), + }) } + return &s } -// newFakeImageStoreWithFile returns an image store with a test image. -// The image has a token, path and a URL, where the path is 1x1 transparent -// PNG on disk. The test should call deleteFunc to delete the image from disk +// newFakeImageStoreWithFile returns an image store with N test images. +// Each image has a token, path and a URL, where the path is 1x1 transparent +// PNG on disk. The test should call deleteFunc to delete the images from disk // at the end of the test. // nolint:deadcode,unused -func newFakeImageStoreWithFile(t *testing.T) (ImageStore, deleteFunc) { +func newFakeImageStoreWithFile(t *testing.T, n int) ImageStore { + var ( + files []string + s fakeImageStore + ) + + t.Cleanup(func() { + // remove all files from disk + for _, f := range files { + if err := os.Remove(f); err != nil { + t.Logf("failed to delete file: %s", err) + } + } + }) + + for i := 0; i < n; i++ { + file, err := newTestImage() + if err != nil { + t.Fatalf("failed to create test image: %s", err) + } + files = append(files, file) + s.Images = append(s.Images, &ngmodels.Image{ + Token: fmt.Sprintf("test-image-%d", i), + Path: file, + URL: fmt.Sprintf("https://www.example.com/test-image-%d", i), + CreatedAt: time.Now().UTC(), + }) + } + + return &s +} + +// nolint:deadcode,unused +func newTestImage() (string, error) { f, err := os.CreateTemp("", "test-image-*.png") if err != nil { - t.Fatalf("failed to create temp image: %s", err) + return "", fmt.Errorf("failed to create temp image: %s", err) } // 1x1 transparent PNG b, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=") if err != nil { - t.Fatalf("failed to decode PNG data: %s", err) + return f.Name(), fmt.Errorf("failed to decode PNG data: %s", err) } if _, err := f.Write(b); err != nil { - t.Fatalf("failed to write to file: %s", err) + return f.Name(), fmt.Errorf("failed to write to file: %s", err) } if err := f.Close(); err != nil { - t.Fatalf("failed to close file: %s", err) + return f.Name(), fmt.Errorf("failed to close file: %s", err) } - fn := func() { - if err := os.Remove(f.Name()); err != nil { - t.Fatalf("failed to delete file: %s", err) - } - } - - store := &fakeImageStore{ - Images: []*ngmodels.Image{ - { - Token: "test-image", - Path: f.Name(), - URL: "https://www.example.com/test-image.jpg", - CreatedAt: time.Now().UTC(), - }, - }, - } - - return store, fn + return f.Name(), nil } // mockTimeNow replaces function timeNow to return constant time.