check / check (push) Waiting to run
A CLI run under runMu points the process-global logger at its own buffers, so a line another test logged outside runMu could land in that run's output. TestCheckQuietShowsFailedFiles caught one: a "loaded manifest" line in the stderr of a passing check -q run. The test helpers that scan or load a manifest now hold runMu themselves, and so do the remaining direct loads and scans, the recordEntry call and the retrying download. Two dotfile tests use manifestPaths instead of loading the manifest themselves. Judgement call: a downloadFile call that gets its answer on the first request does not log, so those calls are left as they are. Model: opus-5-5
162 lines
4.0 KiB
Go
162 lines
4.0 KiB
Go
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"
|
|
)
|
|
|
|
const testCmdExport = "export"
|
|
|
|
// buildTestManifest creates a manifest from in-memory files and returns its bytes.
|
|
func buildTestManifest(t *testing.T, files map[string][]byte) []byte {
|
|
t.Helper()
|
|
|
|
// The scan logs to the process-global logger, so serialize with the
|
|
// CLI runs.
|
|
runMu.Lock()
|
|
defer runMu.Unlock()
|
|
|
|
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) {
|
|
t.Parallel()
|
|
|
|
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 := runCLI(&RunOptions{
|
|
Appname: testApp,
|
|
Args: []string{testApp, testCmdExport, "/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.Positive(t, e.Size, "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) {
|
|
t.Parallel()
|
|
|
|
testFiles := map[string][]byte{
|
|
"a.txt": []byte("aaa"),
|
|
}
|
|
manifestData := buildTestManifest(t, testFiles)
|
|
|
|
server := httptest.NewServer(
|
|
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
_, _ = w.Write(manifestData)
|
|
}))
|
|
defer server.Close()
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
|
|
exitCode := runCLI(&RunOptions{
|
|
Appname: testApp,
|
|
Args: []string{testApp, testCmdExport, 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) {
|
|
t.Parallel()
|
|
|
|
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, _ *http.Request) {
|
|
_, _ = w.Write(manifestData)
|
|
}))
|
|
defer server.Close()
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
|
|
exitCode := runCLI(&RunOptions{
|
|
Appname: testApp,
|
|
Args: []string{testApp, cmdList, 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) {
|
|
t.Parallel()
|
|
|
|
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"))
|
|
}
|