Stop recursive symlink expansion and honor cancellation
This commit is contained in:
@@ -2,10 +2,12 @@ package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestResolveDestinationClassifiesCommittedPaths(t *testing.T) {
|
||||
@@ -81,6 +83,65 @@ func TestResolveDestinationClassifiesCommittedPaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveDestinationHandlesExpandingCyclesAndRepeatedLinks(t *testing.T) {
|
||||
repository := newTreeRepository(t)
|
||||
writeTreeFile(t, repository, "README.md", []byte("source\n"))
|
||||
for name, target := range map[string]string{
|
||||
"direct": "direct/child",
|
||||
"mutual-a": "mutual-b/child",
|
||||
"mutual-b": "mutual-a/child",
|
||||
"alias": ".",
|
||||
} {
|
||||
if err := os.Symlink(target, filepath.Join(repository, name)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
gitTree(t, repository, "add", "--all")
|
||||
gitTree(t, repository, "commit", "-m", "capture recursive links")
|
||||
tree, err := ReadCandidateTree(t.Context(), repository, strings.TrimSpace(gitTree(t, repository, "rev-parse", "HEAD")))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, test := range []struct {
|
||||
destination string
|
||||
kind DestinationKind
|
||||
}{
|
||||
{"direct", DestinationSymlinkCycle},
|
||||
{"mutual-a", DestinationSymlinkCycle},
|
||||
{"alias/alias/README.md", DestinationEntry},
|
||||
} {
|
||||
t.Run(test.destination, func(t *testing.T) {
|
||||
type result struct {
|
||||
destination Destination
|
||||
err error
|
||||
}
|
||||
done := make(chan result, 1)
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Second)
|
||||
defer cancel()
|
||||
go func() {
|
||||
destination, err := tree.ResolveDestination(ctx, "README.md", test.destination)
|
||||
done <- result{destination, err}
|
||||
}()
|
||||
select {
|
||||
case got := <-done:
|
||||
if got.err != nil || got.destination.Kind != test.kind {
|
||||
t.Fatalf("resolution = %#v, %v; want %s", got.destination, got.err, test.kind)
|
||||
}
|
||||
if test.kind == DestinationEntry && got.destination.Path != "README.md" {
|
||||
t.Fatalf("finite repeated link resolved to %q", got.destination.Path)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatal("symlink resolution did not finish")
|
||||
}
|
||||
})
|
||||
}
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
if _, err := tree.ResolveDestination(ctx, "README.md", "alias/README.md"); !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("canceled resolution error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveDestinationIgnoresNeighboringFiles(t *testing.T) {
|
||||
repository := newTreeRepository(t)
|
||||
writeTreeFile(t, repository, "docs/page.md", []byte("source\n"))
|
||||
|
||||
Reference in New Issue
Block a user