Files
notarius/internal/cli/state_surfaces_test.go

97 lines
3.7 KiB
Go

package cli
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
const stateSurfaceRunID = "run-1000000000-55555555555555555555555555555555"
func stateSurfaceRunIDGenerator(time.Time) (string, error) { return stateSurfaceRunID, nil }
func TestRunRejectsDebugDirectoryWithoutDebug(t *testing.T) {
var stdout, stderr bytes.Buffer
code := RunWithOptions([]string{"run", "example", "--input", "source.json", "--debug-dir", t.TempDir()}, &stdout, &stderr, Options{})
if code != 2 || !strings.Contains(stderr.String(), "--debug-dir requires --debug") {
t.Fatalf("code=%d stderr=%q", code, stderr.String())
}
}
func TestRunDebugAllocatesBeforePipelineResolution(t *testing.T) {
root := t.TempDir()
configPath := writeV3Config(t, "")
var stdout, stderr bytes.Buffer
code := RunWithOptions([]string{"run", "missing", "--config", configPath, "--input", "source.json", "--debug", "--debug-dir", root, "--chunk_cache", "bypass"}, &stdout, &stderr, Options{LookupEnv: emptyLookup, RunIDGenerator: stateSurfaceRunIDGenerator})
if code != 1 {
t.Fatalf("code=%d stderr=%q", code, stderr.String())
}
entries, err := os.ReadDir(root)
if err != nil || len(entries) != 1 {
t.Fatalf("debug bundles: %v, %v", entries, err)
}
if entries[0].Name() != stateSurfaceRunID {
t.Fatalf("debug bundle name = %q, want %q", entries[0].Name(), stateSurfaceRunID)
}
bundle := filepath.Join(root, stateSurfaceRunID)
for _, name := range []string{"summary", "trace"} {
if info, err := os.Stat(filepath.Join(bundle, name)); err != nil || !info.IsDir() {
t.Fatalf("%s: %v", name, err)
}
}
if !strings.Contains(stderr.String(), "debug=") {
t.Fatalf("stderr does not include bundle path: %q", stderr.String())
}
}
func TestRunWithoutDebugDoesNotAllocateDebugRoot(t *testing.T) {
root := filepath.Join(t.TempDir(), "not-created")
configPath := writeV3Config(t, "")
var stdout, stderr bytes.Buffer
lookup := func(name string) (string, bool) {
if name == "NOTARIUS_DEBUG_DIR" {
return root, true
}
return "", false
}
code := RunWithOptions([]string{"run", "missing", "--config", configPath, "--input", "source.json", "--chunk_cache", "bypass"}, &stdout, &stderr, Options{LookupEnv: lookup, RunIDGenerator: stateSurfaceRunIDGenerator})
if code != 1 {
t.Fatalf("code=%d stderr=%q", code, stderr.String())
}
if _, err := os.Stat(root); !os.IsNotExist(err) {
t.Fatalf("debug root exists or unexpected error: %v", err)
}
}
func TestConfigValidateUsesVersion3AndRemovedFieldsFail(t *testing.T) {
configPath := writeV3Config(t, "")
var stdout, stderr bytes.Buffer
if code := RunWithOptions([]string{"config", "validate", "--config", configPath}, &stdout, &stderr, Options{LookupEnv: emptyLookup}); code != 0 {
t.Fatalf("code=%d stderr=%q", code, stderr.String())
}
legacy := filepath.Join(t.TempDir(), "legacy.yml")
if err := os.WriteFile(legacy, []byte("version: 3\nworkspace:\n directory: /tmp/old\n"), 0o600); err != nil {
t.Fatal(err)
}
stdout.Reset()
stderr.Reset()
if code := RunWithOptions([]string{"config", "validate", "--config", legacy}, &stdout, &stderr, Options{LookupEnv: emptyLookup}); code != 1 || !strings.Contains(stderr.String(), "field workspace not found") {
t.Fatalf("code=%d stderr=%q", code, stderr.String())
}
}
func writeV3Config(t *testing.T, extra string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "config.yml")
data := "version: 3\noutput:\n directory: ./out\ncache:\n chunk_plans:\n mode: bypass\n checkpoints: {}\ndebug:\n directory: ./debug\n" + extra + "pipelines: {}\n"
if err := os.WriteFile(path, []byte(data), 0o600); err != nil {
t.Fatal(err)
}
return path
}
func emptyLookup(string) (string, bool) { return "", false }