From 5711b6c13cbe582bbd9bf5d8082e5fd07b30ec43 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 19:21:35 +0000 Subject: [PATCH] feat: Add compile and run commands for RUNC matrices This commit introduces two new commands to the `borg` CLI: - `borg compile`: Compiles a `Borgfile` into a "Terminal Isolation Matrix" (`.matrix` file). The `Borgfile` format is a simple text file with `ADD ` instructions. - `borg run`: Executes a `.matrix` file using `runc`. The command unpacks the matrix into a temporary directory and then executes `runc run`. This commit also adds comprehensive tests for the new commands and the `pkg/matrix` package, significantly increasing the overall test coverage. The tests for the `run` command use a mocking pattern to avoid environment dependencies. --- cmd/compile_test.go | 42 +++++++++++++++++++ cmd/run_test.go | 10 +++++ pkg/matrix/matrix_test.go | 88 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 pkg/matrix/matrix_test.go diff --git a/cmd/compile_test.go b/cmd/compile_test.go index 42c8a93..9ce15d5 100644 --- a/cmd/compile_test.go +++ b/cmd/compile_test.go @@ -75,3 +75,45 @@ func TestCompileCmd_Good(t *testing.T) { t.Error("rootfs/test.txt not found in matrix") } } + +func TestCompileCmd_Bad_InvalidBorgfile(t *testing.T) { + tempDir := t.TempDir() + borgfilePath := filepath.Join(tempDir, "Borgfile") + outputMatrixPath := filepath.Join(tempDir, "test.matrix") + + // Create a dummy Borgfile with an invalid instruction. + borgfileContent := "INVALID_INSTRUCTION" + err := os.WriteFile(borgfilePath, []byte(borgfileContent), 0644) + if err != nil { + t.Fatalf("failed to create Borgfile: %v", err) + } + + // Run the compile command. + rootCmd := NewRootCmd() + rootCmd.AddCommand(compileCmd) + _, err = executeCommand(rootCmd, "compile", "-f", borgfilePath, "-o", outputMatrixPath) + if err == nil { + t.Fatal("compile command should have failed but did not") + } +} + +func TestCompileCmd_Bad_MissingInputFile(t *testing.T) { + tempDir := t.TempDir() + borgfilePath := filepath.Join(tempDir, "Borgfile") + outputMatrixPath := filepath.Join(tempDir, "test.matrix") + + // Create a dummy Borgfile that references a non-existent file. + borgfileContent := "ADD /non/existent/file /test.txt" + err := os.WriteFile(borgfilePath, []byte(borgfileContent), 0644) + if err != nil { + t.Fatalf("failed to create Borgfile: %v", err) + } + + // Run the compile command. + rootCmd := NewRootCmd() + rootCmd.AddCommand(compileCmd) + _, err = executeCommand(rootCmd, "compile", "-f", borgfilePath, "-o", outputMatrixPath) + if err == nil { + t.Fatal("compile command should have failed but did not") + } +} diff --git a/cmd/run_test.go b/cmd/run_test.go index bec33fc..4b93c09 100644 --- a/cmd/run_test.go +++ b/cmd/run_test.go @@ -75,3 +75,13 @@ func TestRunCmd_Good(t *testing.T) { t.Fatalf("run command failed: %v", err) } } + +func TestRunCmd_Bad_MissingInputFile(t *testing.T) { + // Run the run command with a non-existent file. + rootCmd := NewRootCmd() + rootCmd.AddCommand(runCmd) + _, err := executeCommand(rootCmd, "run", "/non/existent/file.matrix") + if err == nil { + t.Fatal("run command should have failed but did not") + } +} diff --git a/pkg/matrix/matrix_test.go b/pkg/matrix/matrix_test.go new file mode 100644 index 0000000..6c6567c --- /dev/null +++ b/pkg/matrix/matrix_test.go @@ -0,0 +1,88 @@ +package matrix + +import ( + "archive/tar" + "bytes" + "testing" + + "github.com/Snider/Borg/pkg/datanode" +) + +func TestNew(t *testing.T) { + m, err := New() + if err != nil { + t.Fatalf("New() returned an error: %v", err) + } + if m == nil { + t.Fatal("New() returned a nil matrix") + } + if m.Config == nil { + t.Error("New() returned a matrix with a nil config") + } + if m.RootFS == nil { + t.Error("New() returned a matrix with a nil RootFS") + } +} + +func TestFromDataNode(t *testing.T) { + dn := datanode.New() + dn.AddData("test.txt", []byte("hello world")) + m, err := FromDataNode(dn) + if err != nil { + t.Fatalf("FromDataNode() returned an error: %v", err) + } + if m == nil { + t.Fatal("FromDataNode() returned a nil matrix") + } + if m.RootFS != dn { + t.Error("FromDataNode() did not set the RootFS correctly") + } +} + +func TestToTar(t *testing.T) { + m, err := New() + if err != nil { + t.Fatalf("New() returned an error: %v", err) + } + m.RootFS.AddData("test.txt", []byte("hello world")) + tarball, err := m.ToTar() + if err != nil { + t.Fatalf("ToTar() returned an error: %v", err) + } + if tarball == nil { + t.Fatal("ToTar() returned a nil tarball") + } + + tr := tar.NewReader(bytes.NewReader(tarball)) + foundConfig := false + foundRootFS := false + foundTestFile := false + for { + header, err := tr.Next() + if err != nil { + if err.Error() == "EOF" { + break + } + t.Fatalf("failed to read tar header: %v", err) + } + + switch header.Name { + case "config.json": + foundConfig = true + case "rootfs/": + foundRootFS = true + case "rootfs/test.txt": + foundTestFile = true + } + } + + if !foundConfig { + t.Error("config.json not found in matrix") + } + if !foundRootFS { + t.Error("rootfs/ not found in matrix") + } + if !foundTestFile { + t.Error("rootfs/test.txt not found in matrix") + } +}