Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

services/luci/internal/podman/storage_test.go

Raw
package podman

import (
	"context"
	"fmt"
	"io"
	"strings"
	"testing"
	"time"
)

type storageExecutor struct {
	calls    [][]string
	response func([]string) (string, error)
}

func (e *storageExecutor) Run(_ context.Context, args []string, stdout, _ io.Writer) error {
	e.calls = append(e.calls, append([]string(nil), args...))
	output, err := e.response(args)
	_, _ = io.WriteString(stdout, output)
	return err
}

func TestStorageInfoUsesEngineGraphroot(t *testing.T) {
	executor := &storageExecutor{response: func(args []string) (string, error) {
		if strings.Join(args, " ") != "info --format json" {
			return "", fmt.Errorf("unexpected %v", args)
		}
		return `{"store":{"graphRootAllocated":100,"graphRootUsed":40}}`, nil
	}}
	info, err := StorageInfoFor(context.Background(), executor)
	if err != nil || info.Free() != 60 {
		t.Fatalf("info=%#v err=%v", info, err)
	}
}

func TestPruneLuciBuildCacheOnlyRemovesOldDanglingUnreferencedImages(t *testing.T) {
	images := `[{
		"Id":"old","Size":70,"Created":1,"Containers":0,"Names":["<none>:<none>"],"Labels":{"io.luci.build":"cache-v1"}
	},{
		"Id":"active","Size":70,"Created":1,"Containers":1,"Names":["<none>:<none>"],"Labels":{"io.luci.build":"cache-v1"}
	},{
		"Id":"tagged","Size":70,"Created":1,"Containers":0,"Names":["luci-build-current"],"Labels":{"io.luci.build":"cache-v1"}
	},{
		"Id":"foreign","Size":70,"Created":1,"Containers":0,"Names":["<none>:<none>"],"Labels":{"other":"value"}
	}]`
	executor := &storageExecutor{response: func(args []string) (string, error) {
		if args[0] == "image" && args[1] == "ls" {
			return images, nil
		}
		if args[0] == "image" && args[1] == "rm" {
			if len(args) != 3 || args[2] != "old" || contains(args, "--force") {
				return "", fmt.Errorf("unsafe remove %v", args)
			}
			return "old", nil
		}
		return "", fmt.Errorf("unexpected %v", args)
	}}
	report, err := PruneLuciBuildCache(context.Background(), executor, 80, time.Hour, map[string]bool{"active": true}, time.Unix(7200, 0))
	if err != nil || len(report.Removed) != 1 || report.Removed[0] != "old" || report.Bytes != 0 {
		t.Fatalf("report=%#v err=%v", report, err)
	}
	for _, call := range executor.calls {
		if len(call) > 1 && call[0] == "image" && call[1] == "rm" && call[2] != "old" {
			t.Fatalf("removed protected image: %v", call)
		}
	}
}

func TestPruneFailsClosedWhenSafeCandidatesCannotMeetBudget(t *testing.T) {
	executor := &storageExecutor{response: func(args []string) (string, error) {
		if args[0] == "image" && args[1] == "ls" {
			return `[{"Id":"active","Size":101,"Created":1,"Containers":0,"Names":["<none>:<none>"],"Labels":{"io.luci.build":"cache-v1"}}]`, nil
		}
		return "", fmt.Errorf("unexpected mutation %v", args)
	}}
	_, err := PruneLuciBuildCache(context.Background(), executor, 100, time.Hour, map[string]bool{"active": true}, time.Unix(2, 0))
	if err == nil || !strings.Contains(err.Error(), "above budget") {
		t.Fatalf("err=%v", err)
	}
}