|
|
|
@ -5,7 +5,6 @@ import ( |
|
|
|
|
"testing" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/google/uuid" |
|
|
|
|
"github.com/stretchr/testify/assert" |
|
|
|
|
"github.com/stretchr/testify/require" |
|
|
|
|
|
|
|
|
@ -14,182 +13,175 @@ import ( |
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/tests" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func createTestImg(fakeUrl string, fakePath string) *models.Image { |
|
|
|
|
return &models.Image{ |
|
|
|
|
ID: 0, |
|
|
|
|
Token: "", |
|
|
|
|
Path: fakeUrl + "local", |
|
|
|
|
URL: fakeUrl, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func addID(img *models.Image, id int64) *models.Image { |
|
|
|
|
img.ID = id |
|
|
|
|
return img |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func addToken(img *models.Image) *models.Image { |
|
|
|
|
token, err := uuid.NewRandom() |
|
|
|
|
if err != nil { |
|
|
|
|
panic("wat") |
|
|
|
|
} |
|
|
|
|
img.Token = token.String() |
|
|
|
|
return img |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestIntegrationSaveAndGetImage(t *testing.T) { |
|
|
|
|
if testing.Short() { |
|
|
|
|
t.Skip("skipping integration test") |
|
|
|
|
} |
|
|
|
|
mockTimeNow() |
|
|
|
|
|
|
|
|
|
// our database schema uses second precision for timestamps
|
|
|
|
|
store.TimeNow = func() time.Time { |
|
|
|
|
return time.Now().Truncate(time.Second) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctx := context.Background() |
|
|
|
|
_, dbstore := tests.SetupTestEnv(t, baseIntervalSeconds) |
|
|
|
|
|
|
|
|
|
// Here are some images to save.
|
|
|
|
|
imgs := []struct { |
|
|
|
|
name string |
|
|
|
|
img *models.Image |
|
|
|
|
errors bool |
|
|
|
|
}{ |
|
|
|
|
{ |
|
|
|
|
"with file path", |
|
|
|
|
createTestImg("", "path"), |
|
|
|
|
false, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
"with URL", |
|
|
|
|
createTestImg("url", ""), |
|
|
|
|
false, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
"ID already set, should not change", |
|
|
|
|
addToken(addID(createTestImg("Foo", ""), 123)), |
|
|
|
|
true, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
// create an image with a path on disk
|
|
|
|
|
image1 := models.Image{Path: "example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
require.NotEqual(t, "", image1.Token) |
|
|
|
|
|
|
|
|
|
for _, test := range imgs { |
|
|
|
|
t.Run(test.name, func(t *testing.T) { |
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second) |
|
|
|
|
defer cancel() |
|
|
|
|
err := dbstore.SaveImage(ctx, test.img) |
|
|
|
|
if test.errors { |
|
|
|
|
require.Error(t, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// image should not have expired
|
|
|
|
|
assert.False(t, image1.HasExpired()) |
|
|
|
|
assert.Equal(t, image1.ExpiresAt, image1.CreatedAt.Add(24*time.Hour)) |
|
|
|
|
|
|
|
|
|
// should return the image with a path on disk
|
|
|
|
|
result1, err := dbstore.GetImage(ctx, image1.Token) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
returned, err := dbstore.GetImage(ctx, test.img.Token) |
|
|
|
|
assert.NoError(t, err, "Shouldn't error when getting the image") |
|
|
|
|
assert.Equal(t, test.img, returned) |
|
|
|
|
|
|
|
|
|
// Save again to test update path.
|
|
|
|
|
err = dbstore.SaveImage(ctx, test.img) |
|
|
|
|
require.NoError(t, err, "Should have no error on second write") |
|
|
|
|
returned, err = dbstore.GetImage(ctx, test.img.Token) |
|
|
|
|
assert.NoError(t, err, "Shouldn't error when getting the image a second time") |
|
|
|
|
assert.Equal(t, test.img, returned) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
assert.Equal(t, image1, *result1) |
|
|
|
|
|
|
|
|
|
// save the image a second time should not change the expiration time
|
|
|
|
|
ts := image1.ExpiresAt |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
assert.Equal(t, image1.ExpiresAt, ts) |
|
|
|
|
|
|
|
|
|
// create an image with a URL
|
|
|
|
|
image2 := models.Image{URL: "https://example.com/example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image2)) |
|
|
|
|
require.NotEqual(t, "", image2.Token) |
|
|
|
|
|
|
|
|
|
// image should not have expired
|
|
|
|
|
assert.False(t, image2.HasExpired()) |
|
|
|
|
assert.Equal(t, image2.ExpiresAt, image2.CreatedAt.Add(24*time.Hour)) |
|
|
|
|
|
|
|
|
|
// should return the image with a URL
|
|
|
|
|
result2, err := dbstore.GetImage(ctx, image2.Token) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Equal(t, image2, *result2) |
|
|
|
|
|
|
|
|
|
// expired image should not be returned
|
|
|
|
|
image1.ExpiresAt = time.Now().Add(-time.Second) |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
result1, err = dbstore.GetImage(ctx, image1.Token) |
|
|
|
|
assert.EqualError(t, err, "image not found") |
|
|
|
|
assert.Nil(t, result1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestIntegrationGetImages(t *testing.T) { |
|
|
|
|
if testing.Short() { |
|
|
|
|
t.Skip("skipping integration test") |
|
|
|
|
} |
|
|
|
|
mockTimeNow() |
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
|
|
|
|
defer cancel() |
|
|
|
|
|
|
|
|
|
// our database schema uses second precision for timestamps
|
|
|
|
|
store.TimeNow = func() time.Time { |
|
|
|
|
return time.Now().Truncate(time.Second) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctx := context.Background() |
|
|
|
|
_, dbstore := tests.SetupTestEnv(t, baseIntervalSeconds) |
|
|
|
|
|
|
|
|
|
// create an image foo.png
|
|
|
|
|
img1 := models.Image{Path: "foo.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &img1)) |
|
|
|
|
// create an image with a path on disk
|
|
|
|
|
image1 := models.Image{Path: "example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
|
|
|
|
|
// GetImages should return the first image
|
|
|
|
|
imgs, err := dbstore.GetImages(ctx, []string{img1.Token}) |
|
|
|
|
// should return the first image
|
|
|
|
|
images, mismatched, err := dbstore.GetImages(ctx, []string{image1.Token}) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Equal(t, []models.Image{img1}, imgs) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.Equal(t, []models.Image{image1}, images) |
|
|
|
|
|
|
|
|
|
// create another image bar.png
|
|
|
|
|
img2 := models.Image{Path: "bar.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &img2)) |
|
|
|
|
// create an image with a URL
|
|
|
|
|
image2 := models.Image{Path: "https://example.com/example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image2)) |
|
|
|
|
|
|
|
|
|
// GetImages should return both images
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, []string{img1.Token, img2.Token}) |
|
|
|
|
// should return both images
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{image1.Token, image2.Token}) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.ElementsMatch(t, []models.Image{img1, img2}, imgs) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.ElementsMatch(t, []models.Image{image1, image2}, images) |
|
|
|
|
|
|
|
|
|
// GetImages should return the first image
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, []string{img1.Token}) |
|
|
|
|
// should return the first image
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{image1.Token}) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Equal(t, []models.Image{img1}, imgs) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.Equal(t, []models.Image{image1}, images) |
|
|
|
|
|
|
|
|
|
// GetImages should return the second image
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, []string{img2.Token}) |
|
|
|
|
// should return the second image
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{image2.Token}) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Equal(t, []models.Image{img2}, imgs) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.Equal(t, []models.Image{image2}, images) |
|
|
|
|
|
|
|
|
|
// GetImages should return the first image and an error
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, []string{img1.Token, "unknown"}) |
|
|
|
|
// should return the first image and an error
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{image1.Token, "unknown"}) |
|
|
|
|
assert.EqualError(t, err, "image not found") |
|
|
|
|
assert.Equal(t, []models.Image{img1}, imgs) |
|
|
|
|
assert.Equal(t, []string{"unknown"}, mismatched) |
|
|
|
|
assert.Equal(t, []models.Image{image1}, images) |
|
|
|
|
|
|
|
|
|
// GetImages should return no images for no tokens
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, []string{}) |
|
|
|
|
// should return no images for no tokens
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{}) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Len(t, imgs, 0) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.Len(t, images, 0) |
|
|
|
|
|
|
|
|
|
// GetImages should return no images for nil tokens
|
|
|
|
|
imgs, err = dbstore.GetImages(ctx, nil) |
|
|
|
|
// should return no images for nil tokens
|
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, nil) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Len(t, imgs, 0) |
|
|
|
|
assert.Len(t, mismatched, 0) |
|
|
|
|
assert.Len(t, images, 0) |
|
|
|
|
|
|
|
|
|
// expired image should not be returned
|
|
|
|
|
image1.ExpiresAt = time.Now().Add(-time.Second) |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
images, mismatched, err = dbstore.GetImages(ctx, []string{image1.Token, image2.Token}) |
|
|
|
|
assert.EqualError(t, err, "image not found") |
|
|
|
|
assert.Equal(t, []string{image1.Token}, mismatched) |
|
|
|
|
assert.Equal(t, []models.Image{image2}, images) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestIntegrationDeleteExpiredImages(t *testing.T) { |
|
|
|
|
if testing.Short() { |
|
|
|
|
t.Skip("skipping integration test") |
|
|
|
|
} |
|
|
|
|
mockTimeNow() |
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) |
|
|
|
|
defer cancel() |
|
|
|
|
_, dbstore := tests.SetupTestEnv(t, baseIntervalSeconds) |
|
|
|
|
|
|
|
|
|
// Save two images.
|
|
|
|
|
imgs := []*models.Image{ |
|
|
|
|
createTestImg("", ""), |
|
|
|
|
createTestImg("", ""), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, img := range imgs { |
|
|
|
|
err := dbstore.SaveImage(ctx, img) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
// our database schema uses second precision for timestamps
|
|
|
|
|
store.TimeNow = func() time.Time { |
|
|
|
|
return time.Now().Truncate(time.Second) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Images are availabile
|
|
|
|
|
img, err := dbstore.GetImage(ctx, imgs[0].Token) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
require.NotNil(t, img) |
|
|
|
|
ctx := context.Background() |
|
|
|
|
_, dbstore := tests.SetupTestEnv(t, baseIntervalSeconds) |
|
|
|
|
|
|
|
|
|
img, err = dbstore.GetImage(ctx, imgs[1].Token) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
require.NotNil(t, img) |
|
|
|
|
// create two images
|
|
|
|
|
image1 := models.Image{Path: "example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
image2 := models.Image{URL: "https://example.com/example.png"} |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image2)) |
|
|
|
|
|
|
|
|
|
// Wait until timeout.
|
|
|
|
|
for i := 0; i < 120; i++ { |
|
|
|
|
store.TimeNow() |
|
|
|
|
} |
|
|
|
|
s := dbstore.SQLStore.NewSession(ctx) |
|
|
|
|
t.Cleanup(s.Close) |
|
|
|
|
|
|
|
|
|
// Call expired
|
|
|
|
|
err = dbstore.DeleteExpiredImages(ctx) |
|
|
|
|
// should return both images
|
|
|
|
|
var result1, result2 models.Image |
|
|
|
|
ok, err := s.Where("token = ?", image1.Token).Get(&result1) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.True(t, ok) |
|
|
|
|
ok, err = s.Where("token = ?", image2.Token).Get(&result2) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.True(t, ok) |
|
|
|
|
|
|
|
|
|
// All images are gone.
|
|
|
|
|
img, err = dbstore.GetImage(ctx, imgs[0].Token) |
|
|
|
|
require.Nil(t, img) |
|
|
|
|
require.Error(t, err) |
|
|
|
|
// should delete expired image
|
|
|
|
|
image1.ExpiresAt = time.Now().Add(-time.Second) |
|
|
|
|
require.NoError(t, dbstore.SaveImage(ctx, &image1)) |
|
|
|
|
n, err := dbstore.DeleteExpiredImages(ctx) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.Equal(t, int64(1), n) |
|
|
|
|
|
|
|
|
|
img, err = dbstore.GetImage(ctx, imgs[1].Token) |
|
|
|
|
require.Nil(t, img) |
|
|
|
|
require.Error(t, err) |
|
|
|
|
// should return just the second image
|
|
|
|
|
ok, err = s.Where("token = ?", image1.Token).Get(&result1) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.False(t, ok) |
|
|
|
|
ok, err = s.Where("token = ?", image2.Token).Get(&result2) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
assert.True(t, ok) |
|
|
|
|
} |
|
|
|
|