2110c7dab4
CI / Test (rest) (pull_request) Successful in 39s
CI / Test (store) (pull_request) Successful in 40s
CI / Lint (pull_request) Failing after 11s
CI / Build (linux/amd64) (pull_request) Successful in 8s
CI / Build (linux/arm64) (pull_request) Successful in 7s
CI / Build (windows/amd64) (pull_request) Successful in 25s
CI / Test (server-http) (pull_request) Successful in 1m39s
e2e / Playwright vs docker-compose (pull_request) Successful in 1m16s
179 lines
5.3 KiB
Go
179 lines
5.3 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestListRunningJobActivity(t *testing.T) {
|
|
t.Parallel()
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
hostID := makeSchedHost(t, s)
|
|
started := time.Now().UTC().Add(-8 * time.Hour).Truncate(time.Second)
|
|
|
|
for _, id := range []string{"running-idle", "running-active", "finished"} {
|
|
if err := s.CreateJob(ctx, Job{ID: id, HostID: hostID, Kind: "backup", ActorKind: "user", CreatedAt: started}); err != nil {
|
|
t.Fatalf("create %s: %v", id, err)
|
|
}
|
|
if err := s.MarkJobStarted(ctx, id, started); err != nil {
|
|
t.Fatalf("start %s: %v", id, err)
|
|
}
|
|
}
|
|
activity := started.Add(7 * time.Hour)
|
|
if err := s.AppendJobLog(ctx, "running-active", 1, activity, "stdout", "still working"); err != nil {
|
|
t.Fatalf("append log: %v", err)
|
|
}
|
|
if err := s.MarkJobFinished(ctx, "finished", "succeeded", 0, nil, "", activity); err != nil {
|
|
t.Fatalf("finish: %v", err)
|
|
}
|
|
|
|
got, err := s.ListRunningJobActivity(ctx)
|
|
if err != nil {
|
|
t.Fatalf("list activity: %v", err)
|
|
}
|
|
if len(got) != 2 {
|
|
t.Fatalf("got %d rows, want 2: %+v", len(got), got)
|
|
}
|
|
byID := make(map[string]RunningJobActivity, len(got))
|
|
for _, row := range got {
|
|
byID[row.JobID] = row
|
|
}
|
|
if !byID["running-idle"].LastActivity.Equal(started) {
|
|
t.Errorf("idle last activity = %s, want %s", byID["running-idle"].LastActivity, started)
|
|
}
|
|
if !byID["running-active"].LastActivity.Equal(activity) {
|
|
t.Errorf("active last activity = %s, want %s", byID["running-active"].LastActivity, activity)
|
|
}
|
|
}
|
|
|
|
func TestLatestJobByKind(t *testing.T) {
|
|
t.Parallel()
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
hostID := makeSchedHost(t, s)
|
|
|
|
// No jobs yet → ErrNotFound.
|
|
if _, err := s.LatestJobByKind(ctx, hostID, "forget"); !errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("expected ErrNotFound on empty, got %v", err)
|
|
}
|
|
|
|
// Insert two finished jobs of kind=forget; the newer one should win.
|
|
older := time.Now().UTC().Add(-2 * time.Hour)
|
|
newer := time.Now().UTC().Add(-1 * time.Hour)
|
|
|
|
if err := s.CreateJob(ctx, Job{
|
|
ID: "j-old", HostID: hostID, Kind: "forget",
|
|
ActorKind: "system", CreatedAt: older,
|
|
}); err != nil {
|
|
t.Fatalf("create older: %v", err)
|
|
}
|
|
if err := s.MarkJobFinished(ctx, "j-old", "succeeded", 0, nil, "", older.Add(time.Minute)); err != nil {
|
|
t.Fatalf("finish older: %v", err)
|
|
}
|
|
if err := s.CreateJob(ctx, Job{
|
|
ID: "j-new", HostID: hostID, Kind: "forget",
|
|
ActorKind: "system", CreatedAt: newer,
|
|
}); err != nil {
|
|
t.Fatalf("create newer: %v", err)
|
|
}
|
|
if err := s.MarkJobFinished(ctx, "j-new", "failed", 1, nil, "boom", newer.Add(time.Minute)); err != nil {
|
|
t.Fatalf("finish newer: %v", err)
|
|
}
|
|
|
|
got, err := s.LatestJobByKind(ctx, hostID, "forget")
|
|
if err != nil {
|
|
t.Fatalf("LatestJobByKind: %v", err)
|
|
}
|
|
if got.ID != "j-new" {
|
|
t.Errorf("want j-new, got %q", got.ID)
|
|
}
|
|
|
|
// An in-flight running job must be returned — long-prune-suppresses-tick
|
|
// scenario: if a prune runs >60s the next tick must not re-fire it.
|
|
runningAt := time.Now().UTC()
|
|
if err := s.CreateJob(ctx, Job{
|
|
ID: "j-running", HostID: hostID, Kind: "forget",
|
|
ActorKind: "system", CreatedAt: runningAt,
|
|
}); err != nil {
|
|
t.Fatalf("create running: %v", err)
|
|
}
|
|
if err := s.MarkJobStarted(ctx, "j-running", runningAt); err != nil {
|
|
t.Fatalf("mark started: %v", err)
|
|
}
|
|
got2, err := s.LatestJobByKind(ctx, hostID, "forget")
|
|
if err != nil {
|
|
t.Fatalf("LatestJobByKind 2: %v", err)
|
|
}
|
|
if got2.ID != "j-running" {
|
|
t.Errorf("in-flight running job must be returned; want j-running, got %q", got2.ID)
|
|
}
|
|
|
|
// A queued (not-yet-started) job is also returned (it is newer than
|
|
// j-running because CreatedAt is later).
|
|
queuedAt := runningAt.Add(time.Millisecond)
|
|
if err := s.CreateJob(ctx, Job{
|
|
ID: "j-queued", HostID: hostID, Kind: "forget",
|
|
ActorKind: "system", CreatedAt: queuedAt,
|
|
}); err != nil {
|
|
t.Fatalf("create queued: %v", err)
|
|
}
|
|
got3, err := s.LatestJobByKind(ctx, hostID, "forget")
|
|
if err != nil {
|
|
t.Fatalf("LatestJobByKind 3: %v", err)
|
|
}
|
|
if got3.ID != "j-queued" {
|
|
t.Errorf("queued job must be returned as newest; want j-queued, got %q", got3.ID)
|
|
}
|
|
|
|
// Different kind → ErrNotFound.
|
|
if _, err := s.LatestJobByKind(ctx, hostID, "prune"); !errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("expected ErrNotFound for prune, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestListAllMaintenance(t *testing.T) {
|
|
t.Parallel()
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
// Empty case.
|
|
rows, err := s.ListAllMaintenance(ctx)
|
|
if err != nil {
|
|
t.Fatalf("empty list: %v", err)
|
|
}
|
|
if len(rows) != 0 {
|
|
t.Errorf("want empty, got %+v", rows)
|
|
}
|
|
|
|
// Seed two hosts with maintenance rows.
|
|
h1 := "01HMAINTHOST00000000000A1"
|
|
h2 := "01HMAINTHOST00000000000A2"
|
|
for i, id := range []string{h1, h2} {
|
|
if err := s.CreateHost(ctx, Host{
|
|
ID: id, Name: "maint-host-" + string(rune('a'+i)),
|
|
OS: "linux", Arch: "amd64",
|
|
AgentVersion: "dev", ResticVersion: "0.16.0", ProtocolVersion: 1,
|
|
EnrolledAt: time.Now().UTC(),
|
|
}, "th-"+id, ""); err != nil {
|
|
t.Fatalf("create host %s: %v", id, err)
|
|
}
|
|
}
|
|
if err := s.CreateDefaultRepoMaintenance(ctx, h1); err != nil {
|
|
t.Fatalf("seed h1: %v", err)
|
|
}
|
|
if err := s.CreateDefaultRepoMaintenance(ctx, h2); err != nil {
|
|
t.Fatalf("seed h2: %v", err)
|
|
}
|
|
|
|
rows, err = s.ListAllMaintenance(ctx)
|
|
if err != nil {
|
|
t.Fatalf("list: %v", err)
|
|
}
|
|
if len(rows) != 2 {
|
|
t.Errorf("want 2 rows, got %d", len(rows))
|
|
}
|
|
}
|