161 lines
5.9 KiB
Go
161 lines
5.9 KiB
Go
//go:build integration
|
|
|
|
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/shcizo/package-updater/internal/master/model"
|
|
"github.com/shcizo/package-updater/internal/protocol"
|
|
)
|
|
|
|
const sluskRepo = "gitea.shcizo.se/shcizo/slusk"
|
|
|
|
func versionsOf(t *testing.T, s *Store, repo string) []model.ImageVersion {
|
|
t.Helper()
|
|
got, err := s.RecentVersions(context.Background(), repo, 100)
|
|
require.NoError(t, err)
|
|
return got
|
|
}
|
|
|
|
func TestSetAvailable_RecordsVersion(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
_, svc := jobFixture(t, s, "a")
|
|
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: sluskRepo + ":1.5.0", Digest: "sha256:n1", Source: model.SourcePoll, At: t0}))
|
|
|
|
got, err := s.GetService(ctx, svc)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, sluskRepo+":1.5.0", got.AvailableRef)
|
|
assert.Equal(t, "sha256:n1", got.AvailableDigest)
|
|
assert.Equal(t, model.SourcePoll, got.AvailableSource)
|
|
vs := versionsOf(t, s, sluskRepo)
|
|
var found model.ImageVersion
|
|
for _, v := range vs {
|
|
if v.Digest == "sha256:n1" {
|
|
found = v
|
|
}
|
|
}
|
|
require.NotZero(t, found.ID)
|
|
assert.Equal(t, "1.5.0", found.Tag)
|
|
assert.Equal(t, model.SourcePoll, found.Source)
|
|
|
|
// Seeing the same version again keeps the first sighting.
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: sluskRepo + ":1.5.0", Digest: "sha256:n1", Source: model.SourceWebhook, At: t0.Add(time.Hour)}))
|
|
again, err := s.GetImageVersion(ctx, found.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, model.SourcePoll, again.Source)
|
|
assert.True(t, t0.Equal(again.FirstSeenAt))
|
|
assert.Len(t, versionsOf(t, s, sluskRepo), len(vs))
|
|
}
|
|
|
|
func TestSnapshotRecordsRunningVersions(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
id := newAgent(t, s, "node-2")
|
|
tagless := protocol.Service{Kind: protocol.KindSwarm, SwarmService: "g_g", Image: "gitea/gitea@sha256:87a6", Digest: "sha256:87a6", Status: "running"}
|
|
bare := protocol.Service{Kind: protocol.KindContainer, ContainerName: "pg", Image: "postgres", Digest: "sha256:pg1", Status: "running"}
|
|
nodigest := protocol.Service{Kind: protocol.KindContainer, ContainerName: "nd", Image: "nodigest:1", Status: "running"}
|
|
hello := protocol.Hello{Hostname: "node-2", SwarmManager: true, SwarmClusterID: "c1"}
|
|
svcs := []protocol.Service{slusk, tagless, bare, nodigest}
|
|
|
|
require.NoError(t, s.ApplySnapshot(ctx, id, hello, svcs, t0))
|
|
require.NoError(t, s.ApplySnapshot(ctx, id, hello, svcs, t0.Add(time.Hour)))
|
|
|
|
got := versionsOf(t, s, sluskRepo)
|
|
require.Len(t, got, 1)
|
|
assert.Equal(t, "1.4.2", got[0].Tag)
|
|
assert.Equal(t, "sha256:d1", got[0].Digest)
|
|
assert.Equal(t, model.SourceRunning, got[0].Source)
|
|
assert.True(t, t0.Equal(got[0].FirstSeenAt), "re-snapshot does not bump first_seen_at")
|
|
tl := versionsOf(t, s, "gitea/gitea")
|
|
require.Len(t, tl, 1)
|
|
assert.Equal(t, "", tl[0].Tag)
|
|
assert.Equal(t, "sha256:87a6", tl[0].Digest)
|
|
b := versionsOf(t, s, "postgres")
|
|
require.Len(t, b, 1)
|
|
assert.Equal(t, "", b[0].Tag, "a bare image is recorded without a tag, not as latest")
|
|
assert.Empty(t, versionsOf(t, s, "nodigest"))
|
|
}
|
|
|
|
func TestRecentVersions(t *testing.T) {
|
|
ctx := context.Background()
|
|
t.Run("order, limit and repo filter", func(t *testing.T) {
|
|
s := openTestStore(t)
|
|
_, svc := jobFixture(t, s, "a")
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: "other/repo:x", Digest: "sha256:ox", Source: model.SourcePoll, At: t0}))
|
|
// 12 versions of the service's repo, one per minute.
|
|
for i := 0; i < 12; i++ {
|
|
tag := "t" + string(rune('a'+i))
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: sluskRepo + ":" + tag, Digest: "sha256:" + tag, Source: model.SourcePoll, At: t0.Add(time.Duration(i+1) * time.Minute)}))
|
|
}
|
|
|
|
got, err := s.RecentVersions(ctx, sluskRepo, 10)
|
|
|
|
require.NoError(t, err)
|
|
require.Len(t, got, 10)
|
|
assert.Equal(t, "tl", got[0].Tag, "newest first")
|
|
assert.Equal(t, "tc", got[9].Tag)
|
|
for _, v := range got {
|
|
assert.Equal(t, sluskRepo, v.Repo)
|
|
}
|
|
})
|
|
|
|
t.Run("digest-less row is hidden once its tag has a digest", func(t *testing.T) {
|
|
s := openTestStore(t)
|
|
_, svc := jobFixture(t, s, "a")
|
|
add := func(tag, digest string, at time.Time) {
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: sluskRepo + ":" + tag, Digest: digest, Source: model.SourceWebhook, At: at}))
|
|
}
|
|
add("main", "", t0.Add(time.Minute))
|
|
add("solo", "", t0.Add(2*time.Minute))
|
|
require.Len(t, versionsOf(t, s, sluskRepo), 3, "running 1.4.2 plus two digest-less rows")
|
|
|
|
add("main", "sha256:m1", t0.Add(3*time.Minute))
|
|
|
|
var refs []string
|
|
for _, v := range versionsOf(t, s, sluskRepo) {
|
|
refs = append(refs, v.Ref())
|
|
}
|
|
assert.Equal(t, []string{sluskRepo + ":main@sha256:m1", sluskRepo + ":solo", sluskRepo + ":1.4.2@sha256:d1"}, refs)
|
|
})
|
|
}
|
|
|
|
func TestGetImageVersion_NotFound(t *testing.T) {
|
|
s := openTestStore(t)
|
|
|
|
_, err := s.GetImageVersion(context.Background(), 99999)
|
|
|
|
assert.ErrorIs(t, err, model.ErrNotFound)
|
|
}
|
|
|
|
func TestSetPollError(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
agent, svc := jobFixture(t, s, "a")
|
|
require.NoError(t, s.SetAvailable(ctx, svc, model.Available{Ref: sluskRepo + ":1.5.0", Digest: "sha256:n1", Source: model.SourcePoll, At: t0}))
|
|
|
|
require.NoError(t, s.SetPollError(ctx, []int64{svc}, "boom"))
|
|
require.NoError(t, s.SetPollError(ctx, nil, "ignored"))
|
|
got, err := s.GetService(ctx, svc)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "boom", got.LastPollError)
|
|
|
|
require.NoError(t, s.UpsertService(ctx, agent, "", slusk, t0.Add(time.Hour)))
|
|
got, err = s.GetService(ctx, svc)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "boom", got.LastPollError, "inventory writes do not touch the poll error")
|
|
assert.Equal(t, "sha256:n1", got.AvailableDigest, "nor the suggestion")
|
|
|
|
require.NoError(t, s.SetPollError(ctx, []int64{svc}, ""))
|
|
got, err = s.GetService(ctx, svc)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, got.LastPollError)
|
|
}
|