mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-25 01:35:18 -06:00
0c8463e09b
This commit does a few things: * Extend the low-level file loader and callers to ensure ModuleFile objects have a URL field. This means we can tell if two ModuleFile objects refer to the same source file. Previously we had to keep track of bundle names to do this. This commit does not touch the bundle activation logic which does this already--we can revisit that in the future. * Update the bundle writer to use the URL field by default. This allows us to write merged bundles correctly. * Add a merge function that will be used by the new build command to combine multiple bundles. * Add a helper function for checking if roots contain a path. In the process refactor the overlap helper to use the same logic. Also add a helper function to ensure roots exist in the bundle manifest. * Add a deepcopy function for bundles. This is useful if mutating bundles and there is a need to revert. * Format bundle contents on write by default. Callers of the old Write function will not be affected (it disables formatting.) * Format the overlap error to quote roots in case they are empty. Signed-off-by: Torin Sandall <torinsandall@gmail.com>
179 lines
3.7 KiB
Go
179 lines
3.7 KiB
Go
package bundle
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/open-policy-agent/opa/internal/file/archive"
|
|
|
|
"github.com/open-policy-agent/opa/util/test"
|
|
)
|
|
|
|
const testReadLimit = (1024 * 1024) + 1
|
|
|
|
var archiveFiles = map[string]string{
|
|
"/a.json": "a",
|
|
"/a/b.json": "b",
|
|
"/a/b/c.json": "c",
|
|
"/some.txt": "text",
|
|
"/policy.rego": "package foo\n p = 1",
|
|
"/deeper/dir/path/than/others/foo": "bar",
|
|
}
|
|
|
|
func TestTarballLoader(t *testing.T) {
|
|
|
|
files := map[string]string{
|
|
"/archive.tar.gz": "",
|
|
}
|
|
|
|
test.WithTempFS(files, func(rootDir string) {
|
|
tarballFile := filepath.Join(rootDir, "archive.tar.gz")
|
|
f, err := os.Create(tarballFile)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
}
|
|
|
|
var gzFiles [][2]string
|
|
for name, content := range archiveFiles {
|
|
gzFiles = append(gzFiles, [2]string{name, content})
|
|
}
|
|
|
|
_, err = f.Write(archive.MustWriteTarGz(gzFiles).Bytes())
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
}
|
|
f.Close()
|
|
|
|
f, err = os.Open(tarballFile)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
}
|
|
|
|
loader := NewTarballLoaderWithBaseURL(f, tarballFile)
|
|
defer f.Close()
|
|
|
|
testLoader(t, loader, tarballFile, archiveFiles)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func TestDirectoryLoader(t *testing.T) {
|
|
test.WithTempFS(archiveFiles, func(rootDir string) {
|
|
loader := NewDirectoryLoader(rootDir)
|
|
|
|
testLoader(t, loader, rootDir, archiveFiles)
|
|
})
|
|
}
|
|
|
|
func testLoader(t *testing.T, loader DirectoryLoader, baseURL string, expectedFiles map[string]string) {
|
|
t.Helper()
|
|
|
|
fileCount := 0
|
|
for {
|
|
f, err := loader.NextFile()
|
|
if err != nil && err != io.EOF {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
} else if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
expPath := strings.TrimPrefix(f.URL(), baseURL)
|
|
if f.Path() != expPath {
|
|
t.Fatalf("Expected path to be %v but got %v", expPath, f.Path())
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
n, err := f.Read(&buf, testReadLimit)
|
|
f.Close() // always close, even on error
|
|
if err != nil && err != io.EOF {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
} else if err == nil && n >= testReadLimit {
|
|
t.Fatalf("Attempted to read too much data")
|
|
}
|
|
|
|
expectedContent, found := expectedFiles[f.Path()]
|
|
if !found {
|
|
t.Fatalf("Found unexpected file %s", f.Path())
|
|
}
|
|
if expectedContent != buf.String() {
|
|
t.Fatalf("Content mismatch for file %s\n\nExpected:\n%s\n\nActual:\n%s\n\n",
|
|
f.Path(), expectedContent, buf.String())
|
|
}
|
|
|
|
fileCount++
|
|
}
|
|
|
|
if fileCount != len(expectedFiles) {
|
|
t.Fatalf("Expected to read %d files, read %d", len(expectedFiles), fileCount)
|
|
}
|
|
}
|
|
|
|
func TestNewDirectoryLoaderNormalizedRoot(t *testing.T) {
|
|
cases := []struct {
|
|
note string
|
|
root string
|
|
expected string
|
|
}{
|
|
{
|
|
note: "abs",
|
|
root: "/a/b/c",
|
|
expected: "/a/b/c",
|
|
},
|
|
{
|
|
note: "trailing slash",
|
|
root: "/a/b/c/",
|
|
expected: "/a/b/c/",
|
|
},
|
|
{
|
|
note: "empty",
|
|
root: "",
|
|
expected: "",
|
|
},
|
|
{
|
|
note: "single abs",
|
|
root: "/",
|
|
expected: "/",
|
|
},
|
|
{
|
|
note: "single relative",
|
|
root: "foo",
|
|
expected: "foo",
|
|
},
|
|
{
|
|
note: "single relative dot",
|
|
root: ".",
|
|
expected: ".",
|
|
},
|
|
{
|
|
note: "single relative dot slash",
|
|
root: "./",
|
|
expected: ".",
|
|
},
|
|
{
|
|
note: "relative leading dot slash",
|
|
root: "./a/b/c",
|
|
expected: "a/b/c",
|
|
},
|
|
{
|
|
note: "relative",
|
|
root: "a/b/c",
|
|
expected: "a/b/c",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.note, func(t *testing.T) {
|
|
l := NewDirectoryLoader(tc.root)
|
|
actual := l.(*dirLoader).root
|
|
if actual != tc.expected {
|
|
t.Fatalf("Expected root %s got %s", tc.expected, actual)
|
|
}
|
|
})
|
|
}
|
|
}
|