merge master into strict metis gate

# Conflicts:
#	Jenkinsfile
#	cmd/metis/remote_cmd.go
#	pkg/image/rootfs.go
#	pkg/image/rootfs_test.go
#	pkg/service/app.go
#	pkg/service/cluster.go
#	pkg/service/cluster_test.go
#	pkg/service/remote.go
#	pkg/service/remote_progress_test.go
#	pkg/service/server.go
#	pkg/service/server_test.go
#	pkg/service/settings_test.go
#	scripts/publish_test_metrics.py
This commit is contained in:
codex 2026-04-20 21:54:55 -03:00
commit 651a11f5a5
2 changed files with 67 additions and 1 deletions

View File

@ -1,6 +1,12 @@
package main package main
import "testing" import (
"bytes"
"io"
"os"
"strings"
"testing"
)
func TestOrasPushInvocationUsesRelativeWorkspacePaths(t *testing.T) { func TestOrasPushInvocationUsesRelativeWorkspacePaths(t *testing.T) {
dir, args, err := orasPushInvocation("registry.bstein.dev/metis/titan-13:20260331t235724z", "/workspace/build/titan-13.img.xz", "/workspace/build/metadata.json") dir, args, err := orasPushInvocation("registry.bstein.dev/metis/titan-13:20260331t235724z", "/workspace/build/titan-13.img.xz", "/workspace/build/metadata.json")
@ -32,3 +38,36 @@ func TestHumanHostPathMapsMountedTmpBackToHostTmp(t *testing.T) {
t.Fatalf("expected /tmp/metis-flash-test, got %q", got) t.Fatalf("expected /tmp/metis-flash-test, got %q", got)
} }
} }
func TestNewProgressEmitterWritesStructuredMarker(t *testing.T) {
origStdout := os.Stdout
reader, writer, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: %v", err)
}
os.Stdout = writer
defer func() {
os.Stdout = origStdout
}()
emitter := newProgressEmitter("flash", 92, 98, "Writing the latest image for titan-12", true)
emitter(1024, 2048)
if err := writer.Close(); err != nil {
t.Fatalf("close writer: %v", err)
}
var output bytes.Buffer
if _, err := io.Copy(&output, reader); err != nil {
t.Fatalf("read progress output: %v", err)
}
got := output.String()
if !strings.Contains(got, "METIS_PROGRESS ") {
t.Fatalf("expected structured progress prefix, got %q", got)
}
if !strings.Contains(got, `"stage":"flash"`) {
t.Fatalf("expected flash stage marker, got %q", got)
}
if !strings.Contains(got, `"written_bytes":1024`) || !strings.Contains(got, `"total_bytes":2048`) {
t.Fatalf("expected byte counters in progress marker, got %q", got)
}
}

View File

@ -0,0 +1,27 @@
package service
import (
"errors"
"strings"
"testing"
)
func TestReserveJobRejectsDuplicateActiveNodeJobs(t *testing.T) {
app := newTestApp(t)
active := app.newJob("replace", "titan-15", "titan-22", "/dev/sdk")
_, err := app.reserveJob("build", "titan-15", "", "")
if err == nil {
t.Fatal("expected duplicate job reservation to fail")
}
var activeErr *activeNodeJobError
if !errors.As(err, &activeErr) {
t.Fatalf("expected activeNodeJobError, got %T", err)
}
if activeErr.JobID != active.ID || activeErr.Kind != "replace" {
t.Fatalf("unexpected active job conflict: %#v", activeErr)
}
if !strings.Contains(err.Error(), active.ID) {
t.Fatalf("expected error to mention active job id %s, got %q", active.ID, err.Error())
}
}