package cli import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sneak.berlin/go/mfer/mfer" ) // buildTestManifest creates a manifest from in-memory files and returns its bytes. func buildTestManifest(t *testing.T, files map[string][]byte) []byte { t.Helper() sourceFs := afero.NewMemMapFs() for path, content := range files { require.NoError(t, sourceFs.MkdirAll("/", 0o755)) require.NoError(t, afero.WriteFile(sourceFs, "/"+path, content, 0o644)) } opts := &mfer.ScannerOptions{Fs: sourceFs} s := mfer.NewScannerWithOptions(opts) require.NoError(t, s.EnumerateFS(sourceFs, "/", nil)) var buf bytes.Buffer require.NoError(t, s.ToManifest(context.Background(), &buf, nil)) return buf.Bytes() } func TestExportManifestOperation(t *testing.T) { testFiles := map[string][]byte{ "hello.txt": []byte("Hello, World!"), "sub/file.txt": []byte("nested content"), } manifestData := buildTestManifest(t, testFiles) // Write manifest to memfs fs := afero.NewMemMapFs() require.NoError(t, afero.WriteFile(fs, "/test.mf", manifestData, 0o644)) var stdout, stderr bytes.Buffer exitCode := RunWithOptions(&RunOptions{ Appname: "mfer", Args: []string{"mfer", "export", "/test.mf"}, Stdin: &bytes.Buffer{}, Stdout: &stdout, Stderr: &stderr, Fs: fs, }) require.Equal(t, 0, exitCode, "stderr: %s", stderr.String()) var entries []ExportEntry require.NoError(t, json.Unmarshal(stdout.Bytes(), &entries)) assert.Len(t, entries, 2) // Verify entries have expected fields pathSet := make(map[string]bool) for _, e := range entries { pathSet[e.Path] = true assert.NotEmpty(t, e.Hashes, "entry %s should have hashes", e.Path) assert.Greater(t, e.Size, int64(0), "entry %s should have positive size", e.Path) } assert.True(t, pathSet["hello.txt"]) assert.True(t, pathSet["sub/file.txt"]) } func TestExportFromHTTPURL(t *testing.T) { testFiles := map[string][]byte{ "a.txt": []byte("aaa"), } manifestData := buildTestManifest(t, testFiles) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/octet-stream") _, _ = w.Write(manifestData) })) defer server.Close() var stdout, stderr bytes.Buffer exitCode := RunWithOptions(&RunOptions{ Appname: "mfer", Args: []string{"mfer", "export", server.URL + "/index.mf"}, Stdin: &bytes.Buffer{}, Stdout: &stdout, Stderr: &stderr, Fs: afero.NewMemMapFs(), }) require.Equal(t, 0, exitCode, "stderr: %s", stderr.String()) var entries []ExportEntry require.NoError(t, json.Unmarshal(stdout.Bytes(), &entries)) assert.Len(t, entries, 1) assert.Equal(t, "a.txt", entries[0].Path) } func TestListFromHTTPURL(t *testing.T) { testFiles := map[string][]byte{ "one.txt": []byte("1"), "two.txt": []byte("22"), } manifestData := buildTestManifest(t, testFiles) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(manifestData) })) defer server.Close() var stdout, stderr bytes.Buffer exitCode := RunWithOptions(&RunOptions{ Appname: "mfer", Args: []string{"mfer", "list", server.URL + "/index.mf"}, Stdin: &bytes.Buffer{}, Stdout: &stdout, Stderr: &stderr, Fs: afero.NewMemMapFs(), }) require.Equal(t, 0, exitCode, "stderr: %s", stderr.String()) output := stdout.String() assert.Contains(t, output, "one.txt") assert.Contains(t, output, "two.txt") } func TestIsHTTPURL(t *testing.T) { assert.True(t, isHTTPURL("http://example.com/manifest.mf")) assert.True(t, isHTTPURL("https://example.com/manifest.mf")) assert.False(t, isHTTPURL("/local/path.mf")) assert.False(t, isHTTPURL("relative/path.mf")) assert.False(t, isHTTPURL("ftp://example.com/file")) }