159 lines
4.4 KiB
Go
159 lines
4.4 KiB
Go
package debugbundle
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/core/artifacts"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
|
)
|
|
|
|
func TestAllocateCreatesRestrictiveSummaryAndTrace(t *testing.T) {
|
|
parent := t.TempDir()
|
|
fixed := time.Unix(0, 42).UTC()
|
|
previous := utcNow
|
|
utcNow = func() time.Time { return fixed }
|
|
defer func() { utcNow = previous }()
|
|
bundle, err := Allocate(parent)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bundle.RunID() != "run-42" || bundle.SummaryRoot() != filepath.Join(bundle.Path(), "summary") || bundle.TraceRoot() != filepath.Join(bundle.Path(), "trace") {
|
|
t.Fatalf("bundle=%#v", bundle)
|
|
}
|
|
for _, path := range []string{bundle.Path(), bundle.SummaryRoot(), bundle.TraceRoot()} {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode().Perm() != 0o700 {
|
|
t.Fatalf("%s mode=%#o", path, info.Mode().Perm())
|
|
}
|
|
}
|
|
if err := bundle.Summary().WriteError("failed"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
info, err := os.Stat(filepath.Join(bundle.SummaryRoot(), ArtifactErrorLog))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode().Perm() != 0o600 {
|
|
t.Fatalf("file mode=%#o", info.Mode().Perm())
|
|
}
|
|
}
|
|
func TestAllocateRetriesAndDoesNotDeleteBundle(t *testing.T) {
|
|
parent := t.TempDir()
|
|
fixed := time.Unix(0, 9).UTC()
|
|
previous := utcNow
|
|
defer func() { utcNow = previous }()
|
|
calls := 0
|
|
utcNow = func() time.Time { calls++; return fixed.Add(time.Duration(calls-1) * time.Nanosecond) }
|
|
if err := os.Mkdir(filepath.Join(parent, "run-9"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bundle, err := Allocate(parent)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bundle.RunID() != "run-10" {
|
|
t.Fatalf("run id=%q", bundle.RunID())
|
|
}
|
|
if _, err := os.Stat(bundle.Path()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestAllocateReturnsErrorAfterRunIDCollisionsAreExhausted(t *testing.T) {
|
|
parent := t.TempDir()
|
|
fixed := time.Unix(0, 99).UTC()
|
|
if err := os.Mkdir(filepath.Join(parent, "run-99"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
previous := utcNow
|
|
utcNow = func() time.Time { return fixed }
|
|
defer func() { utcNow = previous }()
|
|
|
|
if _, err := Allocate(parent); err == nil {
|
|
t.Fatal("Allocate succeeded after exhausting run ID collisions")
|
|
}
|
|
}
|
|
|
|
func TestSummaryWriterWritesEverySummaryArtifact(t *testing.T) {
|
|
bundle, err := Allocate(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
summary := bundle.Summary()
|
|
if err := summary.WriteInvocation(Invocation{Operation: "run"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteRedactedEffectiveConfig(testRedactedSummaryPayload{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteResolvedPipeline(map[string]any{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteResolvedReferences(nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteCheckpointEvents(nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteRunManifest(artifacts.RunManifest{RunID: bundle.RunID()}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteChunkPlan(artifacts.ChunkPlanSummary{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteRunReport(RunReport{RunID: bundle.RunID(), PipelineID: "test"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteWarnings([]contracts.Warning{{ReasonCode: "test"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := summary.WriteError("failed"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for _, name := range []string{
|
|
ArtifactInvocationMetadata,
|
|
ArtifactEffectiveConfig,
|
|
ArtifactResolvedPipeline,
|
|
ArtifactResolvedReferences,
|
|
ArtifactCheckpointEvents,
|
|
ArtifactRunManifest,
|
|
ArtifactChunkPlan,
|
|
ArtifactRunReport,
|
|
ArtifactWarnings,
|
|
ArtifactErrorLog,
|
|
} {
|
|
info, err := os.Stat(filepath.Join(bundle.SummaryRoot(), name))
|
|
if err != nil {
|
|
t.Fatalf("summary artifact %q: %v", name, err)
|
|
}
|
|
if info.Mode().Perm() != 0o600 {
|
|
t.Fatalf("summary artifact %q mode=%#o", name, info.Mode().Perm())
|
|
}
|
|
}
|
|
}
|
|
func TestSummaryWriterConfinesArtifacts(t *testing.T) {
|
|
bundle, err := Allocate(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := bundle.Summary().WriteJSON("../outside.json", map[string]any{}); err == nil {
|
|
t.Fatal("accepted traversal")
|
|
}
|
|
if err := bundle.Summary().WriteBytes(`trace\\x`, []byte("x")); err == nil {
|
|
t.Fatal("accepted backslash")
|
|
}
|
|
}
|
|
|
|
type testRedactedSummaryPayload struct{}
|
|
|
|
func (testRedactedSummaryPayload) RedactedSummaryPayload() any {
|
|
return map[string]any{"redacted": true}
|
|
}
|